Compare commits

..

18 Commits

Author SHA1 Message Date
Chun-wei Fan
24d25b0db5 build: Check HarfBuzz has GDI support built in on Windows
We are using APIs from there.  Also enable GDI and DirectWrite if we are
building HarfBuzz as a fallback, and remove an extraneous HarfBuzz dependency
declaration.
2022-07-08 17:14:04 +08:00
Chun-wei Fan
30147b1a99 gtkimcontextime.c: Port to Pango2 APIs
Update the code to use Pango2 APIs, by removing includes to pangowin32, which
is gone, and replacing relevant calls to Pango2 equivilants.

Replace the call to pango_win32_font_logfontw() by retrieving instead the
underlying hb_font_t, and calling hb_uniscribe_font_get_logfontw(), but preedit
fonts are currently not working until a resolution to HarfBuzz issue #3683 can
be found.  Since we are still using Windows IME APIs for input, we need the
HarfBuzz GDI/Uniscribe items to be included in the HarfBuzz builds.
2022-07-08 17:14:04 +08:00
Chun-wei Fan
3979def662 GSK Vulkan: WIP port to Pango2 2022-07-08 17:14:04 +08:00
Chun-wei Fan
71ea2e2ecb gdk/win32: WIP Port to Pango2 2022-07-08 17:13:54 +08:00
Chun-wei Fan
c79b4e2e56 build: Don't try to use pangowin32 in deps
It's no longer there for Pango2.
2022-07-08 11:53:29 +08:00
Matthias Clasen
f7c4b26c59 Make a standalone font explorer
This is the font features demo, broken out as
a standalone application and cleaned up.
2022-07-06 13:45:11 -04:00
Matthias Clasen
a13cfde2a9 fixup clear_template 2022-07-05 20:43:53 -04:00
Emmanuele Bassi
3a5d161b8a Add gtk_widget_clear_template()
The dual of gtk_widget_init_template(), which should be used to clear
the template data associated with a specific GtkWidget type.
2022-07-05 20:43:53 -04:00
Matthias Clasen
baabb57df3 font demo: Keep up with api churn 2022-07-05 14:22:04 -04:00
Matthias Clasen
a69d39d945 fontchooser: Small fixes
Make initial property values match.
2022-07-05 14:22:04 -04:00
Matthias Clasen
646149bc72 Fontchooser: Add palette support
For fonts that have color palettes, optionally
allow the user to select one.

This is behind the new GTK_FONT_CHOOSER_LEVEL_PALETTE
flag. If it is enabled, you can use
gtk_font_chooser_get_palette() to get the
selected palette name.

The testfontchooserdialog test lets you play with
this. Fonts to try tihs with are Amiri Quran Colored
or the Bungee Color family.
2022-07-04 10:37:20 -04:00
Matthias Clasen
b01eb0600c Font demo: Add color palettes 2022-07-04 10:36:52 -04:00
Matthias Clasen
5b92bf51a0 Font demo: Keep a single paragraph
This is currently required for line height to
take effect (we may want to make the leading-trim
changeable).
2022-07-04 10:36:52 -04:00
Matthias Clasen
8ab180b3a9 Port to pango2 api 2022-07-04 10:36:48 -04:00
Matthias Clasen
897195b2f5 Compare family names case-insensitively 2022-07-04 10:36:47 -04:00
Matthias Clasen
d595cc1c55 Use modern C++
This is needed to build HarfBuzz as a subproject.
2022-07-04 10:36:47 -04:00
Matthias Clasen
2841256260 fontchooser: Make size level effective
We were not hiding the size controls on the tweaks
page, which is arguably what should happen when
the size level is disabled.
2022-07-04 10:36:47 -04:00
Matthias Clasen
ff0fec0f7d Beef up testfontchooserdialog
Allow testing levels.
2022-07-04 10:36:47 -04:00
2799 changed files with 156365 additions and 286149 deletions

View File

@@ -4,7 +4,6 @@ AlwaysBreakAfterDefinitionReturnType: All
BreakBeforeBinaryOperators: None
BinPackParameters: false
SpaceAfterCStyleCast: true
PointerAlignment: Right
# Our column limit is actually 80, but setting that results in clang-format
# making a lot of dubious hanging-indent choices; disable it and assume the
# developer will line wrap appropriately. clang-format will still check

View File

@@ -1,2 +0,0 @@
[flake8]
ignore = E501

1
.gitignore vendored
View File

@@ -1,2 +1 @@
/subprojects/*/
.flatpak-builder/

View File

@@ -3,7 +3,6 @@ include:
file: 'flatpak/flatpak_ci_initiative.yml'
stages:
- check
- build
- analysis
- docs
@@ -22,35 +21,29 @@ stages:
# Common variables
variables:
COMMON_MESON_FLAGS: "-Dwerror=true -Dcairo:werror=false -Dgi-docgen:werror=false -Dgraphene:werror=false -Dlibepoxy:werror=false -Dlibsass:werror=false -Dpango:werror=false -Dsassc:werror=false -Dgdk-pixbuf:werror=false -Dglib:werror=false -Dlibcloudproviders:werror=false -Dlibpng:werror=false -Dlibtiff:werror=false -Dsysprof:werror=false -Dwayland-protocols:werror=false -Dharfbuzz:werror=false -Dfreetype2:werror=false -Dfontconfig:werror=false -Dfribidi:werror=false -Dlibffi:werror=false -Dlibjpeg-turbo:werror=false -Dmutest:werror=false -Dpixman:werror=false -Dproxy-libintl:werror=false"
COMMON_MESON_FLAGS: "-Dwerror=true -Dglib:werror=false -Dpango:werror=false -Dgtk-doc:werror=false -Dwayland-protocols:werror=false -Dsysprof:werror=false"
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v48"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v38"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
workflow:
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH
default:
retry:
max: 2
when:
- 'runner_system_failure'
- 'stuck_or_timeout_failure'
- 'scheduler_failure'
- 'api_failure'
interruptible: true
.only-default:
only:
- branches
except:
- tags
style-check-diff:
extends: .only-default
image: $FEDORA_IMAGE
stage: check
when: manual
stage: .pre
allow_failure: true
script:
- .gitlab-ci/run-style-check-diff.sh
.build-fedora-default:
extends: .only-default
image: $FEDORA_IMAGE
artifacts:
when: always
@@ -58,7 +51,6 @@ style-check-diff:
junit:
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland_gles.xml"
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
name: "gtk-${CI_COMMIT_REF_NAME}"
paths:
@@ -70,12 +62,16 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/testsuite/tools/output/*/*"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
- "${CI_PROJECT_DIR}/_build/testsuite/headless/*/*.log"
- "${CI_PROJECT_DIR}/_build_hello/meson-logs"
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
- subprojects/gdk-pixbuf/
- subprojects/glib/
- subprojects/graphene/
- subprojects/libepoxy/
- subprojects/pango/
fedora-x86_64:
extends: .build-fedora-default
@@ -85,18 +81,19 @@ fedora-x86_64:
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- meson subprojects download
- meson subprojects update --reset
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
- meson subprojects update
- mkdir _install
- meson --prefix=${CI_PROJECT_DIR}/_install
${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
_build
- meson compile -C _build
- meson install -C _build
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
- .gitlab-ci/run-tests.sh _build x11
- .gitlab-ci/run-tests.sh _build wayland
- .gitlab-ci/run-tests.sh _build wayland_gles
- .gitlab-ci/run-tests.sh _build waylandgles
- .gitlab-ci/run-tests.sh _build broadway
release-build:
extends: .build-fedora-default
@@ -106,69 +103,38 @@ release-build:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- meson subprojects download
- meson subprojects update --reset
- mkdir _install
- meson setup
--prefix=${CI_PROJECT_DIR}/_install
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
- meson subprojects update
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
_build
- meson compile -C _build
- meson install -C _build
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
- ninja -C _build
- .gitlab-ci/run-tests.sh _build x11
fedora-clang:
installed-tests:
extends: .build-fedora-default
stage: build
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
EXTRA_MESON_FLAGS: "--prefix=/usr --libdir=/usr/lib64 -Dinstall-tests=true"
G_TEST_ACCESSIBLE: 1
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- export CC=clang
- meson subprojects download
- meson subprojects update --reset
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
- meson subprojects update
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
_build
- meson compile -C _build
- ninja -C _build
- sudo ninja -C _build install
- dbus-run-session xvfb-run -a -s "-screen 0 1024x768x24"
gnome-desktop-testing-runner
--report-directory=_build/installed-tests-report/failed/
--parallel=0
gtk-4.0
artifacts:
paths:
- "_build/installed-tests-report/"
fedora-mingw64:
extends: .build-fedora-default
stage: build
needs: []
before_script:
- sudo dnf install -y
mingw64-filesystem
mingw64-gcc
mingw64-binutils
mingw64-cairo
mingw64-gdk-pixbuf
mingw64-gstreamer1-plugins-bad-free
mingw64-glib2
mingw64-libepoxy
mingw64-pango
# mingw64-graphene (rawhide)
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- pip3 install --user meson~=1.0
- meson subprojects download
- meson subprojects update --reset
- meson -Dintrospection=disabled -Dgraphene:introspection=disabled _build
- meson compile -C _build
.mingw-defaults:
extends: .only-default
stage: build
tags:
- win32-ps
@@ -198,45 +164,39 @@ msys2-mingw64:
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
macos:
# Sadly, this fails regularly, and its failure is never enlightening
allow_failure: true
rules:
- if: $CI_PROJECT_NAMESPACE == "GNOME"
extends: .only-default
only:
- branches@GNOME/gtk
stage: build
tags:
- macos
needs: []
before_script:
- bash .gitlab-ci/show-info-osx.sh
- pip3 install --user meson~=1.0
- pip3 install --user meson==0.60.3
- pip3 install --user ninja
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
- export MESON_FORCE_BACKTRACE=1
script:
- meson setup ${COMMON_MESON_FLAGS}
-Dx11-backend=false
- meson -Dx11-backend=false
-Dbroadway-backend=true
-Dmacos-backend=true
-Dmedia-gstreamer=disabled
-Dintrospection=disabled
-Dcpp_std=c++11
-Dpixman:tests=disabled
-Dlibjpeg-turbo:simd=disabled
-Dbuild-demos=false
-Dbuild-tests=false
-Dbuild-examples=false
-Dbuild-testsuite=false
_build
- meson compile -C _build
- ninja -C _build
artifacts:
when: always
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
vs2017-x64:
extends: .only-default
# TODO: Uncomment this when ready to merge.
# rules:
# - if: $CI_PROJECT_NAMESPACE == "GNOME"
#only:
# - branches@GNOME/gtk
stage: build
tags:
- win32-ps
@@ -249,7 +209,7 @@ vs2017-x64:
- "${CI_PROJECT_DIR}/_build/meson-logs"
.flatpak-defaults:
image: "quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master"
image: $FLATPAK_IMAGE
stage: flatpak
allow_failure: true
tags:
@@ -259,104 +219,73 @@ vs2017-x64:
- "${APPID}-dev.flatpak"
- 'repo.tar'
expire_in: 1 day
rules:
# Only build Flatpak bundles automatically on main
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_COMMIT_BRANCH != "main"
when: "manual"
script:
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
flatpak:demo:
extends: '.flatpak-defaults'
# Manual jobs, for branches and MRs
.flatpak-manual:
extends: .flatpak-defaults
when: manual
# Only build Flatpak bundles automatically on main
.flatpak-main:
extends: .flatpak-defaults
only:
- main
flatpak-manual:demo:
extends: .flatpak-manual
needs: []
variables:
APPID: org.gtk.Demo4
flatpak:demo:aarch64:
extends: '.flatpak-defaults'
flatpak-main:demo:
extends: .flatpak-main
needs: []
tags:
- flatpak-aarch64
variables:
APPID: org.gtk.Demo4
flatpak:widget-factory:
extends: '.flatpak-defaults'
flatpak-manual:widget-factory:
extends: .flatpak-manual
needs: []
variables:
APPID: org.gtk.WidgetFactory4
flatpak:widget-factory:aarch64:
extends: '.flatpak-defaults'
flatpak-main:widget-factory:
extends: .flatpak-main
needs: []
tags:
- flatpak-aarch64
variables:
APPID: org.gtk.WidgetFactory4
flatpak:icon-browser:
extends: '.flatpak-defaults'
flatpak-manual:icon-browser:
extends: .flatpak-manual
needs: []
variables:
APPID: org.gtk.IconBrowser4
flatpak:icon-browser:aarch64:
extends: '.flatpak-defaults'
flatpak-main:icon-browser:
extends: .flatpak-main
needs: []
tags:
- flatpak-aarch64
variables:
APPID: org.gtk.IconBrowser4
flatpak:node-editor:
extends: '.flatpak-defaults'
needs: []
variables:
APPID: org.gtk.gtk4.NodeEditor
flatpak:node-editor:aarch64:
extends: '.flatpak-defaults'
needs: []
tags:
- flatpak-aarch64
variables:
APPID: org.gtk.gtk4.NodeEditor
# Publish the demo apps to the GNOME Nightly repo
# https://wiki.gnome.org/Apps/Nightly
# https://gitlab.gnome.org/GNOME/Initiatives/-/wikis/DevOps-with-Flatpak
nightly demo:
extends: '.publish_nightly'
needs: ['flatpak:demo']
nightly demo aarch64:
extends: '.publish_nightly'
needs: ['flatpak:demo:aarch64']
dependencies: ['flatpak-main:demo']
needs: ['flatpak-main:demo']
nightly factory:
extends: '.publish_nightly'
needs: ['flatpak:widget-factory']
nightly factory aarch64:
extends: '.publish_nightly'
needs: ['flatpak:widget-factory:aarch64']
dependencies: ['flatpak-main:widget-factory']
needs: ['flatpak-main:widget-factory']
nightly icon-browser:
extends: '.publish_nightly'
needs: ['flatpak:icon-browser']
nightly icon-browser aarch64:
extends: '.publish_nightly'
needs: ['flatpak:icon-browser:aarch64']
nightly node-editor:
extends: '.publish_nightly'
needs: ['flatpak:node-editor']
nightly node-editor aarch64:
extends: '.publish_nightly'
needs: ['flatpak:node-editor:aarch64']
dependencies: ['flatpak-main:icon-browser']
needs: ['flatpak-main:icon-browser']
static-scan:
image: $FEDORA_IMAGE
@@ -365,21 +294,15 @@ static-scan:
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug"
script:
- export PATH="$HOME/.local/bin:$PATH"
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
_scan_build
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} _scan_build
- ninja -C _scan_build scan-build
artifacts:
paths:
- _scan_build/meson-logs
allow_failure: true
# Run tests with the address sanitizer. We need to turn off introspection
# and f16c, since they are incompatible with asan
# Run tests with the address sanitizer. We need to turn off introspection,
# since it is incompatible with asan
asan-build:
image: $FEDORA_IMAGE
tags: [ asan ]
@@ -387,46 +310,22 @@ asan-build:
needs: []
variables:
script:
- export PATH="$HOME/.local/bin:$PATH"
- CC=clang meson setup
--buildtype=debugoptimized
-Db_sanitize=address
-Db_lundef=false
-Dbuild-demos=false
-Dbuild-tests=false
-Dbuild-examples=false
-Dintrospection=disabled
-Df16c=disabled
_build
- CC=clang meson --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=disabled _build
- ninja -C _build
- .gitlab-ci/run-tests.sh _build wayland
- .gitlab-ci/run-tests.sh _build wayland_gles
- .gitlab-ci/run-tests.sh _build x11
artifacts:
when: always
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
- _build/meson-logs
allow_failure: true
reference:
image: $FEDORA_IMAGE
stage: docs
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=release --force-fallback-for=gdk-pixbuf,pango"
script:
- export PATH="$HOME/.local/bin:$PATH"
- meson setup
${COMMON_MESON_FLAGS}
--buildtype=release
--force-fallback-for=gdk-pixbuf,pango
-Dintrospection=enabled
-Ddocumentation=true
-Dgtk_doc=true
-Dgdk-pixbuf:gtk_doc=true
-Dpango:gtk_doc=true
-Dbuild-demos=false
-Dbuild-examples=false
-Dbuild-tests=false
-Dbuild-testsuite=false
_build
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} -Dgtk_doc=true -Dgdk-pixbuf:gtk_doc=true -Dpango:gtk_doc=true _build
- meson compile -C _build
- mkdir -p _reference/
- mv _build/docs/reference/gdk/gdk4/ _reference/gdk4/
@@ -449,9 +348,9 @@ reference:
publish-docs:
image: fedora:latest
stage: publish
interruptible: false
needs: ['reference']
script:
- "curl -X POST -F token=${PAGES_TRIGGER_TOKEN} -F ref=docs-gtk-org https://gitlab.gnome.org/api/v4/projects/665/trigger/pipeline"
rules:
- if: $CI_COMMIT_REF_NAME == "main"
only:
refs:
- main

View File

@@ -1,4 +1,4 @@
FROM fedora:38
FROM fedora:36
RUN dnf -y install \
adwaita-icon-theme \
@@ -18,9 +18,7 @@ RUN dnf -y install \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
docbook-style-xsl \
elfutils-libelf-devel \
expat-devel \
fribidi-devel \
gcc \
gcc-c++ \
@@ -32,8 +30,7 @@ RUN dnf -y install \
glib2-static \
glibc-devel \
glibc-headers \
glslc \
gnupg2 \
gnome-desktop-testing \
gobject-introspection-devel \
graphene-devel \
graphviz \
@@ -74,22 +71,18 @@ RUN dnf -y install \
mesa-libEGL-devel \
mesa-libGLES-devel \
meson \
mutter \
ninja-build \
pango-devel \
pcre-devel \
pcre-static \
pipewire \
pipewire-gstreamer \
python3 \
python3-docutils \
python3-gobject \
python3-jinja2 \
python3-markdown \
python3-packaging \
python3-pip \
python3-pydbus \
python3-pygments \
python3-toml \
python3-typogrify \
python3-wheel \
redhat-rpm-config \
@@ -100,8 +93,9 @@ RUN dnf -y install \
weston \
weston-libs \
which \
wireplumber \
xorg-x11-server-Xvfb \
&& dnf install -y 'dnf-command(builddep)' \
&& dnf builddep -y wayland \
&& dnf clean all
# Enable sudo for wheel users

View File

@@ -16,15 +16,15 @@ flatpak-builder \
flatpak build ${builddir} meson \
--prefix=/app \
--libdir=/app/lib \
--buildtype=debugoptimized \
--buildtype=release \
-Dx11-backend=true \
-Dwayland-backend=true \
-Dprint-backends=file \
-Dbuild-tests=false \
-Dbuild-testsuite=false \
-Dbuild-examples=false \
-Dintrospection=disabled \
-Dbuild-demos=true \
-Ddemo-profile=devel \
-Ddemos=true \
-Dprofile=devel \
_flatpak_build
flatpak build ${builddir} ninja -C _flatpak_build install

View File

@@ -23,7 +23,6 @@ push=0
list=0
print_help=0
no_login=0
no_cache=0
while (($# > 0)); do
case "${1%%=*}" in
@@ -35,7 +34,6 @@ while (($# > 0)); do
--base|-b) read_arg base "$@" || shift;;
--version|-v) read_arg base_version "$@" || shift;;
--no-login) no_login=1;;
--no-cache) no_cache=1;;
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
esac
shift
@@ -105,21 +103,11 @@ TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
if [ $build == 1 ]; then
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
if [ $no_cache == 0 ]; then
${CMD} build \
${format} \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
else
${CMD} build \
${format} \
--no-cache \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
fi
${CMD} build \
${format} \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
exit $?
fi
@@ -138,8 +126,7 @@ if [ $run == 1 ]; then
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
${CMD} run \
--rm \
--userns=keep-id \
--volume "$(pwd)/..:/home/user/app:rw,z" \
--volume "$(pwd)/..:/home/user/app" \
--workdir "/home/user/app" \
--tty \
--interactive "${TAG}" \

View File

@@ -1,32 +0,0 @@
#!/usr/bin/sh
#
builddir=$1
suite=$2
unit=$3
echo "** builddir: ${builddir}"
echo "** suite: ${suite}"
echo "** unit: ${unit}"
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--print-errorlogs \
--setup=wayland \
--suite=${suite} \
--no-suite=failing \
--no-suite=flaky \
--no-suite=wayland_failing \
--no-suite=gsk-compare-broadway \
--verbose \
"${unit}"
exit_code=$?
kill ${compositor}
exit ${exit_code}

View File

@@ -2,43 +2,25 @@
set -e
ancestor_horizon=31 # days (one month)
# Recently, git is picky about directory ownership. Tell it not to worry.
git config --global --add safe.directory "$PWD"
# We need to add a new remote for the upstream target branch, since this script
# could be running in a personal fork of the repository which has out of date
# branches.
#
# Limit the fetch to a certain date horizon to limit the amount of data we get.
# If the branch was forked from origin/main before this horizon, it should
# probably be rebased.
if ! git ls-remote --exit-code upstream >/dev/null 2>&1 ; then
# We need to add a new remote for the upstream main, since this script could
# be running in a personal fork of the repository which has out of date branches.
if [ "${CI_PROJECT_NAMESPACE}" != "GNOME" ]; then
echo "Retrieving the current upstream repository from ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}..."
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
git fetch upstream
ORIGIN="upstream"
else
echo "Reusing the existing repository on ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"
ORIGIN="origin"
fi
# Work out the newest common ancestor between the detached HEAD that this CI job
# has checked out, and the upstream target branch (which will typically be
# `upstream/main` or `upstream/glib-2-62`).
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` or `${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}`
# are only defined if were running in a merge request pipeline,
# fall back to `${CI_DEFAULT_BRANCH}` or `${CI_COMMIT_BRANCH}` respectively
# otherwise.
source_branch="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-${CI_COMMIT_BRANCH}}"
target_branch="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}"
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" origin "${source_branch}"
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" upstream "${target_branch}"
newest_common_ancestor_sha=$(git merge-base upstream/${target_branch} origin/${source_branch})
if [ -z "${newest_common_ancestor_sha}" ]; then
echo "Couldnt find common ancestor with upstream main branch. This typically"
echo "happens if you branched from main a long time ago. Please update"
echo "your clone, rebase, and re-push your branch."
exit 1
fi
# `upstream/main` or `upstream/gtk-3-24`).
#
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` is only defined if were running in
# a merge request pipeline; fall back to `${CI_DEFAULT_BRANCH}` otherwise.
newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${ORIGIN}/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent HEAD) | head -1)
git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format" -p1
exit_status=$?
@@ -54,7 +36,7 @@ exit_status=$?
echo ""
echo "Note that clang-format output is advisory and cannot always match the"
echo "GTK coding style, documented at:"
echo " https://gitlab.gnome.org/GNOME/gtk/blob/main/docs/CODING-STYLE.md"
echo " https://gitlab.gnome.org/GNOME/gtk/blob/main/docs/CODING-STYLE"
echo "Warnings from this tool can be ignored in favour of the documented "
echo "coding style, or in favour of matching the style of existing"
echo "surrounding code."

View File

@@ -6,23 +6,19 @@ set +e
srcdir=$( pwd )
builddir=$1
backend=$2
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
# Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0
export G_SLICE=always-malloc
case "${backend}" in
x11)
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=gsk-compare-broadway
# Store the exit code for the CI run, but always
@@ -30,7 +26,7 @@ case "${backend}" in
exit_code=$?
;;
wayland*)
wayland)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
@@ -38,17 +34,31 @@ case "${backend}" in
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=${backend}_failing \
--no-suite=gsk-compare-broadway
exit_code=$?
exit_code=$?
kill ${compositor}
;;
waylandgles)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-6 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-6
meson test -C ${builddir} \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=gsk-compare-broadway
exit_code=$?
kill ${compositor}
;;
@@ -60,15 +70,14 @@ case "${backend}" in
export BROADWAY_DISPLAY=:5
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=gsk-compare-opengl
# don't let Broadway failures fail the run, for now
exit_code=0
kill ${server}
;;
@@ -82,18 +91,17 @@ esac
cd ${builddir}
$srcdir/.gitlab-ci/meson-junit-report.py \
--project-name=gtk \
--backend="${backend}" \
--job-id="${CI_JOB_NAME}" \
--output="report-${backend}.xml" \
"meson-logs/testlog-${backend}.json"
--project-name=gtk \
--backend=${backend} \
--job-id="${CI_JOB_NAME}" \
--output=report-${backend}.xml \
meson-logs/testlog-${backend}.json
$srcdir/.gitlab-ci/meson-html-report.py \
--project-name=gtk \
--backend="${backend}" \
--job-id="${CI_JOB_NAME}" \
--reftest-output-dir="testsuite/reftests/output/${backend}" \
--output="report-${backend}.html" \
"meson-logs/testlog-${backend}.json"
--project-name=gtk \
--backend=${backend} \
--job-id="${CI_JOB_NAME}" \
--reftest-output-dir="testsuite/reftests/output/${backend}" \
--output=report-${backend}.html \
meson-logs/testlog-${backend}.json
exit $exit_code

View File

@@ -5,7 +5,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
@echo on
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson~=0.64 || goto :error
pip3 install --upgrade --user meson==0.60.3 || goto :error
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
ninja -C _build || goto :error

View File

@@ -28,17 +28,35 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-graphene \
mingw-w64-$MSYS2_ARCH-json-glib \
mingw-w64-$MSYS2_ARCH-libepoxy \
mingw-w64-$MSYS2_ARCH-pango \
mingw-w64-$MSYS2_ARCH-pango2 \
mingw-w64-$MSYS2_ARCH-fribidi \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
mingw-w64-$MSYS2_ARCH-shared-mime-info \
mingw-w64-$MSYS2_ARCH-python-gobject \
mingw-w64-$MSYS2_ARCH-shaderc
mingw-w64-$MSYS2_ARCH-python-gobject
mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
# https://gitlab.gnome.org/GNOME/gtk/-/issues/2243
# https://gitlab.gnome.org/GNOME/gtk/-/issues/3002
if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
git clone https://gitlab.gnome.org/GNOME/glib.git _glib
meson setup _glib_build _glib
meson compile -C _glib_build
meson install -C _glib_build
fi
pkg-config --modversion glib-2.0
if ! pkg-config --atleast-version=1.50.0 pango; then
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
meson setup _pango_build _pango
meson compile -C _pango_build
meson install -C _pango_build
fi
pkg-config --modversion pango
# Build
ccache --zero-stats
ccache --show-stats

45
AUTHORS
View File

@@ -7,7 +7,7 @@ Peter Mattis <petm@xcf.berkeley.edu>
Spencer Kimball <spencer@xcf.berkeley.edu>
Josh MacDonald <jmacd@xcf.berkeley.edu>
The team that build GTK 2 (in alphabetical order)
The Team that build GTK 2 (in alphabetical order)
-------------------------------------------------
Shawn T. Amundson <amundson@gtk.org>
Jerome Bolliet <bolliet@gtk.org>
@@ -28,8 +28,9 @@ Jay Painter <jpaint@gtk.org>
Manish Singh <manish@gtk.org>
Owen Taylor <otaylor@gtk.org>
The team that built GTK 3
-------------------------
The current team (GTK 3 and 4)
------------------------------
Jonas Ådahl <jadahl@gmail.com>
Tim Bäder <mail@baedert.org>
Emmanuele Bassi <ebassi@gnome.org>
@@ -39,16 +40,6 @@ Carlos Garnacho <mrgarnacho@gmail.com>
Alexander Larsson <alexl@redhat.com>
Benjamin Otte <otte@gnome.org>
The current team (GTK 4)
------------------------
Jonas Ådahl <jadahl@gmail.com>
Emmanuele Bassi <ebassi@gnome.org>
Christian Hergert <chergert@gnome.org>
Chun-wei Fan <fanchunwei@src.gnome.org>
Matthias Clasen <mclasen@redhat.com>
Carlos Garnacho <mrgarnacho@gmail.com>
Benjamin Otte <otte@gnome.org>
There are many others who have contributed patches; we thank them,
GTK is much better because of them.
@@ -58,15 +49,35 @@ Over time, GTK has incorporated some pieces of software which
started as independent projects. We list the original authors here:
MS-Windows theme engine
-----------------------
Raymond Penners
Dom Lachowicz
Pixbuf theme engine
-------------------
Owen Taylor
IME input method
----------------
Takuro Ashie
Kazuki IWAMOTO
MacOS backend
-------------
Mac OS X backend
----------------
Anders Carlsson
GtkInspector (originally gtkparasite)
-------------------------------------
DirectFB backend
----------------
Denis Oliver Kropp
Sven Neumann
Mike Emmel
gtkparasite
-----------
Christian Hammond

View File

@@ -21,7 +21,7 @@ many things that we value:
Please, do not use the issue tracker for support questions. If you have
questions on how to use GTK effectively, you can use:
- the `gtk` [room on matrix](https://matrix.to/#/#gtk:gnome.org)
- the `#gtk` IRC channel on irc.gnome.org
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
You can also look at the GTK tag on [Stack
@@ -44,7 +44,6 @@ If you're reporting a bug make sure to list:
0. which version of GTK are you using?
0. which operating system are you using?
0. what display and graphics driver are you using?
0. the necessary steps to reproduce the issue
0. the expected outcome
0. a description of the behavior; screenshots are also welcome

150
LOG
View File

@@ -1,150 +0,0 @@
TAP version 13
# random seed: R02S22611f6aefc1121b0ab2dc5286960449
# GLib-GIO-DEBUG: _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for gsettings-backend
# GLib-GIO-DEBUG: Using cross-namespace EXTERNAL authentication (this will deadlock if server is GDBus < 2.73.3)
# GLib-GIO-DEBUG: Using cross-namespace EXTERNAL authentication (this will deadlock if server is GDBus < 2.73.3)
1..1
# Start of ops tests
# testcase 0 op 0
collecting#
Cubic 0: # M 100.000000 100.000000 C 150.000000 100.000000 200.000000 100.000000 250.000000 100.000000
Cubic 1: # M 250.000000 100.000000 C 300.000000 100.000000 350.000000 100.000000 400.000000 100.000000
Line 2: # M 400 100 L 200 300
Line 3: # M 200 300 L 100 100
Cubic 4: # M 200.000000 100.000000 C 250.000000 100.000000 300.000000 100.000000 350.000000 100.000000
Cubic 5: # M 350.000000 100.000000 C 400.000000 100.000000 450.000000 100.000000 500.000000 100.000000
Line 6: # M 500 100 L 300 300
Line 7: # M 300 300 L 200 100
splitting#
1 intersections between Cubic 0 and Cubic 1#
1 intersections between Cubic 0 and Line 3#
9 intersections between Cubic 0 and Cubic 4#
# split Cubic 0.0 from Cubic 0 at 0.666666: M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
split Cubic 0.1 from Cubic 0 at 0.666666: M 199.999893 100.000000 C 216.666595 100.000000 233.333298 100.000000 250.000000 100.000000split Cubic 0.4 from Cubic 0 at 0.00600814: M 200.300323 100.000000 C 216.866882 100.000000 233.433441 100.000000 250.000000 100.000000split Cubic 0.7 from Cubic 0 at 0.00604445: M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000# split Cubic 4.9 from Cubic 4 at 0.00533867: M 200.800812 100.000000 C 250.533875 100.000000 300.266937 100.000000 350.000000 100.000000
1 intersections between Cubic 0.1 and Line 7#
1 intersections between Cubic 1 and Line 2#
9 intersections between Cubic 1 and Cubic 4.9#
split Cubic 1.9 from Cubic 1 at 0.00534248: M 250.801361 100.000000 C 300.534241 100.000000 350.267120 100.000000 400.000000 100.000000# split Cubic 4.9.0 from Cubic 4.9 at 0.329756: M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000
# split Cubic 4.9.1 from Cubic 4.9 at 0.329756: M 250.000122 100.000000 C 283.333435 100.000000 316.666718 100.000000 350.000000 100.000000
# split Cubic 4.9.6 from Cubic 4.9 at 0.00500283: M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000
9 intersections between Cubic 1.9 and Cubic 5#
# split Cubic 1.9.0 from Cubic 1.9 at 0.664877: M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000
split Cubic 1.9.1 from Cubic 1.9 at 0.664877: M 350.000122 100.000000 C 366.666748 100.000000 383.333374 100.000000 400.000000 100.000000split Cubic 1.9.4 from Cubic 1.9 at 0.00601021: M 350.300598 100.000000 C 366.867065 100.000000 383.433533 100.000000 400.000000 100.000000split Cubic 1.9.7 from Cubic 1.9 at 0.00604655: M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000# split Cubic 5.9 from Cubic 5 at 0.00534248: M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
1 intersections between Line 2 and Line 3#
1 intersections between Line 2 and Line 7#
# split Line 2.0 from Line 2 at 0.666667: M 400 100 L 266.667 233.333
split Line 2.1 from Line 2 at 0.666667: M 266.667 233.333 L 200 300# split Line 7.0 from Line 7 at 0.333333: M 300 300 L 266.667 233.333
# split Line 7.1 from Line 7 at 0.333333: M 266.667 233.333 L 200 100
1 intersections between Cubic 4 and Cubic 4.9.0#
1 intersections between Cubic 4 and Line 7.1#
1 intersections between Cubic 4.9.0 and Cubic 4.9.1#
1 intersections between Cubic 4.9.1 and Cubic 4.9.6#
1 intersections between Cubic 4.9.6 and Cubic 5#
1 intersections between Cubic 5 and Cubic 5.9#
1 intersections between Cubic 5.9 and Line 6#
1 intersections between Line 6 and Line 7.0#
Cubic 0.0: # M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
Cubic 0.1: # M 199.999893 100.000000 C 200.100037 100.000000 200.200180 100.000000 200.300323 100.000000
Cubic 0.4: # M 200.300323 100.000000 C 200.400452 100.000000 200.500580 100.000000 200.600708 100.000000
Cubic 0.7: # M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000
Cubic 1: # M 250.000000 100.000000 C 250.267120 100.000000 250.534241 100.000000 250.801361 100.000000
Cubic 1.9.0: # M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000
Cubic 1.9.1: # M 350.000122 100.000000 C 350.100281 100.000000 350.200439 100.000000 350.300598 100.000000
Cubic 1.9.4: # M 350.300598 100.000000 C 350.400757 100.000000 350.500916 100.000000 350.601074 100.000000
Cubic 1.9.7: # M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000
Line 2.0: # M 400 100 L 266.667 233.333
Line 2.1: # M 266.667 233.333 L 200 300
Line 3: # M 200 300 L 100 100
Cubic 4: # M 200.000000 100.000000 C 200.266937 100.000000 200.533875 100.000000 200.800812 100.000000
Cubic 4.9.0: # M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000
Cubic 4.9.1: # M 250.000122 100.000000 C 250.166885 100.000000 250.333649 100.000000 250.500412 100.000000
Cubic 4.9.6: # M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000
Cubic 5: # M 350.000000 100.000000 C 350.267120 100.000000 350.534241 100.000000 350.801361 100.000000
Cubic 5.9: # M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
Line 6: # M 500 100 L 300 300
Line 7.0: # M 300 300 L 266.667 233.333
Line 7.1: # M 266.667 233.333 L 200 100
classifying#
01 Cubic 0.0: # M 100.000000 100.000000 C 133.333298 100.000000 166.666595 100.000000 199.999893 100.000000
[11 Cubic 0.7: # M 200.600708 100.000000 C 217.067139 100.000000 233.533569 100.000000 250.000000 100.000000 ]
[11 Cubic 1.9.0: # M 250.801361 100.000000 C 283.867615 100.000000 316.933868 100.000000 350.000122 100.000000 ]
[11 Cubic 1.9.7: # M 350.601074 100.000000 C 367.067383 100.000000 383.533691 100.000000 400.000000 100.000000 ]
[11 Line 2.0: # M 400 100 L 266.667 233.333 ]
01 Line 2.1: # M 266.667 233.333 L 200 300
01 Line 3: # M 200 300 L 100 100
[11 Cubic 4: # M 200.000000 100.000000 C 200.266937 100.000000 200.533875 100.000000 200.800812 100.000000 ]
[11 Cubic 4.9.0: # M 200.800812 100.000000 C 217.200577 100.000000 233.600342 100.000000 250.000122 100.000000 ]
[11 Cubic 4.9.6: # M 250.500412 100.000000 C 283.666931 100.000000 316.833466 100.000000 350.000000 100.000000 ]
[11 Cubic 5: # M 350.000000 100.000000 C 350.267120 100.000000 350.534241 100.000000 350.801361 100.000000 ]
01 Cubic 5.9: # M 350.801361 100.000000 C 400.534241 100.000000 450.267120 100.000000 500.000000 100.000000
01 Line 6: # M 500 100 L 300 300
01 Line 7.0: # M 300 300 L 266.667 233.333
[11 Line 7.1: # M 266.667 233.333 L 200 100 ]
fixups#
# found 3 bad nodes
# split Cubic 0/Cubic 4 BAD 200.600723 100.000000
# [11 Line 7.1 ] 116.565
# [11 Cubic 0.7 ] 180
# [11 Cubic 4 ] 180
# [11 Cubic 4 ] 180
# [11 Cubic 4.9.0 ] 180
# >01 Cubic 0.0 360
# split Cubic 1/Cubic 4.9 BAD 250.801376 100.000000
# [11 Cubic 1.9.0 ] 180
# [11 Cubic 4.9.6 ] 180
# [11 Cubic 0.7 ] 360
# [11 Cubic 4.9.0 ] 360
# split Cubic 1.9/Cubic 5 BAD 350.601105 100.000000
# [11 Cubic 1.9.7 ] 180
# [11 Cubic 5 ] 180
# [11 Cubic 5 ] 180
# <01 Cubic 5.9 180
# [11 Cubic 1.9.0 ] 360
# [11 Cubic 4.9.6 ] 360
reassembling#
start new contour Cubic 0.0#
# Cubic 0.0 ends at:
# start 0 100.000000 100.000000
# >01 Line 3 116.565
# (10 Cubic 0.0 ) 180
picking cw#
append Line 3#
# Line 3 ends at:
# end 2 200.000000 300.000000
# >01 Line 2.1 225
# (10 Line 3 ) 296.565
picking cw#
append Line 2.1#
# Line 2.1 ends at:
# split Line 2/Line 7 266.666656 233.333344
# (10 Line 2.1 ) 45
# >01 Line 7.0 116.565
# [11 Line 2.0 ] 225
# [11 Line 7.1 ] 296.565
picking cw#
append Line 7.0#
# Line 7.0 ends at:
# end 6 300.000000 300.000000
# >01 Line 6 225
# (10 Line 7.0 ) 296.565
picking cw#
append Line 6#
# Line 6 ends at:
# end 5 500.000000 100.000000
# (10 Line 6 ) 45
# >01 Cubic 5.9 360
picking cw#
append Cubic 5.9#
# Cubic 5.9 ends at:
# split Cubic 1.9/Cubic 5 BAD 350.601105 100.000000
# [11 Cubic 1.9.7 ] 180
# [11 Cubic 5 ] 180
# [11 Cubic 5 ] 180
# (10 Cubic 5.9 ) 180
# [11 Cubic 1.9.0 ] 360
# [11 Cubic 4.9.6 ] 360
picking cw#
**
ERROR:../testsuite/gsk/path-ops.c:359:test_ops_simple: assertion failed (s == tests[i].out): ("M 354.60110473632812 100 A 4 4 0 0 0 346.60110473632812 100 A 4 4 0 0 0 354.60110473632812 100 z M 252.80137634277344 100 A 2 2 0 0 0 248.80137634277344 100 A 2 2 0 0 0 252.80137634277344 100 z M 204.60072326660156 100 A 4 4 0 0 0 196.60072326660156 100 A 4 4 0 0 0 204.60072326660156 100 z" == "M 100 100 z")
not ok /ops/simple - ERROR:../testsuite/gsk/path-ops.c:359:test_ops_simple: assertion failed (s == tests[i].out): ("M 354.60110473632812 100 A 4 4 0 0 0 346.60110473632812 100 A 4 4 0 0 0 354.60110473632812 100 z M 252.80137634277344 100 A 2 2 0 0 0 248.80137634277344 100 A 2 2 0 0 0 252.80137634277344 100 z M 204.60072326660156 100 A 4 4 0 0 0 196.60072326660156 100 A 4 4 0 0 0 204.60072326660156 100 z" == "M 100 100 z")
Bail out!

1090
NEWS

File diff suppressed because it is too large Load Diff

View File

@@ -67,13 +67,6 @@ building for:
- [Graphene](https://github.com/ebassi/graphene)
- [Xkb-common](https://github.com/xkbcommon/libxkbcommon)
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
If you are building the X11 backend, you will also need:
- Xlib, and the following X extensions:
@@ -86,24 +79,32 @@ If you are building the X11 backend, you will also need:
- xdamage
- xcomposite
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
Once you have all the necessary dependencies, you can build GTK by using
Meson:
```sh
$ meson setup _build
$ meson compile -C_build
$ meson _build .
$ cd _build
$ ninja
```
You can run the test suite using:
```sh
$ meson test -C_build
$ meson test
```
And, finally, you can install GTK using:
```
$ sudo meson install -C_build
$ sudo ninja install
```
Complete information about installing GTK and related libraries
@@ -115,12 +116,19 @@ docs/reference/gtk/html/gtk-building.html
Or [online](https://docs.gtk.org/gtk4/building.html)
Building from git
-----------------
Default branch renamed to `main`
--------------------------------
The GTK sources are hosted on [gitlab.gnome.org](http://gitlab.gnome.org). The main
development branch is called `main`, and stable branches are named after their minor
version, for example `gtk-4-10`.
The default development branch of GTK has been renamed to `main`.
To update your local checkout, use:
```sh
git checkout master
git branch -m master main
git fetch
git branch --unset-upstream
git branch -u origin/main
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
```
How to report bugs
------------------

View File

@@ -54,7 +54,8 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dtests=false"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
{
@@ -104,8 +105,8 @@
"sources": [
{
"type": "archive",
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2",
"sha256": "475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39"
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.69.0/source/boost_1_69_0.tar.bz2",
"sha256": "8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406"
}
]
},
@@ -185,9 +186,9 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Denable_vulkan=no",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
"-Dprofile=devel"
],
"sources" : [
{

View File

@@ -54,7 +54,8 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dtests=false"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
{
@@ -114,9 +115,9 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Denable_vulkan=no",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
"-Dprofile=devel"
],
"sources" : [
{

View File

@@ -54,7 +54,8 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dtests=false"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
{
@@ -114,9 +115,9 @@
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Denable_vulkan=no",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
"-Dprofile=devel"
],
"sources" : [
{

View File

@@ -1,138 +0,0 @@
{
"app-id" : "org.gtk.gtk4.NodeEditor",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-node-editor",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
{
"name" : "wayland",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"-Ddocumentation=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
"branch" : "main"
}
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dtests=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name" : "pango",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
"branch" : "main"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
"branch" : "main"
}
]
}
],
"build-options" : {
"env" : {
"DBUS_SESSION_BUS_ADDRESS" : "''",
"GSK_RENDERER" : "opengl",
"GDK_DEBUG" : "vulkan-disable",
"G_ENABLE_DEBUG" : "true"
}
}
}

View File

@@ -1,201 +0,0 @@
#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: 2022 Collabora Inc.
# 2023 Emmanuele Bassi
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Original author: Xavier Claessens <xclaesse@gmail.com>
import argparse
import textwrap
from pathlib import Path
# Disable line length warnings as wrapping the C code templates would be hard
# flake8: noqa: E501
def gen_versions_macros(args, current_major_version, current_minor_version, current_micro_version):
with args.out_path.open("w", encoding="utf-8") as ofile, args.in_path.open(
"r", encoding="utf-8"
) as ifile:
for line in ifile.readlines():
if "@GDK_VERSIONS@" in line:
ofile.write(
textwrap.dedent(
f"""\
/**
* GDK_MAJOR_VERSION:
*
* The major version component of the library's version, e.g. "1" for "1.2.3".
*/
#define GDK_MAJOR_VERSION ({current_major_version})
/**
* GDK_MINOR_VERSION:
*
* The minor version component of the library's version, e.g. "2" for "1.2.3".
*/
#define GDK_MINOR_VERSION ({current_minor_version})
/**
* GDK_MICRO_VERSION:
*
* The micro version component of the library's version, e.g. "3" for "1.2.3".
*/
#define GDK_MICRO_VERSION ({current_micro_version})
"""
)
)
for minor in range(0, current_minor_version + 2, 2):
ofile.write(
textwrap.dedent(
f"""\
/**
* GDK_VERSION_{current_major_version}_{minor}:
*
* A macro that evaluates to the {current_major_version}.{minor} version of GTK, in a format
* that can be used by the C pre-processor.
*
* Since: {current_major_version}.{minor}
*/
#define GDK_VERSION_{current_major_version}_{minor} (G_ENCODE_VERSION ({current_major_version}, {minor}))
"""
)
)
else:
ofile.write(line)
def gen_visibility_macros(args, current_major_version, current_minor_version, current_micro_version):
"""
Generates a set of macros for each minor stable version of GTK
- GDK_DEPRECATED
- GDK_DEPRECATED_IN_…
- GDK_DEPRECATED_MACRO_IN_…
- GDK_DEPRECATED_ENUMERATOR_IN_…
- GDK_DEPRECATED_TYPE_IN_…
- GDK_AVAILABLE_IN_ALL
- GDK_AVAILABLE_IN_…
- GDK_AVAILABLE_STATIC_INLINE_IN_…
- GDK_AVAILABLE_MACRO_IN_…
- GDK_AVAILABLE_ENUMERATOR_IN_…
- GDK_AVAILABLE_TYPE_IN_…
- GDK_UNAVAILABLE(maj,min)
- GDK_UNAVAILABLE_STATIC_INLINE(maj,min)
"""
ns = args.namespace
with args.out_path.open("w", encoding="utf-8") as f:
f.write(
textwrap.dedent(
f"""\
#pragma once
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined({ns}_STATIC_COMPILATION)
# define _{ns}_EXPORT __declspec(dllexport)
# define _{ns}_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
# define _{ns}_EXPORT __attribute__((visibility("default")))
# define _{ns}_IMPORT
#else
# define _{ns}_EXPORT
# define _{ns}_IMPORT
#endif
#ifdef GTK_COMPILATION
# define _{ns}_API _{ns}_EXPORT
#else
# define _{ns}_API _{ns}_IMPORT
#endif
#define _{ns}_EXTERN _{ns}_API extern
#define {ns}_VAR _{ns}_EXTERN
#define {ns}_AVAILABLE_IN_ALL _{ns}_EXTERN
#ifdef GDK_DISABLE_DEPRECATION_WARNINGS
#define {ns}_DEPRECATED _{ns}_EXTERN
#define {ns}_DEPRECATED_FOR(f) _{ns}_EXTERN
#define {ns}_UNAVAILABLE(maj,min) _{ns}_EXTERN
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min)
#else
#define {ns}_DEPRECATED G_DEPRECATED _{ns}_EXTERN
#define {ns}_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _{ns}_EXTERN
#define {ns}_UNAVAILABLE(maj,min) G_UNAVAILABLE(maj,min) _{ns}_EXTERN
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min) G_UNAVAILABLE(maj,min)
#endif
"""
)
)
for minor in range(0, current_minor_version + 2, 2):
f.write(
textwrap.dedent(
f"""
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_{minor}
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} {ns}_DEPRECATED
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) {ns}_DEPRECATED_FOR (f)
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor} GDK_DEPRECATED_MACRO
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_MACRO_FOR (f)
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor} GDK_DEPRECATED_ENUMERATOR
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_ENUMERATOR_FOR (f)
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor} GDK_DEPRECATED_TYPE
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_TYPE_FOR (f)
#else
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} _{ns}_EXTERN
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) _{ns}_EXTERN
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f)
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f)
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f)
#endif
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_{current_major_version}_{minor}
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} {ns}_UNAVAILABLE ({current_major_version}, {minor})
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_STATIC_INLINE ({current_major_version}, {minor})
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_MACRO ({current_major_version}, {minor})
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_ENUMERATOR ({current_major_version}, {minor})
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_TYPE ({current_major_version}, {minor})
#else
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} _{ns}_EXTERN
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor}
#endif
"""
)
)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("gtk_version", help="Current GLib version")
subparsers = parser.add_subparsers()
versions_parser = subparsers.add_parser(
"versions-macros", help="Generate versions macros"
)
versions_parser.add_argument("in_path", help="input file", type=Path)
versions_parser.add_argument("out_path", help="output file", type=Path)
versions_parser.set_defaults(func=gen_versions_macros)
visibility_parser = subparsers.add_parser(
"visibility-macros", help="Generate visibility macros"
)
visibility_parser.add_argument("namespace", help="Macro namespace")
visibility_parser.add_argument("out_path", help="output file", type=Path)
visibility_parser.set_defaults(func=gen_visibility_macros)
args = parser.parse_args()
version = [int(i) for i in args.gtk_version.split(".")]
args.func(args, version[0], version[1], version[2])
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
if 'DESTDIR' not in os.environ:
gtk_api_version = sys.argv[1]
gtk_abi_version = sys.argv[2]
gtk_libdir = sys.argv[3]
gtk_datadir = sys.argv[4]
gtk_bindir = sys.argv[5]
gtk_moduledir = os.path.join(gtk_libdir, 'gtk-' + gtk_api_version, gtk_abi_version)
gtk_printmodule_dir = os.path.join(gtk_moduledir, 'printbackends')
gtk_mediamodule_dir = os.path.join(gtk_moduledir, 'media')
print('Compiling GSettings schemas...')
glib_compile_schemas = subprocess.check_output(['pkg-config',
'--variable=glib_compile_schemas',
'gio-2.0']).strip()
if not os.path.exists(glib_compile_schemas):
# pkg-config variables only available since GLib 2.62.0.
glib_compile_schemas = 'glib-compile-schemas'
subprocess.call([glib_compile_schemas,
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
print('Updating icon cache...')
update_icon_cache = os.path.join(gtk_bindir, 'gtk4-update-icon-cache')
subprocess.call([update_icon_cache, '-q', '-t' ,'-f',
os.path.join(gtk_datadir, 'icons', 'hicolor')])
print('Updating module cache for print backends...')
os.makedirs(gtk_printmodule_dir, exist_ok=True)
gio_querymodules = subprocess.check_output(['pkg-config',
'--variable=gio_querymodules',
'gio-2.0']).strip()
if not os.path.exists(gio_querymodules):
# pkg-config variables only available since GLib 2.62.0.
gio_querymodules = 'gio-querymodules'
subprocess.call([gio_querymodules, gtk_printmodule_dir])
print('Updating module cache for media backends...')
os.makedirs(gtk_mediamodule_dir, exist_ok=True)
subprocess.call([gio_querymodules, gtk_mediamodule_dir])

View File

@@ -202,36 +202,43 @@ constraint_editor_window_load (ConstraintEditorWindow *self,
}
static void
open_response_cb (GObject *source,
GAsyncResult *result,
void *user_data)
open_response_cb (GtkNativeDialog *dialog,
int response,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
ConstraintEditorWindow *self = user_data;
GFile *file;
gtk_native_dialog_hide (dialog);
file = gtk_file_dialog_open_finish (dialog, result, NULL);
if (file)
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
constraint_editor_window_load (self, file);
g_object_unref (file);
}
gtk_native_dialog_destroy (dialog);
}
static void
open_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog;
GFile *cwd;
GtkFileChooserNative *dialog;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_title (dialog, "Open file");
cwd = g_file_new_for_path (".");
gtk_file_dialog_set_initial_folder (dialog, cwd);
dialog = gtk_file_chooser_native_new ("Open file",
GTK_WINDOW (self),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Load",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
GFile *cwd = g_file_new_for_path (".");
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
g_object_unref (cwd);
gtk_file_dialog_open (dialog, GTK_WINDOW (self), NULL, open_response_cb, self);
g_object_unref (dialog);
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
@@ -287,23 +294,22 @@ serialize_model (GListModel *list)
static void
save_response_cb (GObject *source,
GAsyncResult *result,
void *user_data)
save_response_cb (GtkNativeDialog *dialog,
int response,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
ConstraintEditorWindow *self = user_data;
GFile *file;
gtk_native_dialog_hide (dialog);
file = gtk_file_dialog_save_finish (dialog, result, NULL);
if (file)
if (response == GTK_RESPONSE_ACCEPT)
{
GListModel *model;
GFile *file;
char *text;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
g_file_replace_contents (file, text, strlen (text),
NULL, FALSE,
G_FILE_CREATE_NONE,
@@ -312,46 +318,54 @@ save_response_cb (GObject *source,
&error);
if (error != NULL)
{
GtkAlertDialog *alert;
GtkWidget *message_dialog;
alert = gtk_alert_dialog_new ("Saving failed");
gtk_alert_dialog_set_detail (alert, error->message);
gtk_alert_dialog_show (alert,
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))));
g_object_unref (alert);
message_dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog),
"%s", error->message);
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
gtk_widget_show (message_dialog);
g_error_free (error);
}
g_free (text);
g_object_unref (file);
}
gtk_native_dialog_destroy (dialog);
}
static void
save_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog;
GFile *cwd;
GtkFileChooserNative *dialog;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_title (dialog, "Save constraints");
cwd = g_file_new_for_path (".");
gtk_file_dialog_set_initial_folder (dialog, cwd);
dialog = gtk_file_chooser_native_new ("Save constraints",
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Save",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
GFile *cwd = g_file_new_for_path (".");
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
g_object_unref (cwd);
gtk_file_dialog_save (dialog,
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
NULL,
save_response_cb, self);
g_object_unref (dialog);
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
constraint_editor_window_dispose (GObject *object)
constraint_editor_window_finalize (GObject *object)
{
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_WINDOW_TYPE);
//ConstraintEditorWindow *self = (ConstraintEditorWindow *)object;
G_OBJECT_CLASS (constraint_editor_window_parent_class)->dispose (object);
G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object);
}
static int child_counter;
@@ -426,7 +440,7 @@ edit_constraint (ConstraintEditorWindow *win,
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
gtk_window_present (GTK_WINDOW (window));
gtk_widget_show (window);
}
static void
@@ -459,7 +473,7 @@ edit_guide (ConstraintEditorWindow *win,
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
gtk_window_present (GTK_WINDOW (window));
gtk_widget_show (window);
}
static void
@@ -483,9 +497,7 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->dispose = constraint_editor_window_dispose;
object_class->finalize = constraint_editor_window_finalize;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor-window.ui");

View File

@@ -20,7 +20,6 @@
#include "config.h"
#include "constraint-editor.h"
#include "constraint-view.h"
struct _ConstraintEditor
{
@@ -65,7 +64,7 @@ static const char *
get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "Super";
return "super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
@@ -79,29 +78,62 @@ constraint_target_combo (GListModel *model,
GtkWidget *combo,
gboolean is_source)
{
GtkStringList *targets;
int i;
targets = gtk_string_list_new (NULL);
gtk_string_list_append (targets, "Super");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "super", "Super");
if (model)
{
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
const char *name;
if (GTK_IS_CONSTRAINT (item))
continue;
gtk_string_list_append (targets, get_target_name (GTK_CONSTRAINT_TARGET (item)));
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
g_object_unref (item);
}
}
}
gtk_drop_down_set_model (GTK_DROP_DOWN (combo), G_LIST_MODEL (targets));
g_object_unref (targets);
static void
constraint_attribute_combo (GtkWidget *combo,
gboolean is_source)
{
if (is_source)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "none", "None");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "left", "Left");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "right", "Right");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "top", "Top");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "bottom", "Bottom");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "start", "Start");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "end", "End");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "width", "Width");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "height", "Height");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-x", "Center X");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-y", "Center Y");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "baseline", "Baseline");
}
static void
constraint_relation_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "le", "");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "eq", "=");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "ge", "");
}
static void
constraint_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static gpointer
@@ -113,7 +145,7 @@ get_target (GListModel *model,
if (id == NULL)
return NULL;
if (strcmp ("Super", id) == 0)
if (strcmp ("super", id) == 0)
return NULL;
for (i = 0; i < g_list_model_get_n_items (model); i++)
@@ -137,65 +169,16 @@ get_target (GListModel *model,
return NULL;
}
static void
select_target (GtkDropDown *combo,
const char *target_name)
{
GListModel *model = gtk_drop_down_get_model (combo);
for (unsigned int i = 0; i < g_list_model_get_n_items (model); i++)
{
GtkStringObject *s = g_list_model_get_item (model, i);
g_object_unref (s);
if (strcmp (target_name, gtk_string_object_get_string (s)) == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), i);
return;
}
}
}
static GtkConstraintAttribute
get_attr (unsigned int id)
get_target_attr (const char *id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_ATTRIBUTE_NONE;
case 1: return GTK_CONSTRAINT_ATTRIBUTE_LEFT;
case 2: return GTK_CONSTRAINT_ATTRIBUTE_RIGHT;
case 3: return GTK_CONSTRAINT_ATTRIBUTE_TOP;
case 4: return GTK_CONSTRAINT_ATTRIBUTE_BOTTOM;
case 5: return GTK_CONSTRAINT_ATTRIBUTE_START;
case 6: return GTK_CONSTRAINT_ATTRIBUTE_END;
case 7: return GTK_CONSTRAINT_ATTRIBUTE_WIDTH;
case 8: return GTK_CONSTRAINT_ATTRIBUTE_HEIGHT;
case 9: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_X;
case 10: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y;
case 11: return GTK_CONSTRAINT_ATTRIBUTE_BASELINE;
default: g_assert_not_reached ();
}
}
GtkConstraintAttribute attr;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
attr = value->value;
g_type_class_unref (class);
static unsigned int
get_attr_id (GtkConstraintAttribute attr)
{
switch (attr)
{
case GTK_CONSTRAINT_ATTRIBUTE_NONE: return 0;
case GTK_CONSTRAINT_ATTRIBUTE_LEFT: return 1;
case GTK_CONSTRAINT_ATTRIBUTE_RIGHT: return 2;
case GTK_CONSTRAINT_ATTRIBUTE_TOP: return 3;
case GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: return 4;
case GTK_CONSTRAINT_ATTRIBUTE_START: return 5;
case GTK_CONSTRAINT_ATTRIBUTE_END: return 6;
case GTK_CONSTRAINT_ATTRIBUTE_WIDTH: return 7;
case GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: return 8;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: return 9;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: return 10;
case GTK_CONSTRAINT_ATTRIBUTE_BASELINE: return 11;
default: g_assert_not_reached ();
}
return attr;
}
static const char *
@@ -210,27 +193,15 @@ get_attr_nick (GtkConstraintAttribute attr)
}
static GtkConstraintRelation
get_relation (unsigned int id)
get_relation (const char *id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_RELATION_LE;
case 1: return GTK_CONSTRAINT_RELATION_EQ;
case 2: return GTK_CONSTRAINT_RELATION_GE;
default: g_assert_not_reached ();
}
}
GtkConstraintRelation relation;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
relation = value->value;
g_type_class_unref (class);
static unsigned int
get_relation_id (GtkConstraintRelation relation)
{
switch (relation)
{
case GTK_CONSTRAINT_RELATION_LE: return 0;
case GTK_CONSTRAINT_RELATION_EQ: return 1;
case GTK_CONSTRAINT_RELATION_GE: return 2;
default: g_assert_not_reached ();
}
return relation;
}
static const char *
@@ -261,29 +232,15 @@ get_relation_display_name (GtkConstraintRelation relation)
}
static GtkConstraintStrength
get_strength (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
get_strength (const char *id)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
@@ -335,7 +292,7 @@ static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
{
gpointer obj;
const char *id;
gpointer target;
GtkConstraintAttribute target_attr;
gpointer source;
@@ -346,27 +303,25 @@ create_constraint (GtkButton *button,
int strength;
GtkConstraint *constraint;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
if (obj)
target = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
target = NULL;
target_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->target_attr)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
target = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
target_attr = get_target_attr (id);
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
if (obj)
source = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
source = NULL;
source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN(editor->source_attr)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
relation = get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation));
relation = get_relation (id);
multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL);
constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL);
strength = get_strength (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
constraint = gtk_constraint_new (target, target_attr,
relation,
@@ -381,9 +336,12 @@ create_constraint (GtkButton *button,
static void
source_attr_changed (ConstraintEditor *editor)
{
if (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))) == GTK_CONSTRAINT_ATTRIBUTE_NONE)
const char *id;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (id, "none") == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source), GTK_INVALID_LIST_POSITION);
gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), -1);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "");
gtk_widget_set_sensitive (editor->source, FALSE);
gtk_widget_set_sensitive (editor->multiplier, FALSE);
@@ -449,7 +407,7 @@ update_preview (ConstraintEditor *editor)
GString *str;
const char *name;
const char *attr;
const char *relation;
char *relation;
const char *multiplier;
const char *constant;
double c, m;
@@ -459,22 +417,23 @@ update_preview (ConstraintEditor *editor)
str = g_string_new ("");
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target))));
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected ((GTK_DROP_DOWN (editor->target_attr)))));
relation = get_relation_nick (get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation))));
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
g_free (relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (attr, "none") != 0)
{
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source))));
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
@@ -502,18 +461,12 @@ update_preview (ConstraintEditor *editor)
static void
update_button (ConstraintEditor *editor)
{
gpointer obj;
const char *target;
const char *source;
GtkConstraintAttribute source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr)));
const char *target = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
const char *source = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
const char *source_attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
target = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
source = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
if (target && (source || (source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
if (target &&
(source || (source_attr && get_target_attr (source_attr) == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
@@ -531,7 +484,12 @@ constraint_editor_constructed (GObject *object)
ConstraintEditor *editor = CONSTRAINT_EDITOR (object);
constraint_target_combo (editor->model, editor->target, FALSE);
constraint_attribute_combo (editor->target_attr, FALSE);
constraint_relation_combo (editor->relation);
constraint_target_combo (editor->model, editor->source, TRUE);
constraint_attribute_combo (editor->source_attr, TRUE);
constraint_strength_combo (editor->strength);
if (editor->constraint)
{
@@ -539,24 +497,30 @@ constraint_editor_constructed (GObject *object)
GtkConstraintAttribute attr;
GtkConstraintRelation relation;
GtkConstraintStrength strength;
const char *nick;
char *val;
double multiplier;
double constant;
target = gtk_constraint_get_target (editor->constraint);
select_target (GTK_DROP_DOWN (editor->target), get_target_name (target));
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick);
attr = gtk_constraint_get_target_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (attr));
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), nick);
target = gtk_constraint_get_source (editor->constraint);
select_target (GTK_DROP_DOWN (editor->source), get_target_name (target));
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), nick);
attr = gtk_constraint_get_source_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (attr));
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), nick);
relation = gtk_constraint_get_relation (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (relation));
nick = get_relation_nick (relation);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), nick);
multiplier = gtk_constraint_get_multiplier (editor->constraint);
val = g_strdup_printf ("%g", multiplier);
@@ -569,16 +533,17 @@ constraint_editor_constructed (GObject *object)
g_free (val);
strength = gtk_constraint_get_strength (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (GTK_CONSTRAINT_RELATION_EQ));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "required");
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0");
gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0");
@@ -642,11 +607,10 @@ constraint_editor_dispose (GObject *object)
{
ConstraintEditor *self = (ConstraintEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->model);
g_clear_object (&self->constraint);
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_TYPE);
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
}

View File

@@ -1,21 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkStringList" id="targets">
<items>
<item>None</item>
<item>Left</item>
<item>Right</item>
<item>Top</item>
<item>Bottom</item>
<item>Start</item>
<item>End</item>
<item>Width</item>
<item>Height</item>
<item>Center X</item>
<item>Center Y</item>
<item>Baseline</item>
</items>
</object>
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
@@ -35,9 +19,9 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="target">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="target">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">1</property>
@@ -45,9 +29,8 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="target_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<object class="GtkComboBoxText" id="target_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">1</property>
@@ -64,17 +47,8 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="relation">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<property name="model">
<object class="GtkStringList">
<items>
<item>≤</item>
<item>=</item>
<item>≥</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="relation">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">2</property>
@@ -91,9 +65,9 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="source">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="source">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
@@ -101,11 +75,10 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="source_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="source_attr_changed" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="source_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="source_attr_changed" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
@@ -158,17 +131,7 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="column">1</property>
<property name="row">6</property>

View File

@@ -57,30 +57,25 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
static GtkConstraintStrength
get_strength (unsigned int id)
static void
guide_strength_combo (GtkWidget *combo)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
static GtkConstraintStrength
get_strength (const char *id)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
@@ -121,11 +116,11 @@ static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
const char *id;
int strength;
const char *name;
int w, h;
GtkConstraintGuide *guide;
unsigned int id;
if (editor->guide)
guide = g_object_ref (editor->guide);
@@ -147,7 +142,7 @@ create_guide (GtkButton *button,
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
id = gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
@@ -194,9 +189,14 @@ guide_editor_constructed (GObject *object)
{
GuideEditor *editor = GUIDE_EDITOR (object);
guide_strength_combo (editor->strength);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
if (editor->guide)
@@ -222,7 +222,8 @@ guide_editor_constructed (GObject *object)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_constraint_guide_get_strength (editor->guide);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
@@ -242,7 +243,7 @@ guide_editor_constructed (GObject *object)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_MEDIUM));
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
@@ -293,10 +294,9 @@ guide_editor_dispose (GObject *object)
{
GuideEditor *self = (GuideEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->guide);
gtk_widget_dispose_template (GTK_WIDGET (self), GUIDE_EDITOR_TYPE);
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
}

View File

@@ -167,17 +167,7 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="column">1</property>
<property name="row">4</property>

View File

@@ -9,7 +9,7 @@ constraint_editor_sources = [
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
'constraint-editor.gresource.xml',
source_dir: meson.current_source_dir(),
source_dir: '.',
)
executable('gtk4-constraint-editor',

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
#include "fontcolors.h"
#include "rangeedit.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_FONT_DESC = 1,
PROP_PALETTE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontColors
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
gboolean has_colors;
char *palette;
GtkCheckButton *default_check;
};
struct _FontColorsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (FontColors, font_colors, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontColors *self)
{
Pango2Context *context;
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
return pango2_context_load_font (context, self->font_desc);
}
static void
palette_changed (GtkCheckButton *button,
FontColors *self)
{
g_free (self->palette);
self->palette = g_strdup ((const char *) g_object_get_data (G_OBJECT (button), "palette"));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
}
static void
update_colors (FontColors *self)
{
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
GtkWidget *child;
GtkWidget *check;
unsigned int n_colors;
hb_color_t *colors;
GtkWidget *box;
g_object_ref (self->label);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
gtk_grid_remove (self->grid, child);
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -4, 2, 1);
g_object_unref (self->label);
self->default_check = NULL;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
self->has_colors = hb_ot_color_has_palettes (hb_face);
gtk_widget_set_visible (GTK_WIDGET (self), self->has_colors);
if (!self->has_colors)
{
g_simple_action_set_enabled (self->reset_action, FALSE);
return;
}
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
gtk_grid_attach (self->grid, box, 0, -3, 2, 1);
check = gtk_check_button_new_with_label ("Default");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"default");
if (g_strcmp0 ("default", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_box_append (GTK_BOX (box), check);
self->default_check = GTK_CHECK_BUTTON (check);
check = gtk_check_button_new_with_label ("Light");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"light");
if (g_strcmp0 ("light", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_box_append (GTK_BOX (box), check);
check = gtk_check_button_new_with_label ("Dark");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"dark");
if (g_strcmp0 ("dark", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_box_append (GTK_BOX (box), check);
for (int i = 0; i < hb_ot_color_palette_get_count (hb_face); i++)
{
char *id = g_strdup_printf ("palette%d", i);
char *label = g_strdup_printf ("Palette %d", i);
GtkWidget *palette;
check = gtk_check_button_new_with_label (label);
g_object_set_data_full (G_OBJECT (check), "palette", id, g_free);
if (g_strcmp0 (id, self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_grid_attach (self->grid, check, 0, i, 1, 1);
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, NULL, NULL);
colors = g_new (hb_color_t, n_colors);
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, &n_colors, colors);
palette = gtk_grid_new ();
gtk_widget_set_valign (palette, GTK_ALIGN_CENTER);
gtk_grid_attach (self->grid, palette, 1, i, 1, 1);
/* HACK - defeat first-child/last-child theming */
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), -1, 0, 1, 1);
for (int k = 0; k < n_colors; k++)
{
GtkWidget *swatch;
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
"rgba", &(GdkRGBA){ hb_color_get_red (colors[k])/255.,
hb_color_get_green (colors[k])/255.,
hb_color_get_blue (colors[k])/255.,
hb_color_get_alpha (colors[k])/255.},
"selectable", FALSE,
"has-menu", FALSE,
"can-drag", FALSE,
"width-request", 16,
"height-request", 16,
NULL);
gtk_grid_attach (GTK_GRID (palette), swatch, k % 6, k / 6, 1, 1);
}
/* HACK - defeat first-child/last-child theming */
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), 6, 0, 1, 1);
}
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontColors *self)
{
g_free (self->palette);
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
if (self->has_colors)
gtk_check_button_set_active (self->default_check, TRUE);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_colors_init (FontColors *self)
{
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_colors_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_COLORS_TYPE);
G_OBJECT_CLASS (font_colors_parent_class)->dispose (object);
}
static void
font_colors_finalize (GObject *object)
{
FontColors *self = FONT_COLORS (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
g_free (self->palette);
G_OBJECT_CLASS (font_colors_parent_class)->finalize (object);
}
static void
font_colors_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontColors *self = FONT_COLORS (object);
switch (prop_id)
{
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
update_colors (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_colors_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontColors *self = FONT_COLORS (object);
switch (prop_id)
{
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_colors_class_init (FontColorsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_colors_dispose;
object_class->finalize = font_colors_finalize;
object_class->get_property = font_colors_get_property;
object_class->set_property = font_colors_set_property;
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontcolors.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, label);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcolors");
}
FontColors *
font_colors_new (void)
{
return g_object_new (FONT_COLORS_TYPE, NULL);
}
GAction *
font_colors_get_reset_action (FontColors *self)
{
return G_ACTION (self->reset_action);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_COLORS_TYPE (font_colors_get_type ())
#define FONT_COLORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_COLORS_TYPE, FontColors))
typedef struct _FontColors FontColors;
typedef struct _FontColorsClass FontColorsClass;
GType font_colors_get_type (void);
FontColors * font_colors_new (void);
GAction * font_colors_get_reset_action (FontColors *self);

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontColors" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Colors</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-2</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,271 @@
#include "fontcontrols.h"
#include "rangeedit.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_SIZE = 1,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
PROP_DISABLE_SIZE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontControls
{
GtkWidget parent;
GtkAdjustment *size_adjustment;
GtkAdjustment *letterspacing_adjustment;
GtkAdjustment *line_height_adjustment;
GtkColorButton *foreground;
GtkColorButton *background;
GSimpleAction *reset_action;
gboolean disable_size;
};
struct _FontControlsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontControls, font_controls, GTK_TYPE_WIDGET);
static void
size_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
letterspacing_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LETTERSPACING]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
line_height_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_HEIGHT]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
color_set (GtkColorButton *button,
GParamSpec *pspec,
FontControls *self)
{
if (button == self->foreground)
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOREGROUND]);
else
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
swap_colors (GtkButton *button,
FontControls *self)
{
GdkRGBA fg;
GdkRGBA bg;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &fg);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &bg);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &bg);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &fg);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontControls *self)
{
gtk_adjustment_set_value (self->size_adjustment, 12.);
gtk_adjustment_set_value (self->letterspacing_adjustment, 0.);
gtk_adjustment_set_value (self->line_height_adjustment, 1.);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &(GdkRGBA){0., 0., 0., 1.0 });
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &(GdkRGBA){1., 1., 1., 1.0 });
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_controls_init (FontControls *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_controls_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_CONTROLS_TYPE);
G_OBJECT_CLASS (font_controls_parent_class)->dispose (object);
}
static void
font_controls_finalize (GObject *object)
{
//FontControls *self = FONT_CONTROLS (object);
G_OBJECT_CLASS (font_controls_parent_class)->finalize (object);
}
static void
font_controls_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontControls *self = FONT_CONTROLS (object);
switch (prop_id)
{
case PROP_SIZE:
gtk_adjustment_set_value (self->size_adjustment, g_value_get_float (value));
break;
case PROP_DISABLE_SIZE:
self->disable_size = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_controls_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontControls *self = FONT_CONTROLS (object);
switch (prop_id)
{
case PROP_SIZE:
g_value_set_float (value, gtk_adjustment_get_value (self->size_adjustment));
break;
case PROP_LETTERSPACING:
g_value_set_int (value, (int) gtk_adjustment_get_value (self->letterspacing_adjustment));
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, gtk_adjustment_get_value (self->line_height_adjustment));
break;
case PROP_FOREGROUND:
{
GdkRGBA rgba;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &rgba);
g_value_set_boxed (value, &rgba);
}
break;
case PROP_BACKGROUND:
{
GdkRGBA rgba;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &rgba);
g_value_set_boxed (value, &rgba);
}
break;
case PROP_DISABLE_SIZE:
g_value_set_boolean (value, self->disable_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_controls_class_init (FontControlsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_ensure (RANGE_EDIT_TYPE);
object_class->dispose = font_controls_dispose;
object_class->finalize = font_controls_finalize;
object_class->get_property = font_controls_get_property;
object_class->set_property = font_controls_set_property;
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READABLE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READABLE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READABLE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READABLE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READABLE);
properties[PROP_DISABLE_SIZE] =
g_param_spec_boolean ("disable-size", "", "",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontcontrols.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, size_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, letterspacing_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, line_height_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, foreground);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, background);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), size_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), letterspacing_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), line_height_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), color_set);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), swap_colors);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcontrols");
}
FontControls *
font_controls_new (void)
{
return g_object_new (FONT_CONTROLS_TYPE, NULL);
}
GAction *
font_controls_get_reset_action (FontControls *self)
{
return G_ACTION (self->reset_action);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_CONTROLS_TYPE (font_controls_get_type ())
#define FONT_CONTROLS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_CONTROLS_TYPE, FontControls))
typedef struct _FontControls FontControls;
typedef struct _FontControlsClass FontControlsClass;
GType font_controls_get_type (void);
FontControls * font_controls_new (void);
GAction * font_controls_get_reset_action (FontControls *self);

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontControls" parent="GtkWidget">
<property name="layout-manager"><object class="GtkGridLayout"/></property>
<child>
<object class="GtkLabel">
<property name="sensitive" bind-source="FontControls" bind-property="disable-size" bind-flags="invert-boolean"/>
<property name="label">Size</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="sensitive" bind-source="FontControls" bind-property="disable-size" bind-flags="invert-boolean"/>
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="size_adjustment">
<property name="lower">7</property>
<property name="upper">100</property>
<property name="value">14</property>
<property name="step_increment">0.5</property>
<property name="page_increment">10</property>
<signal name="value-changed" handler="size_changed"/>
</object>
</property>
<property name="default-value">12</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Letterspacing</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="letterspacing_adjustment">
<property name="lower">-1024</property>
<property name="upper">8192</property>
<property name="value">0</property>
<property name="step_increment">1</property>
<property name="page_increment">512</property>
<signal name="value-changed" handler="letterspacing_changed"/>
</object>
</property>
<property name="default-value">0</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Line Height</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="line_height_adjustment">
<property name="lower">0.75</property>
<property name="upper">2.5</property>
<property name="value">1.0</property>
<property name="step_increment">0.1</property>
<property name="page_increment">1</property>
<signal name="value-changed" handler="line_height_changed"/>
</object>
</property>
<property name="default-value">1</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Foreground</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="foreground">
<property name="rgba">black</property>
<signal name="notify::rgba" handler="color_set"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Background</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="background">
<property name="rgba">white</property>
<signal name="notify::rgba" handler="color_set"/>
<layout>
<property name="column">1</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">object-flip-vertical-symbolic</property>
<property name="halign">start</property>
<property name="valign">center</property>
<style>
<class name="circular"/>
</style>
<signal name="clicked" handler="swap_colors"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
<property name="row-span">2</property>
</layout>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,20 @@
box.sidebar {
padding: 20px;
border-spacing: 20px;
}
fontcontrols {
border-spacing: 10px;
}
fontvariations > grid {
border-spacing: 10px;
}
fontcolors > grid {
border-spacing: 10px;
}
samplechooser {
border-spacing: 10px;
}
fontview {
padding: 10px;
border-spacing: 10px;
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/fontexplorer">
<file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
<file preprocess="xml-stripblanks">fontview.ui</file>
<file preprocess="xml-stripblanks">fontcontrols.ui</file>
<file preprocess="xml-stripblanks">samplechooser.ui</file>
<file preprocess="xml-stripblanks">fontcolors.ui</file>
<file preprocess="xml-stripblanks">fontfeatures.ui</file>
<file preprocess="xml-stripblanks">fontvariations.ui</file>
<file preprocess="xml-stripblanks">rangeedit.ui</file>
<file>fontexplorer.css</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,165 @@
#include "config.h"
#include <gtk/gtk.h>
#include "fontexplorerapp.h"
#include "fontexplorerwin.h"
#include "demo_conf.h"
struct _FontExplorerApp
{
GtkApplication parent;
};
struct _FontExplorerAppClass
{
GtkApplicationClass parent_class;
};
G_DEFINE_TYPE(FontExplorerApp, font_explorer_app, GTK_TYPE_APPLICATION);
static void
font_explorer_app_init (FontExplorerApp *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer app)
{
g_application_quit (G_APPLICATION (app));
}
static void
inspector_activated (GSimpleAction *action,
GVariant *parameter,
gpointer app)
{
gtk_window_set_interactive_debugging (TRUE);
}
static void
about_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkApplication *app = user_data;
const char *authors[] = {
"The GTK Team",
NULL
};
char *icon_theme;
char *version;
GString *s;
char *os_name;
char *os_version;
g_object_get (gtk_settings_get_default (),
"gtk-icon-theme-name", &icon_theme,
NULL);
s = g_string_new ("");
os_name = g_get_os_info (G_OS_INFO_KEY_NAME);
os_version = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
if (os_name && os_version)
g_string_append_printf (s, "OS\t%s %s\n\n", os_name, os_version);
g_string_append (s, "System libraries\n");
g_string_append_printf (s, "\tGLib\t%d.%d.%d\n",
glib_major_version,
glib_minor_version,
glib_micro_version);
g_string_append_printf (s, "\tPango2\t%s\n",
pango2_version_string ());
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
g_string_append_printf (s, "\nIcon theme\n\t%s", icon_theme);
version = g_strdup_printf ("%s%s%s\nRunning against GTK %d.%d.%d",
PACKAGE_VERSION,
g_strcmp0 (PROFILE, "devel") == 0 ? "-" : "",
g_strcmp0 (PROFILE, "devel") == 0 ? VCS_TAG : "",
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (app)),
"program-name", g_strcmp0 (PROFILE, "devel") == 0
? "GTK Font Explorer (Development)"
: "GTK Font Explorer",
"version", version,
"copyright", "©1997—2021 The GTK Team",
"license-type", GTK_LICENSE_LGPL_2_1,
"website", "http://www.gtk.org",
"comments", "Program to explore font features",
"authors", authors,
"logo-icon-name", "org.gtk.FontExplorer",
"title", "About GTK Font Explorer",
"system-information", s->str,
NULL);
g_string_free (s, TRUE);
g_free (version);
g_free (icon_theme);
g_free (os_name);
g_free (os_version);
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL },
{ "inspector", inspector_activated, NULL, NULL, NULL },
{ "about", about_activated, NULL, NULL, NULL }
};
static void
font_explorer_app_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (font_explorer_app_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
"app.quit",
quit_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/fontexplorer/fontexplorer.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static void
font_explorer_app_activate (GApplication *app)
{
FontExplorerWindow *win;
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (win), "devel");
gtk_window_present (GTK_WINDOW (win));
}
static void
font_explorer_app_class_init (FontExplorerAppClass *class)
{
G_APPLICATION_CLASS (class)->startup = font_explorer_app_startup;
G_APPLICATION_CLASS (class)->activate = font_explorer_app_activate;
}
FontExplorerApp *
font_explorer_app_new (void)
{
return g_object_new (FONT_EXPLORER_APP_TYPE,
"application-id", "org.gtk.FontExplorer",
NULL);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_EXPLORER_APP_TYPE (font_explorer_app_get_type ())
#define FONT_EXPLORER_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_APP_TYPE, FontExplorerApp))
typedef struct _FontExplorerApp FontExplorerApp;
typedef struct _FontExplorerAppClass FontExplorerAppClass;
GType font_explorer_app_get_type (void);
FontExplorerApp * font_explorer_app_new (void);

View File

@@ -0,0 +1,131 @@
#include "fontexplorerapp.h"
#include "fontexplorerwin.h"
#include "fontview.h"
#include "fontcontrols.h"
#include "samplechooser.h"
#include "fontcolors.h"
#include "fontfeatures.h"
#include "fontvariations.h"
#include <gtk/gtk.h>
#include <string.h>
struct _FontExplorerWindow
{
GtkApplicationWindow parent;
GtkFontButton *fontbutton;
FontControls *controls;
FontFeatures *features;
FontVariations *variations;
FontColors *colors;
FontView *view;
};
struct _FontExplorerWindowClass
{
GtkApplicationWindowClass parent_class;
};
G_DEFINE_TYPE(FontExplorerWindow, font_explorer_window, GTK_TYPE_APPLICATION_WINDOW);
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontExplorerWindow *win)
{
g_action_activate (font_controls_get_reset_action (win->controls), NULL);
g_action_activate (font_features_get_reset_action (win->features), NULL);
g_action_activate (font_variations_get_reset_action (win->variations), NULL);
g_action_activate (font_colors_get_reset_action (win->colors), NULL);
}
static void
update_reset (GSimpleAction *action,
GParamSpec *pspec,
FontExplorerWindow *win)
{
gboolean enabled;
GAction *reset_action;
enabled = g_action_get_enabled (font_controls_get_reset_action (win->controls)) ||
g_action_get_enabled (font_features_get_reset_action (win->features)) ||
g_action_get_enabled (font_variations_get_reset_action (win->variations)) ||
g_action_get_enabled (font_colors_get_reset_action (win->colors));
reset_action = g_action_map_lookup_action (G_ACTION_MAP (win), "reset");
g_simple_action_set_enabled (G_SIMPLE_ACTION (reset_action), enabled);
}
static void
font_explorer_window_init (FontExplorerWindow *win)
{
GSimpleAction *reset_action;
gtk_widget_init_template (GTK_WIDGET (win));
reset_action = g_simple_action_new ("reset", NULL);
g_signal_connect (reset_action, "activate", G_CALLBACK (reset), win);
g_signal_connect (font_controls_get_reset_action (win->controls),
"notify::enabled", G_CALLBACK (update_reset), win);
g_signal_connect (font_variations_get_reset_action (win->variations),
"notify::enabled", G_CALLBACK (update_reset), win);
g_signal_connect (font_colors_get_reset_action (win->colors),
"notify::enabled", G_CALLBACK (update_reset), win);
g_signal_connect (font_features_get_reset_action (win->features),
"notify::enabled", G_CALLBACK (update_reset), win);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (reset_action));
update_reset (NULL, NULL, win);
}
static void
font_explorer_window_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_EXPLORER_WINDOW_TYPE);
G_OBJECT_CLASS (font_explorer_window_parent_class)->dispose (object);
}
static void
font_explorer_window_finalize (GObject *object)
{
// FontExplorerWindow *win = FONT_EXPLORER_WINDOW (object);
G_OBJECT_CLASS (font_explorer_window_parent_class)->finalize (object);
}
static void
font_explorer_window_class_init (FontExplorerWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_ensure (FONT_VIEW_TYPE);
g_type_ensure (FONT_CONTROLS_TYPE);
g_type_ensure (SAMPLE_CHOOSER_TYPE);
g_type_ensure (FONT_VARIATIONS_TYPE);
g_type_ensure (FONT_COLORS_TYPE);
g_type_ensure (FONT_FEATURES_TYPE);
object_class->dispose = font_explorer_window_dispose;
object_class->finalize = font_explorer_window_finalize;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontexplorerwin.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, fontbutton);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, controls);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, variations);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, colors);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, features);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, view);
}
FontExplorerWindow *
font_explorer_window_new (FontExplorerApp *app)
{
return g_object_new (FONT_EXPLORER_WINDOW_TYPE, "application", app, NULL);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <gtk/gtk.h>
#include "fontexplorerapp.h"
#define FONT_EXPLORER_WINDOW_TYPE (font_explorer_window_get_type ())
#define FONT_EXPLORER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_WINDOW_TYPE, FontExplorerWindow))
typedef struct _FontExplorerWindow FontExplorerWindow;
typedef struct _FontExplorerWindowClass FontExplorerWindowClass;
GType font_explorer_window_get_type (void);
FontExplorerWindow * font_explorer_window_new (FontExplorerApp *app);

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="gear_menu">
<section>
<item>
<attribute name="label" translatable="yes">_Inspector</attribute>
<attribute name="action">app.inspector</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About GTK Font Explorer</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>
<template class="FontExplorerWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">Font Explorer</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<property name="icon-name">view-refresh-symbolic</property>
<property name="action-name">win.reset</property>
</object>
</child>
<child type="end">
<object class="GtkMenuButton" id="gear_menu_button">
<property name="focus-on-click">0</property>
<property name="valign">center</property>
<property name="menu-model">gear_menu</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<style>
<class name="sidebar"/>
</style>
<child>
<object class="GtkFontButton" id="fontbutton">
<property name="level">family|style</property>
</object>
</child>
<child>
<object class="FontControls" id="controls">
<property name="disable-size" bind-source="view" bind-property="ignore-size" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="SampleChooser" id="samplechooser"/>
</child>
<child>
<object class="FontVariations" id="variations">
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="FontFeatures" id="features">
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="language" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="FontColors" id="colors">
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="FontView" id="view">
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="size" bind-source="controls" bind-flags="sync-create"/>
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
<property name="background" bind-source="controls" bind-flags="sync-create"/>
<property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
<property name="features" bind-source="features" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,727 @@
#include "fontfeatures.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include <glib/gi18n.h>
#include "open-type-layout.h"
#include "language-names.h"
enum {
PROP_FONT_DESC = 1,
PROP_LANGUAGE,
PROP_FEATURES,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
typedef struct {
unsigned int tag;
const char *name;
GtkWidget *feat;
} FeatureItem;
struct _FontFeatures
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
Pango2Language *lang;
GList *feature_items;
};
struct _FontFeaturesClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontFeatures, font_features, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontFeatures *self)
{
Pango2Context *context;
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
return pango2_context_load_font (context, self->font_desc);
}
static gboolean
is_ssNN (const char *buf)
{
return g_str_has_prefix (buf, "ss") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
}
static gboolean
is_cvNN (const char *buf)
{
return g_str_has_prefix (buf, "cv") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
}
static char *
get_feature_display_name (unsigned int tag)
{
int i;
static char buf[5] = { 0, };
if (tag == HB_TAG ('x', 'x', 'x', 'x'))
return g_strdup (_("Default"));
hb_tag_to_string (tag, buf);
if (is_ssNN (buf))
{
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Stylistic Set %d"), num);
}
else if (is_cvNN (buf))
{
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Character Variant %d"), num);
}
for (i = 0; i < G_N_ELEMENTS (open_type_layout_features); i++)
{
if (tag == open_type_layout_features[i].tag)
return g_strdup (g_dpgettext2 (NULL, "OpenType layout", open_type_layout_features[i].name));
}
g_warning ("unknown OpenType layout feature tag: %s", buf);
return g_strdup (buf);
}
static void
update_feature_label (FontFeatures *self,
FeatureItem *item,
hb_font_t *hb_font,
hb_tag_t script_tag,
hb_tag_t lang_tag)
{
hb_face_t *hb_face;
unsigned int script_index, lang_index, feature_index;
hb_ot_name_id_t id;
unsigned int len;
char *label;
char name[5] = { 0, };
hb_face = hb_font_get_face (hb_font);
hb_tag_to_string (item->tag, name);
if (!is_ssNN (name) && !is_cvNN (name))
return;
hb_ot_layout_table_find_script (hb_face, HB_OT_TAG_GSUB, script_tag, &script_index);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
hb_ot_layout_script_find_language (hb_face, HB_OT_TAG_GSUB, script_index, lang_tag, &lang_index);
G_GNUC_END_IGNORE_DEPRECATIONS
if (hb_ot_layout_language_find_feature (hb_face, HB_OT_TAG_GSUB, script_index, lang_index, item->tag, &feature_index) &&
hb_ot_layout_feature_get_name_ids (hb_face, HB_OT_TAG_GSUB, feature_index, &id, NULL, NULL, NULL, NULL))
{
len = hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, NULL, NULL);
len++;
label = g_new (char, len);
hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, &len, label);
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
g_free (label);
}
else
{
label = get_feature_display_name (item->tag);
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
g_free (label);
}
}
static void
set_inconsistent (GtkCheckButton *button,
gboolean inconsistent)
{
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), inconsistent);
gtk_widget_set_opacity (gtk_widget_get_first_child (GTK_WIDGET (button)), inconsistent ? 0.0 : 1.0);
}
static void
find_language_and_script (FontFeatures *self,
hb_face_t *hb_face,
hb_tag_t *lang_tag,
hb_tag_t *script_tag)
{
int i, j, k;
hb_tag_t scripts[80];
unsigned int n_scripts;
unsigned int count;
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
hb_language_t lang;
const char *langname, *p;
langname = pango2_language_to_string (self->lang);
p = strchr (langname, '-');
lang = hb_language_from_string (langname, p ? p - langname : -1);
n_scripts = 0;
for (i = 0; i < 2; i++)
{
count = G_N_ELEMENTS (scripts);
hb_ot_layout_table_get_script_tags (hb_face, table[i], n_scripts, &count, scripts);
n_scripts += count;
}
for (j = 0; j < n_scripts; j++)
{
hb_tag_t languages[80];
unsigned int n_languages;
n_languages = 0;
for (i = 0; i < 2; i++)
{
count = G_N_ELEMENTS (languages);
hb_ot_layout_script_get_language_tags (hb_face, table[i], j, n_languages, &count, languages);
n_languages += count;
}
for (k = 0; k < n_languages; k++)
{
if (lang == hb_ot_tag_to_language (languages[k]))
{
*script_tag = scripts[j];
*lang_tag = languages[k];
return;
}
}
}
*lang_tag = HB_OT_TAG_DEFAULT_LANGUAGE;
*script_tag = HB_OT_TAG_DEFAULT_SCRIPT;
}
static void
hide_feature_maybe (FeatureItem *item,
gboolean has_feature)
{
gtk_widget_set_visible (item->feat, has_feature);
if (has_feature)
gtk_widget_set_visible (gtk_widget_get_parent (item->feat), TRUE);
}
/* Make features insensitive if the font/langsys does not have them,
* and reset all others to their initial value
*/
static void
update_features (FontFeatures *self)
{
guint script_index, lang_index;
hb_tag_t lang_tag;
hb_tag_t script_tag;
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
{
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
hb_tag_t features[256];
unsigned int count;
unsigned int n_features = 0;
find_language_and_script (self, hb_face, &lang_tag, &script_tag);
/* Collect all features */
for (int i = 0; i < 2; i++)
{
hb_ot_layout_table_find_script (hb_face,
table[i],
script_tag,
&script_index);
hb_ot_layout_script_select_language (hb_face,
table[i],
script_index,
1,
&lang_tag,
&lang_index);
count = G_N_ELEMENTS (features);
hb_ot_layout_language_get_feature_tags (hb_face,
table[i],
script_index,
lang_index,
n_features,
&count,
features);
n_features += count;
}
/* Update all the features */
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
gboolean has_feature = FALSE;
for (int j = 0; j < n_features; j++)
{
if (item->tag == features[j])
{
has_feature = TRUE;
break;
}
}
update_feature_label (self, item, hb_font, script_tag, lang_tag);
hide_feature_maybe (item, has_feature);
if (GTK_IS_CHECK_BUTTON (item->feat))
{
GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default"));
if (def)
{
gtk_widget_show (def);
gtk_widget_show (gtk_widget_get_parent (def));
gtk_check_button_set_active (GTK_CHECK_BUTTON (def), TRUE);
}
else
set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE);
}
}
}
/* Hide empty groups */
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
GtkWidget *box;
box = gtk_widget_get_parent (item->feat);
if (gtk_widget_get_visible (box))
{
GtkWidget *c;
int count;
count = 0;
for (c = gtk_widget_get_first_child (box); c; c = gtk_widget_get_next_sibling (c))
{
if (gtk_widget_get_visible (c))
count++;
}
if (count == 1)
gtk_widget_hide (box);
else if (count == 2 &&
item->tag == HB_TAG ('x', 'x', 'x', 'x'))
gtk_widget_hide (box);
}
}
}
static void
script_changed (GtkComboBox *combo,
FontFeatures *self)
{
update_features (self);
}
static char *
get_features (FontFeatures *self)
{
GString *s;
char buf[128];
s = g_string_new ("");
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
if (!gtk_widget_is_sensitive (item->feat))
continue;
if (GTK_IS_CHECK_BUTTON (item->feat) && g_object_get_data (G_OBJECT (item->feat), "default"))
{
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat)) &&
item->tag != HB_TAG ('x', 'x', 'x', 'x'))
{
hb_feature_to_string (&(hb_feature_t) { item->tag, 1, 0, -1 }, buf, sizeof (buf));
if (s->len > 0)
g_string_append_c (s, ',');
g_string_append (s, buf);
}
}
else if (GTK_IS_CHECK_BUTTON (item->feat))
{
guint32 value;
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (item->feat)))
continue;
value = gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat));
hb_feature_to_string (&(hb_feature_t) { item->tag, value, 0, -1 }, buf, sizeof (buf));
if (s->len > 0)
g_string_append_c (s, ',');
g_string_append (s, buf);
}
}
return g_string_free (s, FALSE);
}
static void
update_display (FontFeatures *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static GtkWidget *
make_title_label (const char *title)
{
GtkWidget *label;
label = gtk_label_new (title);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
gtk_widget_add_css_class (label, "heading");
return label;
}
static void
feat_toggled_cb (GtkCheckButton *check_button,
gpointer data)
{
set_inconsistent (check_button, FALSE);
}
static void
feat_pressed (GtkGestureClick *gesture,
int n_press,
double x,
double y,
GtkWidget *feat)
{
const guint button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_PRIMARY)
{
g_signal_handlers_block_by_func (feat, feat_pressed, NULL);
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat)))
{
set_inconsistent (GTK_CHECK_BUTTON (feat), FALSE);
gtk_check_button_set_active (GTK_CHECK_BUTTON (feat), TRUE);
}
g_signal_handlers_unblock_by_func (feat, feat_pressed, NULL);
}
else if (button == GDK_BUTTON_SECONDARY)
{
gboolean inconsistent = gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat));
set_inconsistent (GTK_CHECK_BUTTON (feat), !inconsistent);
}
}
static void
add_check_group (FontFeatures *self,
const char *title,
const char **tags,
unsigned int n_tags,
int row)
{
GtkWidget *group;
int i;
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign (group, GTK_ALIGN_START);
gtk_box_append (GTK_BOX (group), make_title_label (title));
for (i = 0; i < n_tags; i++)
{
unsigned int tag;
GtkWidget *feat;
FeatureItem *item;
GtkGesture *gesture;
char *name;
tag = hb_tag_from_string (tags[i], -1);
name = get_feature_display_name (tag);
feat = gtk_check_button_new_with_label (name);
g_free (name);
set_inconsistent (GTK_CHECK_BUTTON (feat), TRUE);
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
g_signal_connect_swapped (feat, "notify::inconsistent", G_CALLBACK (update_display), self);
g_signal_connect (feat, "toggled", G_CALLBACK (feat_toggled_cb), NULL);
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (feat_pressed), feat);
gtk_widget_add_controller (feat, GTK_EVENT_CONTROLLER (gesture));
gtk_box_append (GTK_BOX (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
item->tag = tag;
item->feat = feat;
self->feature_items = g_list_prepend (self->feature_items, item);
}
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
}
static void
add_radio_group (FontFeatures *self,
const char *title,
const char **tags,
unsigned int n_tags,
int row)
{
GtkWidget *group;
int i;
GtkWidget *group_button = NULL;
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign (group, GTK_ALIGN_START);
gtk_box_append (GTK_BOX (group), make_title_label (title));
for (i = 0; i < n_tags; i++)
{
unsigned int tag;
GtkWidget *feat;
FeatureItem *item;
char *name;
tag = hb_tag_from_string (tags[i], -1);
name = get_feature_display_name (tag);
feat = gtk_check_button_new_with_label (name ? name : _("Default"));
g_free (name);
if (group_button == NULL)
group_button = feat;
else
gtk_check_button_set_group (GTK_CHECK_BUTTON (feat), GTK_CHECK_BUTTON (group_button));
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
g_object_set_data (G_OBJECT (feat), "default", group_button);
gtk_box_append (GTK_BOX (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
item->tag = tag;
item->feat = feat;
self->feature_items = g_list_prepend (self->feature_items, item);
}
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
}
static void
setup_features (FontFeatures *self)
{
const char *kerning[] = { "kern" };
const char *ligatures[] = { "liga", "dlig", "hlig", "clig", "rlig" };
const char *letter_case[] = {
"smcp", "c2sc", "pcap", "c2pc", "unic", "cpsp", "case"
};
const char *number_case[] = { "xxxx", "lnum", "onum" };
const char *number_spacing[] = { "xxxx", "pnum", "tnum" };
const char *fractions[] = { "xxxx", "frac", "afrc" };
const char *num_extras[] = { "zero", "nalt", "sinf" };
const char *char_alt[] = {
"swsh", "cswh", "locl", "calt", "falt", "hist",
"salt", "jalt", "titl", "rand", "subs", "sups",
"ordn", "ltra", "ltrm", "rtla", "rtlm", "rclt"
};
const char *pos_alt[] = {
"init", "medi", "med2", "fina", "fin2", "fin3", "isol"
};
const char *width_var[] = {
"fwid", "hwid", "halt", "pwid", "palt", "twid", "qwid"
};
const char *style_alt[] = {
"ss01", "ss02", "ss03", "ss04", "ss05", "ss06",
"ss07", "ss08", "ss09", "ss10", "ss11", "ss12",
"ss13", "ss14", "ss15", "ss16", "ss17", "ss18",
"ss19", "ss20"
};
const char *char_var[] = {
"cv01", "cv02", "cv03", "cv04", "cv05", "cv06",
"cv07", "cv08", "cv09", "cv10", "cv11", "cv12",
"cv13", "cv14", "cv15", "cv16", "cv17", "cv18",
"cv19", "cv20"
};
const char *math[] = { "dtls", "flac", "mgrk", "ssty" };
const char *bounds[] = { "opbd", "lfbd", "rtbd" };
int row = 0;
add_check_group (self, _("Kerning"), kerning, G_N_ELEMENTS (kerning), row++);
add_check_group (self, _("Ligatures"), ligatures, G_N_ELEMENTS (ligatures), row++);
add_check_group (self, _("Letter Case"), letter_case, G_N_ELEMENTS (letter_case), row++);
add_radio_group (self, _("Number Case"), number_case, G_N_ELEMENTS (number_case), row++);
add_radio_group (self, _("Number Spacing"), number_spacing, G_N_ELEMENTS (number_spacing), row++);
add_radio_group (self, _("Fractions"), fractions, G_N_ELEMENTS (fractions), row++);
add_check_group (self, _("Numeric Extras"), num_extras, G_N_ELEMENTS (num_extras), row++);
add_check_group (self, _("Character Alternatives"), char_alt, G_N_ELEMENTS (char_alt), row++);
add_check_group (self, _("Positional Alternatives"), pos_alt, G_N_ELEMENTS (pos_alt), row++);
add_check_group (self, _("Width Variants"), width_var, G_N_ELEMENTS (width_var), row++);
add_check_group (self, _("Alternative Stylistic Sets"), style_alt, G_N_ELEMENTS (style_alt), row++);
add_check_group (self, _("Character Variants"), char_var, G_N_ELEMENTS (char_var), row++);
add_check_group (self, _("Mathematical"), math, G_N_ELEMENTS (math), row++);
add_check_group (self, _("Optical Bounds"), bounds, G_N_ELEMENTS (bounds), row++);
self->feature_items = g_list_reverse (self->feature_items);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontFeatures *self)
{
update_features (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_features_init (FontFeatures *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->font_desc = pango2_font_description_from_string ("sans 12");
self->lang = pango2_language_get_default ();
setup_features (self);
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_features_dispose (GObject *object)
{
FontFeatures *self = FONT_FEATURES (object);
gtk_widget_clear_template (GTK_WIDGET (object), FONT_FEATURES_TYPE);
g_list_free_full (self->feature_items, g_free);
G_OBJECT_CLASS (font_features_parent_class)->dispose (object);
}
static void
font_features_finalize (GObject *object)
{
FontFeatures *self = FONT_FEATURES (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
G_OBJECT_CLASS (font_features_parent_class)->finalize (object);
}
static void
font_features_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontFeatures *self = FONT_FEATURES (object);
switch (prop_id)
{
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
update_features (self);
break;
case PROP_LANGUAGE:
self->lang = pango2_language_from_string (g_value_get_string (value));
update_features (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_features_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontFeatures *self = FONT_FEATURES (object);
switch (prop_id)
{
case PROP_FEATURES:
g_value_take_string (value, get_features (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_features_class_init (FontFeaturesClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_features_dispose;
object_class->finalize = font_features_finalize;
object_class->get_property = font_features_get_property;
object_class->set_property = font_features_set_property;
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_LANGUAGE] =
g_param_spec_string ("language", "", "",
"en",
G_PARAM_WRITABLE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontfeatures.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, label);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), script_changed);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontfeatures");
}
FontFeatures *
font_features_new (void)
{
return g_object_new (FONT_FEATURES_TYPE, NULL);
}
GAction *
font_features_get_reset_action (FontFeatures *self)
{
return G_ACTION (self->reset_action);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_FEATURES_TYPE (font_features_get_type ())
#define FONT_FEATURES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_FEATURES_TYPE, FontFeatures))
typedef struct _FontFeatures FontFeatures;
typedef struct _FontFeaturesClass FontFeaturesClass;
GType font_features_get_type (void);
FontFeatures * font_features_new (void);
GAction * font_features_get_reset_action (FontFeatures *self);

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontFeatures" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Features</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-1</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,488 @@
#include "fontvariations.h"
#include "rangeedit.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_FONT_DESC = 1,
PROP_VARIATIONS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontVariations
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
gboolean has_variations;
GtkWidget *instance_combo;
GHashTable *axes;
GHashTable *instances;
};
struct _FontVariationsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontVariations, font_variations, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontVariations *self)
{
Pango2Context *context;
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
return pango2_context_load_font (context, self->font_desc);
}
typedef struct {
guint32 tag;
GtkAdjustment *adjustment;
double default_value;
} Axis;
static guint
axes_hash (gconstpointer v)
{
const Axis *p = v;
return p->tag;
}
static gboolean
axes_equal (gconstpointer v1, gconstpointer v2)
{
const Axis *p1 = v1;
const Axis *p2 = v2;
return p1->tag == p2->tag;
}
static void
unset_instance (GtkAdjustment *adjustment,
FontVariations *self)
{
if (self->instance_combo)
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
add_axis (FontVariations *self,
hb_face_t *hb_face,
hb_ot_var_axis_info_t *ax,
int i)
{
GtkWidget *axis_label;
GtkWidget *axis_scale;
GtkAdjustment *adjustment;
Axis *axis;
char name[20];
unsigned int name_len = 20;
hb_ot_name_get_utf8 (hb_face, ax->name_id, HB_LANGUAGE_INVALID, &name_len, name);
axis_label = gtk_label_new (name);
gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
gtk_grid_attach (self->grid, axis_label, 0, i, 1, 1);
adjustment = gtk_adjustment_new (ax->default_value, ax->min_value, ax->max_value,
1.0, 10.0, 0.0);
axis_scale = g_object_new (RANGE_EDIT_TYPE,
"adjustment", adjustment,
"default-value", ax->default_value,
"n-chars", 5,
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"valign", GTK_ALIGN_BASELINE,
NULL);
gtk_grid_attach (self->grid, axis_scale, 1, i, 1, 1);
axis = g_new0 (Axis, 1);
axis->tag = ax->tag;
axis->adjustment = adjustment;
axis->default_value = ax->default_value;
g_hash_table_add (self->axes, axis);
g_signal_connect (adjustment, "value-changed", G_CALLBACK (unset_instance), self);
}
typedef struct {
char *name;
unsigned int index;
} Instance;
static guint
instance_hash (gconstpointer v)
{
const Instance *p = v;
return g_str_hash (p->name);
}
static gboolean
instance_equal (gconstpointer v1, gconstpointer v2)
{
const Instance *p1 = v1;
const Instance *p2 = v2;
return g_str_equal (p1->name, p2->name);
}
static void
free_instance (gpointer data)
{
Instance *instance = data;
g_free (instance->name);
g_free (instance);
}
static void
add_instance (FontVariations *self,
hb_face_t *face,
unsigned int index,
GtkWidget *combo,
int pos)
{
Instance *instance;
hb_ot_name_id_t name_id;
char name[20];
unsigned int name_len = 20;
instance = g_new0 (Instance, 1);
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, index);
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
instance->name = g_strdup (name);
instance->index = index;
g_hash_table_add (self->instances, instance);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
}
static void
instance_changed (GtkComboBox *combo,
FontVariations *self)
{
char *text;
Instance *instance;
Instance ikey;
int i;
unsigned int coords_length;
float *coords = NULL;
hb_ot_var_axis_info_t *ai = NULL;
unsigned int n_axes;
Pango2Font *font = NULL;
hb_font_t *hb_font;
hb_face_t *hb_face;
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));
if (text[0] == '\0')
goto out;
ikey.name = text;
instance = g_hash_table_lookup (self->instances, &ikey);
if (!instance)
{
g_print ("did not find instance %s\n", text);
goto out;
}
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
ai = g_new (hb_ot_var_axis_info_t, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
coords = g_new (float, n_axes);
hb_ot_var_named_instance_get_design_coords (hb_face,
instance->index,
&coords_length,
coords);
for (i = 0; i < n_axes; i++)
{
Axis *axis;
Axis akey;
double value;
value = coords[ai[i].axis_index];
akey.tag = ai[i].tag;
axis = g_hash_table_lookup (self->axes, &akey);
if (axis)
{
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
gtk_adjustment_set_value (axis->adjustment, value);
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
}
}
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, TRUE);
out:
g_free (text);
g_clear_object (&font);
g_free (ai);
g_free (coords);
}
static void
update_variations (FontVariations *self)
{
GtkWidget *child;
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
unsigned int n_axes;
hb_ot_var_axis_info_t *ai = NULL;
int i;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
g_object_ref (self->label);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
gtk_grid_remove (self->grid, child);
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -2, 2, 1);
g_object_unref (self->label);
self->instance_combo = NULL;
g_hash_table_remove_all (self->axes);
g_hash_table_remove_all (self->instances);
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
self->has_variations = n_axes > 0;
gtk_widget_set_visible (GTK_WIDGET (self), self->has_variations);
if (!self->has_variations)
{
g_simple_action_set_enabled (self->reset_action, FALSE);
return;
}
if (hb_ot_var_get_named_instance_count (hb_face) > 0)
{
GtkWidget *label;
GtkWidget *combo;
label = gtk_label_new ("Instance");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (self->grid, label, 0, -1, 1, 1);
combo = gtk_combo_box_text_new ();
gtk_widget_set_halign (combo, GTK_ALIGN_START);
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
gtk_widget_set_hexpand (combo, TRUE);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
add_instance (self, hb_face, i, combo, i);
gtk_grid_attach (GTK_GRID (self->grid), combo, 1, -1, 1, 1);
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), self);
self->instance_combo = combo;
}
ai = g_new (hb_ot_var_axis_info_t, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
for (i = 0; i < n_axes; i++)
add_axis (self, hb_face, &ai[i], i);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_clear_object (&font);
g_free (ai);
}
static char *
get_variations (FontVariations *self)
{
GHashTableIter iter;
Axis *axis;
char buf[G_ASCII_DTOSTR_BUF_SIZE];
const char *sep = "";
GString *s;
if (!self->has_variations)
return g_strdup ("");
s = g_string_new ("");
g_hash_table_iter_init (&iter, self->axes);
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
{
char tag[5];
double value;
hb_tag_to_string (axis->tag, tag);
tag[4] = '\0';
value = gtk_adjustment_get_value (axis->adjustment);
g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof (buf), value));
sep = ",";
}
return g_string_free (s, FALSE);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontVariations *self)
{
GHashTableIter iter;
Axis *axis;
if (self->instance_combo)
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
g_hash_table_iter_init (&iter, self->axes);
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
{
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
gtk_adjustment_set_value (axis->adjustment, axis->default_value);
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
}
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_variations_init (FontVariations *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
self->instances = g_hash_table_new_full (instance_hash, instance_equal,
NULL, free_instance);
self->axes = g_hash_table_new_full (axes_hash, axes_equal,
NULL, g_free);
}
static void
font_variations_dispose (GObject *object)
{
FontVariations *self = FONT_VARIATIONS (object);
gtk_widget_clear_template (GTK_WIDGET (object), FONT_VARIATIONS_TYPE);
g_hash_table_unref (self->instances);
g_hash_table_unref (self->axes);
G_OBJECT_CLASS (font_variations_parent_class)->dispose (object);
}
static void
font_variations_finalize (GObject *object)
{
FontVariations *self = FONT_VARIATIONS (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
G_OBJECT_CLASS (font_variations_parent_class)->finalize (object);
}
static void
font_variations_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontVariations *self = FONT_VARIATIONS (object);
switch (prop_id)
{
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
update_variations (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_variations_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontVariations *self = FONT_VARIATIONS (object);
switch (prop_id)
{
case PROP_VARIATIONS:
g_value_take_string (value, get_variations (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_variations_class_init (FontVariationsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_variations_dispose;
object_class->finalize = font_variations_finalize;
object_class->get_property = font_variations_get_property;
object_class->set_property = font_variations_set_property;
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontvariations.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, label);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontvariations");
}
FontVariations *
font_variations_new (void)
{
return g_object_new (FONT_VARIATIONS_TYPE, NULL);
}
GAction *
font_variations_get_reset_action (FontVariations *self)
{
return G_ACTION (self->reset_action);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_VARIATIONS_TYPE (font_variations_get_type ())
#define FONT_VARIATIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_VARIATIONS_TYPE, FontVariations))
typedef struct _FontVariations FontVariations;
typedef struct _FontVariationsClass FontVariationsClass;
GType font_variations_get_type (void);
FontVariations * font_variations_new (void);
GAction * font_variations_get_reset_action (FontVariations *self);

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontVariations" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Variations</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-2</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,413 @@
#include "fontview.h"
#include <gtk/gtk.h>
enum {
PROP_FONT_DESC = 1,
PROP_SIZE,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
PROP_VARIATIONS,
PROP_FEATURES,
PROP_PALETTE,
PROP_SAMPLE_TEXT,
PROP_IGNORE_SIZE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontView
{
GtkWidget parent;
GtkStack *stack;
GtkTextView *edit;
GtkLabel *content;
GtkScrolledWindow *swin;
Pango2FontDescription *font_desc;
float size;
char *variations;
char *features;
char *palette;
int letterspacing;
float line_height;
GdkRGBA foreground;
GdkRGBA background;
GtkCssProvider *bg_provider;
char *sample_text;
gboolean do_waterfall;
};
struct _FontViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontView, font_view, GTK_TYPE_WIDGET);
static void
font_view_init (FontView *self)
{
self->font_desc = pango2_font_description_from_string ("sans 12");
self->size = 12.;
self->letterspacing = 0;
self->line_height = 1.;
self->variations = g_strdup ("");
self->features = g_strdup ("");
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
self->foreground = (GdkRGBA){0., 0., 0., 1. };
self->background = (GdkRGBA){1., 1., 1., 1. };
self->sample_text = g_strdup ("Some sample text is better than other sample text");
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
self->bg_provider = gtk_css_provider_new ();
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
GTK_STYLE_PROVIDER (self->bg_provider), 800);
}
static void
font_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_VIEW_TYPE);
G_OBJECT_CLASS (font_view_parent_class)->dispose (object);
}
static void
font_view_finalize (GObject *object)
{
FontView *self = FONT_VIEW (object);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
g_free (self->features);
g_free (self->palette);
G_OBJECT_CLASS (font_view_parent_class)->finalize (object);
}
static void
update_view (FontView *self)
{
Pango2FontDescription *desc;
Pango2AttrList *attrs;
char *fg, *bg, *css;
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
pango2_font_description_set_variations (desc, self->variations);
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
65535 * self->foreground.green,
65535 * self->foreground.blue,
65535 * self->foreground.alpha}));
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
pango2_font_description_free (desc);
gtk_scrolled_window_set_policy (self->swin,
self->do_waterfall ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_label_set_wrap (self->content, !self->do_waterfall);
if (self->do_waterfall)
{
GString *str;
int sizes[] = { 7, 8, 9, 10, 12, 14, 16, 20, 24, 30, 40, 50, 60, 70, 90 };
int start, text_len;
str = g_string_new ("");
start = 0;
text_len = strlen (self->sample_text);
for (int i = 0; i < G_N_ELEMENTS (sizes); i++)
{
Pango2Attribute *attr;
g_string_append (str, self->sample_text);
g_string_append (str, ""); /* Unicode line separator */
attr = pango2_attr_size_new (sizes[i] * PANGO2_SCALE);
pango2_attribute_set_range (attr, start, start + text_len);
pango2_attr_list_insert (attrs, attr);
start += text_len + strlen ("");
}
gtk_label_set_text (self->content, str->str);
gtk_label_set_attributes (self->content, attrs);
g_string_free (str, TRUE);
}
else
{
gtk_label_set_label (self->content, self->sample_text);
gtk_label_set_attributes (self->content, attrs);
}
pango2_attr_list_unref (attrs);
fg = gdk_rgba_to_string (&self->foreground);
bg = gdk_rgba_to_string (&self->background);
css = g_strdup_printf (".view_background { caret-color: %s; background-color: %s; }", fg, bg);
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
g_free (css);
g_free (fg);
g_free (bg);
}
static void
toggle_edit (GtkToggleButton *button,
FontView *self)
{
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (self->edit);
if (gtk_toggle_button_get_active (button))
{
gtk_text_buffer_set_text (buffer, self->sample_text, -1);
gtk_stack_set_visible_child_name (self->stack, "edit");
gtk_widget_grab_focus (GTK_WIDGET (self->edit));
}
else
{
GtkTextIter start, end;
g_free (self->sample_text);
gtk_text_buffer_get_bounds (buffer, &start, &end);
self->sample_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
update_view (self);
gtk_stack_set_visible_child_name (self->stack, "content");
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
}
static void
waterfall_changed (GtkToggleButton *button,
GParamSpec *pspec,
FontView *self)
{
self->do_waterfall = gtk_toggle_button_get_active (button);
update_view (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_SIZE]);
}
static void
font_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontView *self = FONT_VIEW (object);
switch (prop_id)
{
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_SIZE:
self->size = g_value_get_float (value);
break;
case PROP_LETTERSPACING:
self->letterspacing = g_value_get_int (value);
break;
case PROP_LINE_HEIGHT:
self->line_height = g_value_get_float (value);
break;
case PROP_FOREGROUND:
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_BACKGROUND:
self->background = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
case PROP_FEATURES:
g_free (self->features);
self->features = g_strdup (g_value_get_string (value));
break;
case PROP_PALETTE:
g_free (self->palette);
self->palette = g_strdup (g_value_get_string (value));
break;
case PROP_SAMPLE_TEXT:
g_free (self->sample_text);
self->sample_text = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_view (self);
}
static void
font_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
FontView *self = FONT_VIEW (object);
switch (prop_id)
{
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_SIZE:
g_value_set_float (value, self->size);
break;
case PROP_LETTERSPACING:
g_value_set_int (value, self->letterspacing);
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, self->line_height);
break;
case PROP_FOREGROUND:
g_value_set_boxed (value, &self->foreground);
break;
case PROP_BACKGROUND:
g_value_set_boxed (value, &self->background);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
case PROP_FEATURES:
g_value_set_string (value, self->features);
break;
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
case PROP_IGNORE_SIZE:
g_value_set_boolean (value, self->do_waterfall);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_view_class_init (FontViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_view_dispose;
object_class->finalize = font_view_finalize;
object_class->get_property = font_view_get_property;
object_class->set_property = font_view_set_property;
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READWRITE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READWRITE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READWRITE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READWRITE);
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_IGNORE_SIZE] =
g_param_spec_boolean ("ignore-size", "", "",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontView, swin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontView, content);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontView, stack);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontView, edit);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), toggle_edit);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), waterfall_changed);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontview");
}
FontView *
font_view_new (void)
{
return g_object_new (FONT_VIEW_TYPE, NULL);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_VIEW_TYPE (font_view_get_type ())
#define FONT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_VIEW_TYPE, FontView))
typedef struct _FontView FontView;
typedef struct _FontViewClass FontViewClass;
GType font_view_get_type (void);
FontView * font_view_new (void);

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontView" parent="GtkWidget">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkStack" id="stack">
<child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow" id="swin">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkLabel" id="content">
<property name="label">ContentContent</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<style>
<class name="view_background"/>
</style>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">edit</property>
<property name="child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkTextView" id="edit">
<property name="wrap-mode">word-char</property>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkToggleButton" id="plain_toggle">
<property name="label" translatable="yes">Plain</property>
<property name="active">1</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="waterfall_toggle">
<property name="label" translatable="yes">Waterfall</property>
<property name="group">plain_toggle</property>
<signal name="notify::active" handler="waterfall_changed"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToggleButton">
<property name="icon-name">document-edit-symbolic</property>
<property name="tooltip-text" translatable="yes">Edit the sample</property>
<property name="halign">end</property>
<property name="valign">end</property>
<property name="hexpand">1</property>
<signal name="clicked" handler="toggle_edit"/>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,336 @@
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <hb-ot.h>
#include "language-names.h"
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#ifndef ISO_CODES_PREFIX
#define ISO_CODES_PREFIX "/usr"
#endif
#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
#endif
static GHashTable *language_map;
#ifdef G_OS_WIN32
/* if we are using native Windows use native Windows API for language names */
static BOOL CALLBACK
get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
{
wchar_t *langname_w = NULL;
wchar_t locale_abbrev_w[9];
gchar *langname, *locale_abbrev, *locale, *p;
gint i;
const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
GHashTable *ht_scripts_langs = (GHashTable *) param;
Pango2Language *lang;
gint langname_size, locale_abbrev_size;
langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
if (langname_size == 0)
return FALSE;
langname_w = g_new0 (wchar_t, langname_size);
if (langname_size == 0)
return FALSE;
GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, langname_size);
langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
p = strchr (locale, '-');
lang = pango2_language_from_string (locale);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
/*
* Track 3+-letter ISO639-2/3 language codes as well (these have a max length of 9 including terminating NUL)
* ISO639-2: iso639_lctypes[0] = LOCALE_SISO639LANGNAME
* ISO639-3: iso639_lctypes[1] = LOCALE_SISO639LANGNAME2
*/
for (i = 0; i < 2; i++)
{
locale_abbrev_size = GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, 0);
if (locale_abbrev_size > 0)
{
GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
lang = pango2_language_from_string (locale_abbrev);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
g_free (locale_abbrev);
}
}
g_free (locale);
g_free (langname_w);
return TRUE;
}
#else /* non-Windows */
static char *
get_first_item_in_semicolon_list (const char *list)
{
char **items;
char *item;
items = g_strsplit (list, "; ", 2);
item = g_strdup (items[0]);
g_strfreev (items);
return item;
}
static char *
capitalize_utf8_string (const char *str)
{
char first[8] = { 0 };
if (!str)
return NULL;
g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL);
}
static char *
get_display_name (const char *language)
{
const char *translated;
char *tmp;
char *name;
translated = dgettext ("iso_639", language);
tmp = get_first_item_in_semicolon_list (translated);
name = capitalize_utf8_string (tmp);
g_free (tmp);
return name;
}
static void
languages_parse_start_tag (GMarkupParseContext *ctx,
const char *element_name,
const char **attr_names,
const char **attr_values,
gpointer user_data,
GError **error)
{
const char *ccode_longB;
const char *ccode_longT;
const char *ccode;
const char *ccode_id;
const char *lang_name;
char *display_name;
const char *long_names[] = {
"Dogri",
"Greek, Modern",
"Interlingua",
"Konkani",
"Tonga",
"Turkish, Ottoman",
};
int i;
if (!(g_str_equal (element_name, "iso_639_entry") ||
g_str_equal (element_name, "iso_639_3_entry")) ||
attr_names == NULL ||
attr_values == NULL)
return;
ccode = NULL;
ccode_longB = NULL;
ccode_longT = NULL;
ccode_id = NULL;
lang_name = NULL;
while (*attr_names && *attr_values)
{
if (g_str_equal (*attr_names, "iso_639_1_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 2)
return;
ccode = *attr_values;
}
}
else if (g_str_equal (*attr_names, "iso_639_2B_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 3)
return;
ccode_longB = *attr_values;
}
}
else if (g_str_equal (*attr_names, "iso_639_2T_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 3)
return;
ccode_longT = *attr_values;
}
}
else if (g_str_equal (*attr_names, "id"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 2 &&
strlen (*attr_values) != 3)
return;
ccode_id = *attr_values;
}
}
else if (g_str_equal (*attr_names, "name"))
{
lang_name = *attr_values;
}
++attr_names;
++attr_values;
}
if (lang_name == NULL)
return;
display_name = get_display_name (lang_name);
/* Fix up some egregious names */
for (i = 0; i < G_N_ELEMENTS (long_names); i++)
{
if (g_str_has_prefix (display_name, long_names[i]))
display_name[strlen (long_names[i])] = '\0';
}
if (ccode != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode),
g_strdup (display_name));
if (ccode_longB != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longB),
g_strdup (display_name));
if (ccode_longT != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longT),
g_strdup (display_name));
if (ccode_id != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_id),
g_strdup (display_name));
g_free (display_name);
}
static void
languages_variant_init (const char *variant)
{
gboolean res;
gsize buf_len;
char *buf;
char *filename;
GError *error;
bindtextdomain (variant, ISO_CODES_LOCALESDIR);
bind_textdomain_codeset (variant, "UTF-8");
error = NULL;
filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
res = g_file_get_contents (filename, &buf, &buf_len, &error);
if (res)
{
GMarkupParseContext *ctx = NULL;
GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
g_free (ctx);
if (!res)
{
g_warning ("Failed to parse '%s': %s\n", filename, error->message);
g_error_free (error);
}
}
else
{
g_warning ("Failed to load '%s': %s\n", filename, error->message);
g_error_free (error);
}
g_free (filename);
g_free (buf);
}
#endif
static void
languages_init (void)
{
if (language_map)
return;
language_map = g_hash_table_new_full (NULL, NULL, NULL, g_free);
#ifdef G_OS_WIN32
g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
#else
languages_variant_init ("iso_639");
languages_variant_init ("iso_639_3");
#endif
}
const char *
get_language_name (Pango2Language *language)
{
languages_init ();
return (const char *) g_hash_table_lookup (language_map, language);
}
const char *
get_language_name_for_tag (guint32 tag)
{
hb_language_t lang;
const char *s;
lang = hb_ot_tag_to_language (tag);
s = hb_language_to_string (lang);
return get_language_name (pango2_language_from_string (s));
}

View File

@@ -0,0 +1,13 @@
#ifndef LANGUAGE_NAMES_H
#define LANGUAGE_NAMES_H
#include <pango2/pango.h>
G_BEGIN_DECLS
const char * get_language_name (Pango2Language *language);
const char * get_language_name_for_tag (guint32 tag);
G_END_DECLS
#endif

View File

@@ -0,0 +1,8 @@
#include <gtk/gtk.h>
#include <fontexplorerapp.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (font_explorer_app_new ()), argc, argv);
}

View File

@@ -0,0 +1,27 @@
fontexplorer_sources = [
'main.c',
'fontexplorerapp.c',
'fontexplorerwin.c',
'fontcontrols.c',
'samplechooser.c',
'fontcolors.c',
'fontfeatures.c',
'fontvariations.c',
'fontview.c',
'rangeedit.c',
'language-names.c',
]
fontexplorer_resources = gnome.compile_resources('fontexplorer_resources',
'fontexplorer.gresource.xml',
source_dir: '.',
)
executable('gtk4-font-explorer',
sources: [fontexplorer_sources, fontexplorer_resources],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
include_directories: confinc,
link_args: extra_demo_ldflags,
install: true,
)

View File

@@ -0,0 +1,173 @@
#include "rangeedit.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_ADJUSTMENT = 1,
PROP_DEFAULT_VALUE,
PROP_N_CHARS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _RangeEdit
{
GtkWidget parent;
GtkAdjustment *adjustment;
GtkScale *scale;
GtkEntry *entry;
double default_value;
int n_chars;
};
struct _RangeEditClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (RangeEdit, range_edit, GTK_TYPE_WIDGET);
static void
range_edit_init (RangeEdit *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
range_edit_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), RANGE_EDIT_TYPE);
G_OBJECT_CLASS (range_edit_parent_class)->dispose (object);
}
static void
range_edit_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
RangeEdit *self = RANGE_EDIT (object);
switch (prop_id)
{
case PROP_ADJUSTMENT:
g_value_set_object (value, self->adjustment);
break;
case PROP_DEFAULT_VALUE:
g_value_set_double (value, self->default_value);
break;
case PROP_N_CHARS:
g_value_set_int (value, self->n_chars);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
adjustment_changed (GtkAdjustment *adjustment,
RangeEdit *self)
{
char *str;
str = g_strdup_printf ("%.1f", gtk_adjustment_get_value (adjustment));
gtk_editable_set_text (GTK_EDITABLE (self->entry), str);
g_free (str);
}
static void
range_edit_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
RangeEdit *self = RANGE_EDIT (object);
switch (prop_id)
{
case PROP_ADJUSTMENT:
g_set_object (&self->adjustment, g_value_get_object (value));
g_signal_connect (self->adjustment, "value-changed", G_CALLBACK (adjustment_changed), self);
adjustment_changed (self->adjustment, self);
break;
case PROP_DEFAULT_VALUE:
self->default_value = g_value_get_double (value);
break;
case PROP_N_CHARS:
self->n_chars = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
range_edit_constructed (GObject *object)
{
RangeEdit *self = RANGE_EDIT (object);
gtk_scale_add_mark (self->scale, self->default_value, GTK_POS_TOP, NULL);
}
static void
entry_activated (GtkEntry *entry,
RangeEdit *self)
{
double value;
char *err = NULL;
value = g_strtod (gtk_editable_get_text (GTK_EDITABLE (entry)), &err);
if (err != NULL)
gtk_adjustment_set_value (self->adjustment, value);
}
static void
range_edit_class_init (RangeEditClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = range_edit_dispose;
object_class->get_property = range_edit_get_property;
object_class->set_property = range_edit_set_property;
object_class->constructed = range_edit_constructed;
properties[PROP_ADJUSTMENT] =
g_param_spec_object ("adjustment", "", "",
GTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_DEFAULT_VALUE] =
g_param_spec_double ("default-value", "", "",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_N_CHARS] =
g_param_spec_int ("n-chars", "", "",
0, G_MAXINT, 10,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/rangeedit.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, scale);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, entry);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), entry_activated);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "rangeedit");
}
RangeEdit *
range_edit_new (void)
{
return g_object_new (RANGE_EDIT_TYPE, NULL);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <gtk/gtk.h>
#define RANGE_EDIT_TYPE (range_edit_get_type ())
#define RANGE_EDIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RANGE_EDIT_TYPE, RangeEdit))
typedef struct _RangeEdit RangeEdit;
typedef struct _RangeEditClass RangeEditClass;
GType range_edit_get_type (void);
RangeEdit * range_edit_new (void);

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="RangeEdit" parent="GtkWidget">
<property name="layout-manager">
<object class="GtkBoxLayout">
<property name="spacing">10</property>
</object>
</property>
<child>
<object class="GtkScale" id="scale">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="adjustment" bind-source="RangeEdit" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="GtkEntry" id="entry">
<property name="width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
<property name="max-width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
<signal name="activate" handler="entry_activated"/>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,162 @@
#include "samplechooser.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_SAMPLE_TEXT = 1,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _SampleChooser
{
GtkWidget parent;
int sample;
const char *sample_text;
};
struct _SampleChooserClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(SampleChooser, sample_chooser, GTK_TYPE_WIDGET);
static const char *pangrams[] = {
"The quick brown fox jumps over the lazy dog.",
"Waltz, bad nymph, for quick jigs vex.",
"Quick zephyrs blow, vexing daft Jim.",
"Crazy Fredrick bought many very exquisite opal jewels.",
"Jaded zombies acted quaintly but kept driving their oxen forward.",
};
static const char *paragraphs[] = {
"Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.",
" Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!",
"Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός",
};
static const char *alphabets[] = {
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"!@#$%^&*()?",
};
static const char *titles[] = {
"From My Cold Dead Hands",
"From Afar Upon the Back of a Tiger",
"Spontaneous Apple Creation",
"Big Bizness (Screwed & Chopped)",
"Pizza Shop Extended",
"Good News & Bad News",
};
static void
next_pangram (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = pangrams[self->sample % G_N_ELEMENTS (pangrams)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_paragraph (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = paragraphs[self->sample % G_N_ELEMENTS (paragraphs)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_alphabet (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = alphabets[self->sample % G_N_ELEMENTS (alphabets)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_title (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = titles[self->sample % G_N_ELEMENTS (titles)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
sample_chooser_init (SampleChooser *self)
{
self->sample_text = "Boring sample text";
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
sample_chooser_dispose (GObject *object)
{
GtkWidget *child;
gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_CHOOSER_TYPE);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))) != NULL)
gtk_widget_unparent (child);
G_OBJECT_CLASS (sample_chooser_parent_class)->dispose (object);
}
static void
sample_chooser_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
SampleChooser *self = SAMPLE_CHOOSER (object);
switch (prop_id)
{
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sample_chooser_class_init (SampleChooserClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = sample_chooser_dispose;
object_class->get_property = sample_chooser_get_property;
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/samplechooser.ui");
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_pangram);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_paragraph);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_alphabet);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_title);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "samplechooser");
}
SampleChooser *
sample_chooser_new (void)
{
return g_object_new (SAMPLE_CHOOSER_TYPE, NULL);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <gtk/gtk.h>
#define SAMPLE_CHOOSER_TYPE (sample_chooser_get_type ())
#define SAMPLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_CHOOSER_TYPE, SampleChooser))
typedef struct _SampleChooser SampleChooser;
typedef struct _SampleChooserClass SampleChooserClass;
GType sample_chooser_get_type (void);
SampleChooser * sample_chooser_new (void);

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SampleChooser" parent="GtkWidget">
<property name="layout-manager"><object class="GtkGridLayout"/></property>
<child>
<object class="GtkButton">
<property name="label">Pangram</property>
<signal name="clicked" handler="next_pangram"/>
<layout>
<property name="row">0</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Paragraph</property>
<signal name="clicked" handler="next_paragraph"/>
<layout>
<property name="row">0</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Alphabet</property>
<signal name="clicked" handler="next_alphabet"/>
<layout>
<property name="row">1</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Title</property>
<signal name="clicked" handler="next_title"/>
<layout>
<property name="row">1</property>
<property name="column">1</property>
</layout>
</object>
</child>
</template>
</interface>

View File

@@ -33,12 +33,22 @@ static void create_window (GApplication *app, const char *contents);
static void
show_action_dialog (GSimpleAction *action)
{
GtkAlertDialog *dialog;
const char *name;
GtkWidget *dialog;
dialog = gtk_alert_dialog_new ("You activated action: \"%s\n",
g_action_get_name (G_ACTION (action)));
gtk_alert_dialog_show (dialog, NULL);
g_object_unref (dialog);
name = g_action_get_name (G_ACTION (action));
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
"You activated action: \"%s\"",
name);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_window_destroy), NULL);
gtk_widget_show (dialog);
}
static void
@@ -57,7 +67,7 @@ show_action_infobar (GSimpleAction *action,
text = g_strdup_printf ("You activated radio action: \"%s\".\n"
"Current value: %s", name, value);
gtk_label_set_text (GTK_LABEL (window->message), text);
gtk_widget_set_visible (window->infobar, TRUE);
gtk_widget_show (window->infobar);
g_free (text);
}
@@ -80,38 +90,43 @@ activate_new (GSimpleAction *action,
}
static void
open_response_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
open_response_cb (GtkNativeDialog *dialog,
int response_id,
gpointer user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GApplication *app = G_APPLICATION (user_data);
GtkFileChooserNative *native = user_data;
GApplication *app = g_object_get_data (G_OBJECT (native), "app");
GtkWidget *message_dialog;
GFile *file;
char *contents;
GError *error = NULL;
file = gtk_file_dialog_open_finish (dialog, result, &error);
if (file)
if (response_id == GTK_RESPONSE_ACCEPT)
{
char *contents;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error))
{
create_window (app, contents);
g_free (contents);
}
else
{
message_dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Error loading file: \"%s\"",
error->message);
g_signal_connect (message_dialog, "response",
G_CALLBACK (gtk_window_destroy), NULL);
gtk_widget_show (message_dialog);
g_error_free (error);
}
}
if (error)
{
GtkAlertDialog *alert;
alert = gtk_alert_dialog_new ("Error loading file: \"%s\"", error->message);
gtk_alert_dialog_show (alert, NULL);
g_object_unref (alert);
g_error_free (error);
}
g_object_unref (app);
gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
g_object_unref (native);
}
@@ -121,11 +136,21 @@ activate_open (GSimpleAction *action,
gpointer user_data)
{
GApplication *app = user_data;
GtkFileDialog *dialog;
GtkFileChooserNative *native;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_open (dialog, NULL, NULL, open_response_cb, g_object_ref (app));
g_object_unref (dialog);
native = gtk_file_chooser_native_new ("Open File",
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Open",
"_Cancel");
g_object_set_data_full (G_OBJECT (native), "app", g_object_ref (app), g_object_unref);
g_signal_connect (native,
"response",
G_CALLBACK (open_response_cb),
native);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
}
static void
@@ -214,41 +239,6 @@ activate_quit (GSimpleAction *action,
}
}
static void
delete_messages (gpointer data)
{
g_list_free_full ((GList *)data, g_free);
}
static void
pop_message (GtkWidget *status)
{
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
if (messages)
{
char *message = messages->data;
messages = g_list_remove (messages, message);
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
gtk_label_set_label (GTK_LABEL (status), message);
}
}
static void
push_message (GtkWidget *status,
const char *message)
{
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
gtk_label_set_label (GTK_LABEL (status), message);
messages = g_list_prepend (messages, g_strdup (message));
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
}
static void
update_statusbar (GtkTextBuffer *buffer,
DemoApplicationWindow *window)
@@ -259,7 +249,7 @@ update_statusbar (GtkTextBuffer *buffer,
GtkTextIter iter;
/* clear any previous message, underflow is allowed */
pop_message (window->status);
gtk_statusbar_pop (GTK_STATUSBAR (window->status), 0);
count = gtk_text_buffer_get_char_count (buffer);
@@ -273,7 +263,7 @@ update_statusbar (GtkTextBuffer *buffer,
msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
row, col, count);
push_message (window->status, msg);
gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, msg);
g_free (msg);
}
@@ -330,7 +320,7 @@ static GActionEntry win_entries[] = {
static void
clicked_cb (GtkWidget *widget, DemoApplicationWindow *window)
{
gtk_widget_set_visible (window->infobar, FALSE);
gtk_widget_hide (window->infobar);
}
static void
@@ -514,8 +504,6 @@ demo_application_window_dispose (GObject *object)
demo_application_window_store_state (window);
gtk_widget_dispose_template (GTK_WIDGET (window), demo_application_window_get_type ());
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
}

View File

@@ -76,13 +76,8 @@
</object>
</child>
<child>
<object class="GtkLabel" id="status">
<object class="GtkStatusbar" id="status">
<property name="hexpand">1</property>
<property name="xalign">0</property>
<property name="margin-start">2</property>
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>

View File

@@ -7,8 +7,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *progress_bar = NULL;
static gboolean
@@ -142,6 +140,7 @@ create_page3 (GtkWidget *assistant)
label = gtk_label_new ("This is a confirmation page, press 'Apply' to apply changes");
gtk_widget_show (label);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), label);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), label, GTK_ASSISTANT_PAGE_CONFIRM);
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), label, TRUE);
@@ -158,14 +157,11 @@ create_page4 (GtkWidget *assistant)
gtk_widget_set_margin_start (progress_bar, 40);
gtk_widget_set_margin_end (progress_bar, 40);
gtk_widget_show (progress_bar);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), progress_bar);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), progress_bar, GTK_ASSISTANT_PAGE_PROGRESS);
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), progress_bar, "Applying changes");
gtk_accessible_update_property (GTK_ACCESSIBLE (progress_bar),
GTK_ACCESSIBLE_PROPERTY_LABEL, "Applying changes",
-1);
/* This prevents the assistant window from being
* closed while we're "busy" applying changes.
*/
@@ -203,7 +199,7 @@ do_assistant (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (assistant))
gtk_widget_set_visible (assistant, TRUE);
gtk_widget_show (assistant);
else
gtk_window_destroy (GTK_WINDOW (assistant));

View File

@@ -116,8 +116,7 @@ effective_align (GtkAlign align,
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
case GTK_ALIGN_FILL:
case GTK_ALIGN_CENTER:
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
return align;
}
@@ -259,8 +258,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
case GTK_ALIGN_END:
alloc->x += width - alloc->width;
break;
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
@@ -283,8 +281,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
case GTK_ALIGN_END:
alloc->y += height - alloc->height;
break;
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
@@ -300,13 +297,12 @@ blur_overlay_snapshot (GtkWidget *widget,
GtkWidget *main_widget;
GskRenderNode *main_widget_node = NULL;
GtkWidget *child;
int width, height;
GtkAllocation main_alloc;
cairo_region_t *clip = NULL;
int i;
main_widget = BLUR_OVERLAY (widget)->main_widget;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_widget_get_allocation (widget, &main_alloc);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
@@ -319,7 +315,7 @@ blur_overlay_snapshot (GtkWidget *widget,
if (blur > 0)
{
cairo_rectangle_int_t rect;
GtkAllocation alloc;
graphene_rect_t bounds;
if (main_widget_node == NULL)
@@ -331,8 +327,8 @@ blur_overlay_snapshot (GtkWidget *widget,
main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
}
if (!gtk_widget_compute_bounds (child, gtk_widget_get_parent (child), &bounds))
graphene_rect_init (&bounds, 0, 0, 0, 0);
gtk_widget_get_allocation (child, &alloc);
graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
gtk_snapshot_push_blur (snapshot, blur);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
@@ -341,17 +337,13 @@ blur_overlay_snapshot (GtkWidget *widget,
if (clip == NULL)
{
cairo_rectangle_int_t rect;
rect.x = rect.y = 0;
rect.width = width;
rect.height = height;
rect.width = main_alloc.width;
rect.height = main_alloc.height;
clip = cairo_region_create_rectangle (&rect);
}
rect.x = floor (bounds.origin.x);
rect.y = floor (bounds.origin.y);
rect.width = ceil (bounds.origin.x + bounds.size.width - rect.x);
rect.height = ceil (bounds.origin.y + bounds.size.height - rect.y);
cairo_region_subtract_rectangle (clip, &rect);
cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
}
}

View File

@@ -51,11 +51,15 @@ struct _BlurOverlayClass
GtkAllocation *allocation);
};
GDK_AVAILABLE_IN_ALL
GType blur_overlay_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget *blur_overlay_new (void);
GDK_AVAILABLE_IN_ALL
void blur_overlay_add_overlay (BlurOverlay *overlay,
GtkWidget *widget,
double blur);
GDK_AVAILABLE_IN_ALL
void blur_overlay_set_child (BlurOverlay *overlay,
GtkWidget *widget);

View File

@@ -1,5 +1,5 @@
/* Builder
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkShortcutController, toolbar
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkStatusBar, GtkShortcutController, toolbar
*
* Demonstrates a traditional interface, loaded from a XML description,
* and shows how to connect actions to the menu items and toolbar buttons.
@@ -37,30 +37,22 @@ remove_timeout (gpointer data)
g_source_remove (id);
}
static int
pop_message (gpointer data)
static gboolean
pop_status (gpointer data)
{
GtkWidget *status = data;
gtk_label_set_label (GTK_LABEL (status), "");
g_object_set_data (G_OBJECT (status), "timeout", GUINT_TO_POINTER (0));
gtk_statusbar_pop (GTK_STATUSBAR (data), 0);
g_object_set_data (G_OBJECT (data), "timeout", NULL);
return G_SOURCE_REMOVE;
}
static void
status_message (GtkWidget *status,
const char *text)
status_message (GtkStatusbar *status,
const char *text)
{
guint id;
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (status), "timeout"));
if (id)
g_source_remove (id);
gtk_label_set_text (GTK_LABEL (status), text);
id = g_timeout_add (5000, pop_message, status);
gtk_statusbar_push (GTK_STATUSBAR (status), 0, text);
id = g_timeout_add (5000, pop_status, status);
g_object_set_data_full (G_OBJECT (status), "timeout", GUINT_TO_POINTER (id), remove_timeout);
}
@@ -73,7 +65,7 @@ help_activate (GSimpleAction *action,
GtkWidget *status;
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, "Help not available");
status_message (GTK_STATUSBAR (status), "Help not available");
}
static void
@@ -86,7 +78,7 @@ not_implemented (GSimpleAction *action,
text = g_strdup_printf ("Action “%s” not implemented", g_action_get_name (G_ACTION (action)));
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, text);
status_message (GTK_STATUSBAR (status), text);
g_free (text);
}
@@ -176,7 +168,7 @@ do_builder (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -1,5 +1,4 @@
/* Clipboard
* #Keywords: drag-and-drop, dnd
*
* GdkClipboard is used for clipboard handling. This demo shows how to
* copy and paste text, images, colors or files to and from the clipboard.
@@ -51,10 +50,10 @@ copy_button_clicked (GtkStack *source_stack,
}
else if (strcmp (visible_child_name, "Color") == 0)
{
const GdkRGBA *color;
GdkRGBA color;
color = gtk_color_dialog_button_get_rgba (GTK_COLOR_DIALOG_BUTTON (visible_child));
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, color);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (visible_child), &color);
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, &color);
}
else if (strcmp (visible_child_name, "File") == 0)
{
@@ -216,71 +215,37 @@ file_button_set_file (GtkButton *button,
}
static void
file_chooser_response (GObject *source,
GAsyncResult *result,
gpointer user_data)
file_chooser_response (GtkNativeDialog *dialog,
int response,
GtkButton *button)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GtkButton *button = GTK_BUTTON (user_data);
GFile *file;
gtk_native_dialog_hide (dialog);
file = gtk_file_dialog_open_finish (dialog, result, NULL);
if (file)
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
file_button_set_file (button, file);
g_object_unref (file);
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
}
gtk_native_dialog_destroy (dialog);
}
static void
open_file_cb (GtkWidget *button)
{
GtkFileDialog *dialog;
GtkFileChooserNative *chooser;
dialog = gtk_file_dialog_new ();
chooser = gtk_file_chooser_native_new ("Choose a file",
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Open",
"_Cancel");
gtk_file_dialog_open (dialog,
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
NULL,
file_chooser_response, button);
g_object_unref (dialog);
}
static void
folder_chooser_response (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GtkButton *button = GTK_BUTTON (user_data);
GFile *file;
file = gtk_file_dialog_select_folder_finish (dialog, result, NULL);
if (file)
{
file_button_set_file (button, file);
g_object_unref (file);
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
}
}
static void
open_folder_cb (GtkWidget *button)
{
GtkFileDialog *dialog;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_select_folder (dialog,
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
NULL,
folder_chooser_response, button);
g_object_unref (dialog);
g_signal_connect (chooser, "response", G_CALLBACK (file_chooser_response), button);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
}
static void
@@ -381,7 +346,6 @@ do_clipboard (GtkWidget *do_widget)
gtk_builder_cscope_add_callback (scope, source_changed_cb);
gtk_builder_cscope_add_callback (scope, text_changed_cb);
gtk_builder_cscope_add_callback (scope, open_file_cb);
gtk_builder_cscope_add_callback (scope, open_folder_cb);
gtk_builder_cscope_add_callback (scope, on_drop);
gtk_builder_cscope_add_callback (scope, drag_prepare);
builder = gtk_builder_new ();
@@ -405,7 +369,7 @@ do_clipboard (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -4,9 +4,6 @@
<object class="GtkWindow" id="window">
<property name="resizable">1</property>
<property name="title">Clipboard</property>
<accessibility>
<relation name="described-by">label</relation>
</accessibility>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
@@ -16,7 +13,7 @@
<property name="margin-bottom">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label">
<object class="GtkLabel">
<property name="label">“Copy” will copy the selected data the clipboard, “Paste” will show the current clipboard contents. You can also drag the data to the bottom.</property>
<property name="wrap">1</property>
<property name="max-width-chars">40</property>
@@ -27,9 +24,6 @@
<property name="spacing">12</property>
<child>
<object class="GtkDropDown" id="source_chooser">
<accessibility>
<property name="label">Source Type</property>
</accessibility>
<property name="valign">center</property>
<property name="model">
<object class="GtkStringList">
@@ -38,7 +32,6 @@
<item>Color</item>
<item>Image</item>
<item>File</item>
<item>Folder</item>
</items>
</object>
</property>
@@ -60,9 +53,6 @@
<property name="name">Text</property>
<property name="child">
<object class="GtkEntry" id="source_text">
<accessibility>
<property name="label">Text Drag Source</property>
</accessibility>
<property name="valign">center</property>
<signal name="notify::text" handler="text_changed_cb" object="copy_button"/>
<property name="text">Copy this!</property>
@@ -74,14 +64,7 @@
<object class="GtkStackPage">
<property name="name">Color</property>
<property name="child">
<object class="GtkColorDialogButton" id="source_color">
<accessibility>
<property name="label">Color Drag Source</property>
</accessibility>
<property name="dialog">
<object class="GtkColorDialog">
</object>
</property>
<object class="GtkColorButton" id="source_color">
<property name="valign">center</property>
<property name="rgba">purple</property>
</object>
@@ -99,17 +82,14 @@
</style>
<child>
<object class="GtkToggleButton" id="image_rose">
<accessibility>
<property name="label">Photo Drag Source</property>
</accessibility>
<property name="active">1</property>
<child>
<object class="GtkDragSource">
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">Portland Rose Photo</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
@@ -120,9 +100,6 @@
</child>
<child>
<object class="GtkToggleButton" id="image_floppy">
<accessibility>
<property name="label">Icon Drag Source</property>
</accessibility>
<property name="group">image_rose</property>
<child>
<object class="GtkDragSource">
@@ -131,9 +108,6 @@
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">Floppy Buddy Icon</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
@@ -144,9 +118,6 @@
</child>
<child>
<object class="GtkToggleButton" id="image_logo">
<accessibility>
<property name="label">SVG Drag Source</property>
</accessibility>
<property name="group">image_floppy</property>
<child>
<object class="GtkDragSource">
@@ -155,9 +126,6 @@
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">gtk-demo logo</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
@@ -175,9 +143,6 @@
<property name="name">File</property>
<property name="child">
<object class="GtkButton" id="source_file">
<accessibility>
<property name="label">File Drag Source</property>
</accessibility>
<child>
<object class="GtkDragSource">
<property name="propagation-phase">capture</property>
@@ -197,33 +162,6 @@
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Folder</property>
<property name="child">
<object class="GtkButton" id="source_folder">
<accessibility>
<property name="label">Folder Drag Source</property>
</accessibility>
<child>
<object class="GtkDragSource">
<property name="propagation-phase">capture</property>
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<property name="valign">center</property>
<property name="child">
<object class="GtkLabel">
<property name="label">—</property>
<property name="xalign">0</property>
<property name="ellipsize">start</property>
</object>
</property>
<signal name="clicked" handler="open_folder_cb"/>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
@@ -258,7 +196,7 @@
</object>
</child>
<child>
<object class="GtkLabel" id="paste_label">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="visible-child-name" type="GtkStack">
@@ -285,9 +223,6 @@
<property name="name">Text</property>
<property name="child">
<object class="GtkLabel">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="xalign">0</property>
@@ -301,9 +236,6 @@
<property name="name">Image</property>
<property name="child">
<object class="GtkImage">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<style>
@@ -322,9 +254,6 @@
<property name="valign">center</property>
<child>
<object class="GtkColorSwatch">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="accessible-role">img</property>
<property name="can-focus">0</property>
<property name="selectable">0</property>
@@ -340,9 +269,6 @@
<property name="name">File</property>
<property name="child">
<object class="GtkLabel">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="xalign">0</property>

View File

@@ -11,8 +11,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum
{
ICON_NAME_COL,
@@ -262,12 +260,13 @@ mask_entry_set_background (MaskEntry *entry)
{
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
{
PangoAttrList *attrs;
Pango2AttrList *attrs;
Pango2Color color = { 65535, 32767, 32767, 65535 };
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&color));
gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
pango_attr_list_unref (attrs);
pango2_attr_list_unref (attrs);
return;
}
}
@@ -449,7 +448,7 @@ do_combobox (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -277,7 +277,7 @@ do_constraints (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -66,7 +66,7 @@ do_constraints_builder (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -229,7 +229,7 @@ do_constraints_interactive (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -152,7 +152,7 @@ do_constraints_vfl (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -1,16 +1,20 @@
/* Theming/CSS Accordion
*
* A simple accordion demo written using CSS transitions and multiple backgrounds
*
*/
#include <gtk/gtk.h>
static void
destroy_provider (GtkWidget *window,
GtkStyleProvider *provider)
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_remove_provider_for_display (gtk_widget_get_display (window), provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -20,8 +24,8 @@ do_css_accordion (GtkWidget *do_widget)
if (!window)
{
GtkWidget *container, *styled_box, *child;
GtkCssProvider *provider;
GtkWidget *container, *child;
GtkStyleProvider *provider;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "CSS Accordion");
@@ -29,13 +33,10 @@ do_css_accordion (GtkWidget *do_widget)
gtk_window_set_default_size (GTK_WINDOW (window), 600, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
styled_box = gtk_frame_new (NULL);
gtk_window_set_child (GTK_WINDOW (window), styled_box);
gtk_widget_add_css_class (styled_box, "accordion");
container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (container, GTK_ALIGN_CENTER);
gtk_widget_set_valign (container, GTK_ALIGN_CENTER);
gtk_frame_set_child (GTK_FRAME (styled_box), container);
gtk_window_set_child (GTK_WINDOW (window), container);
child = gtk_button_new_with_label ("This");
gtk_box_append (GTK_BOX (container), child);
@@ -55,20 +56,14 @@ do_css_accordion (GtkWidget *do_widget)
child = gtk_button_new_with_label (":-)");
gtk_box_append (GTK_BOX (container), child);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/css_accordion/css_accordion.css");
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/css_accordion/css_accordion.css");
gtk_style_context_add_provider_for_display (gtk_widget_get_display (window),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy_provider), provider);
g_object_unref (provider);
apply_css (window, provider);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -1,13 +1,13 @@
.accordion, .accordion * {
all: unset;
@import url("resource://css_accordion/reset.css");
* {
transition-property: color, background-color, border-color, background-image, padding, border-width;
transition-duration: 1s;
font: 20px Cantarell;
}
.accordion {
window {
background: linear-gradient(153deg, #151515, #151515 5px, transparent 5px) 0 0,
linear-gradient(333deg, #151515, #151515 5px, transparent 5px) 10px 5px,
linear-gradient(153deg, #222, #222 5px, transparent 5px) 0 5px,
@@ -18,7 +18,7 @@
background-size: 20px 20px;
}
.accordion button {
button {
color: black;
background-color: #bbb;
border-style: solid;
@@ -28,25 +28,25 @@
padding: 12px 4px;
}
.accordion button:first-child {
button:first-child {
border-radius: 5px 0 0 5px;
}
.accordion button:last-child {
button:last-child {
border-radius: 0 5px 5px 0;
border-width: 2px;
}
.accordion button:hover {
button:hover {
padding: 12px 48px;
background-color: #4870bc;
}
.accordion button *:hover {
button *:hover {
color: white;
}
.accordion button:hover:active,
.accordion button:active {
button:hover:active,
button:active {
background-color: #993401;
}

View File

@@ -47,23 +47,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -82,17 +79,16 @@ do_css_basics (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "CSS Basics");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO_UNDERLINE_SINGLE,
"underline", PANGO2_LINE_STYLE_SOLID,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO_UNDERLINE_ERROR,
"underline", PANGO2_LINE_STYLE_DOTTED,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -117,7 +113,7 @@ do_css_basics (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -4,24 +4,23 @@
* anymore. :)
*/
/* This resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
@import url("resource://css_shadows/reset.css");
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use */
@import url("resource://css_basics/reset.css");
/* Set a very futuristic style by default */
.demo * {
* {
color: green;
font-family: Monospace;
border: 1px solid;
}
window.demo {
window {
background-color: white;
}
/* Make sure selections are visible */
.demo selection {
selection {
background-color: darkGreen;
color: black;
}

View File

@@ -50,7 +50,7 @@ update_css_for_blend_mode (GtkCssProvider *provider,
blend_mode,
blend_mode);
gtk_css_provider_load_from_string (provider, css);
gtk_css_provider_load_from_data (provider, css, -1);
g_bytes_unref (bytes);
g_free (css);
@@ -139,7 +139,7 @@ do_css_blendmodes (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -48,23 +48,33 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
drawing_area_draw (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
GtkStyleProvider *provider = data;
GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (da));
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -83,17 +93,16 @@ do_css_multiplebgs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Multiple Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
child = gtk_drawing_area_new ();
/* Don't set a draw_func, since we are only interested in CSS drawing,
* which happens automatically.
*/
gtk_widget_set_name (child, "canvas");
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
drawing_area_draw,
NULL, NULL);
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
child = gtk_button_new ();
@@ -113,11 +122,11 @@ do_css_multiplebgs (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO_UNDERLINE_SINGLE,
"underline", PANGO2_LINE_STYLE_SOLID,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO_UNDERLINE_ERROR,
"underline", PANGO2_LINE_STYLE_DOTTED,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -144,7 +153,7 @@ do_css_multiplebgs (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -49,23 +49,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -84,7 +81,6 @@ do_css_pixbufs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Animated Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
@@ -97,11 +93,11 @@ do_css_pixbufs (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO_UNDERLINE_SINGLE,
"underline", PANGO2_LINE_STYLE_SOLID,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO_UNDERLINE_ERROR,
"underline", PANGO2_LINE_STYLE_DOTTED,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -126,7 +122,7 @@ do_css_pixbufs (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -50,7 +50,7 @@
100% { background-size: 12px, 96px, 12px, 96px, 12px, 96px, 12px, 96px, auto; }
}
window.demo {
window {
background-image: url("resource://css_pixbufs/images/apple-red.png"),
url("resource://css_pixbufs/images/gnome-applets.png"),
url("resource://css_pixbufs/images/gnome-calendar.png"),
@@ -66,11 +66,11 @@ window.demo {
}
/* Make the text editor has a nice style */
window.demo .view, scrollbar, separator {
.view, scrollbar, separator {
color: black;
background-color: rgba(255,255,255,0.5);
}
window.demo .view:selected {
.view:selected {
background-color: rgba(127,127,255,0.5);
}

View File

@@ -46,23 +46,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
static GtkWidget *
@@ -102,7 +99,6 @@ do_css_shadows (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Shadows");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
@@ -115,11 +111,11 @@ do_css_shadows (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO_UNDERLINE_SINGLE,
"underline", PANGO2_LINE_STYLE_SOLID,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO_UNDERLINE_ERROR,
"underline", PANGO2_LINE_STYLE_DOTTED,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -144,7 +140,7 @@ do_css_shadows (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -5,13 +5,12 @@
*/
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
* and overrides all user settings and the theme in use */
@import url("resource://css_shadows/reset.css");
@import url("resource://css_shadows/cssview.css");
/* Get a nice background for the window */
window.demo.background {
.background {
background-color: #4870bc;
background-image: linear-gradient(to left, transparent, rgba(255,255,255,.07) 50%, transparent 50%),
linear-gradient(to left, transparent, rgba(255,255,255,.13) 50%, transparent 50%),
@@ -20,7 +19,7 @@ window.demo.background {
background-size: 29px, 59px, 73px, 109px;
}
window.demo button {
button {
color: black;
padding: 10px;
border-radius: 5px;
@@ -28,15 +27,18 @@ window.demo button {
border: 1px transparent solid;
}
window.demo button:hover {
button:hover {
text-shadow: 3px 3px 5px alpha(black, 0.75);
-gtk-icon-shadow: 3px 3px 5px alpha(black, 0.75);
box-shadow: 3px 3px 5px alpha(black, 0.5) inset;
border: solid 1px alpha(black, 0.75);
}
window.demo button:active {
button:active {
padding: 11px 9px 9px 11px;
text-shadow: 1px 1px 2.5px alpha(black, 0.6);
-gtk-icon-shadow: 1px 1px 2.5px alpha(black, 0.6);
}

View File

@@ -1,21 +1,21 @@
/* Make the text editor has a nice style */
window.demo .view {
.view {
color: #2e3436;
font-family: Monospace;
background-color: alpha(white, 0.30);
}
window.demo .view:selected {
.view:selected {
color: white;
background-color: #4a90d9;
}
window.demo scrollbar trough,
scrollbar trough,
.scrollbars-junction {
background-color: alpha(white, 0.80);
}
window.demo scrollbar slider {
scrollbar slider {
border-width: 3px;
border-style: solid;
border-radius: 10px;
@@ -24,11 +24,11 @@ window.demo scrollbar slider {
background-color: #999;
}
window.demo scrollbar slider:hover {
scrollbar slider:hover {
background-color: #555;
}
window.demo paned separator {
paned separator {
background-color: alpha(white, 0.80);
background-image: linear-gradient(transparent, transparent 1px, #999 1px, #999 4px, transparent 4px);
background-size: 40px auto;
@@ -36,6 +36,6 @@ window.demo paned separator {
background-position: center;
}
window.demo paned separator:hover {
paned separator:hover {
background-image: linear-gradient(transparent, transparent 1px, #555 1px, #555 4px, transparent 4px);
}

View File

@@ -33,7 +33,7 @@ do_cursors (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -24,6 +24,7 @@
</gresource>
<gresource prefix="/css_accordion">
<file>css_accordion.css</file>
<file>reset.css</file>
</gresource>
<gresource prefix="/css_basics">
<file>css_basics.css</file>
@@ -43,7 +44,7 @@
<file>cssview.css</file>
<file>reset.css</file>
</gresource>
<gresource prefix="/listview_selections">
<gresource prefix="/dropdown">
<file>suggestionentry.h</file>
<file>suggestionentry.c</file>
<file>suggestionentry.css</file>
@@ -195,9 +196,6 @@
<gresource prefix="/listview_settings">
<file>listview_settings.ui</file>
</gresource>
<gresource prefix="/listview_settings2">
<file>listview_settings2.ui</file>
</gresource>
<gresource prefix="/listview_ucd_data/">
<file>ucdnames.data</file>
</gresource>
@@ -218,12 +216,6 @@
<file>demo3widget.h</file>
<file>demo3widget.ui</file>
</gresource>
<gresource prefix="/mask">
<file>demo4widget.c</file>
<file>demo4widget.h</file>
<file>hsla.h</file>
<file>hsla.c</file>
</gresource>
<gresource prefix="/paintable_svg">
<file>svgpaintable.h</file>
<file>svgpaintable.c</file>
@@ -277,6 +269,7 @@
<file>cursors.c</file>
<file>dialog.c</file>
<file>drawingarea.c</file>
<file>dropdown.c</file>
<file>dnd.c</file>
<file>editable_cells.c</file>
<file>entry_completion.c</file>
@@ -300,7 +293,6 @@
<file>iconscroll.c</file>
<file>iconview.c</file>
<file>iconview_edit.c</file>
<file>image_scaling.c</file>
<file>images.c</file>
<file>infobar.c</file>
<file>layoutmanager.c</file>
@@ -313,16 +305,14 @@
<file>listview_clocks.c</file>
<file>listview_filebrowser.c</file>
<file>listview_minesweeper.c</file>
<file>listview_selections.c</file>
<file>listview_settings.c</file>
<file>listview_settings2.c</file>
<file>listview_ucd.c</file>
<file>listview_weather.c</file>
<file>listview_words.c</file>
<file>list_store.c</file>
<file>main.c</file>
<file>markup.c</file>
<file>mask.c</file>
<file>menu.c</file>
<file>overlay.c</file>
<file>overlay_decorative.c</file>
<file>paint.c</file>
@@ -335,8 +325,6 @@
<file>paintable_symbolic.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>printing.c</file>
@@ -422,9 +410,6 @@
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>
@@ -443,8 +428,6 @@
<file>icons/16x16/emotes/face-laugh-symbolic.symbolic.png</file>
<file>icons/16x16/status/battery-caution-charging-symbolic.symbolic.png</file>
<file>icons/16x16/categories/applications-other.png</file>
<file>icons/48x48/status/starred.png</file>
<file alias="icons/scalable/apps/org.gtk.Demo4.svg">data/scalable/apps/org.gtk.Demo4.svg</file>
</gresource>
<gresource prefix="/org/gtk/Demo4/gtk">
<file preprocess="xml-stripblanks">help-overlay.ui</file>

View File

@@ -208,13 +208,7 @@
</object>
</child>
<child>
<object class="GtkLabel" id="statusbar1">
<property name="xalign">0</property>
<property name="margin-start">2</property>
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
</object>
<object class="GtkStatusbar" id="statusbar1"/>
</child>
</object>
</child>

View File

@@ -3,20 +3,16 @@
enum
{
PROP_TEXTURE = 1,
PROP_FILTER,
PROP_SCALE,
PROP_ANGLE,
PROP_PAINTABLE = 1,
PROP_SCALE
};
struct _Demo3Widget
{
GtkWidget parent_instance;
GdkTexture *texture;
GdkPaintable *paintable;
float scale;
float angle;
GskScalingFilter filter;
GtkWidget *menu;
};
@@ -28,86 +24,10 @@ struct _Demo3WidgetClass
G_DEFINE_TYPE (Demo3Widget, demo3_widget, GTK_TYPE_WIDGET)
static gboolean
query_tooltip (GtkWidget *widget,
int x,
int y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
gpointer data)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
GtkWidget *grid;
GtkWidget *label;
char *s, *s2;
const char *filter[] = { "Linear", "Nearest", "Trilinear" };
int precision, l;
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
label = gtk_label_new ("Texture");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
s = g_strdup_printf ("%d\342\200\206\303\227\342\200\206%d",
gdk_texture_get_width (self->texture),
gdk_texture_get_height (self->texture));
label = gtk_label_new (s);
g_free (s);
gtk_label_set_xalign (GTK_LABEL (label), 1);
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
label = gtk_label_new ("Rotation");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
s = g_strdup_printf ("%.1f", self->angle);
if (g_str_has_suffix (s, ".0"))
s[strlen (s) - 2] = '\0';
s2 = g_strconcat (s, "\302\260", NULL);
label = gtk_label_new (s2);
g_free (s2);
g_free (s);
gtk_label_set_xalign (GTK_LABEL (label), 1);
gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
label = gtk_label_new ("Scale");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
precision = 1;
do {
s = g_strdup_printf ("%.*f", precision, self->scale);
l = strlen (s) - 1;
while (s[l] == '0')
l--;
if (s[l] == '.')
s[l] = '\0';
precision++;
} while (strcmp (s, "0") == 0);
label = gtk_label_new (s);
g_free (s);
gtk_label_set_xalign (GTK_LABEL (label), 1);
gtk_grid_attach (GTK_GRID (grid), label, 1, 2, 1, 1);
label = gtk_label_new ("Filter");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
label = gtk_label_new (filter[self->filter]);
gtk_label_set_xalign (GTK_LABEL (label), 1);
gtk_grid_attach (GTK_GRID (grid), label, 1, 3, 1, 1);
gtk_tooltip_set_custom (tooltip, grid);
return TRUE;
}
static void
demo3_widget_init (Demo3Widget *self)
{
self->scale = 1.f;
self->angle = 0.f;
self->filter = GSK_SCALING_FILTER_LINEAR;
gtk_widget_init_template (GTK_WIDGET (self));
}
@@ -116,9 +36,8 @@ demo3_widget_dispose (GObject *object)
{
Demo3Widget *self = DEMO3_WIDGET (object);
g_clear_object (&self->texture);
gtk_widget_dispose_template (GTK_WIDGET (self), DEMO3_TYPE_WIDGET);
g_clear_object (&self->paintable);
g_clear_pointer (&self->menu, gtk_widget_unparent);
G_OBJECT_CLASS (demo3_widget_parent_class)->dispose (object);
}
@@ -129,35 +48,21 @@ demo3_widget_snapshot (GtkWidget *widget,
{
Demo3Widget *self = DEMO3_WIDGET (widget);
int x, y, width, height;
double w, h, w2, h2;
double w, h;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
w2 = w = self->scale * gdk_texture_get_width (self->texture);
h2 = h = self->scale * gdk_texture_get_height (self->texture);
w = self->scale * gdk_paintable_get_intrinsic_width (self->paintable);
h = self->scale * gdk_paintable_get_intrinsic_height (self->paintable);
if (G_APPROX_VALUE (self->angle, 90.f, FLT_EPSILON) ||
G_APPROX_VALUE (self->angle, 270.f, FLT_EPSILON))
{
double s = w2;
w2 = h2;
h2 = s;
}
x = (width - ceil (w2)) / 2;
y = (height - ceil (h2)) / 2;
x = MAX (0, (width - ceil (w)) / 2);
y = MAX (0, (height - ceil (h)) / 2);
gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (w2 / 2, h2 / 2));
gtk_snapshot_rotate (snapshot, self->angle);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- w / 2, - h / 2));
gtk_snapshot_append_scaled_texture (snapshot,
self->texture,
self->filter,
&GRAPHENE_RECT_INIT (0, 0, w, h));
gdk_paintable_snapshot (self->paintable, snapshot, w, h);
gtk_snapshot_restore (snapshot);
gtk_snapshot_pop (snapshot);
}
@@ -172,26 +77,14 @@ demo3_widget_measure (GtkWidget *widget,
int *natural_baseline)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
int width, height;
int size;
width = gdk_texture_get_width (self->texture);
height = gdk_texture_get_height (self->texture);
if (G_APPROX_VALUE (self->angle, 90.f, FLT_EPSILON) ||
G_APPROX_VALUE (self->angle, 270.f, FLT_EPSILON))
{
int s = width;
width = height;
height = s;
}
if (orientation == GTK_ORIENTATION_HORIZONTAL)
size = width;
size = gdk_paintable_get_intrinsic_width (self->paintable);
else
size = height;
size = gdk_paintable_get_intrinsic_height (self->paintable);
*minimum = *natural = (int) ceil (self->scale * size);
*minimum = *natural = self->scale * size;
}
static void
@@ -209,8 +102,6 @@ demo3_widget_size_allocate (GtkWidget *widget,
gtk_popover_present (GTK_POPOVER (self->menu));
}
static void update_actions (Demo3Widget *self);
static void
demo3_widget_set_property (GObject *object,
guint prop_id,
@@ -221,32 +112,14 @@ demo3_widget_set_property (GObject *object,
switch (prop_id)
{
case PROP_TEXTURE:
g_clear_object (&self->texture);
self->texture = g_value_dup_object (value);
self->scale = 1.f;
self->angle = 0.f;
self->filter = GSK_SCALING_FILTER_LINEAR;
update_actions (self);
case PROP_PAINTABLE:
g_clear_object (&self->paintable);
self->paintable = g_value_dup_object (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
g_object_notify (object, "scale");
g_object_notify (object, "angle");
g_object_notify (object, "filter");
break;
case PROP_SCALE:
self->scale = g_value_get_float (value);
update_actions (self);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
case PROP_ANGLE:
self->angle = fmodf (g_value_get_float (value), 360.f);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
case PROP_FILTER:
self->filter = g_value_get_enum (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
@@ -266,22 +139,14 @@ demo3_widget_get_property (GObject *object,
switch (prop_id)
{
case PROP_TEXTURE:
g_value_set_object (value, self->texture);
case PROP_PAINTABLE:
g_value_set_object (value, self->paintable);
break;
case PROP_SCALE:
g_value_set_float (value, self->scale);
break;
case PROP_ANGLE:
g_value_set_float (value, self->angle);
break;
case PROP_FILTER:
g_value_set_enum (value, self->filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -303,14 +168,6 @@ pressed_cb (GtkGestureClick *gesture,
gtk_popover_popup (GTK_POPOVER (self->menu));
}
static void
update_actions (Demo3Widget *self)
{
gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.in", self->scale < 1024.);
gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.out", self->scale > 1./1024.);
gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.reset", self->scale != 1.);
}
static void
zoom_cb (GtkWidget *widget,
const char *action_name,
@@ -320,30 +177,19 @@ zoom_cb (GtkWidget *widget,
float scale;
if (g_str_equal (action_name, "zoom.in"))
scale = MIN (1024., self->scale * M_SQRT2);
scale = MIN (10, self->scale * M_SQRT2);
else if (g_str_equal (action_name, "zoom.out"))
scale = MAX (1./1024., self->scale / M_SQRT2);
else if (g_str_equal (action_name, "zoom.reset"))
scale = 1.0;
scale = MAX (0.01, self->scale / M_SQRT2);
else
g_assert_not_reached ();
scale = 1.0;
gtk_widget_action_set_enabled (widget, "zoom.in", scale < 10);
gtk_widget_action_set_enabled (widget, "zoom.out", scale > 0.01);
gtk_widget_action_set_enabled (widget, "zoom.reset", scale != 1);
g_object_set (widget, "scale", scale, NULL);
}
static void
rotate_cb (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
int angle;
g_variant_get (parameter, "i", &angle);
g_object_set (widget, "angle", fmodf (self->angle + angle, 360.f), NULL);
}
static void
demo3_widget_class_init (Demo3WidgetClass *class)
{
@@ -358,55 +204,40 @@ demo3_widget_class_init (Demo3WidgetClass *class)
widget_class->measure = demo3_widget_measure;
widget_class->size_allocate = demo3_widget_size_allocate;
g_object_class_install_property (object_class, PROP_TEXTURE,
g_param_spec_object ("texture", NULL, NULL,
GDK_TYPE_TEXTURE,
g_object_class_install_property (object_class, PROP_PAINTABLE,
g_param_spec_object ("paintable", "Paintable", "Paintable",
GDK_TYPE_PAINTABLE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_SCALE,
g_param_spec_float ("scale", NULL, NULL,
1./1024., 1024., 1.0,
g_param_spec_float ("scale", "Scale", "Scale",
0.0, 10.0, 1.0,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_ANGLE,
g_param_spec_float ("angle", NULL, NULL,
0.0, 360.0, 0.0,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_FILTER,
g_param_spec_enum ("filter", NULL, NULL,
GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_LINEAR,
G_PARAM_READWRITE));
/* These are the actions that we are using in the menu */
gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "zoom.reset", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "rotate", "i", rotate_cb);
gtk_widget_class_set_template_from_resource (widget_class, "/menu/demo3widget.ui");
gtk_widget_class_bind_template_child (widget_class, Demo3Widget, menu);
gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
}
GtkWidget *
demo3_widget_new (const char *resource)
{
Demo3Widget *self;
GdkTexture *texture;
GdkPixbuf *pixbuf;
GdkPaintable *paintable;
texture = gdk_texture_new_from_resource (resource);
pixbuf = gdk_pixbuf_new_from_resource (resource, NULL);
paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
self = g_object_new (DEMO3_TYPE_WIDGET,
"texture", texture,
"has-tooltip", TRUE,
NULL);
self = g_object_new (DEMO3_TYPE_WIDGET, "paintable", paintable, NULL);
g_signal_connect (self, "query-tooltip", G_CALLBACK (query_tooltip), NULL);
g_object_unref (texture);
g_object_unref (pixbuf);
g_object_unref (paintable);
return GTK_WIDGET (self);
}

View File

@@ -12,21 +12,10 @@
<attribute name="label">11</attribute>
<attribute name="action">zoom.reset</attribute>
</item>
<item>
<attribute name="label">Rotate</attribute>
<attribute name="action">rotate</attribute>
<attribute name="target" type="i">90</attribute>
</item>
</menu>
<template class="Demo3Widget">
<accessibility>
<property name="label">Demo image</property>
</accessibility>
<child>
<object class="GtkPopoverMenu" id="menu">
<accessibility>
<property name="label">Context menu</property>
</accessibility>
<property name="has-arrow">0</property>
<property name="menu-model">model</property>
</object>

View File

@@ -1,226 +0,0 @@
#include <math.h>
#include "demo4widget.h"
#include "hsla.h"
enum
{
PROP_0,
PROP_PROGRESS,
};
struct _Demo4Widget
{
GtkWidget parent_instance;
PangoLayout *layout;
GskColorStop stops[8];
gsize n_stops;
double progress;
guint tick;
};
struct _Demo4WidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (Demo4Widget, demo4_widget, GTK_TYPE_WIDGET)
static void
rotate_color (GdkRGBA *rgba)
{
GdkHSLA hsla;
_gdk_hsla_init_from_rgba (&hsla, rgba);
hsla.hue -= 1;
_gdk_rgba_init_from_hsla (rgba, &hsla);
}
static gboolean
rotate_colors (GtkWidget *widget,
GdkFrameClock *clock,
gpointer user_data)
{
Demo4Widget *self = DEMO4_WIDGET (widget);
for (unsigned int i = 0; i < self->n_stops; i++)
rotate_color (&self->stops[i].color);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
demo4_widget_init (Demo4Widget *self)
{
PangoFontDescription *desc;
self->progress = 0.5;
self->n_stops = 8;
self->stops[0].offset = 0;
self->stops[0].color = (GdkRGBA) { 1, 0, 0, 1 };
for (unsigned int i = 1; i < self->n_stops; i++)
{
GdkHSLA hsla;
self->stops[i].offset = i / (double)(self->n_stops - 1);
_gdk_hsla_init_from_rgba (&hsla, &self->stops[i - 1].color);
hsla.hue += 360.0 / (double)(self->n_stops - 1);
_gdk_rgba_init_from_hsla (&self->stops[i].color, &hsla);
}
self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "123");
desc = pango_font_description_from_string ("Cantarell Bold 210");
pango_layout_set_font_description (self->layout, desc);
pango_font_description_free (desc);
self->tick = gtk_widget_add_tick_callback (GTK_WIDGET (self), rotate_colors, NULL, NULL);
}
static void
demo4_widget_dispose (GObject *object)
{
Demo4Widget *self = DEMO4_WIDGET (object);
g_clear_object (&self->layout);
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick);
G_OBJECT_CLASS (demo4_widget_parent_class)->dispose (object);
}
static void
demo4_widget_snapshot_content (GtkWidget *widget,
GtkSnapshot *snapshot,
GskMaskMode mode)
{
Demo4Widget *self = DEMO4_WIDGET (widget);
int width, height, layout_width, layout_height;
double scale;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_snapshot_push_mask (snapshot, mode);
pango_layout_get_pixel_size (self->layout, &layout_width, &layout_height);
scale = MIN ((double) width / layout_width, (double) height / layout_height);
gtk_snapshot_translate (snapshot,
&GRAPHENE_POINT_INIT ((width - scale * layout_width) / 2,
(height - scale * layout_height) / 2));
gtk_snapshot_scale (snapshot, scale, scale);
gtk_snapshot_append_layout (snapshot, self->layout, &(GdkRGBA) { 0, 0, 0, 1 });
gtk_snapshot_pop (snapshot);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
self->stops,
self->n_stops);
gtk_snapshot_pop (snapshot);
}
static void
demo4_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
Demo4Widget *self = DEMO4_WIDGET (widget);
int width, height;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_INVERTED_LUMINANCE);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, 0),
(GskColorStop[2]) {
{ MAX (0.0, self->progress - 5.0 / width), { 1, 1, 1, 1 } },
{ MIN (1.0, self->progress + 5.0 / width), { 0, 0, 0, 1 } }
}, 2);
gtk_snapshot_pop (snapshot);
demo4_widget_snapshot_content (widget, snapshot, GSK_MASK_MODE_INVERTED_ALPHA);
gtk_snapshot_pop (snapshot);
gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_LUMINANCE);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, 0),
(GskColorStop[2]) {
{ MAX (0.0, self->progress - 5.0 / width), { 1, 1, 1, 1 } },
{ MIN (1.0, self->progress + 5.0 / width), { 0, 0, 0, 1 } }
}, 2);
gtk_snapshot_pop (snapshot);
demo4_widget_snapshot_content (widget, snapshot, GSK_MASK_MODE_ALPHA);
gtk_snapshot_pop (snapshot);
}
static void
demo4_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
Demo4Widget *self = DEMO4_WIDGET (object);
switch (prop_id)
{
case PROP_PROGRESS:
self->progress = g_value_get_double (value);
gtk_widget_queue_draw (GTK_WIDGET (object));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo4_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
Demo4Widget *self = DEMO4_WIDGET (object);
switch (prop_id)
{
case PROP_PROGRESS:
g_value_set_double (value, self->progress);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo4_widget_class_init (Demo4WidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo4_widget_dispose;
object_class->get_property = demo4_widget_get_property;
object_class->set_property = demo4_widget_set_property;
widget_class->snapshot = demo4_widget_snapshot;
g_object_class_install_property (object_class, PROP_PROGRESS,
g_param_spec_double ("progress", NULL, NULL,
0.0, 1.0, 0.5,
G_PARAM_READWRITE));
}
GtkWidget *
demo4_widget_new (void)
{
return g_object_new (DEMO4_TYPE_WIDGET, NULL);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define DEMO4_TYPE_WIDGET (demo4_widget_get_type ())
G_DECLARE_FINAL_TYPE (Demo4Widget, demo4_widget, DEMO4, WIDGET, GtkWidget)
GtkWidget * demo4_widget_new (void);

View File

@@ -8,8 +8,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *window = NULL;
static GtkWidget *entry1 = NULL;
static GtkWidget *entry2 = NULL;
@@ -29,7 +27,7 @@ message_dialog_clicked (GtkButton *button,
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
ngettext ("Has been shown once", "Has been shown %d times", i), i);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
gtk_window_present (GTK_WINDOW (dialog));
gtk_widget_show (dialog);
i++;
}
@@ -116,7 +114,7 @@ interactive_dialog_clicked (GtkButton *button,
data, (GClosureNotify) g_free,
0);
gtk_window_present (GTK_WINDOW (dialog));
gtk_widget_show (dialog);
}
GtkWidget *
@@ -186,7 +184,7 @@ do_dialog (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -11,7 +11,6 @@
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
struct _CanvasItem {
@@ -25,9 +24,6 @@ struct _CanvasItem {
double delta;
GtkWidget *editor;
GtkStyleProvider *provider;
char *css_class;
};
struct _CanvasItemClass {
@@ -38,41 +34,32 @@ G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
static int n_items = 0;
static void
unstyle_item (CanvasItem *item)
{
if (item->provider)
{
gtk_style_context_remove_provider_for_display (gtk_widget_get_display (item->label), item->provider);
g_clear_object (&item->provider);
}
if (item->css_class)
{
gtk_widget_remove_css_class (item->label, item->css_class);
g_clear_pointer (&item->css_class, g_free);
}
}
static void
set_color (CanvasItem *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
const char *name;
unstyle_item (item);
const char *old_class;
str = gdk_rgba_to_string (color);
name = gtk_widget_get_name (item->label);
css = g_strdup_printf ("#%s { background: %s; }", name, str);
css = g_strdup_printf ("* { background: %s; }", str);
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_string (provider, css);
gtk_style_context_add_provider_for_display (gtk_widget_get_display (item->label), GTK_STYLE_PROVIDER (provider), 700);
item->provider = GTK_STYLE_PROVIDER (provider);
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
@@ -82,10 +69,21 @@ static void
set_css (CanvasItem *item,
const char *class)
{
unstyle_item (item);
GtkStyleContext *context;
GtkCssProvider *provider;
const char *old_class;
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
g_object_set_data_full (G_OBJECT (item->label), "css-class", g_strdup (class), g_free);
gtk_widget_add_css_class (item->label, class);
item->css_class = g_strdup (class);
}
static gboolean
@@ -109,21 +107,15 @@ static void
apply_transform (CanvasItem *item)
{
GskTransform *transform;
graphene_rect_t bounds;
double x, y;
/* Add css padding and margin */
if (!gtk_widget_compute_bounds (item->label, item->label, &bounds))
return;
x = bounds.size.width / 2.;
y = bounds.size.height / 2.;
item->r = sqrt (x * x + y * y);
x = gtk_widget_get_allocated_width (item->label) / 2.0;
y = gtk_widget_get_allocated_height (item->label) / 2.0;
item->r = sqrt (x*x + y*y);
transform = gsk_transform_translate (NULL, &(graphene_point_t) { item->r, item->r });
transform = gsk_transform_rotate (transform, item->angle + item->delta);
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-x, -y));
transform = gsk_transform_translate (transform, &(graphene_point_t) { -x, -y });
gtk_fixed_set_child_transform (GTK_FIXED (item->fixed), item->label, transform);
gsk_transform_unref (transform);
@@ -162,39 +154,27 @@ click_done (GtkGesture *gesture)
gtk_widget_insert_after (item, canvas, last_child);
}
/* GtkSettings treats `GTK_THEME=foo:dark` as theme name `foo`, variant `dark`,
* and our embedded CSS files let `foo-dark` work as an alias for `foo:dark`. */
static gboolean
has_dark_suffix (const char *theme)
{
return g_str_has_suffix (theme, ":dark") ||
g_str_has_suffix (theme, "-dark");
}
/* So we can make a good guess whether the current theme is dark by checking for
* either: it is suffixed `[:-]dark`, or Settings:…prefer-dark-theme is TRUE. */
static gboolean
theme_is_dark (void)
{
const char *env_theme;
GtkSettings *settings;
char *theme;
gboolean prefer_dark;
gboolean dark;
/* Like GtkSettings, 1st see if theme is overridden by environment variable */
env_theme = g_getenv ("GTK_THEME");
if (env_theme != NULL)
return has_dark_suffix (env_theme);
/* If not, test Settings:…theme-name in the same way OR :…prefer-dark-theme */
settings = gtk_settings_get_default ();
g_object_get (settings,
"gtk-theme-name", &theme,
"gtk-application-prefer-dark-theme", &prefer_dark,
NULL);
dark = prefer_dark || has_dark_suffix (theme);
if ((strcmp (theme, "Adwaita") == 0 && prefer_dark) || strcmp (theme, "HighContrastInverse") == 0)
dark = TRUE;
else
dark = FALSE;
g_free (theme);
return dark;
}
@@ -342,7 +322,7 @@ canvas_item_start_editing (CanvasItem *item)
GtkWidget *canvas = gtk_widget_get_parent (GTK_WIDGET (item));
GtkWidget *entry;
GtkWidget *scale;
graphene_point_t p;
double x, y;
if (item->editor)
return;
@@ -368,17 +348,12 @@ canvas_item_start_editing (CanvasItem *item)
gtk_box_append (GTK_BOX (item->editor), scale);
if (!gtk_widget_compute_point (GTK_WIDGET (item), canvas, &GRAPHENE_POINT_INIT (0, 0), &p))
graphene_point_init (&p, 0, 0);
gtk_fixed_put (GTK_FIXED (canvas), item->editor, p.x, p.y + 2 * item->r);
gtk_widget_translate_coordinates (GTK_WIDGET (item), canvas, 0, 0, &x, &y);
gtk_fixed_put (GTK_FIXED (canvas), item->editor, x, y + 2 * item->r);
gtk_widget_grab_focus (entry);
}
typedef struct {
double x, y;
} Hotspot;
static GdkContentProvider *
prepare (GtkDragSource *source,
double x,
@@ -386,8 +361,6 @@ prepare (GtkDragSource *source,
{
GtkWidget *canvas;
GtkWidget *item;
Hotspot *hotspot;
graphene_point_t p;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
@@ -398,13 +371,6 @@ prepare (GtkDragSource *source,
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
hotspot = g_new (Hotspot, 1);
if (!gtk_widget_compute_point (canvas, item, &GRAPHENE_POINT_INIT (x, y), &p))
graphene_point_init (&p, x, y);
hotspot->x = p.x;
hotspot->y = p.y;
g_object_set_data_full (G_OBJECT (canvas), "hotspot", hotspot, g_free);
return gdk_content_provider_new_typed (GTK_TYPE_WIDGET, item);
}
@@ -415,14 +381,12 @@ drag_begin (GtkDragSource *source,
GtkWidget *canvas;
CanvasItem *item;
GdkPaintable *paintable;
Hotspot *hotspot;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = CANVAS_ITEM (g_object_get_data (G_OBJECT (canvas), "dragged-item"));
hotspot = (Hotspot *) g_object_get_data (G_OBJECT (canvas), "hotspot");
paintable = canvas_item_get_drag_icon (item);
gtk_drag_source_set_icon (source, paintable, hotspot->x, hotspot->y);
gtk_drag_source_set_icon (source, paintable, item->r, item->r);
g_object_unref (paintable);
gtk_widget_set_opacity (GTK_WIDGET (item), 0.3);
@@ -758,9 +722,8 @@ do_dnd (GtkWidget *do_widget)
int i;
int x, y;
GtkCssProvider *provider;
GString *css;
button = gtk_color_dialog_button_new (gtk_color_dialog_new ());
button = gtk_color_button_new ();
g_object_unref (g_object_ref_sink (button));
provider = gtk_css_provider_new ();
@@ -770,18 +733,6 @@ do_dnd (GtkWidget *do_widget)
800);
g_object_unref (provider);
css = g_string_new ("");
for (i = 0; colors[i]; i++)
g_string_append_printf (css, ".canvasitem.%s { background: %s; }\n", colors[i], colors[i]);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_string (provider, css->str);
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
g_string_free (css, TRUE);
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
@@ -834,7 +785,7 @@ do_dnd (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -334,17 +334,11 @@ do_drawingarea (GtkWidget *do_widget)
gtk_widget_set_vexpand (frame, TRUE);
gtk_box_append (GTK_BOX (vbox), frame);
da = g_object_new (GTK_TYPE_DRAWING_AREA,
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
gtk_accessible_update_relation (GTK_ACCESSIBLE (da),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
-1);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), groups_draw, NULL, NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
/*
* Create the scribble area
@@ -358,23 +352,17 @@ do_drawingarea (GtkWidget *do_widget)
gtk_widget_set_vexpand (frame, TRUE);
gtk_box_append (GTK_BOX (vbox), frame);
da = g_object_new (GTK_TYPE_DRAWING_AREA,
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
gtk_accessible_update_relation (GTK_ACCESSIBLE (da),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
-1);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), scribble_draw, NULL, NULL);
gtk_frame_set_child (GTK_FRAME (frame), da);
g_signal_connect (da, "resize",
G_CALLBACK (scribble_resize), NULL);
drag = gtk_gesture_drag_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), 0);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
gtk_widget_add_controller (da, GTK_EVENT_CONTROLLER (drag));
g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), da);
@@ -384,7 +372,7 @@ do_drawingarea (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -164,14 +164,14 @@ strings_bind_item (GtkSignalListItemFactory *factory,
popup = gtk_widget_get_ancestor (title, GTK_TYPE_POPOVER);
if (popup && gtk_widget_is_ancestor (popup, GTK_WIDGET (dropdown)))
{
gtk_widget_set_visible (checkmark, TRUE);
gtk_widget_show (checkmark);
g_signal_connect (dropdown, "notify::selected-item",
G_CALLBACK (selected_item_changed), item);
selected_item_changed (dropdown, NULL, item);
}
else
{
gtk_widget_set_visible (checkmark, FALSE);
gtk_widget_hide (checkmark);
}
}
@@ -263,7 +263,7 @@ drop_down_new_from_strings (const char *const *titles,
static char *
get_family_name (gpointer item)
{
return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
return g_strdup (pango2_font_family_get_name (PANGO2_FONT_FAMILY (item)));
}
static char *
@@ -326,8 +326,8 @@ bind_highlight_item (GtkSignalListItemFactory *factory,
{
MatchObject *obj;
GtkWidget *label;
PangoAttrList *attrs;
PangoAttribute *attr;
Pango2AttrList *attrs;
Pango2Attribute *attr;
const char *str;
obj = MATCH_OBJECT (gtk_list_item_get_item (item));
@@ -336,13 +336,14 @@ bind_highlight_item (GtkSignalListItemFactory *factory,
str = match_object_get_string (obj);
gtk_label_set_label (GTK_LABEL (label), str);
attrs = pango_attr_list_new ();
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
attr->start_index = match_object_get_match_start (obj);
attr->end_index = match_object_get_match_end (obj);
pango_attr_list_insert (attrs, attr);
attrs = pango2_attr_list_new ();
attr = pango2_attr_weight_new (PANGO2_WEIGHT_BOLD);
pango2_attribute_set_range (attr,
match_object_get_match_start (obj),
match_object_get_match_end (obj));
pango2_attr_list_insert (attrs, attr);
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango_attr_list_unref (attrs);
pango2_attr_list_unref (attrs);
}
static void
@@ -368,40 +369,8 @@ match_func (MatchObject *obj,
g_free (tmp2);
}
static void
setup_header (GtkSignalListItemFactory *factory,
GObject *list_item,
gpointer data)
{
GtkListHeader *self = GTK_LIST_HEADER (list_item);
GtkWidget *child;
child = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (child), 0);
gtk_label_set_use_markup (GTK_LABEL (child), TRUE);
gtk_widget_set_margin_top (child, 10);
gtk_widget_set_margin_bottom (child, 10);
gtk_list_header_set_child (self, child);
}
static void
bind_header (GtkSignalListItemFactory *factory,
GObject *list_item,
gpointer data)
{
GtkListHeader *self = GTK_LIST_HEADER (list_item);
GtkWidget *child = gtk_list_header_get_child (self);
GObject *item = gtk_list_header_get_item (self);
if (strstr (gtk_string_object_get_string (GTK_STRING_OBJECT (item)), "hour"))
gtk_label_set_label (GTK_LABEL (child), "<big><b>Hours</b></big>");
else
gtk_label_set_label (GTK_LABEL (child), "<big><b>Minutes</b></big>");
}
GtkWidget *
do_listview_selections (GtkWidget *do_widget)
do_dropdown (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *button, *box, *spin, *check, *hbox, *label, *entry;
@@ -409,12 +378,10 @@ do_listview_selections (GtkWidget *do_widget)
GtkExpression *expression;
GtkListItemFactory *factory;
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL };
const char * const minutes[] = {
const char * const many_times[] = {
"1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
"25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
"55 minutes", NULL
};
const char * const hours[] = { "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
"55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
"8 hours", "9 hours", "10 hours", "11 hours", "12 hours", NULL
};
const char * const device_titles[] = { "Digital Output", "Headphones", "Digital Output", "Analog Output", NULL };
@@ -429,10 +396,6 @@ do_listview_selections (GtkWidget *do_widget)
if (!window)
{
GtkStringList *minutes_model, *hours_model;
GListStore *store;
GtkFlattenListModel *flat;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
@@ -460,30 +423,19 @@ do_listview_selections (GtkWidget *do_widget)
gtk_box_append (GTK_BOX (box), button);
/* A dropdown using an expression to obtain strings */
minutes_model = gtk_string_list_new (minutes);
hours_model = gtk_string_list_new (hours);
store = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (store, minutes_model);
g_list_store_append (store, hours_model);
g_object_unref (minutes_model);
g_object_unref (hours_model);
flat = gtk_flatten_list_model_new (G_LIST_MODEL (store));
button = drop_down_new_from_strings (many_times, NULL, NULL);
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
button = gtk_drop_down_new (G_LIST_MODEL (flat), expression);
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_header), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_header), NULL);
gtk_drop_down_set_header_factory (GTK_DROP_DOWN (button), factory);
g_object_unref (factory);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
button = gtk_drop_down_new (NULL, NULL);
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
model = G_LIST_MODEL (pango2_font_map_get_default ());
gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
@@ -612,7 +564,7 @@ do_listview_selections (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -14,8 +14,6 @@
#include <string.h>
#include <stdlib.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct
{
int number;
@@ -409,7 +407,7 @@ do_editable_cells (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -8,8 +8,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Creates a tree model containing the completions */
static GtkTreeModel *
create_completion_model (void)
@@ -95,13 +93,6 @@ do_entry_completion (GtkWidget *do_widget)
entry = gtk_entry_new ();
gtk_box_append (GTK_BOX (vbox), entry);
gtk_accessible_update_relation (GTK_ACCESSIBLE (entry),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
-1);
gtk_accessible_update_property (GTK_ACCESSIBLE (entry),
GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE, GTK_ACCESSIBLE_AUTOCOMPLETE_LIST,
-1);
/* Create the completion object */
completion = gtk_entry_completion_new ();
@@ -122,7 +113,7 @@ do_entry_completion (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -43,14 +43,10 @@ do_entry_undo (GtkWidget *do_widget)
entry = gtk_entry_new ();
gtk_editable_set_enable_undo (GTK_EDITABLE (entry), TRUE);
gtk_box_append (GTK_BOX (vbox), entry);
gtk_accessible_update_relation (GTK_ACCESSIBLE (entry),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
-1);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));

Some files were not shown because too many files have changed in this diff Show More