Compare commits
4 Commits
pango2
...
shader-cac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d497b83a | ||
|
|
37767e056f | ||
|
|
c7e1ab67c6 | ||
|
|
4a2e73a07c |
@@ -1,11 +0,0 @@
|
||||
# See https://wiki.apertis.org/Guidelines/Coding_conventions#Code_formatting
|
||||
BasedOnStyle: GNU
|
||||
AlwaysBreakAfterDefinitionReturnType: All
|
||||
BreakBeforeBinaryOperators: None
|
||||
BinPackParameters: false
|
||||
SpaceAfterCStyleCast: true
|
||||
# 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
|
||||
# existing hanging indents.
|
||||
ColumnLimit: 0
|
||||
@@ -1,32 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2021 The GTK Authors
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.[ch]]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
# For the legacy tabs which still exist in the code:
|
||||
tab_width = 8
|
||||
|
||||
[*.ui]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
|
||||
[*.xml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[meson.build]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.md]
|
||||
max_line_length = 80
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/subprojects/*/
|
||||
365
.gitlab-ci.yml
365
.gitlab-ci.yml
@@ -1,356 +1,43 @@
|
||||
include:
|
||||
- project: 'gnome/citemplates'
|
||||
file: 'flatpak/flatpak_ci_initiative.yml'
|
||||
|
||||
stages:
|
||||
- build
|
||||
- analysis
|
||||
- docs
|
||||
- flatpak
|
||||
- publish
|
||||
- deploy
|
||||
|
||||
.cache-paths: &cache-paths
|
||||
paths:
|
||||
- _ccache/
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
|
||||
# Common variables
|
||||
variables:
|
||||
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"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 3
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v38"
|
||||
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
|
||||
|
||||
.only-default:
|
||||
only:
|
||||
- branches
|
||||
except:
|
||||
- tags
|
||||
|
||||
style-check-diff:
|
||||
extends: .only-default
|
||||
image: $FEDORA_IMAGE
|
||||
stage: .pre
|
||||
allow_failure: true
|
||||
gtk:
|
||||
image: ebassi/gitlab-gtk:latest
|
||||
stage: build
|
||||
before_script:
|
||||
- export CCACHE_DISABLE=true_
|
||||
script:
|
||||
- .gitlab-ci/run-style-check-diff.sh
|
||||
|
||||
.build-fedora-default:
|
||||
extends: .only-default
|
||||
image: $FEDORA_IMAGE
|
||||
- bash -x ./.gitlab-ci/test-docker.sh
|
||||
cache:
|
||||
paths:
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit:
|
||||
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
|
||||
when: on_failure
|
||||
name: "gtk-${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
- "${CI_PROJECT_DIR}/_build/report*.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report*.html"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.png"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.node"
|
||||
- "${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_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
|
||||
stage: build
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- 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 waylandgles
|
||||
- .gitlab-ci/run-tests.sh _build broadway
|
||||
|
||||
release-build:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release"
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- meson subprojects update
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
|
||||
_build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
|
||||
installed-tests:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--prefix=/usr --libdir=/usr/lib64 -Dinstall-tests=true"
|
||||
G_TEST_ACCESSIBLE: 1
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- meson subprojects update
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
|
||||
_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/"
|
||||
|
||||
|
||||
.mingw-defaults:
|
||||
extends: .only-default
|
||||
stage: build
|
||||
tags:
|
||||
- win32-ps
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
|
||||
cache:
|
||||
key: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- _ccache/
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
|
||||
msys2-mingw64:
|
||||
extends: .mingw-defaults
|
||||
needs: []
|
||||
variables:
|
||||
MSYSTEM: "MINGW64"
|
||||
CHERE_INVOKING: "yes"
|
||||
artifacts:
|
||||
when: always
|
||||
expose_as: 'Windows_DLL_MSYS2_64_bit_toolchain'
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
|
||||
|
||||
macos:
|
||||
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==0.60.3
|
||||
- pip3 install --user ninja
|
||||
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
|
||||
- export MESON_FORCE_BACKTRACE=1
|
||||
script:
|
||||
- meson -Dx11-backend=false
|
||||
-Dbroadway-backend=true
|
||||
-Dmacos-backend=true
|
||||
-Dmedia-gstreamer=disabled
|
||||
-Dintrospection=disabled
|
||||
-Dcpp_std=c++11
|
||||
-Dpixman:tests=disabled
|
||||
_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.
|
||||
#only:
|
||||
# - branches@GNOME/gtk
|
||||
stage: build
|
||||
tags:
|
||||
- win32-ps
|
||||
needs: []
|
||||
script:
|
||||
- .gitlab-ci/test-msvc.bat
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
|
||||
.flatpak-defaults:
|
||||
image: $FLATPAK_IMAGE
|
||||
flatpak:demo:
|
||||
image: registry.gitlab.com/alatiera/gnome-nightly-oci/gnome-master:latest
|
||||
stage: flatpak
|
||||
allow_failure: true
|
||||
tags:
|
||||
- flatpak
|
||||
script:
|
||||
- bash -x ./.gitlab-ci/flatpak-build.sh org.gtk.Demo
|
||||
artifacts:
|
||||
paths:
|
||||
- "${APPID}-dev.flatpak"
|
||||
- 'repo.tar'
|
||||
- org.gtk.Demo-dev.flatpak
|
||||
expire_in: 1 day
|
||||
|
||||
flatpak:widget-factory:
|
||||
image: registry.gitlab.com/alatiera/gnome-nightly-oci/gnome-master:latest
|
||||
stage: flatpak
|
||||
script:
|
||||
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
|
||||
|
||||
# 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-main:demo:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
|
||||
flatpak-manual:widget-factory:
|
||||
extends: .flatpak-manual
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak-main:widget-factory:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak-manual:icon-browser:
|
||||
extends: .flatpak-manual
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
flatpak-main:icon-browser:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
# 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'
|
||||
dependencies: ['flatpak-main:demo']
|
||||
needs: ['flatpak-main:demo']
|
||||
|
||||
nightly factory:
|
||||
extends: '.publish_nightly'
|
||||
dependencies: ['flatpak-main:widget-factory']
|
||||
needs: ['flatpak-main:widget-factory']
|
||||
|
||||
nightly icon-browser:
|
||||
extends: '.publish_nightly'
|
||||
dependencies: ['flatpak-main:icon-browser']
|
||||
needs: ['flatpak-main:icon-browser']
|
||||
|
||||
static-scan:
|
||||
image: $FEDORA_IMAGE
|
||||
stage: analysis
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug"
|
||||
script:
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} _scan_build
|
||||
- ninja -C _scan_build scan-build
|
||||
- bash -x ./.gitlab-ci/flatpak-build.sh org.gtk.WidgetFactory
|
||||
artifacts:
|
||||
paths:
|
||||
- _scan_build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
# 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 ]
|
||||
stage: analysis
|
||||
needs: []
|
||||
variables:
|
||||
script:
|
||||
- CC=clang meson --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=disabled _build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
artifacts:
|
||||
paths:
|
||||
- _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:
|
||||
- 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/
|
||||
- mv _build/docs/reference/gdk/gdk4-x11/ _reference/gdk4-x11/
|
||||
- mv _build/docs/reference/gdk/gdk4-wayland/ _reference/gdk4-wayland/
|
||||
- mv _build/docs/reference/gsk/gsk4/ _reference/gsk4/
|
||||
- mv _build/docs/reference/gtk/gtk4/ _reference/gtk4/
|
||||
- mv _build/subprojects/pango/docs/Pango/ _reference/Pango/
|
||||
- mv _build/subprojects/pango/docs/PangoCairo/ _reference/PangoCairo/
|
||||
- mv _build/subprojects/pango/docs/PangoFc/ _reference/PangoFc/
|
||||
- mv _build/subprojects/pango/docs/PangoFT2/ _reference/PangoFT2/
|
||||
- mv _build/subprojects/pango/docs/PangoOT/ _reference/PangoOT/
|
||||
- mv _build/subprojects/pango/docs/PangoXft/ _reference/PangoXft/
|
||||
- mv _build/subprojects/gdk-pixbuf/docs/gdk-pixbuf/ _reference/gdk-pixbuf/
|
||||
- mv _build/subprojects/gdk-pixbuf/docs/gdk-pixdata/ _reference/gdk-pixdata/
|
||||
artifacts:
|
||||
paths:
|
||||
- _reference
|
||||
|
||||
publish-docs:
|
||||
image: fedora:latest
|
||||
stage: publish
|
||||
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"
|
||||
only:
|
||||
refs:
|
||||
- main
|
||||
- org.gtk.WidgetFactory-dev.flatpak
|
||||
expire_in: 1 day
|
||||
|
||||
79
.gitlab-ci/Dockerfile
Normal file
79
.gitlab-ci/Dockerfile
Normal file
@@ -0,0 +1,79 @@
|
||||
FROM fedora:27
|
||||
|
||||
RUN dnf -y install \
|
||||
adwaita-icon-theme \
|
||||
atk-devel \
|
||||
at-spi2-atk-devel \
|
||||
avahi-gobject-devel \
|
||||
cairo-devel \
|
||||
cairo-gobject-devel \
|
||||
ccache \
|
||||
colord-devel \
|
||||
cups-devel \
|
||||
desktop-file-utils \
|
||||
elfutils-libelf-devel \
|
||||
fribidi-devel \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
gdk-pixbuf2-devel \
|
||||
gdk-pixbuf2-modules \
|
||||
gettext \
|
||||
git \
|
||||
glib2-devel \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
gobject-introspection-devel \
|
||||
graphene-devel \
|
||||
gstreamer1-devel \
|
||||
gstreamer1-plugins-good \
|
||||
gstreamer1-plugins-bad-free-devel \
|
||||
gstreamer1-plugins-base-devel \
|
||||
iso-codes \
|
||||
itstool \
|
||||
json-glib-devel \
|
||||
libattr-devel \
|
||||
libepoxy-devel \
|
||||
libffi-devel \
|
||||
libmount-devel \
|
||||
librsvg2 \
|
||||
libselinux-devel \
|
||||
libXcomposite-devel \
|
||||
libXcursor-devel \
|
||||
libXcursor-devel \
|
||||
libXdamage-devel \
|
||||
libXfixes-devel \
|
||||
libXi-devel \
|
||||
libXinerama-devel \
|
||||
libxkbcommon-devel \
|
||||
libXrandr-devel \
|
||||
libXrender-devel \
|
||||
libxslt \
|
||||
mesa-dri-drivers \
|
||||
mesa-libEGL-devel \
|
||||
mesa-libwayland-egl-devel \
|
||||
ninja-build \
|
||||
pango-devel \
|
||||
pcre-devel \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-wheel \
|
||||
redhat-rpm-config \
|
||||
sassc \
|
||||
systemtap-sdt-devel \
|
||||
vulkan-devel \
|
||||
wayland-devel \
|
||||
wayland-protocols-devel \
|
||||
which \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf clean all
|
||||
|
||||
RUN pip3 install meson
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
@@ -1,50 +0,0 @@
|
||||
## GTK CI infrastructure
|
||||
|
||||
GTK uses different CI images depending on platform and jobs.
|
||||
|
||||
The CI images are Docker containers, generated either using `docker` or
|
||||
`podman`, and pushed to the GitLab [container registry][registry].
|
||||
|
||||
Each Docker image has a tag composed of two parts:
|
||||
|
||||
- `${image}`: the base image for a given platform, like "fedora" or
|
||||
"debian-stable"
|
||||
- `${number}`: an incremental version number, or `latest`
|
||||
|
||||
See the [container registry][registry] for the available images for each
|
||||
branch, as well as their available versions.
|
||||
|
||||
Note that using `latest` as version number will overwrite the most
|
||||
recently uploaded image in the registry.
|
||||
|
||||
### Checklist for Updating a CI image
|
||||
|
||||
- [ ] Update the `${image}.Dockerfile` file with the dependencies
|
||||
- [ ] Run `./run-docker.sh build --base ${image} --version ${number}`
|
||||
- [ ] Run `./run-docker.sh push --base ${image} --version ${number}`
|
||||
once the Docker image is built; you may need to log in by using
|
||||
`docker login` or `podman login`
|
||||
- [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new
|
||||
image tag
|
||||
- [ ] Open a merge request with your changes and let it run
|
||||
|
||||
### Checklist for Adding a new CI image
|
||||
|
||||
- [ ] Write a new `${image}.Dockerfile` with the instructions to set up
|
||||
a build environment
|
||||
- [ ] Add the `pip3 install meson` incantation
|
||||
- [ ] Run `./run-docker.sh build --base ${image} --version ${number}`
|
||||
- [ ] Run `./run-docker.sh push --base ${image} --version ${number}`
|
||||
- [ ] Add the new job to `.gitlab-ci.yml` referencing the image
|
||||
- [ ] Open a merge request with your changes and let it run
|
||||
|
||||
### Checklist for Adding a new dependency to a CI image
|
||||
|
||||
Our images are layered, and the base (called fedora-base) contains
|
||||
all the rpm payload. Therefore, adding a new dependency is a 2-step
|
||||
process:
|
||||
|
||||
1. [ ] Build and upload fedora-base:$version+1
|
||||
1. [ ] Build and upload fedora:$version+1 based on fedora-base:version+1
|
||||
|
||||
[registry]: https://gitlab.gnome.org/GNOME/gtk/container_registry
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# === clang-format-diff.py - ClangFormat Diff Reformatter ---*- python -*-=== #
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===---------------------------------------------------------------------=== #
|
||||
|
||||
"""
|
||||
This script reads input from a unified diff and reformats all the changed
|
||||
lines. This is useful to reformat all the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
|
||||
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.version_info.major >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('-i', action='store_true', default=False,
|
||||
help='apply edits to files instead of displaying a '
|
||||
'diff')
|
||||
parser.add_argument('-p', metavar='NUM', default=0,
|
||||
help='strip the smallest prefix containing P slashes')
|
||||
parser.add_argument('-regex', metavar='PATTERN', default=None,
|
||||
help='custom pattern selecting file paths to reformat '
|
||||
'(case sensitive, overrides -iregex)')
|
||||
parser.add_argument('-iregex', metavar='PATTERN',
|
||||
default=r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hh|hpp|m|mm|inc'
|
||||
r'|js|ts|proto|protodevel|java|cs)',
|
||||
help='custom pattern selecting file paths to reformat '
|
||||
'(case insensitive, overridden by -regex)')
|
||||
parser.add_argument('-sort-includes', action='store_true', default=False,
|
||||
help='let clang-format sort include blocks')
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
help='be more verbose, ineffective without -i')
|
||||
parser.add_argument('-style',
|
||||
help='formatting style to apply (LLVM, Google, '
|
||||
'Chromium, Mozilla, WebKit)')
|
||||
parser.add_argument('-binary', default='clang-format',
|
||||
help='location of binary to use for clang-format')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename is None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match('^%s$' % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
continue
|
||||
end_line = start_line + line_count - 1
|
||||
lines_by_file.setdefault(filename, []).extend(
|
||||
['-lines', str(start_line) + ':' + str(end_line)])
|
||||
|
||||
# Reformat files containing changes in place.
|
||||
# We need to count amount of bytes generated in the output of
|
||||
# clang-format-diff. If clang-format-diff doesn't generate any bytes it
|
||||
# means there is nothing to format.
|
||||
format_line_counter = 0
|
||||
for filename, lines in lines_by_file.items():
|
||||
if args.i and args.verbose:
|
||||
print('Formatting {}'.format(filename))
|
||||
command = [args.binary, filename]
|
||||
if args.i:
|
||||
command.append('-i')
|
||||
if args.sort_includes:
|
||||
command.append('-sort-includes')
|
||||
command.extend(lines)
|
||||
if args.style:
|
||||
command.extend(['-style', args.style])
|
||||
p = subprocess.Popen(command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=None,
|
||||
stdin=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
stdout, _ = p.communicate()
|
||||
if p.returncode != 0:
|
||||
sys.exit(p.returncode)
|
||||
|
||||
if not args.i:
|
||||
with open(filename) as f:
|
||||
code = f.readlines()
|
||||
formatted_code = StringIO(stdout).readlines()
|
||||
diff = difflib.unified_diff(code, formatted_code,
|
||||
filename, filename,
|
||||
'(before formatting)',
|
||||
'(after formatting)')
|
||||
diff_string = ''.join(diff)
|
||||
if diff_string:
|
||||
format_line_counter += sys.stdout.write(diff_string)
|
||||
|
||||
if format_line_counter > 0:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,111 +0,0 @@
|
||||
FROM fedora:36
|
||||
|
||||
RUN dnf -y install \
|
||||
adwaita-icon-theme \
|
||||
atk-devel \
|
||||
at-spi2-atk-devel \
|
||||
avahi-gobject-devel \
|
||||
cairo-devel \
|
||||
cairo-gobject-devel \
|
||||
ccache \
|
||||
clang \
|
||||
clang-analyzer \
|
||||
clang-tools-extra \
|
||||
colord-devel \
|
||||
cups-devel \
|
||||
dbus-daemon \
|
||||
dbus-x11 \
|
||||
dejavu-sans-mono-fonts \
|
||||
desktop-file-utils \
|
||||
diffutils \
|
||||
elfutils-libelf-devel \
|
||||
fribidi-devel \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
gdk-pixbuf2-devel \
|
||||
gdk-pixbuf2-modules \
|
||||
gettext \
|
||||
git \
|
||||
glib2-devel \
|
||||
glib2-static \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
gnome-desktop-testing \
|
||||
gobject-introspection-devel \
|
||||
graphene-devel \
|
||||
graphviz \
|
||||
gstreamer1-devel \
|
||||
gstreamer1-plugins-good \
|
||||
gstreamer1-plugins-bad-free-devel \
|
||||
gstreamer1-plugins-base-devel \
|
||||
hicolor-icon-theme \
|
||||
iso-codes \
|
||||
itstool \
|
||||
json-glib-devel \
|
||||
lcov \
|
||||
libasan \
|
||||
libattr-devel \
|
||||
libcloudproviders-devel \
|
||||
libepoxy-devel \
|
||||
libffi-devel \
|
||||
libjpeg-turbo-devel \
|
||||
libmount-devel \
|
||||
libpng-devel \
|
||||
librsvg2 \
|
||||
libselinux-devel \
|
||||
libtiff-devel \
|
||||
libubsan \
|
||||
libXcomposite-devel \
|
||||
libXcursor-devel \
|
||||
libXcursor-devel \
|
||||
libXdamage-devel \
|
||||
libXfixes-devel \
|
||||
libXi-devel \
|
||||
libXinerama-devel \
|
||||
libxkbcommon-devel \
|
||||
libXrandr-devel \
|
||||
libXrender-devel \
|
||||
libXtst-devel \
|
||||
libxslt \
|
||||
mesa-dri-drivers \
|
||||
mesa-libEGL-devel \
|
||||
mesa-libGLES-devel \
|
||||
meson \
|
||||
ninja-build \
|
||||
pango-devel \
|
||||
pcre-devel \
|
||||
pcre-static \
|
||||
python3 \
|
||||
python3-docutils \
|
||||
python3-gobject \
|
||||
python3-jinja2 \
|
||||
python3-markdown \
|
||||
python3-pip \
|
||||
python3-pygments \
|
||||
python3-toml \
|
||||
python3-typogrify \
|
||||
python3-wheel \
|
||||
redhat-rpm-config \
|
||||
sassc \
|
||||
vulkan-devel \
|
||||
wayland-devel \
|
||||
wayland-protocols-devel \
|
||||
weston \
|
||||
weston-libs \
|
||||
which \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf install -y 'dnf-command(builddep)' \
|
||||
&& dnf builddep -y wayland \
|
||||
&& dnf clean all
|
||||
|
||||
# Enable sudo for wheel users
|
||||
RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -G wheel -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
@@ -4,33 +4,34 @@ set -e
|
||||
|
||||
appid=$1
|
||||
|
||||
builddir=flatpak_app
|
||||
builddir=app
|
||||
repodir=repo
|
||||
|
||||
flatpak-builder \
|
||||
--user --disable-rofiles-fuse \
|
||||
--stop-at=gtk \
|
||||
${builddir} \
|
||||
build-aux/flatpak/${appid}.json
|
||||
|
||||
flatpak build ${builddir} meson \
|
||||
--prefix=/app \
|
||||
--libdir=/app/lib \
|
||||
--buildtype=release \
|
||||
flatpak-builder \
|
||||
--run ${builddir} build-aux/flatpak/${appid}.json \
|
||||
meson \
|
||||
--prefix /app \
|
||||
--libdir /app/lib \
|
||||
--buildtype debug \
|
||||
-Dx11-backend=true \
|
||||
-Dwayland-backend=true \
|
||||
-Dprint-backends=file \
|
||||
-Dbuild-tests=false \
|
||||
-Dbuild-examples=false \
|
||||
-Dintrospection=disabled \
|
||||
-Dintrospection=false \
|
||||
-Ddemos=true \
|
||||
-Dprofile=devel \
|
||||
_flatpak_build
|
||||
|
||||
flatpak build ${builddir} ninja -C _flatpak_build install
|
||||
_build .
|
||||
|
||||
flatpak-builder \
|
||||
--run ${builddir} build-aux/flatpak/${appid}.json \
|
||||
ninja -C _build install
|
||||
|
||||
flatpak-builder \
|
||||
--user --disable-rofiles-fuse \
|
||||
--finish-only \
|
||||
--repo=${repodir} \
|
||||
${builddir} \
|
||||
@@ -39,10 +40,5 @@ flatpak-builder \
|
||||
flatpak build-bundle \
|
||||
${repodir} \
|
||||
${appid}-dev.flatpak \
|
||||
--runtime-repo=https://nightly.gnome.org/gnome-nightly.flatpakrepo \
|
||||
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo \
|
||||
${appid}
|
||||
|
||||
# to be consumed by the nightly publish jobs
|
||||
if [[ $CI_COMMIT_BRANCH == main ]]; then
|
||||
tar cf repo.tar ${repodir}
|
||||
fi
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Turns a Mason testlog.json file into an HTML report
|
||||
#
|
||||
# Copyright 2019 GNOME Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Emmanuele Bassi
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from jinja2 import Template
|
||||
|
||||
REPORT_TEMPLATE = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ report.project_name }} Test Report</title>
|
||||
<meta charset="utf-8" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background: white;
|
||||
color: #333;
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333333;
|
||||
font-size: 1.9em;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
border-bottom: 1px solid #333333;
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 24px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
z-index: 500;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(0px);
|
||||
transition: .2s background-color, color;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
article {
|
||||
padding-top: 200px;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
div.report-meta {
|
||||
width: auto;
|
||||
border: 1px solid #ccc;
|
||||
padding: .5em 2em;
|
||||
color: #3c3c3c;
|
||||
}
|
||||
|
||||
span.result {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.pass {
|
||||
color: rgb(51, 209, 122);
|
||||
}
|
||||
|
||||
span.skip {
|
||||
color: rgb(255, 163, 72);
|
||||
}
|
||||
|
||||
span.fail {
|
||||
color: rgb(224, 27, 36);
|
||||
}
|
||||
|
||||
span.xfail {
|
||||
color: rgb(163, 71, 186);
|
||||
}
|
||||
|
||||
div.result {
|
||||
border-top: 1px solid #c0c0c0;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.result h4 {
|
||||
border-bottom: 1px solid #c0c0c0;
|
||||
margin-bottom: 0.7em;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #fafafa;
|
||||
background-color: black;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 5px 8px 0px rgba(0, 0, 0, 0.25);
|
||||
font-family: monospace;
|
||||
line-height: 1.2em;
|
||||
border: none;
|
||||
padding: 10px 1em;
|
||||
font-size: 0.9em;
|
||||
overflow: auto;
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
ul.passed li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
ul.passed li:after {
|
||||
content: ",";
|
||||
}
|
||||
|
||||
ul.passed li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
ul.images {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
ul.images li {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>{{ report.project_name }}/{{ report.backend }}/{{ report.branch_name }} :: Test Reports</h1>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<section>
|
||||
<div class="report-meta">
|
||||
<p><strong>Backend:</strong> {{ report.backend }}</p>
|
||||
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
|
||||
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
|
||||
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="summary">
|
||||
<h3><a name="summary">Summary</a></h3>
|
||||
<ul>
|
||||
<li><strong>Total units:</strong> {{ report.total_units }}</li>
|
||||
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
|
||||
<li><strong>Passed:</strong> {{ report.total_successes }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% for suite_result in report.results_list %}
|
||||
<section>
|
||||
<div class="result">
|
||||
<h3><a name="results">Suite: {{ suite_result.suite_name }}</a></h3>
|
||||
<ul>
|
||||
<li><strong>Units:</strong> {{ suite_result.n_units }}</li>
|
||||
<li><strong>Failed:</strong> <a href="#{{ suite_result.suite_name }}-failed">{{ suite_result.n_failures }}</a></li>
|
||||
<li><strong>Passed:</strong> <a href="#{{ suite_result.suite_name }}-passed">{{ suite_result.n_successes }}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="failures">
|
||||
<h4><a name="{{ suite_result.suite_name }}-failed">Failures</a></h4>
|
||||
<ul class="failed">
|
||||
{% for failure in suite_result.failures if failure.result in [ 'ERROR', 'FAIL', 'UNEXPECTEDPASS' ] %}
|
||||
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
|
||||
{% if failure.stdout %}
|
||||
Output: <pre>{{ failure.stdout }}</pre>
|
||||
{% endif %}
|
||||
{% if failure.image_data is defined %}
|
||||
<ul class="images">
|
||||
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
|
||||
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
|
||||
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
|
||||
<li><a href="{{ failure.image_data.refnode }}">ref node</a></li>
|
||||
<li><a href="{{ failure.image_data.outnode }}">out node</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-timed-out">Timed out</a></h4>
|
||||
<ul class="failed">
|
||||
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
|
||||
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
|
||||
{% if failure.stdout %}
|
||||
Output: <pre>{{ failure.stdout }}</pre>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="successes">
|
||||
<h4><a name="{{ suite_result.suite_name }}-expected-fail">Expected failures</a></h4>
|
||||
<ul>
|
||||
{% for success in suite_result.successes if success.result == 'EXPECTEDFAIL' %}
|
||||
<li><a name="{{ success.name }}">{{ success.name }}</a> - result: <span class="result xfail">{{ success.result }}</span><br/>
|
||||
{% if success.stdout %}
|
||||
Output: <pre>{{ success.stdout }}</pre>
|
||||
{% endif %}
|
||||
{% if success.image_data is defined %}
|
||||
<ul class="images">
|
||||
<li><img alt="ref" src="{{ success.image_data.ref }}" /></li>
|
||||
<li><img alt="out" src="{{ success.image_data.out }}" /></li>
|
||||
<li><img alt="diff" src="{{ success.image_data.diff }}" /></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-skipped">Skipped</a></h4>
|
||||
<ul>
|
||||
{% for success in suite_result.successes if success.result == 'SKIP' %}
|
||||
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-passed">Passed</a></h4>
|
||||
<ul class="passed">
|
||||
{% for success in suite_result.successes if success.result == 'OK' %}
|
||||
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
aparser = argparse.ArgumentParser(description='Turns a Meson test log into an HTML report')
|
||||
aparser.add_argument('--project-name', metavar='NAME',
|
||||
help='The project name',
|
||||
default='Unknown')
|
||||
aparser.add_argument('--backend', metavar='NAME',
|
||||
help='The used backend',
|
||||
default='unknown')
|
||||
aparser.add_argument('--job-id', metavar='ID',
|
||||
help='The job ID for the report',
|
||||
default=None)
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='main')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output HTML file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
default=sys.stdout)
|
||||
aparser.add_argument('--reftest-suite', metavar='NAME',
|
||||
help='The name of the reftests suite',
|
||||
default='reftest')
|
||||
aparser.add_argument('--reftest-output-dir', metavar='DIR',
|
||||
help='The output directory for reftests data',
|
||||
default=None)
|
||||
aparser.add_argument('infile', metavar='FILE',
|
||||
help='The input testlog.json, stdin by default',
|
||||
type=argparse.FileType('r', encoding='UTF-8'),
|
||||
default=sys.stdin)
|
||||
|
||||
args = aparser.parse_args()
|
||||
|
||||
outfile = args.output
|
||||
|
||||
suites = {}
|
||||
for line in args.infile:
|
||||
data = json.loads(line)
|
||||
(full_suite, unit_name) = data['name'].split(' / ')
|
||||
(project_name, suite_name) = full_suite.split(':')
|
||||
|
||||
unit = {
|
||||
'project-name': project_name,
|
||||
'suite': suite_name,
|
||||
'name': unit_name,
|
||||
'duration': data['duration'],
|
||||
'returncode': data['returncode'],
|
||||
'result': data['result'],
|
||||
'stdout': data['stdout'],
|
||||
}
|
||||
|
||||
if args.reftest_output_dir is not None and suite_name == args.reftest_suite:
|
||||
filename = unit_name.split(' ')[1]
|
||||
basename = os.path.splitext(filename)[0]
|
||||
|
||||
image_data = {
|
||||
'ref': os.path.join(args.reftest_output_dir, '{}.ref.png'.format(basename)),
|
||||
'out': os.path.join(args.reftest_output_dir, '{}.out.png'.format(basename)),
|
||||
'refnode': os.path.join(args.reftest_output_dir, '{}.ref.node'.format(basename)),
|
||||
'outnode': os.path.join(args.reftest_output_dir, '{}.out.node'.format(basename)),
|
||||
'diff': os.path.join(args.reftest_output_dir, '{}.diff.png'.format(basename)),
|
||||
}
|
||||
|
||||
unit['image_data'] = image_data
|
||||
|
||||
units = suites.setdefault(full_suite, [])
|
||||
units.append(unit)
|
||||
|
||||
report = {}
|
||||
report['date'] = datetime.datetime.utcnow()
|
||||
report['locale_date'] = report['date'].strftime("%c")
|
||||
report['project_name'] = args.project_name
|
||||
report['backend'] = args.backend
|
||||
report['job_id'] = args.job_id
|
||||
report['branch_name'] = args.branch
|
||||
report['total_successes'] = 0
|
||||
report['total_failures'] = 0
|
||||
report['total_units'] = 0
|
||||
report['results_list'] = []
|
||||
|
||||
for name, units in suites.items():
|
||||
(project_name, suite_name) = name.split(':')
|
||||
print('Processing {} suite {}:'.format(project_name, suite_name))
|
||||
|
||||
def if_failed(unit):
|
||||
if unit['result'] in ['FAIL', 'UNEXPECTEDPASS', 'TIMEOUT', 'ERROR',]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def if_succeded(unit):
|
||||
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
|
||||
return True
|
||||
return False
|
||||
|
||||
successes = list(filter(if_succeded, units))
|
||||
failures = list(filter(if_failed, units))
|
||||
|
||||
n_units = len(units)
|
||||
n_successes = len(successes)
|
||||
n_failures = len(failures)
|
||||
|
||||
report['total_units'] += n_units
|
||||
report['total_successes'] += n_successes
|
||||
report['total_failures'] += n_failures
|
||||
print(' - {}: {} total, {} pass, {} fail'.format(suite_name, n_units, n_successes, n_failures))
|
||||
|
||||
suite_report = {
|
||||
'suite_name': suite_name,
|
||||
'n_units': n_units,
|
||||
'successes': successes,
|
||||
'n_successes': n_successes,
|
||||
'failures': failures,
|
||||
'n_failures': n_failures,
|
||||
}
|
||||
report['results_list'].append(suite_report)
|
||||
|
||||
template = Template(REPORT_TEMPLATE)
|
||||
outfile.write(template.render({'report': report}))
|
||||
@@ -1,114 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Turns a Meson testlog.json file into a JUnit XML report
|
||||
#
|
||||
# Copyright 2019 GNOME Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Emmanuele Bassi
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
aparser = argparse.ArgumentParser(description='Turns a Meson test log into a JUnit report')
|
||||
aparser.add_argument('--project-name', metavar='NAME',
|
||||
help='The project name',
|
||||
default='unknown')
|
||||
aparser.add_argument('--backend', metavar='NAME',
|
||||
help='The used backend',
|
||||
default='unknown')
|
||||
aparser.add_argument('--job-id', metavar='ID',
|
||||
help='The job ID for the report',
|
||||
default='Unknown')
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='main')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
default=sys.stdout)
|
||||
aparser.add_argument('infile', metavar='FILE',
|
||||
help='The input testlog.json, stdin by default',
|
||||
type=argparse.FileType('r', encoding='UTF-8'),
|
||||
default=sys.stdin)
|
||||
|
||||
args = aparser.parse_args()
|
||||
|
||||
outfile = args.output
|
||||
|
||||
testsuites = ET.Element('testsuites')
|
||||
testsuites.set('id', '{}/{}'.format(args.job_id, args.branch))
|
||||
testsuites.set('package', args.project_name)
|
||||
testsuites.set('timestamp', datetime.datetime.utcnow().isoformat(timespec='minutes'))
|
||||
|
||||
suites = {}
|
||||
for line in args.infile:
|
||||
data = json.loads(line)
|
||||
(full_suite, unit_name) = data['name'].split(' / ')
|
||||
(project_name, suite_name) = full_suite.split(':')
|
||||
|
||||
duration = data['duration']
|
||||
return_code = data['returncode']
|
||||
result = data['result']
|
||||
log = data['stdout']
|
||||
|
||||
unit = {
|
||||
'suite': suite_name,
|
||||
'name': unit_name,
|
||||
'duration': duration,
|
||||
'returncode': return_code,
|
||||
'result': result,
|
||||
'stdout': log,
|
||||
}
|
||||
|
||||
units = suites.setdefault(suite_name, [])
|
||||
units.append(unit)
|
||||
|
||||
for name, units in suites.items():
|
||||
print('Processing suite {} (units: {})'.format(name, len(units)))
|
||||
|
||||
def if_failed(unit):
|
||||
if unit['result'] in ['ERROR', 'FAIL', 'UNEXPECTEDPASS', 'TIMEOUT']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def if_succeded(unit):
|
||||
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
|
||||
return True
|
||||
return False
|
||||
|
||||
successes = list(filter(if_succeded, units))
|
||||
failures = list(filter(if_failed, units))
|
||||
print(' - {}: {} pass, {} fail'.format(name, len(successes), len(failures)))
|
||||
|
||||
testsuite = ET.SubElement(testsuites, 'testsuite')
|
||||
testsuite.set('name', '{}/{}'.format(args.project_name, name))
|
||||
testsuite.set('tests', str(len(units)))
|
||||
testsuite.set('errors', str(len(failures)))
|
||||
testsuite.set('failures', str(len(failures)))
|
||||
|
||||
for unit in successes:
|
||||
testcase = ET.SubElement(testsuite, 'testcase')
|
||||
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
testcase.set('time', str(unit['duration']))
|
||||
|
||||
for unit in failures:
|
||||
testcase = ET.SubElement(testsuite, 'testcase')
|
||||
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
testcase.set('time', str(unit['duration']))
|
||||
|
||||
failure = ET.SubElement(testcase, 'failure')
|
||||
failure.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
failure.set('type', 'error')
|
||||
failure.text = unit['stdout']
|
||||
|
||||
output = ET.tostring(testsuites, encoding='unicode')
|
||||
outfile.write(output)
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 GNOME Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
* RedHat Fonts taken from https://github.com/RedHatOfficial/RedHatFont
|
||||
* License: SIL Open Font License 1.1 http://scripts.sil.org/OFL
|
||||
*/
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Red+Hat+Display:ital,wght@0,400;0,500;0,700;0,900;1,400;1,500;1,700;1,900&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&display=swap');
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-Regular.woff2") format("woff2"),
|
||||
url("RedHatDisplay-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-RegularItalic.woff2") format("woff2"),
|
||||
url("RedHatDisplay-RegularItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-Medium.woff2") format("woff2"),
|
||||
url("RedHatDisplay-Medium.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-MediumItalic.woff2") format("woff2"),
|
||||
url("RedHatDisplay-MediumItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-Bold.woff2") format("woff2"),
|
||||
url("RedHatDisplay-Bold.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-BoldItalic.woff2") format("woff2"),
|
||||
url("RedHatDisplay-BoldItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-Black.woff2") format("woff2"),
|
||||
url("RedHatDisplay-Black.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayWeb";
|
||||
src: local('RedHatDisplayWeb'),
|
||||
url("RedHatDisplay-BlackItalic.woff2") format("woff2"),
|
||||
url("RedHatDisplay-BlackItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-Regular.woff2") format("woff2"),
|
||||
url("RedHatText-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-RegularItalic.woff2") format("woff2"),
|
||||
url("RedHatText-RegularItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-Medium.woff2") format("woff2"),
|
||||
url("RedHatText-Medium.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-MediumItalic.woff2") format("woff2"),
|
||||
url("RedHatText-MediumItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-Bold.woff2") format("woff2"),
|
||||
url("RedHatText-Bold.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: fallback;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextWeb";
|
||||
src: local('RedHatTextWeb'),
|
||||
url("RedHatText-BoldItalic.woff2") format("woff2"),
|
||||
url("RedHatText-BoldItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: fallback;
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="128"
|
||||
height="128"
|
||||
id="svg6843"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
version="1.0"
|
||||
sodipodi:docname="gtk-logo.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/home/ebassi/Pictures/gtk-logo-256.png"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192">
|
||||
<defs
|
||||
id="defs6845">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="-50 : 600 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="700 : 600 : 1"
|
||||
inkscape:persp3d-origin="300 : 400 : 1"
|
||||
id="perspective13" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8284271"
|
||||
inkscape:cx="69.874353"
|
||||
inkscape:cy="64.313526"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
width="128px"
|
||||
height="128px"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid7947" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata6848">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:date />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier />
|
||||
<dc:source />
|
||||
<dc:relation />
|
||||
<dc:language />
|
||||
<dc:subject>
|
||||
<rdf:Bag />
|
||||
</dc:subject>
|
||||
<dc:coverage />
|
||||
<dc:description />
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
<cc:license
|
||||
rdf:resource="" />
|
||||
</cc:Work>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path6976"
|
||||
d="M 20.88413,30.82696 L 53.816977,55.527708 L 107.33282,39.060543 L 70.587303,17.177763 L 20.88413,30.82696 z"
|
||||
style="fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
|
||||
<path
|
||||
id="path6978"
|
||||
d="M 22.94243,82.287118 L 20.88413,30.82696 L 53.816977,55.527708 L 53.816977,111.10486 L 22.94243,82.287118 z"
|
||||
style="fill:#e40000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
|
||||
<path
|
||||
id="path6980"
|
||||
d="M 53.816977,111.10486 L 103.21619,90.5207 L 107.33282,39.060543 L 53.816977,55.527708 L 53.816977,111.10486 z"
|
||||
style="fill:#7fe719;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path6982"
|
||||
d="M 23.216626,81.319479 L 70.48573,67.361442 L 103.38422,90.444516"
|
||||
style="opacity:1;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path6984"
|
||||
d="M 70.434539,17.875593 L 70.434539,66.984877"
|
||||
style="opacity:1;fill:#babdb6;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
@@ -1,149 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 GNOME Foundation
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GTK Documentation</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<meta property="og:site_name" content="https://docs.gtk.org"/>
|
||||
<meta property="og:title" content="GTK Documentation"/>
|
||||
<meta property="og:url" content="https://docs.gtk.org"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:description" content="API reference for GTK"/>
|
||||
|
||||
<meta name="twitter:title" content="GTK Documentation"/>
|
||||
<meta name="twitter:url" content="https://docs.gtk.org"/>
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
|
||||
<link rel="canonical" href="https://docs.gtk.org"/>
|
||||
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
|
||||
<script src="main.js"></script>
|
||||
|
||||
<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="body-wrapper" tabindex="-1">
|
||||
|
||||
<nav class="sidebar">
|
||||
|
||||
<div class="section">
|
||||
<img src="gtk-logo.svg" class="logo"/>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>Sections</h5>
|
||||
<div class="links">
|
||||
<a href="#user-interface">User interface</a>
|
||||
<a href="#core-libraries">Core libraries</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<button id="btn-to-top" class="hidden"><span class="up-arrow"></span></button>
|
||||
|
||||
<section id="main" class="content">
|
||||
<header>
|
||||
<h1>GTK Documentation</h1>
|
||||
</header>
|
||||
|
||||
<div class="toggle-wrapper">
|
||||
<h4 id="user-interface">
|
||||
User interface
|
||||
<a href="#user-interface" class="anchor"></a>
|
||||
</h4>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gdk">GTK</h5>
|
||||
<p>GTK is the primary library used to construct user interfaces. It
|
||||
provides user interface controls and signal callbacks to respond to
|
||||
user actions.</p>
|
||||
<p><a href="https://docs.gtk.org/gtk4/">GTK API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gdk">GSK</h5>
|
||||
<p>An intermediate layer which provides a rendering API implemented using Cairo, OpenGL or Vulkan.</p>
|
||||
<p><a href="https://docs.gtk.org/gsk4/">GSK API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gdk">GDK</h5>
|
||||
<p>An intermediate layer which isolates GTK from the details of the windowing system.</p>
|
||||
<p><a href="https://docs.gtk.org/gdk4/">GDK API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="pango">Pango</h5>
|
||||
<p>Pango is the core text and font handling library used in GTK
|
||||
applications. It has extensive support for the different writing
|
||||
systems used throughout the world.</p>
|
||||
<p><a href="https://docs.gtk.org/Pango/">Pango API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gdk-pixbuf">GdkPixbuf</h5>
|
||||
<p>GdkPixbuf is a library for image loading and manipulation.</p>
|
||||
<p><a href="https://docs.gtk.org/gdk-pixbuf/">GdkPixbuf API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="cairo">Cairo</h5>
|
||||
<p>Cairo is a 2D graphics library with support for multiple output
|
||||
devices. It is designed to produce consistent, high quality output
|
||||
on all media.</p>
|
||||
<p><a href="https://www.cairographics.org/manual/" class="external">Cairo API reference</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toggle-wrapper">
|
||||
<h4 id="core-libraries" style="display:flex;">
|
||||
Core libraries
|
||||
<a href="#core-libraries" class="anchor"></a>
|
||||
</h4>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="glib">GLib</h5>
|
||||
<p>GLib provides the core application building blocks for libraries
|
||||
and applications written in C. It provides common data types
|
||||
used in GTK, the main loop implementation, and a large set of
|
||||
utility functions for strings and general portability across
|
||||
different platforms.</p>
|
||||
<p><a href="https://developer.gnome.org/glib/" class="external">GLib API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gobject">GObject</h5>
|
||||
<p>GObject provides the object system used by GTK.</p>
|
||||
<p><a href="https://developer.gnome.org/gobject/" class="external">GObject API reference</a></p>
|
||||
</div>
|
||||
|
||||
<div class="docblock">
|
||||
<h5 id="gio">GIO</h5>
|
||||
<p>GIO provides a portable, modern and easy-to-use file system
|
||||
abstraction API for accessing local and remote files; a set of
|
||||
low and high level abstractions over the <a href="https://www.freedesktop.org/wiki/Software/dbus/" class="external">DBus</a>
|
||||
IPC specification; an application settings API; portable networking
|
||||
abstractions; and additional utilities for writing asynchronous
|
||||
operations without blocking the user interface of your application.</p>
|
||||
<p><a href="https://developer.gnome.org/gio/" class="external">GIO API reference</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,140 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2021 GNOME Foundation
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hasClass(elem, className) {
|
||||
return elem && elem.classList && elem.classList.contains(className);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function addClass(elem, className) {
|
||||
if (!elem || !elem.classList) {
|
||||
return;
|
||||
}
|
||||
elem.classList.add(className);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function removeClass(elem, className) {
|
||||
if (!elem || !elem.classList) {
|
||||
return;
|
||||
}
|
||||
elem.classList.remove(className);
|
||||
}
|
||||
|
||||
function insertAfter(newNode, referenceNode) {
|
||||
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
|
||||
}
|
||||
|
||||
function onEach(arr, func, reversed) {
|
||||
if (arr && arr.length > 0 && func) {
|
||||
var length = arr.length;
|
||||
var i;
|
||||
if (reversed !== true) {
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (func(arr[i]) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = length - 1; i >= 0; --i) {
|
||||
if (func(arr[i]) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onEachLazy(lazyArray, func, reversed) {
|
||||
return onEach(
|
||||
Array.prototype.slice.call(lazyArray),
|
||||
func,
|
||||
reversed);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hasOwnProperty(obj, property) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, property);
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
"use strict;"
|
||||
|
||||
var main = document.getElementById("main");
|
||||
var btnToTop = document.getElementById("btn-to-top");
|
||||
|
||||
function labelForToggleButton(isCollapsed) {
|
||||
if (isCollapsed) {
|
||||
return "+";
|
||||
}
|
||||
return "\u2212";
|
||||
}
|
||||
|
||||
function createToggle(isCollapsed) {
|
||||
var toggle = document.createElement("a");
|
||||
toggle.href = "javascript:void(0)";
|
||||
toggle.className = "collapse-toggle";
|
||||
toggle.innerHTML = "[<span class=\"inner\">"
|
||||
+ labelForToggleButton(isCollapsed)
|
||||
+ "</span>]";
|
||||
|
||||
return toggle;
|
||||
}
|
||||
|
||||
function toggleClicked() {
|
||||
if (hasClass(this, "collapsed")) {
|
||||
removeClass(this, "collapsed");
|
||||
this.innerHTML = "[<span class=\"inner\">"
|
||||
+ labelForToggleButton(false)
|
||||
+ "</span>]";
|
||||
onEachLazy(this.parentNode.getElementsByClassName("docblock"), function(e) {
|
||||
removeClass(e, "hidden");
|
||||
});
|
||||
} else {
|
||||
addClass(this, "collapsed");
|
||||
this.innerHTML = "[<span class=\"inner\">"
|
||||
+ labelForToggleButton(true)
|
||||
+ "</span>]";
|
||||
onEachLazy(this.parentNode.getElementsByClassName("docblock"), function(e) {
|
||||
addClass(e, "hidden");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onEachLazy(document.getElementsByClassName("toggle-wrapper"), function(e) {
|
||||
let sectionHeader = e.querySelector(".section-header");
|
||||
let fragmentMatches = sectionHeader !== null && location.hash === "#" + sectionHeader.getAttribute('id');
|
||||
collapsedByDefault = hasClass(e, "default-hide") && !fragmentMatches;
|
||||
var toggle = createToggle(collapsedByDefault);
|
||||
toggle.onclick = toggleClicked;
|
||||
e.insertBefore(toggle, e.firstChild);
|
||||
if (collapsedByDefault) {
|
||||
addClass(toggle, "collapsed");
|
||||
onEachLazy(e.getElementsByClassName("docblock"), function(d) {
|
||||
addClass(d, "hidden");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function scrollBackTop(e) {
|
||||
e.preventDefault();
|
||||
window.scroll({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
|
||||
function toggleScrollButton() {
|
||||
if (window.scrollY < 400) {
|
||||
addClass(btnToTop, "hidden");
|
||||
} else {
|
||||
removeClass(btnToTop, "hidden");
|
||||
}
|
||||
}
|
||||
|
||||
window.onscroll = toggleScrollButton;
|
||||
btnToTop.onclick = scrollBackTop;
|
||||
}, false);
|
||||
@@ -1,747 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 GNOME Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
@import url("fonts.css");
|
||||
|
||||
/*********************************
|
||||
* LIGHT THEME
|
||||
*********************************/
|
||||
:root {
|
||||
|
||||
/* colors */
|
||||
--text-color: #333;
|
||||
--text-color-muted: #999;
|
||||
--primary: rgb(28, 118, 228);
|
||||
--body-bg: #fff;
|
||||
--sidebar-primary: rgb(144, 194, 255);
|
||||
--sidebar-bg: #151515;
|
||||
--sidebar-selected-bg: var(--primary);
|
||||
--sidebar-text-color: #fafafa;
|
||||
--sidebar-padding: 1.5em;
|
||||
|
||||
/* boxes, e.g. code blocks */
|
||||
--box-bg: rgba(135, 135, 135, 0.085);
|
||||
--box-radius: 0.35rem;
|
||||
--box-padding: 0.75rem;
|
||||
--box-margin: 0.75rem 0;
|
||||
--box-text-color: #111;
|
||||
|
||||
/* typography */
|
||||
--body-font-family: "Noto Serif",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||
--body-font-scale: 0.95;
|
||||
--body-font-size: calc(var(--body-font-scale) * clamp(16px, 1vw, 20px));
|
||||
--body-font-weight: normal;
|
||||
|
||||
--monospace-font-family: "Source Code Pro", monospace;
|
||||
--monospace-font-size: calc(0.86 * var(--body-font-size)); /* Monospace fonts are very different in terms of font-sizes. Adjust this value to scale it */
|
||||
|
||||
--heading-font-family: "Red Hat Display", var(--body-font-family);
|
||||
--heading-weight: 900;
|
||||
--heading-font-scale: 1.05;
|
||||
|
||||
--heading-small-font-family: var(--heading-font-family);
|
||||
--heading-small-weight: 600;
|
||||
--heading-small-font-scale: 1;
|
||||
|
||||
--heading-table-font-family: var(--heading-font-family);
|
||||
--heading-table-weight: 600;
|
||||
|
||||
--heading-docblock-color: #6d6d6d; /* docblocks have headings from source comments. we want them to differ.*/
|
||||
--heading-docblock-scale: 0.9; /* docblocks have headings from source comments. we want them to differ.*/
|
||||
|
||||
--symbol-font-family: var(--heading-font-family);
|
||||
--symbol-font-weight: 500;
|
||||
--symbol-font-scale: 1;
|
||||
|
||||
--table-font-size: 0.92em; /* Tables often contain lots information. It's better to scale them down a big to get more sutff fitted inside */
|
||||
|
||||
/* misc */
|
||||
--prefered-content-width: 90ch; /* The preferred width for the readable content */
|
||||
--anchor-sign: "#";
|
||||
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* DARK THEME (overrides)
|
||||
*********************************/
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--primary: rgb(144, 194, 255);
|
||||
--text-color: #f6f6f6;
|
||||
--text-color-muted: #686868;
|
||||
--body-bg: #121212;
|
||||
--sidebar-primary: rgb(144, 194, 255);
|
||||
--sidebar-bg: #1e1e1e;
|
||||
--sidebar-selected-bg: rgb(17, 112, 228);
|
||||
--sidebar-text-color: #fafafa;
|
||||
--box-bg: rgba(135, 135, 135, 0.1);
|
||||
--box-text-color: #fff;
|
||||
--heading-docblock-color: #b7b7b7;
|
||||
}
|
||||
|
||||
/* fix dark theme syntax highlighting with a filter (for now) */
|
||||
.highlight pre span {
|
||||
filter: brightness(6);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* GENERAL STYLING
|
||||
*********************************/
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
color: white;
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
::selection {
|
||||
color: white;
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: rgba(128, 128, 128, 0.6);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(128, 128, 128, 1);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(128, 128, 128, 0.15);
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: initial;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 16px/1.5 var(--body-font-family);
|
||||
font-weight: var(--body-font-weight);
|
||||
font-size: var(--body-font-size);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
-webkit-font-feature-settings: "kern", "liga";
|
||||
-moz-font-feature-settings: "kern", "liga";
|
||||
font-feature-settings: "kern", "liga";
|
||||
color: var(--text-color);
|
||||
background: var(--body-bg);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--heading-font-family);
|
||||
font-weight: var(--heading-weight);
|
||||
margin: 1.75em 0 0.75em 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.75em * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
|
||||
header h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.4em * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.2em * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
header h3 {
|
||||
color: var(--text-color-muted);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h4, h5 {
|
||||
font-size: calc(1em * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: calc(1em * var(--heading-small-font-scale));
|
||||
font-family: var(--heading-small-font-family);
|
||||
font-weight: var(--heading-small-weight);
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
ul ul, ol ul, ul ol, ol ol {
|
||||
margin-bottom: .6em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 .6em 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
summary {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--primary);
|
||||
background: var(--box-bg);
|
||||
padding: var(--box-padding);
|
||||
border-radius: var(--box-radius);
|
||||
margin: var(--box--margin);
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: var(--monospace-font-family);
|
||||
font-size: var(--monospace-font-size);
|
||||
color: var(--box-text-color);
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--box-bg);
|
||||
padding: var(--box-padding);
|
||||
border-radius: var(--box-radius);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--box-bg);
|
||||
padding: 0 0.35em;
|
||||
border-radius: 0.35rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
a > code {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
pre pre,
|
||||
pre code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
background: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
strong, b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* fix unwanted margins in tables, code, lists and blockquotes */
|
||||
li > *:first-child,
|
||||
li > *:first-child > *:first-child,
|
||||
li > *:first-child > *:first-child > *:first-child,
|
||||
td > *:first-child,
|
||||
td > *:first-child > *:first-child,
|
||||
td > *:first-child > *:first-child > *:first-child,
|
||||
pre > *:first-child,
|
||||
pre > *:first-child > *:first-child,
|
||||
pre > *:first-child > *:first-child > *:first-child,
|
||||
blockquote > *:first-child,
|
||||
blockquote > *:first-child > *:first-child,
|
||||
blockquote > *:first-child > *:first-child > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
li > *:last-child,
|
||||
li > *:last-child > *:last-child,
|
||||
li > *:last-child > *:last-child > *:last-child,
|
||||
td > *:last-child,
|
||||
td > *:last-child > *:last-child,
|
||||
td > *:last-child > *:last-child > *:last-child,
|
||||
pre > *:last-child,
|
||||
pre > *:last-child > *:last-child,
|
||||
pre > *:last-child > *:last-child > *:last-child,
|
||||
blockquote > *:last-child,
|
||||
blockquote > *:last-child > *:last-child,
|
||||
blockquote > *:last-child > *:last-child > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* PAGE STRUCTURE
|
||||
*********************************/
|
||||
#body-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#body-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#main {
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
box-shadow: 0 0 134px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* Button
|
||||
*********************************/
|
||||
|
||||
#btn-to-top {
|
||||
position: fixed;
|
||||
bottom: 12px;
|
||||
right: 32px;
|
||||
z-index: 1000;
|
||||
border-radius: 50%;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border: 1px solid var(--primary);
|
||||
background: var(--box-bg);
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
#btn-to-top > .up-arrow:after {
|
||||
content: "🡅"
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* SIDEBAR
|
||||
*********************************/
|
||||
.sidebar {
|
||||
scrollbar-width: thin;
|
||||
background: var(--sidebar-bg);
|
||||
border-right: 1px solid var(--sidebar-bg);
|
||||
min-width: 40ch;
|
||||
padding: var(--sidebar-padding);
|
||||
color: var(--sidebar-text-color);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sidebar a,
|
||||
.sidebar a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sidebar .logo {
|
||||
display: block;
|
||||
margin: 2rem auto 0 auto;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.sidebar .section > ul > li {
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.sidebar .section h3, .sidebar .section h5 {
|
||||
text-align: left;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
font-weight: var(--heading-weight);
|
||||
}
|
||||
|
||||
.sidebar .section h5 {
|
||||
font-size: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.sidebar .namespace > h3 {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
font-size: 1.5em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.sidebar .namespace > p {
|
||||
font-size: 0.9em;
|
||||
opacity: 0.8;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar .section {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar .links {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sidebar .section a {
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
transition: background-color 150ms ease;
|
||||
color: var(--sidebar-primary);
|
||||
border-radius: var(--box-radius);
|
||||
padding: 0.2rem 0.5rem;
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.sidebar .section a:hover {
|
||||
background-color: rgba(127, 127, 127, 0.2);
|
||||
color: var(--sidebar-text-color);
|
||||
}
|
||||
|
||||
.sidebar .section a.current {
|
||||
background-color: var(--sidebar-selected-bg);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar .search {
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sidebar .search input[type="text"] {
|
||||
border-color: transparent;
|
||||
width: 100%;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 50px;
|
||||
padding: 6px 12px;
|
||||
display: inline-block;
|
||||
font-size: 80%;
|
||||
box-shadow: inset 0 1px 3px #ddd;
|
||||
transition: border .3s linear;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* ANCHORS & TOGGLERS
|
||||
*********************************/
|
||||
.anchor,
|
||||
.md-anchor {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
text-decoration: none;
|
||||
padding: 0 0.5em;
|
||||
color: var(--text-color-muted);
|
||||
}
|
||||
|
||||
.anchor:hover,
|
||||
.md-anchor:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.anchor:not([href]),
|
||||
.md-anchor:not([href]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.anchor:before,
|
||||
.md-anchor:before {
|
||||
content: var(--anchor-sign); /*'§'*/
|
||||
}
|
||||
|
||||
.toggle-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.collapse-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: -2em;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
font-size: 0.8em;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.collapse-toggle > .inner {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: calc(0.75 * var(--box-radius));
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: var(--box-text-color);
|
||||
position: relative;
|
||||
left: -0.25rem;
|
||||
font-family: monospace;
|
||||
font-size: 0.7rem;
|
||||
font-weight: bold;
|
||||
background: var(--box-bg);
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* UTILITY
|
||||
*********************************/
|
||||
.deprecated > h6 > a {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* CONTENT STYLING
|
||||
*********************************/
|
||||
.content {
|
||||
padding: 2em 4em;
|
||||
overflow: visible;
|
||||
max-width: calc(var(--prefered-content-width) + 8em);
|
||||
}
|
||||
|
||||
.content table:not(.table-display) {
|
||||
border-spacing: 0 0.25rem;
|
||||
}
|
||||
|
||||
.content td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.content td:first-child {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.content td p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content td h1, .content td h2 {
|
||||
margin-left: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.content tr:first-child td {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font: 15px monospace;
|
||||
line-height: 10px;
|
||||
vertical-align: middle;
|
||||
border: solid 1px;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.content tr:first-child {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.content td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.content td:first-child {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.content td p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content td h4, .content td h5 {
|
||||
margin-left: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.content tr:first-child td {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.srclink {
|
||||
color: var(--text-color-muted);
|
||||
font-size: 1rem;
|
||||
font-weight: var(--body-font-weight);
|
||||
flex-grow: 0;
|
||||
text-decoration: none;
|
||||
margin-left: auto;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.meta tr > td:not(:first-child) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.meta tr > td:first-child {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* DOCBLOCK STYLING
|
||||
*********************************/
|
||||
.docblock {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.docblock h1 {
|
||||
font-size: calc(1.3em * var(--heading-docblock-scale) * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
.docblock h2 {
|
||||
font-size: calc(1.2em * var(--heading-docblock-scale) * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
.docblock h3 {
|
||||
font-size: calc(1.1em * var(--heading-docblock-scale) * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
.docblock h4 {
|
||||
font-size: calc(1.05em * var(--heading-docblock-scale) * var(--heading-font-scale));
|
||||
}
|
||||
|
||||
.docblock h1,
|
||||
.docblock h2,
|
||||
.docblock h3,
|
||||
.docblock h4,
|
||||
.docblock h5,
|
||||
.docblock h6 {
|
||||
color: var(--heading-docblock-color)
|
||||
}
|
||||
|
||||
.docblock table {
|
||||
margin: .25em 0;
|
||||
max-width: 100%;
|
||||
font-size: var(--table-font-size);
|
||||
}
|
||||
|
||||
.docblock table td {
|
||||
padding: .25em;
|
||||
}
|
||||
|
||||
.docblock table th {
|
||||
padding: .25em;
|
||||
text-align: left;
|
||||
font-family: var(--heading-table-font-family);
|
||||
font-weight: var(--heading-table-weight);
|
||||
}
|
||||
|
||||
.docblock table tr th:first-child,
|
||||
.docblock table tr td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.docblock table tr th:last-child,
|
||||
.docblock table tr td:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
table.enum-members,
|
||||
table.results {
|
||||
border-radius: var(--box-radius);
|
||||
border: 1px solid var(--text-color-muted);
|
||||
border-spacing: 0 0 !important;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
table.enum-members tr th,
|
||||
table.results tr th {
|
||||
border-top-color: var(--body-bg);
|
||||
background-color: var(--box-bg);
|
||||
border-bottom: 1px solid var(--text-color-muted);
|
||||
}
|
||||
|
||||
table.enum-members tr th:first-child,
|
||||
table.enum-members tr td:first-child {
|
||||
min-width: 25em;
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
table.results tr th:first-child,
|
||||
table.results tr td:first-child {
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
table.enum-members tr th:last-child,
|
||||
table.enum-members tr td:last-child,
|
||||
table.results tr th:last-child,
|
||||
table.results tr td:last-child {
|
||||
max-width: 35em;
|
||||
padding-right: .5em;
|
||||
}
|
||||
|
||||
table.results tr td code {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.docblock ul li,
|
||||
.docblock ol li {
|
||||
padding-top: 0.15rem;
|
||||
padding-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.docblock ul.type {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.docblock ul.type li::before {
|
||||
content: "»";
|
||||
color: var(--text-color);
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
/**************************
|
||||
RESPONSIVENESS
|
||||
**************************/
|
||||
@media (max-width: 700px) {
|
||||
body {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
#body-wrapper {
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 100%;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: static;
|
||||
height: initial;
|
||||
order: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,135 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
read_arg() {
|
||||
# $1 = arg name
|
||||
# $2 = arg value
|
||||
# $3 = arg parameter
|
||||
local rematch='^[^=]*=(.*)$'
|
||||
if [[ $2 =~ $rematch ]]; then
|
||||
read "$1" <<< "${BASH_REMATCH[1]}"
|
||||
else
|
||||
read "$1" <<< "$3"
|
||||
# There is no way to shift our callers args, so
|
||||
# return 1 to indicate they should do it instead.
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
build=0
|
||||
run=0
|
||||
push=0
|
||||
list=0
|
||||
print_help=0
|
||||
no_login=0
|
||||
TAG="ebassi/gitlab-gtk:latest"
|
||||
|
||||
while (($# > 0)); do
|
||||
case "${1%%=*}" in
|
||||
build) build=1;;
|
||||
run) run=1;;
|
||||
push) push=1;;
|
||||
list) list=1;;
|
||||
help) print_help=1;;
|
||||
--base|-b) read_arg base "$@" || shift;;
|
||||
--version|-v) read_arg base_version "$@" || shift;;
|
||||
--no-login) no_login=1;;
|
||||
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $print_help == 1 ]; then
|
||||
echo "$0 - Build and run Docker images"
|
||||
echo ""
|
||||
echo "Usage: $0 <command> [options] [basename]"
|
||||
echo ""
|
||||
echo "Available commands"
|
||||
echo ""
|
||||
echo " build --base=<BASENAME> - Build Docker image <BASENAME>.Dockerfile"
|
||||
echo " run --base=<BASENAME> - Run Docker image <BASENAME>"
|
||||
echo " push --base=<BASENAME> - Push Docker image <BASENAME> to the registry"
|
||||
echo " list - List available images"
|
||||
echo " help - This help message"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ $list == 1 ]; then
|
||||
echo "Available Docker images:"
|
||||
for f in *.Dockerfile; do
|
||||
filename=$( basename -- "$f" )
|
||||
basename="${filename%.*}"
|
||||
|
||||
echo -e " \e[1;39m$basename\e[0m"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# All commands after this require --base to be set
|
||||
if [ -z $base ]; then
|
||||
echo "Usage: $0 <command>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$base.Dockerfile" ]; then
|
||||
echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $base_version ]; then
|
||||
base_version="latest"
|
||||
elif [ $base_version != "latest" ]; then
|
||||
base_version="v$base_version"
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then
|
||||
# Docker is actually implemented by podman, and its OCI output
|
||||
# is incompatible with some of the dockerd instances on GitLab
|
||||
# CI runners.
|
||||
echo "Using: Podman"
|
||||
format="--format docker"
|
||||
CMD="podman"
|
||||
else
|
||||
echo "Using: Docker"
|
||||
format=""
|
||||
CMD="sudo docker"
|
||||
fi
|
||||
|
||||
REGISTRY="registry.gitlab.gnome.org"
|
||||
TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
|
||||
|
||||
if [ $build == 1 ]; then
|
||||
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} build \
|
||||
${format} \
|
||||
--build-arg HOST_USER_ID="$UID" \
|
||||
--tag "${TAG}" \
|
||||
--file "${base}.Dockerfile" .
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ $push == 1 ]; then
|
||||
echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}"
|
||||
|
||||
if [ $no_login == 0 ]; then
|
||||
${CMD} login ${REGISTRY}
|
||||
fi
|
||||
|
||||
${CMD} push ${TAG}
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ $run == 1 ]; then
|
||||
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} run \
|
||||
--rm \
|
||||
--volume "$(pwd)/..:/home/user/app" \
|
||||
--workdir "/home/user/app" \
|
||||
--tty \
|
||||
--interactive "${TAG}" \
|
||||
bash
|
||||
exit $?
|
||||
fi
|
||||
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
|
||||
--file "Dockerfile" .
|
||||
sudo docker run --rm --security-opt label=disable \
|
||||
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
|
||||
--tty --interactive "${TAG}" bash
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# 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/gtk-3-24`).
|
||||
#
|
||||
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` is only defined if we’re 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=$?
|
||||
|
||||
# The style check is not infallible. The clang-format configuration cannot
|
||||
# perfectly describe GTK’s coding style: in particular, it cannot align
|
||||
# function arguments. The documented coding style for GTK takes priority over
|
||||
# clang-format suggestions. Hopefully we can eventually improve clang-format to
|
||||
# be configurable enough for our coding style. That’s why this CI check is OK
|
||||
# to fail: the idea is that people can look through the output and ignore it if
|
||||
# it’s wrong. (That situation can also happen if someone touches pre-existing
|
||||
# badly formatted code and it doesn’t make sense to tidy up the wider coding
|
||||
# style with the changes they’re making.)
|
||||
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"
|
||||
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."
|
||||
|
||||
exit ${exit_status}
|
||||
@@ -1,107 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set +x
|
||||
set +e
|
||||
|
||||
srcdir=$( pwd )
|
||||
builddir=$1
|
||||
backend=$2
|
||||
|
||||
# Ignore memory leaks lower in dependencies
|
||||
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} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
# Store the exit code for the CI run, but always
|
||||
# generate the reports
|
||||
exit_code=$?
|
||||
;;
|
||||
|
||||
wayland)
|
||||
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} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
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}
|
||||
;;
|
||||
|
||||
broadway)
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
${builddir}/gdk/broadway/gtk4-broadwayd :5 &
|
||||
server=$!
|
||||
export BROADWAY_DISPLAY=:5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-opengl
|
||||
|
||||
# don't let Broadway failures fail the run, for now
|
||||
exit_code=0
|
||||
kill ${server}
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Failed to add ${backend} to .gitlab-ci/run-tests.sh"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
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
|
||||
$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
|
||||
|
||||
exit $exit_code
|
||||
@@ -1,5 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
. /etc/os-release
|
||||
|
||||
echo $PRETTY_NAME
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux -o pipefail
|
||||
|
||||
xcodebuild -version || :
|
||||
xcodebuild -showsdks || :
|
||||
|
||||
system_profiler SPSoftwareDataType || :
|
||||
@@ -4,53 +4,20 @@ set -e
|
||||
|
||||
srcdir=$(pwd)
|
||||
|
||||
mkdir -p _ccache
|
||||
export CCACHE_BASEDIR="$(pwd)"
|
||||
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
|
||||
|
||||
ccache --zero-stats
|
||||
ccache --show-stats
|
||||
export CCACHE_DISABLE=true
|
||||
meson \
|
||||
-Dx11-backend=true \
|
||||
-Dwayland-backend=true \
|
||||
-Dbroadway-backend=true \
|
||||
-Dvulkan=enabled \
|
||||
-Dprofiler=true \
|
||||
--werror \
|
||||
${EXTRA_MESON_FLAGS:-} \
|
||||
-Dvulkan=yes \
|
||||
_build $srcdir
|
||||
unset CCACHE_DISABLE
|
||||
|
||||
cd _build
|
||||
|
||||
ninja
|
||||
ccache --show-stats
|
||||
|
||||
set +e
|
||||
|
||||
xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
meson test \
|
||||
--timeout-multiplier 2 \
|
||||
--print-errorlogs \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:a11y
|
||||
|
||||
# Save the exit code
|
||||
exit_code=$?
|
||||
|
||||
# We always want to run the report generators
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
--project-name=gtk \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--output=report.xml \
|
||||
meson-logs/testlog.json
|
||||
|
||||
$srcdir/.gitlab-ci/meson-html-report.py \
|
||||
--project-name=GTK \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--reftest-output-dir="testsuite/reftests/output" \
|
||||
--output=report.html \
|
||||
meson-logs/testlog.json
|
||||
|
||||
exit $exit_code
|
||||
--suite=gtk+ \
|
||||
--no-suite=gtk+:gsk \
|
||||
--no-suite=gtk+:a11y
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
@echo on
|
||||
:: vcvarsall.bat sets various env vars like PATH, INCLUDE, LIB, LIBPATH for the
|
||||
:: specified build architecture
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
@echo on
|
||||
|
||||
:: FIXME: make warnings fatal
|
||||
pip3 install --upgrade --user meson==0.60.3 || goto :error
|
||||
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
|
||||
ninja -C _build || goto :error
|
||||
|
||||
goto :EOF
|
||||
:error
|
||||
exit /b 1
|
||||
@@ -1,77 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$MSYSTEM" == "MINGW32" ]]; then
|
||||
export MSYS2_ARCH="i686"
|
||||
else
|
||||
export MSYS2_ARCH="x86_64"
|
||||
fi
|
||||
|
||||
# Update everything
|
||||
pacman --noconfirm -Suy
|
||||
|
||||
# Install the required packages
|
||||
pacman --noconfirm -S --needed \
|
||||
base-devel \
|
||||
git \
|
||||
mingw-w64-$MSYS2_ARCH-cc \
|
||||
mingw-w64-$MSYS2_ARCH-ccache \
|
||||
mingw-w64-$MSYS2_ARCH-pkgconf \
|
||||
mingw-w64-$MSYS2_ARCH-gobject-introspection \
|
||||
mingw-w64-$MSYS2_ARCH-meson \
|
||||
mingw-w64-$MSYS2_ARCH-adwaita-icon-theme \
|
||||
mingw-w64-$MSYS2_ARCH-atk \
|
||||
mingw-w64-$MSYS2_ARCH-cairo \
|
||||
mingw-w64-$MSYS2_ARCH-gdk-pixbuf2 \
|
||||
mingw-w64-$MSYS2_ARCH-glib2 \
|
||||
mingw-w64-$MSYS2_ARCH-graphene \
|
||||
mingw-w64-$MSYS2_ARCH-json-glib \
|
||||
mingw-w64-$MSYS2_ARCH-libepoxy \
|
||||
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
|
||||
|
||||
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
|
||||
export CCACHE_DISABLE=true
|
||||
meson \
|
||||
-Dx11-backend=false \
|
||||
-Dwayland-backend=false \
|
||||
-Dwin32-backend=true \
|
||||
-Dvulkan=disabled \
|
||||
-Dintrospection=enabled \
|
||||
-Dgtk:werror=true \
|
||||
_build
|
||||
unset CCACHE_DISABLE
|
||||
|
||||
ninja -C _build
|
||||
ccache --show-stats
|
||||
|
||||
tar zcf _build/gtkdll.tar.gz _build/gtk/libgtk*.dll
|
||||
@@ -1,13 +1,4 @@
|
||||
<!--
|
||||
Please, read the CONTRIBUTING.md guide on how to file a new issue.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
## Steps to reproduce
|
||||
<!--
|
||||
Please, explain the sequence of actions necessary to reproduce the
|
||||
bug
|
||||
-->
|
||||
|
||||
1. ...
|
||||
2. ...
|
||||
@@ -16,8 +7,8 @@
|
||||
<!--
|
||||
You should try and reproduce with the demos applications available
|
||||
under the `demos` directory, or the test programs in the `tests` directory.
|
||||
Alternatively, please attach a *small and self-contained* example
|
||||
*written in C* that exhibits the issue.
|
||||
Alternatively, please attach a *small and self-contained* example that
|
||||
exhibits the issue.
|
||||
-->
|
||||
|
||||
## Current behavior
|
||||
@@ -32,17 +23,17 @@
|
||||
|
||||
## Version information
|
||||
<!--
|
||||
- Which version of GTK you are using
|
||||
- What operating system and version
|
||||
- For Linux, which distribution
|
||||
- If you built GTK yourself, the list of options used to configure the build
|
||||
- which version of GTK+ you are using
|
||||
- what operating system and version
|
||||
- for Linux, which distribution
|
||||
- if you built GTK+ yourself, the list of options used to configure the build
|
||||
-->
|
||||
|
||||
## Additional information
|
||||
<!--
|
||||
- Screenshots or screen recordings are useful for visual errors
|
||||
- Attaching a screenshot or a video without explaining the current
|
||||
behavior and the actions necessary to reproduce the bug will lead
|
||||
to the bug being closed
|
||||
- Please report any warning or message printed on the terminal
|
||||
-->
|
||||
- If the bug was a crash, the exact text that was printed out
|
||||
when the crash occurred.
|
||||
- If the bug was a crash, attaching a stack trace obtained using
|
||||
GDB is appreciated; follow the instructions on the wiki:
|
||||
https://wiki.gnome.org/Community/GettingInTouch/Bugzilla/GettingTraces
|
||||
-->
|
||||
@@ -1,44 +0,0 @@
|
||||
<!--
|
||||
Please, read the CONTRIBUTING.md guide on how to file a new issue.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
## Steps to reproduce
|
||||
<!--
|
||||
Please, explain the sequence of actions necessary to reproduce the
|
||||
crash
|
||||
-->
|
||||
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
<!--
|
||||
You should try and reproduce with the demos applications available
|
||||
under the `demos` directory, or the test programs in the `tests` directory.
|
||||
Alternatively, please attach a *small and self-contained* example that
|
||||
exhibits the issue.
|
||||
-->
|
||||
|
||||
## Version information
|
||||
<!--
|
||||
- Which version of GTK you are using
|
||||
- What operating system and version
|
||||
- for Linux, which distribution
|
||||
- If you built GTK yourself, the list of options used to configure the build
|
||||
-->
|
||||
|
||||
## Warnings
|
||||
<!--
|
||||
- If the application generates warning messages before crashing please
|
||||
report them here
|
||||
-->
|
||||
|
||||
## Backtrace
|
||||
<!--
|
||||
- Attaching a stack trace obtained using GDB is appreciated; follow the
|
||||
instructions on the wiki:
|
||||
|
||||
https://wiki.gnome.org/Community/GettingInTouch/Bugzilla/GettingTraces
|
||||
-->
|
||||
30
AUTHORS
30
AUTHORS
@@ -1,5 +1,5 @@
|
||||
Please do not mail any of the authors listed here
|
||||
asking questions about this version of GTK.
|
||||
Please do not mail any of the authors listed here
|
||||
asking questions about this version of GTK+.
|
||||
|
||||
Original Authors
|
||||
----------------
|
||||
@@ -7,8 +7,8 @@ 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 GTK+ Team (in alphabetical order)
|
||||
-------------------------------------
|
||||
Shawn T. Amundson <amundson@gtk.org>
|
||||
Jerome Bolliet <bolliet@gtk.org>
|
||||
Damon Chaplin <damon@gtk.org>
|
||||
@@ -28,24 +28,11 @@ Jay Painter <jpaint@gtk.org>
|
||||
Manish Singh <manish@gtk.org>
|
||||
Owen Taylor <otaylor@gtk.org>
|
||||
|
||||
The current team (GTK 3 and 4)
|
||||
------------------------------
|
||||
|
||||
Jonas Ådahl <jadahl@gmail.com>
|
||||
Tim Bäder <mail@baedert.org>
|
||||
Emmanuele Bassi <ebassi@gnome.org>
|
||||
Chun-wei Fan <fanchunwei@src.gnome.org>
|
||||
Matthias Clasen <mclasen@redhat.com>
|
||||
Carlos Garnacho <mrgarnacho@gmail.com>
|
||||
Alexander Larsson <alexl@redhat.com>
|
||||
Benjamin Otte <otte@gnome.org>
|
||||
|
||||
|
||||
There are many others who have contributed patches; we thank them,
|
||||
GTK is much better because of them.
|
||||
GTK+ is much better because of them.
|
||||
|
||||
|
||||
Over time, GTK has incorporated some pieces of software which
|
||||
Over time, GTK+ has incorporated some pieces of software which
|
||||
started as independent projects. We list the original authors here:
|
||||
|
||||
|
||||
@@ -76,8 +63,3 @@ DirectFB backend
|
||||
Denis Oliver Kropp
|
||||
Sven Neumann
|
||||
Mike Emmel
|
||||
|
||||
|
||||
gtkparasite
|
||||
-----------
|
||||
Christian Hammond
|
||||
|
||||
242
CONTRIBUTING.md
242
CONTRIBUTING.md
@@ -1,145 +1,31 @@
|
||||
# Contribution guidelines
|
||||
|
||||
Thank you for considering contributing to the GTK project!
|
||||
|
||||
These guidelines are meant for new contributors, regardless of their level
|
||||
of proficiency; following them allows the maintainers of the GTK project to
|
||||
more effectively evaluate your contribution, and provide prompt feedback to
|
||||
you. Additionally, by following these guidelines you clearly communicate
|
||||
that you respect the time and effort that the people developing GTK put into
|
||||
managing the project.
|
||||
|
||||
GTK is a complex free software GUI toolkit, and it would not exist without
|
||||
contributions from the free and open source software community. There are
|
||||
many things that we value:
|
||||
|
||||
- bug reporting and fixing
|
||||
- documentation and examples
|
||||
- tests
|
||||
- new features
|
||||
|
||||
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` 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
|
||||
Overflow](https://stackoverflow.com/questions/tagged/gtk).
|
||||
|
||||
The issue tracker is meant to be used for actionable issues only.
|
||||
|
||||
## How to report bugs
|
||||
|
||||
### Security issues
|
||||
|
||||
You should not open a new issue for security related questions.
|
||||
|
||||
When in doubt, send an email to the [security](mailto:security@gnome.org)
|
||||
mailing list.
|
||||
|
||||
### Bug reports
|
||||
|
||||
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. the necessary steps to reproduce the issue
|
||||
0. the expected outcome
|
||||
0. a description of the behavior; screenshots are also welcome
|
||||
0. a small, self-contained example exhibiting the behavior; if this
|
||||
is not available, try reproducing the issue using the GTK examples
|
||||
or interactive tests
|
||||
|
||||
If the issue includes a crash, you should also include:
|
||||
|
||||
0. the eventual warnings printed on the terminal
|
||||
0. a backtrace, obtained with tools such as GDB or LLDB
|
||||
|
||||
It is fine to include screenshots of screen recordings to demonstrate
|
||||
an issue that is best to understand visually, but please don't just
|
||||
dump screen recordings without further details into issues. It is
|
||||
essential that the problem is described in enough detail to reproduce
|
||||
it without watching a video.
|
||||
|
||||
For small issues, such as:
|
||||
|
||||
- spelling/grammar fixes in the documentation
|
||||
- typo correction
|
||||
- comment clean ups
|
||||
- changes to metadata files (CI, `.gitignore`)
|
||||
- build system changes
|
||||
- source tree clean ups and reorganizations
|
||||
|
||||
You should directly open a merge request instead of filing a new issue.
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
Feature discussion can be open ended and require high bandwidth channels; if
|
||||
you are proposing a new feature on the issue tracker, make sure to make
|
||||
an actionable proposal, and list:
|
||||
|
||||
0. what you're trying to achieve
|
||||
0. prior art, in other toolkits or applications
|
||||
0. design and theming changes
|
||||
|
||||
If you're proposing the integration of new features it helps to have
|
||||
multiple applications using shared or similar code, especially if they have
|
||||
iterated over it various times.
|
||||
|
||||
Each feature should also come fully documented, and with tests.
|
||||
|
||||
## Your first contribution
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you want to contribute to the GTK project, you will need to have the
|
||||
development tools appropriate for your operating system, including:
|
||||
If you want to hack on the GTK+ project, you'll need to have the development
|
||||
tools appropriate for your operating system, including:
|
||||
|
||||
- Python 3.x
|
||||
- Meson
|
||||
- Ninja
|
||||
- Gettext (19.7 or newer)
|
||||
- a [C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
|
||||
- a C99 compatible compiler
|
||||
|
||||
Up-to-date instructions about developing GNOME applications and libraries
|
||||
can be found on [the GNOME Developer Center](https://developer.gnome.org).
|
||||
can be found here:
|
||||
|
||||
The GTK project uses GitLab for code hosting and for tracking issues. More
|
||||
information about using GitLab can be found [on the GNOME
|
||||
wiki](https://wiki.gnome.org/GitLab).
|
||||
* https://developer.gnome.org
|
||||
|
||||
### Dependencies
|
||||
Information about using GitLab with GNOME can be found here:
|
||||
|
||||
In order to get GTK from Git installed on your system, you need to have the
|
||||
required versions of all the software dependencies required by GTK; typically,
|
||||
this means a recent version of GLib, Cairo, Pango, and ATK, as well as the
|
||||
platform-specific dependencies for the windowing system you are using (Wayland,
|
||||
X11, Windows, or macOS).
|
||||
* https://wiki.gnome.org/GitLab
|
||||
|
||||
The core dependencies for GTK are:
|
||||
|
||||
- [GLib, GObject, and GIO](https://gitlab.gnome.org/GNOME/glib)
|
||||
- [Cairo](http://cairographics.org)
|
||||
- [Pango](https://gitlab.gnome.org/GNOME/pango)
|
||||
- [GdkPixbuf](https://gitlab.gnome.org/GNOME/gdk-pixbuf)
|
||||
- [Epoxy](https://github.com/anholt/libepoxy)
|
||||
- [ATK](https://gitlab.gnome.org/GNOME/atk)
|
||||
- [Graphene](https://github.com/ebassi/graphene)
|
||||
|
||||
GTK will attempt to download and build some of these dependencies if it
|
||||
cannot find them on your system.
|
||||
|
||||
Additionally, you may want to look at projects that create a development
|
||||
environment for you, like [jhbuild](https://wiki.gnome.org/HowDoI/Jhbuild)
|
||||
and [gvsbuild](https://github.com/wingtk/gvsbuild).
|
||||
|
||||
### Getting started
|
||||
In order to get Git GTK+ installed on your system, you need to have the
|
||||
required versions of all the GTK+ dependencies; typically, this means a
|
||||
recent version of GLib, Cairo, Pango, and ATK, as well as the platform
|
||||
specific dependencies for the windowing system you are using (Wayland, X11,
|
||||
Windows, or macOS).
|
||||
|
||||
You should start by forking the GTK repository from the GitLab web UI, and
|
||||
cloning from your fork:
|
||||
|
||||
```sh
|
||||
```ssh
|
||||
$ git clone https://gitlab.gnome.org/yourusername/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
@@ -152,7 +38,7 @@ $ git clone git@gitlab.gnome.org:GNOME/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
|
||||
To compile the Git version of GTK on your system, you will need to
|
||||
To compile the Git version of GTK+ on your system, you will need to
|
||||
configure your build using Meson:
|
||||
|
||||
```sh
|
||||
@@ -161,6 +47,11 @@ $ cd _builddir
|
||||
$ ninja
|
||||
```
|
||||
|
||||
**Note**: For information about submitting patches and pushing changes
|
||||
to Git, see the `README.md` and `README.commits` files. In particular,
|
||||
don't, under any circumstances, push anything to Git before reading and
|
||||
understanding `README.commmits`.
|
||||
|
||||
Typically, you should work on your own branch:
|
||||
|
||||
```sh
|
||||
@@ -170,98 +61,3 @@ $ git checkout -b your-branch
|
||||
Once you've finished working on the bug fix or feature, push the branch
|
||||
to the Git repository and open a new merge request, to let the GTK
|
||||
maintainers review your contribution.
|
||||
|
||||
### Code reviews
|
||||
|
||||
Each contribution is reviewed by the core developers of the GTK project.
|
||||
|
||||
The [CODEOWNERS](./docs/CODEOWNERS) document contains the list of core
|
||||
contributors to GTK and the areas for which they are responsible; you
|
||||
should ensure to receive their review and signoff on your changes.
|
||||
|
||||
### Commit messages
|
||||
|
||||
The expected format for git commit messages is as follows:
|
||||
|
||||
```plain
|
||||
Short explanation of the commit
|
||||
|
||||
Longer explanation explaining exactly what's changed, whether any
|
||||
external or private interfaces changed, what bugs were fixed (with bug
|
||||
tracker reference if applicable) and so forth. Be concise but not too
|
||||
brief.
|
||||
|
||||
Closes #1234
|
||||
```
|
||||
|
||||
- Always add a brief description of the commit to the _first_ line of
|
||||
the commit and terminate by two newlines (it will work without the
|
||||
second newline, but that is not nice for the interfaces).
|
||||
|
||||
- First line (the brief description) must only be one sentence and
|
||||
should start with a capital letter unless it starts with a lowercase
|
||||
symbol or identifier. Don't use a trailing period either. Don't exceed
|
||||
72 characters.
|
||||
|
||||
- The main description (the body) is normal prose and should use normal
|
||||
punctuation and capital letters where appropriate. Consider the commit
|
||||
message as an email sent to the developers (or yourself, six months
|
||||
down the line) detailing **why** you changed something. There's no need
|
||||
to specify the **how**: the changes can be inlined.
|
||||
|
||||
- When committing code on behalf of others use the `--author` option, e.g.
|
||||
`git commit -a --author "Joe Coder <joe@coder.org>"` and `--signoff`.
|
||||
|
||||
- If your commit is addressing an issue, use the
|
||||
[GitLab syntax](https://docs.gitlab.com/ce/user/project/issues/automatic_issue_closing.html)
|
||||
to automatically close the issue when merging the commit with the upstream
|
||||
repository:
|
||||
|
||||
```plain
|
||||
Closes #1234
|
||||
Fixes #1234
|
||||
Closes: https://gitlab.gnome.org/GNOME/gtk/issues/1234
|
||||
```
|
||||
|
||||
- If you have a merge request with multiple commits and none of them
|
||||
completely fixes an issue, you should add a reference to the issue in
|
||||
the commit message, e.g. `Bug: #1234`, and use the automatic issue
|
||||
closing syntax in the description of the merge request.
|
||||
|
||||
### Commit access to the GTK repository
|
||||
|
||||
GTK is part of the GNOME infrastructure. At the current time, any
|
||||
person with write access to the GNOME repository can merge changes to
|
||||
GTK. This is a good thing, in that it encourages many people to work
|
||||
on GTK, and progress can be made quickly. However, GTK is a fairly
|
||||
large and complicated project on which many other things depend, so to
|
||||
avoid unnecessary breakage, and to take advantage of the knowledge
|
||||
about GTK that has been built up over the years, we'd like to ask
|
||||
people committing to GTK to follow a few rules:
|
||||
|
||||
0. Ask first. If your changes are major, or could possibly break existing
|
||||
code, you should always ask. If your change is minor and you've been
|
||||
working on GTK for a while it probably isn't necessary to ask. But when
|
||||
in doubt, ask. Even if your change is correct, somebody may know a
|
||||
better way to do things. If you are making changes to GTK, you should
|
||||
be subscribed to the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
|
||||
mailing list; this is a good place to ask about intended changes.
|
||||
The `#gtk` IRC channel on irc.gnome.org is also a good place to find GTK
|
||||
developers to discuss changes, but if you live outside of the EU/US time
|
||||
zones, an email to the gtk-devel mailing list is the most certain and
|
||||
preferred method.
|
||||
|
||||
0. Ask _first_.
|
||||
|
||||
0. Always write a meaningful commit message. Changes without a sufficient
|
||||
commit message will be reverted.
|
||||
|
||||
0. Never push to the `main` branch, or any stable branches, directly; you
|
||||
should always go through a merge request, to ensure that the code is
|
||||
tested on the CI infrastructure at the very least. A merge request is
|
||||
also the proper place to get a comprehensive code review from the core
|
||||
developers of GTK.
|
||||
|
||||
If you have been contributing to GTK for a while and you don't have commit
|
||||
access to the repository, you may ask to obtain it following the [GNOME account
|
||||
process](https://wiki.gnome.org/AccountsTeam/NewAccounts).
|
||||
|
||||
9178
NEWS.pre-4.0
9178
NEWS.pre-4.0
File diff suppressed because it is too large
Load Diff
72
README.commits
Normal file
72
README.commits
Normal file
@@ -0,0 +1,72 @@
|
||||
GTK+ is part of the GNOME git repository. At the current time, any
|
||||
person with write access to the GNOME repository, can make changes to
|
||||
GTK+. This is a good thing, in that it encourages many people to work
|
||||
on GTK+, and progress can be made quickly. However, GTK+ is a fairly
|
||||
large and complicated package that many other things depend on, so to
|
||||
avoid unnecessary breakage, and to take advantage of the knowledge
|
||||
about GTK+ that has been built up over the years, we'd like to ask
|
||||
people committing to GTK+ to follow a few rules:
|
||||
|
||||
0) Ask first. If your changes are major, or could possibly break existing
|
||||
code, you should always ask. If your change is minor and you've
|
||||
been working on GTK+ for a while it probably isn't necessary
|
||||
to ask. But when in doubt, ask. Even if your change is correct,
|
||||
somebody may know a better way to do things.
|
||||
|
||||
If you are making changes to GTK+, you should be subscribed
|
||||
to gtk-devel-list@gnome.org. (Subscription address:
|
||||
gtk-devel-list-request@gnome.org.) This is a good place to ask
|
||||
about intended changes.
|
||||
|
||||
#gtk+ on GIMPNet (irc.gimp.org, irc.us.gimp.org, irc.eu.gimp.org, ...)
|
||||
is also a good place to find GTK+ developers to discuss changes with,
|
||||
however, email to gtk-devel-list is the most certain and preferred
|
||||
method.
|
||||
|
||||
1) Ask _first_.
|
||||
|
||||
2) With git, we no longer maintain a ChangeLog file, but you are expected
|
||||
to produce a meaningful commit message. Changes without a sufficient
|
||||
commit message will be reverted. See below for the expected format
|
||||
of commit messages.
|
||||
|
||||
Notes:
|
||||
|
||||
* When developing larger features or complicated bug fixes, it is
|
||||
advisable to work in a branch in your own cloned GTK+ repository.
|
||||
You may even consider making your repository publically available
|
||||
so that others can easily test and review your changes.
|
||||
|
||||
* The expected format for git commit messages is as follows:
|
||||
|
||||
=== begin example commit ===
|
||||
Short explanation of the commit
|
||||
|
||||
Longer explanation explaining exactly what's changed, whether any
|
||||
external or private interfaces changed, what bugs were fixed (with bug
|
||||
tracker reference if applicable) and so forth. Be concise but not too brief.
|
||||
=== end example commit ===
|
||||
|
||||
- Always add a brief description of the commit to the _first_ line of
|
||||
the commit and terminate by two newlines (it will work without the
|
||||
second newline, but that is not nice for the interfaces).
|
||||
|
||||
- First line (the brief description) must only be one sentence and
|
||||
should start with a capital letter unless it starts with a lowercase
|
||||
symbol or identifier. Don't use a trailing period either. Don't exceed
|
||||
72 characters.
|
||||
|
||||
- The main description (the body) is normal prose and should use normal
|
||||
punctuation and capital letters where appropriate. Normally, for patches
|
||||
sent to a mailing list it's copied from there.
|
||||
|
||||
- When committing code on behalf of others use the --author option, e.g.
|
||||
git commit -a --author "Joe Coder <joe@coder.org>" and --signoff.
|
||||
|
||||
|
||||
Owen Taylor
|
||||
13 Aug 1998
|
||||
17 Apr 2001
|
||||
|
||||
Matthias Clasen
|
||||
31 Mar 2009
|
||||
101
README.md
101
README.md
@@ -1,25 +1,23 @@
|
||||
GTK — The GTK toolkit
|
||||
=====================
|
||||
GTK+ — The GTK toolkit
|
||||
======================
|
||||
|
||||
[](https://gitlab.gnome.org/GNOME/gtk/-/commits/main)
|
||||
[](https://gitlab.gnome.org/GNOME/gtk/pipelines)
|
||||
|
||||
General information
|
||||
-------------------
|
||||
|
||||
GTK is a multi-platform toolkit for creating graphical user interfaces.
|
||||
Offering a complete set of widgets, GTK is suitable for projects ranging
|
||||
GTK+ is a multi-platform toolkit for creating graphical user interfaces.
|
||||
Offering a complete set of widgets, GTK+ is suitable for projects ranging
|
||||
from small one-off projects to complete application suites.
|
||||
|
||||
GTK is a free and open-source software project. The licensing terms
|
||||
for GTK, the GNU LGPL, allow it to be used by all developers, including those
|
||||
developing proprietary software, without any license fees or royalties.
|
||||
|
||||
GTK is hosted by the GNOME project (thanks!) and used by a wide variety
|
||||
of applications and projects.
|
||||
GTK+ is free software and part of the GNU Project. However, the
|
||||
licensing terms for GTK+, the GNU LGPL, allow it to be used by all
|
||||
developers, including those developing proprietary software, without any
|
||||
license fees or royalties.
|
||||
|
||||
The official download location
|
||||
|
||||
- https://download.gnome.org/sources/gtk/
|
||||
- https://download.gnome.org/sources/gtk+
|
||||
|
||||
The official web site
|
||||
|
||||
@@ -29,26 +27,14 @@ The official developers blog
|
||||
|
||||
- https://blog.gtk.org
|
||||
|
||||
Discussion forum
|
||||
Information about mailing lists can be found at
|
||||
|
||||
- https://discourse.gnome.org/c/platform/core/
|
||||
|
||||
Nightly documentation can be found at
|
||||
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk4/
|
||||
- Gdk: https://gnome.pages.gitlab.gnome.org/gtk/gdk4/
|
||||
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk4/
|
||||
|
||||
Nightly flatpaks of our demos can be installed from the
|
||||
[GNOME Nightly](https://wiki.gnome.org/Apps/Nightly) repository:
|
||||
- `flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo`
|
||||
- `flatpak install gnome-nightly org.gtk.Demo4`
|
||||
- `flatpak install gnome-nightly org.gtk.WidgetFactory4`
|
||||
- `flatpak install gnome-nightly org.gtk.IconBrowser4`
|
||||
- http://www.gtk.org/mailing-lists.php
|
||||
|
||||
Building and installing
|
||||
-----------------------
|
||||
|
||||
In order to build GTK you will need:
|
||||
In order to build GTK+ you will need:
|
||||
|
||||
- [a C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
|
||||
- [Python 3](https://www.python.org/)
|
||||
@@ -58,13 +44,14 @@ In order to build GTK you will need:
|
||||
You will also need various dependencies, based on the platform you are
|
||||
building for:
|
||||
|
||||
- [GLib](https://download.gnome.org/sources/glib/)
|
||||
- [GdkPixbuf](https://download.gnome.org/sources/gdk-pixbuf/)
|
||||
- [GObject-Introspection](https://download.gnome.org/sources/gobject-introspection/)
|
||||
- [Cairo](https://www.cairographics.org/)
|
||||
- [Pango](https://download.gnome.org/sources/pango/)
|
||||
- [GLib](https://download.gnome.org/sources/glib)
|
||||
- [GdkPixbuf](https://download.gnome.org/sources/gdk-pixbuf)
|
||||
- [GObject-Introspection](https://download.gnome.org/sources/gobject-introspection)
|
||||
- [Cairo](https://www.cairographics.org)
|
||||
- [Pango](https://download.gnome.org/sources/pango)
|
||||
- [Epoxy](https://github.com/anholt/libepoxy)
|
||||
- [Graphene](https://github.com/ebassi/graphene)
|
||||
- [ATK](https://download.gnome.org/sources/atk)
|
||||
- [Xkb-common](https://github.com/xkbcommon/libxkbcommon)
|
||||
|
||||
If you are building the X11 backend, you will also need:
|
||||
@@ -78,6 +65,7 @@ If you are building the X11 backend, you will also need:
|
||||
- xcursor
|
||||
- xdamage
|
||||
- xcomposite
|
||||
- [atk-bridge-2.0](https://download.gnome.org/sources/at-spi2-atk)
|
||||
|
||||
If you are building the Wayland backend, you will also need:
|
||||
|
||||
@@ -86,7 +74,7 @@ If you are building the Wayland backend, you will also need:
|
||||
- Wayland-cursor
|
||||
- Wayland-EGL
|
||||
|
||||
Once you have all the necessary dependencies, you can build GTK by using
|
||||
Once you have all the necessary dependencies, you can build GTK+ by using
|
||||
Meson:
|
||||
|
||||
```sh
|
||||
@@ -101,34 +89,20 @@ You can run the test suite using:
|
||||
$ meson test
|
||||
```
|
||||
|
||||
And, finally, you can install GTK using:
|
||||
And, finally, you can install GTK+ using:
|
||||
|
||||
```
|
||||
$ sudo ninja install
|
||||
```
|
||||
|
||||
Complete information about installing GTK and related libraries
|
||||
Complete information about installing GTK+ and related libraries
|
||||
can be found in the file:
|
||||
|
||||
```
|
||||
docs/reference/gtk/html/gtk-building.html
|
||||
```
|
||||
|
||||
Or [online](https://docs.gtk.org/gtk4/building.html)
|
||||
|
||||
Default branch renamed to `main`
|
||||
--------------------------------
|
||||
|
||||
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
|
||||
```
|
||||
Or [online](https://developer.gnome.org/gtk4/stable/gtk-building.html)
|
||||
|
||||
How to report bugs
|
||||
------------------
|
||||
@@ -139,10 +113,10 @@ In the bug report please include:
|
||||
|
||||
* Information about your system. For instance:
|
||||
|
||||
- which version of GTK you are using
|
||||
- which version of GTK+ you are using
|
||||
- what operating system and version
|
||||
- for Linux, which distribution
|
||||
- if you built GTK, the list of options used to configure the build
|
||||
- if you built GTK+, the list of options used to configure the build
|
||||
|
||||
And anything else you think is relevant.
|
||||
|
||||
@@ -161,33 +135,20 @@ In the bug report please include:
|
||||
* Further information such as stack traces may be useful, but
|
||||
is not necessary.
|
||||
|
||||
Contributing to GTK
|
||||
-------------------
|
||||
|
||||
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
|
||||
start contributing to GTK.
|
||||
|
||||
If you want to support GTK financially, please consider donating to
|
||||
the GNOME project, which runs the infrastructure hosting GTK.
|
||||
|
||||
Release notes
|
||||
-------------
|
||||
|
||||
The release notes for GTK are part of the migration guide in the API
|
||||
The release notes for GTK+ are part of the migration guide in the API
|
||||
reference. See:
|
||||
|
||||
- [3.x release notes](https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html)
|
||||
- [4.x release notes](https://docs.gtk.org/gtk4/migrating-3to4.html)
|
||||
- [3.x release notes](https://developer.gnome.org/gtk3/unstable/gtk-migrating-2-to-3.html)
|
||||
- [4.x release notes](https://developer.gnome.org/gtk4/unstable/gtk-migrating-3-to-4.html)
|
||||
|
||||
Licensing terms
|
||||
---------------
|
||||
|
||||
GTK is released under the terms of the GNU Lesser General Public License,
|
||||
GTK+ is released under the terms of the GNU Lesser General Public License,
|
||||
version 2.1 or, at your option, any later version, as published by the Free
|
||||
Software Foundation.
|
||||
|
||||
Please, see the [`COPYING`](./COPYING) file for further information.
|
||||
|
||||
GTK includes a small number of source files under the Apache license:
|
||||
- A fork of the roaring bitmaps implementation in [gtk/roaring](./gtk/roaring)
|
||||
- An adaptation of timsort from python in [gtk/timsort](./gtk/timsort)
|
||||
Please, see the `COPYING` file for further information.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
diff -ur lua-5.1.4/src/Makefile lua-5.1.4-new/src/Makefile
|
||||
--- lua-5.1.4/src/Makefile 2008-01-19 20:37:58.000000000 +0100
|
||||
+++ lua-5.1.4-new/src/Makefile 2012-02-23 18:26:43.000000000 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
|
||||
|
||||
LUA_A= liblua.a
|
||||
+LUA_SO= liblua.so
|
||||
CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
|
||||
lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \
|
||||
lundump.o lvm.o lzio.o
|
||||
@@ -36,7 +37,7 @@
|
||||
LUAC_O= luac.o print.o
|
||||
|
||||
ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O)
|
||||
-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
|
||||
+ALL_T= $(LUA_A) $(LUA_SO) $(LUA_T) $(LUAC_T)
|
||||
ALL_A= $(LUA_A)
|
||||
|
||||
default: $(PLAT)
|
||||
@@ -51,6 +52,11 @@
|
||||
$(AR) $@ $?
|
||||
$(RANLIB) $@
|
||||
|
||||
+$(LUA_SO): $(CORE_O) $(LIB_O)
|
||||
+ $(CC) -shared -ldl -Wl,-soname,$(LUA_SO).$(V) -o $@.$(R) $? -lm $(MYLDFLAGS)
|
||||
+ ln -sf $(LUA_SO).$(R) $(LUA_SO).$(V)
|
||||
+ ln -sf $(LUA_SO).$(R) $(LUA_SO)
|
||||
+
|
||||
$(LUA_T): $(LUA_O) $(LUA_A)
|
||||
$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
|
||||
|
||||
--- lua-5.1.4/Makefile 2008-08-12 02:40:48.000000000 +0200
|
||||
+++ lua-5.1.4-new/Makefile 2012-02-23 19:06:32.000000000 +0100
|
||||
@@ -53,7 +53,7 @@
|
||||
all: $(PLAT)
|
||||
|
||||
$(PLATS) clean:
|
||||
- cd src && $(MAKE) $@
|
||||
+ cd src && $(MAKE) $@ V=$(V) R=$(R)
|
||||
|
||||
test: dummy
|
||||
src/lua test/hello.lua
|
||||
59
build-aux/flatpak/org.gtk.Demo.json
Normal file
59
build-aux/flatpak/org.gtk.Demo.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"app-id": "org.gtk.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk4-demo",
|
||||
"tags": ["devel", "development", "nightly"],
|
||||
"rename-desktop-file": "gtk4-demo.desktop",
|
||||
"rename-icon": "gtk4-demo",
|
||||
"desktop-file-name-prefix": "(Development) ",
|
||||
"finish-args": [
|
||||
"--device=dri",
|
||||
"--share=ipc",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*",
|
||||
"--talk-name=ca.desrt.conf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
|
||||
],
|
||||
"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": "graphene",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/ebassi/graphene.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
{
|
||||
"app-id" : "org.gtk.Demo4",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "gtk4-demo",
|
||||
"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",
|
||||
"-Dbenchmarks=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": "boost",
|
||||
"buildsystem": "simple",
|
||||
"build-commands": [
|
||||
"./bootstrap.sh --prefix=/app --with-libraries=date_time,filesystem,iostreams,locale,regex,system,thread,python,program_options,test,serialization",
|
||||
"./b2 --build-type=minimal link=shared -j $FLATPAK_BUILDER_N_JOBS",
|
||||
"./b2 --build-type=minimal link=shared install"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.69.0/source/boost_1_69_0.tar.bz2",
|
||||
"sha256": "8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lua-5.1",
|
||||
"buildsystem": "simple",
|
||||
"build-commands": [
|
||||
"make -j $FLATPAK_BUILDER_N_JOBS CFLAGS=\"$CFLAGS -fPIC -DLUA_USE_LINUX\" linux",
|
||||
"make INSTALL_TOP=$FLATPAK_DEST TO_LIB='liblua.a liblua.so.5.1.5' install",
|
||||
"ln -sf liblua.so.5.1.5 $FLATPAK_DEST/lib/liblua.so",
|
||||
"ln -sf liblua.so.5.1.5 $FLATPAK_DEST/lib/liblua.so.5.1",
|
||||
"install -Dm0644 etc/lua.pc $FLATPAK_DEST/lib/pkgconfig/lua.pc",
|
||||
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua51.pc",
|
||||
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua5.1.pc",
|
||||
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua-5.1.pc"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://www.lua.org/ftp/lua-5.1.5.tar.gz",
|
||||
"sha256": "2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "lua-5.1.5-so.patch"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"commands": [
|
||||
"sed -i \"s|/usr/local|$FLATPAK_DEST|\" etc/lua.pc src/luaconf.h"
|
||||
]
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
"*.a",
|
||||
"/bin",
|
||||
"/include",
|
||||
"/lib/pkgconfig",
|
||||
"/man"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "highlight",
|
||||
"buildsystem" : "simple",
|
||||
"builddir" : true,
|
||||
"build-commands" : [
|
||||
"sed -i -e 's#^PREFIX = /usr#PREFIX = /app#' makefile",
|
||||
"make",
|
||||
"make install"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "archive",
|
||||
"url" : "http://www.andre-simon.de/zip/highlight-4.0.tar.bz2",
|
||||
"sha256" : "f40dcba26e011a2c67df874f4d9b0238c2c6b065163ce8de3d8371b9dfce864d"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"build-options" : {
|
||||
"env" : {
|
||||
"GSK_RENDERER" : "opengl"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
{
|
||||
"app-id" : "org.gtk.IconBrowser4",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "gtk4-icon-browser",
|
||||
"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",
|
||||
"-Dbenchmarks=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",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"build-options" : {
|
||||
"env" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
59
build-aux/flatpak/org.gtk.WidgetFactory.json
Normal file
59
build-aux/flatpak/org.gtk.WidgetFactory.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"app-id": "org.gtk.WidgetFactory",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk4-widget-factory",
|
||||
"tags": ["devel", "development", "nightly"],
|
||||
"rename-desktop-file": "gtk4-widget-factory.desktop",
|
||||
"rename-icon": "gtk4-widget-factory",
|
||||
"desktop-file-name-prefix": "(Development) ",
|
||||
"finish-args": [
|
||||
"--device=dri",
|
||||
"--share=ipc",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*",
|
||||
"--talk-name=ca.desrt.conf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
|
||||
],
|
||||
"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": "graphene",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/ebassi/graphene.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
{
|
||||
"app-id" : "org.gtk.WidgetFactory4",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "gtk4-widget-factory",
|
||||
"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",
|
||||
"-Dbenchmarks=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",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from pathlib import PurePath
|
||||
|
||||
|
||||
stylesheets = [
|
||||
'gtk/theme/Default/Default-light.css',
|
||||
'gtk/theme/Default/Default-dark.css',
|
||||
'gtk/theme/Default/Default-hc.css',
|
||||
'gtk/theme/Default/Default-hc-dark.css',
|
||||
]
|
||||
|
||||
references = [
|
||||
'docs/reference/gtk/gtk4',
|
||||
'docs/reference/gsk/gsk4',
|
||||
'docs/reference/gdk/gdk4',
|
||||
'docs/reference/gdk/gdk4-wayland',
|
||||
'docs/reference/gdk/gdk4-x11',
|
||||
]
|
||||
|
||||
sourceroot = os.environ.get('MESON_SOURCE_ROOT')
|
||||
buildroot = os.environ.get('MESON_BUILD_ROOT')
|
||||
distroot = os.environ.get('MESON_DIST_ROOT')
|
||||
|
||||
for stylesheet in stylesheets:
|
||||
stylesheet_path = PurePath(stylesheet)
|
||||
src = PurePath(sourceroot, stylesheet_path.with_suffix('.scss'))
|
||||
dst = PurePath(distroot, stylesheet_path)
|
||||
subprocess.call(['sassc', '-a', '-M', '-t', 'compact', src, dst])
|
||||
|
||||
for reference in references:
|
||||
src_path = os.path.join(buildroot, reference)
|
||||
if os.path.isdir(src_path):
|
||||
dst_path = os.path.join(distroot, reference)
|
||||
shutil.copytree(src_path, dst_path)
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
repodir = sys.argv[1]
|
||||
profile = sys.argv[2]
|
||||
|
||||
sys.stdout.write("/* This file is auto-generated. Do not edit. */\n")
|
||||
sys.stdout.write("#pragma once\n")
|
||||
sys.stdout.write("\n")
|
||||
sys.stdout.write(f"#define PROFILE \"{profile}\"\n")
|
||||
|
||||
short_sha = os.environ.get('CI_COMMIT_SHORT_SHA')
|
||||
if short_sha is None:
|
||||
cmd = ["git", "-C", repodir, "rev-parse", "--short", "HEAD"]
|
||||
try:
|
||||
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as p:
|
||||
short_sha = p.stdout.read().decode('utf-8').rstrip("\n")
|
||||
except FileNotFoundError:
|
||||
short_sha = ''
|
||||
if profile != 'default':
|
||||
short_sha = 'devel'
|
||||
|
||||
sys.stdout.write(f"#define VCS_TAG \"{short_sha}\"\n")
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/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])
|
||||
26
build-aux/meson/post-install.sh
Executable file
26
build-aux/meson/post-install.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
gtk_api_version=$1
|
||||
gtk_abi_version=$2
|
||||
gtk_libdir=$3
|
||||
gtk_datadir=$4
|
||||
|
||||
# Package managers set this so we don't need to run
|
||||
if [ -z "$DESTDIR" ]; then
|
||||
echo Compiling GSettings schemas...
|
||||
glib-compile-schemas ${gtk_datadir}/glib-2.0/schemas
|
||||
|
||||
echo Updating desktop database...
|
||||
update-desktop-database -q ${gtk_datadir}/applications
|
||||
|
||||
echo Updating icon cache...
|
||||
gtk-update-icon-cache -q -t -f ${gtk_datadir}/icons/hicolor
|
||||
|
||||
echo Updating module cache for print backends...
|
||||
mkdir -p ${gtk_libdir}/gtk-4.0/4.0.0/printbackends
|
||||
gio-querymodules ${gtk_libdir}/gtk-4.0/4.0.0/printbackends
|
||||
|
||||
echo Updating module cache for input methods...
|
||||
mkdir -p ${gtk_libdir}/gtk-4.0/4.0.0/immodules
|
||||
gio-querymodules ${gtk_libdir}/gtk-4.0/4.0.0/immodules
|
||||
fi
|
||||
303
config.h.meson
Normal file
303
config.h.meson
Normal file
@@ -0,0 +1,303 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* always defined to indicate that i18n is enabled */
|
||||
#define ENABLE_NLS 1
|
||||
|
||||
/* The prefix for our gettext translation domains. */
|
||||
#mesondefine GETTEXT_PACKAGE
|
||||
|
||||
/* Disable deprecation warnings from glib */
|
||||
#mesondefine GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
/* Define the location where the catalogs will be installed */
|
||||
#mesondefine GTK_LOCALEDIR
|
||||
|
||||
/* Define to 1 if you have the `bind_textdomain_codeset' function. */
|
||||
#mesondefine HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
|
||||
/* Have the cloudproviders library */
|
||||
#mesondefine HAVE_CLOUDPROVIDERS
|
||||
|
||||
/* define if we have colord */
|
||||
#mesondefine HAVE_COLORD
|
||||
|
||||
/* Define to 1 if you have the <crt_externs.h> header file. */
|
||||
#mesondefine HAVE_CRT_EXTERNS_H
|
||||
|
||||
/* Define to 1 if CUPS 1.6 API is available */
|
||||
#mesondefine HAVE_CUPS_API_1_6
|
||||
|
||||
/* Define to 1 if you have the `dcgettext' function. */
|
||||
#mesondefine HAVE_DCGETTEXT
|
||||
|
||||
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISINF
|
||||
|
||||
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISNAN
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#mesondefine HAVE_DLFCN_H
|
||||
|
||||
/* Have the ffmpeg library */
|
||||
#mesondefine HAVE_FFMPEG
|
||||
|
||||
/* Define to 1 if you have the <ftw.h> header file. */
|
||||
#mesondefine HAVE_FTW_H
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#mesondefine HAVE_GETPAGESIZE
|
||||
|
||||
/* Define to 1 if you have the `getresuid' function. */
|
||||
#mesondefine HAVE_GETRESUID
|
||||
|
||||
/* Define if gio-unix is available */
|
||||
#mesondefine HAVE_GIO_UNIX
|
||||
|
||||
/* Define if GStreamer support is available */
|
||||
#mesondefine HAVE_GSTREAMER
|
||||
|
||||
/* Define to 1 if you have the `httpGetAuthString' function. */
|
||||
#mesondefine HAVE_HTTPGETAUTHSTRING
|
||||
|
||||
/* Define if cups http_t authstring field is accessible */
|
||||
#mesondefine HAVE_HTTP_AUTHSTRING
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#mesondefine HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if the system has the type `IPrintDialogCallback'. */
|
||||
#mesondefine HAVE_IPRINTDIALOGCALLBACK
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#mesondefine HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if you have the `lstat' function. */
|
||||
#mesondefine HAVE_LSTAT
|
||||
|
||||
/* Define to 1 if you have the `mallinfo' function. */
|
||||
#mesondefine HAVE_MALLINFO
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#mesondefine HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */
|
||||
#mesondefine HAVE_MKSTEMP
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#mesondefine HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the `nearbyint' function. */
|
||||
#mesondefine HAVE_NEARBYINT
|
||||
|
||||
/* Define to 1 if you have the `posix_fallocate' function. */
|
||||
#mesondefine HAVE_POSIX_FALLOCATE
|
||||
|
||||
/* Have the Xrandr extension library */
|
||||
#mesondefine HAVE_RANDR
|
||||
|
||||
/* Have the Xrandr 1.5 extension library */
|
||||
#mesondefine HAVE_RANDR15
|
||||
|
||||
/* Define to 1 if you have the `rint' function. */
|
||||
#mesondefine HAVE_RINT
|
||||
|
||||
/* Define to 1 if you have the `round' function. */
|
||||
#mesondefine HAVE_ROUND
|
||||
|
||||
/* Define to 1 if you have the `sincos' function. */
|
||||
#mesondefine HAVE_SINCOS
|
||||
|
||||
/* Define to 1 if you have the `log2` function */
|
||||
#mesondefine HAVE_LOG2
|
||||
|
||||
/* Define to 1 if you ahve the `exp2` function */
|
||||
#mesondefine HAVE_EXP2
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#mesondefine HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#mesondefine HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#mesondefine HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#mesondefine HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#mesondefine HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#mesondefine HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#mesondefine HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#mesondefine HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#mesondefine HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#mesondefine HAVE_UNISTD_H
|
||||
|
||||
/* Have the XCOMPOSITE X extension */
|
||||
#mesondefine HAVE_XCOMPOSITE
|
||||
|
||||
/* Have the Xcursor library */
|
||||
#mesondefine HAVE_XCURSOR
|
||||
|
||||
/* Have the XDAMAGE X extension */
|
||||
#mesondefine HAVE_XDAMAGE
|
||||
|
||||
/* Have the XFIXES X extension */
|
||||
#mesondefine HAVE_XFIXES
|
||||
|
||||
/* Define to 1 if XFree Xinerama is available */
|
||||
#mesondefine HAVE_XFREE_XINERAMA
|
||||
|
||||
/* Have XGenericEvent */
|
||||
#mesondefine HAVE_XGENERICEVENTS
|
||||
|
||||
/* Define to use XKB extension */
|
||||
#mesondefine HAVE_XKB
|
||||
|
||||
/* Have the SYNC extension library */
|
||||
#mesondefine HAVE_XSYNC
|
||||
|
||||
/* Define to 1 if you have the `_lock_file' function */
|
||||
#mesondefine HAVE__LOCK_FILE
|
||||
|
||||
/* Define to 1 if you have the `flockfile' function */
|
||||
#mesondefine HAVE_FLOCKFILE
|
||||
|
||||
/* Define if _NL_MEASUREMENT_MEASUREMENT is available */
|
||||
#mesondefine HAVE__NL_MEASUREMENT_MEASUREMENT
|
||||
|
||||
/* Define if _NL_PAPER_HEIGHT is available */
|
||||
#mesondefine HAVE__NL_PAPER_HEIGHT
|
||||
|
||||
/* Define if _NL_PAPER_WIDTH is available */
|
||||
#mesondefine HAVE__NL_PAPER_WIDTH
|
||||
|
||||
/* Define if _NL_TIME_FIRST_WEEKDAY is available */
|
||||
#mesondefine HAVE__NL_TIME_FIRST_WEEKDAY
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#mesondefine LT_OBJDIR
|
||||
|
||||
/* Define if <X11/extensions/XIproto.h> needed for xReply */
|
||||
#mesondefine NEED_XIPROTO_H_FOR_XREPLY
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#mesondefine NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#mesondefine PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#mesondefine PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#mesondefine PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#mesondefine PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#mesondefine PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#mesondefine PACKAGE_VERSION
|
||||
|
||||
/* Use NSBundle functions to determine load paths for libraries, translations,
|
||||
etc. */
|
||||
#mesondefine QUARTZ_RELOCATION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#mesondefine STDC_HEADERS
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to 1 if XInput 2.0 is available */
|
||||
#mesondefine XINPUT_2
|
||||
|
||||
/* Define to 1 if XInput 2.2 is available */
|
||||
#mesondefine XINPUT_2_2
|
||||
|
||||
/* Define to 1 if the X Window System is missing or not being used. */
|
||||
#mesondefine X_DISPLAY_MISSING
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#mesondefine _FILE_OFFSET_BITS
|
||||
|
||||
/* defines how to decorate public symbols while building */
|
||||
#mesondefine _GDK_EXTERN
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#mesondefine _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#mesondefine _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#mesondefine _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#mesondefine _POSIX_SOURCE
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#mesondefine gid_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#mesondefine uid_t
|
||||
|
||||
/* Define to 1 if linux/memfd.h exists */
|
||||
#mesondefine HAVE_LINUX_MEMFD_H
|
||||
|
||||
#mesondefine GTK_SYSCONFDIR
|
||||
|
||||
#mesondefine GTK_LOCALEDIR
|
||||
|
||||
#mesondefine GTK_DATADIR
|
||||
|
||||
#mesondefine GTK_LIBDIR
|
||||
|
||||
#mesondefine GTK_PRINT_BACKENDS
|
||||
|
||||
#mesondefine HAVE_HARFBUZZ
|
||||
|
||||
#mesondefine HAVE_PANGOFT
|
||||
|
||||
#mesondefine ISO_CODES_PREFIX
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "constraint-editor-application.h"
|
||||
#include "constraint-editor-window.h"
|
||||
|
||||
struct _ConstraintEditorApplication
|
||||
{
|
||||
GtkApplication parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(ConstraintEditorApplication, constraint_editor_application, GTK_TYPE_APPLICATION);
|
||||
|
||||
static void
|
||||
constraint_editor_application_init (ConstraintEditorApplication *app)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer data)
|
||||
{
|
||||
g_application_quit (G_APPLICATION (data));
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] =
|
||||
{
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
constraint_editor_application_startup (GApplication *app)
|
||||
{
|
||||
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
|
||||
const char *open_accels[2] = { "<Ctrl>O", NULL };
|
||||
GtkCssProvider *provider;
|
||||
|
||||
G_APPLICATION_CLASS (constraint_editor_application_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);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_application_activate (GApplication *app)
|
||||
{
|
||||
ConstraintEditorWindow *win;
|
||||
|
||||
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_application_open (GApplication *app,
|
||||
GFile **files,
|
||||
int n_files,
|
||||
const char *hint)
|
||||
{
|
||||
ConstraintEditorWindow *win;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
|
||||
constraint_editor_window_load (win, files[i]);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_application_class_init (ConstraintEditorApplicationClass *class)
|
||||
{
|
||||
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
|
||||
|
||||
application_class->startup = constraint_editor_application_startup;
|
||||
application_class->activate = constraint_editor_application_activate;
|
||||
application_class->open = constraint_editor_application_open;
|
||||
}
|
||||
|
||||
ConstraintEditorApplication *
|
||||
constraint_editor_application_new (void)
|
||||
{
|
||||
return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE,
|
||||
"application-id", "org.gtk.gtk4.ConstraintEditor",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define CONSTRAINT_EDITOR_APPLICATION_TYPE (constraint_editor_application_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintEditorApplication, constraint_editor_application, CONSTRAINT, EDITOR_APPLICATION, GtkApplication)
|
||||
|
||||
ConstraintEditorApplication *constraint_editor_application_new (void);
|
||||
@@ -1,664 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "constraint-editor-window.h"
|
||||
#include "constraint-view.h"
|
||||
#include "constraint-editor.h"
|
||||
#include "guide-editor.h"
|
||||
|
||||
struct _ConstraintEditorWindow
|
||||
{
|
||||
GtkApplicationWindow parent_instance;
|
||||
|
||||
GtkWidget *paned;
|
||||
GtkWidget *view;
|
||||
GtkWidget *list;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW);
|
||||
|
||||
static GtkConstraintTarget *
|
||||
find_target (GListModel *model,
|
||||
GtkConstraintTarget *orig)
|
||||
{
|
||||
const char *name;
|
||||
const char *model_name;
|
||||
gpointer item;
|
||||
int i;
|
||||
|
||||
if (orig == NULL)
|
||||
return NULL;
|
||||
|
||||
if (GTK_IS_LABEL (orig))
|
||||
name = gtk_label_get_label (GTK_LABEL (orig));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (orig))
|
||||
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig));
|
||||
else
|
||||
{
|
||||
g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig));
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
item = g_list_model_get_item (model, i);
|
||||
g_object_unref (item);
|
||||
if (GTK_IS_WIDGET (item))
|
||||
model_name = gtk_widget_get_name (GTK_WIDGET (item));
|
||||
else
|
||||
model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
|
||||
|
||||
if (strcmp (name, model_name) == 0)
|
||||
return GTK_CONSTRAINT_TARGET (item);
|
||||
}
|
||||
g_warning ("Failed to find target '%s'", name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
constraint_editor_window_load (ConstraintEditorWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
char *path;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
GtkWidget *view;
|
||||
GtkLayoutManager *layout;
|
||||
GtkWidget *child;
|
||||
const char *name;
|
||||
gpointer item;
|
||||
int i;
|
||||
GListModel *list;
|
||||
|
||||
path = g_file_get_path (file);
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
if (!gtk_builder_add_from_file (builder, path, &error))
|
||||
{
|
||||
g_print ("Could not load %s: %s", path, error->message);
|
||||
g_error_free (error);
|
||||
g_free (path);
|
||||
g_object_unref (builder);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
|
||||
if (!GTK_IS_BOX (view))
|
||||
{
|
||||
g_print ("Could not load %s: No GtkBox named 'view'", path);
|
||||
g_free (path);
|
||||
g_object_unref (builder);
|
||||
return FALSE;
|
||||
}
|
||||
layout = gtk_widget_get_layout_manager (view);
|
||||
if (!GTK_IS_CONSTRAINT_LAYOUT (layout))
|
||||
{
|
||||
g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path);
|
||||
g_free (path);
|
||||
g_object_unref (builder);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (child = gtk_widget_get_first_child (view);
|
||||
child;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
if (!GTK_IS_LABEL (child))
|
||||
{
|
||||
g_print ("Skipping non-GtkLabel child\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
name = gtk_label_get_label (GTK_LABEL (child));
|
||||
constraint_view_add_child (CONSTRAINT_VIEW (self->view), name);
|
||||
}
|
||||
|
||||
list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout));
|
||||
for (i = 0; i < g_list_model_get_n_items (list); i++)
|
||||
{
|
||||
GtkConstraintGuide *guide, *clone;
|
||||
int w, h;
|
||||
|
||||
item = g_list_model_get_item (list, i);
|
||||
guide = GTK_CONSTRAINT_GUIDE (item);
|
||||
|
||||
/* need to clone here, to attach to the right targets */
|
||||
clone = gtk_constraint_guide_new ();
|
||||
gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide));
|
||||
gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide));
|
||||
gtk_constraint_guide_get_min_size (guide, &w, &h);
|
||||
gtk_constraint_guide_set_min_size (clone, w, h);
|
||||
gtk_constraint_guide_get_nat_size (guide, &w, &h);
|
||||
gtk_constraint_guide_set_nat_size (clone, w, h);
|
||||
gtk_constraint_guide_get_max_size (guide, &w, &h);
|
||||
gtk_constraint_guide_set_max_size (clone, w, h);
|
||||
constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone);
|
||||
g_object_unref (guide);
|
||||
g_object_unref (clone);
|
||||
}
|
||||
g_object_unref (list);
|
||||
|
||||
list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout));
|
||||
for (i = 0; i < g_list_model_get_n_items (list); i++)
|
||||
{
|
||||
GtkConstraint *constraint;
|
||||
GtkConstraint *clone;
|
||||
GtkConstraintTarget *target;
|
||||
GtkConstraintTarget *source;
|
||||
GtkConstraintAttribute source_attr;
|
||||
|
||||
item = g_list_model_get_item (list, i);
|
||||
constraint = GTK_CONSTRAINT (item);
|
||||
|
||||
target = gtk_constraint_get_target (constraint);
|
||||
source = gtk_constraint_get_source (constraint);
|
||||
source_attr = gtk_constraint_get_source_attribute (constraint);
|
||||
|
||||
if (source == NULL && source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)
|
||||
clone = gtk_constraint_new_constant (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
|
||||
gtk_constraint_get_target_attribute (constraint),
|
||||
gtk_constraint_get_relation (constraint),
|
||||
gtk_constraint_get_constant (constraint),
|
||||
gtk_constraint_get_strength (constraint));
|
||||
else
|
||||
clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
|
||||
gtk_constraint_get_target_attribute (constraint),
|
||||
gtk_constraint_get_relation (constraint),
|
||||
find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source),
|
||||
source_attr,
|
||||
gtk_constraint_get_multiplier (constraint),
|
||||
gtk_constraint_get_constant (constraint),
|
||||
gtk_constraint_get_strength (constraint));
|
||||
|
||||
constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone);
|
||||
|
||||
g_object_unref (constraint);
|
||||
g_object_unref (clone);
|
||||
}
|
||||
g_object_unref (list);
|
||||
|
||||
g_free (path);
|
||||
g_object_unref (builder);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
open_response_cb (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
ConstraintEditorWindow *self)
|
||||
{
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
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)
|
||||
{
|
||||
GtkFileChooserNative *dialog;
|
||||
|
||||
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);
|
||||
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
serialize_child (GString *str,
|
||||
int indent,
|
||||
GtkWidget *child)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = gtk_widget_get_name (child);
|
||||
g_string_append_printf (str, "%*s<child>\n", indent, "");
|
||||
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
|
||||
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
|
||||
g_string_append_printf (str, "%*s </object>\n", indent, "");
|
||||
g_string_append_printf (str, "%*s</child>\n", indent, "");
|
||||
}
|
||||
|
||||
static char *
|
||||
serialize_model (GListModel *list)
|
||||
{
|
||||
GString *str = g_string_new ("");
|
||||
int i;
|
||||
|
||||
g_string_append (str, "<interface>\n");
|
||||
g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n");
|
||||
g_string_append (str, " <property name=\"layout-manager\">\n");
|
||||
g_string_append (str, " <object class=\"GtkConstraintLayout\">\n");
|
||||
g_string_append (str, " <constraints>\n");
|
||||
for (i = 0; i < g_list_model_get_n_items (list); i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (list, i);
|
||||
g_object_unref (item);
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item));
|
||||
}
|
||||
g_string_append (str, " </constraints>\n");
|
||||
g_string_append (str, " </object>\n");
|
||||
g_string_append (str, " </property>\n");
|
||||
for (i = 0; i < g_list_model_get_n_items (list); i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (list, i);
|
||||
g_object_unref (item);
|
||||
if (GTK_IS_WIDGET (item))
|
||||
serialize_child (str, 4, GTK_WIDGET (item));
|
||||
}
|
||||
g_string_append (str, " </object>\n");
|
||||
g_string_append (str, "</interface>\n");
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
save_response_cb (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
ConstraintEditorWindow *self)
|
||||
{
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
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,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
GtkWidget *message_dialog;
|
||||
|
||||
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)
|
||||
{
|
||||
GtkFileChooserNative *dialog;
|
||||
|
||||
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);
|
||||
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_window_finalize (GObject *object)
|
||||
{
|
||||
//ConstraintEditorWindow *self = (ConstraintEditorWindow *)object;
|
||||
|
||||
G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static int child_counter;
|
||||
static int guide_counter;
|
||||
|
||||
static void
|
||||
add_child (ConstraintEditorWindow *win)
|
||||
{
|
||||
char *name;
|
||||
|
||||
child_counter++;
|
||||
name = g_strdup_printf ("Child %d", child_counter);
|
||||
constraint_view_add_child (CONSTRAINT_VIEW (win->view), name);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static void
|
||||
add_guide (ConstraintEditorWindow *win)
|
||||
{
|
||||
char *name;
|
||||
GtkConstraintGuide *guide;
|
||||
|
||||
guide_counter++;
|
||||
name = g_strdup_printf ("Guide %d", guide_counter);
|
||||
guide = gtk_constraint_guide_new ();
|
||||
gtk_constraint_guide_set_name (guide, name);
|
||||
g_free (name);
|
||||
|
||||
constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_done (ConstraintEditor *editor,
|
||||
GtkConstraint *constraint,
|
||||
ConstraintEditorWindow *win)
|
||||
{
|
||||
GtkConstraint *old_constraint;
|
||||
|
||||
g_object_get (editor, "constraint", &old_constraint, NULL);
|
||||
|
||||
if (old_constraint)
|
||||
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), old_constraint);
|
||||
|
||||
constraint_view_add_constraint (CONSTRAINT_VIEW (win->view), constraint);
|
||||
|
||||
g_clear_object (&old_constraint);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
|
||||
}
|
||||
|
||||
static void
|
||||
edit_constraint (ConstraintEditorWindow *win,
|
||||
GtkConstraint *constraint)
|
||||
{
|
||||
GtkWidget *window;
|
||||
ConstraintEditor *editor;
|
||||
GListModel *model;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
if (constraint)
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Edit Constraint");
|
||||
else
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Create Constraint");
|
||||
|
||||
model = constraint_view_get_model (CONSTRAINT_VIEW (win->view));
|
||||
|
||||
editor = constraint_editor_new (model, constraint);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
|
||||
|
||||
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
static void
|
||||
add_constraint (ConstraintEditorWindow *win)
|
||||
{
|
||||
edit_constraint (win, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_done (GuideEditor *editor,
|
||||
GtkConstraintGuide *guide,
|
||||
ConstraintEditorWindow *win)
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
|
||||
}
|
||||
|
||||
static void
|
||||
edit_guide (ConstraintEditorWindow *win,
|
||||
GtkConstraintGuide *guide)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GuideEditor *editor;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Edit Guide");
|
||||
|
||||
editor = guide_editor_new (guide);
|
||||
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
|
||||
|
||||
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
static void
|
||||
row_activated (GtkListBox *list,
|
||||
GtkListBoxRow *row,
|
||||
ConstraintEditorWindow *win)
|
||||
{
|
||||
GObject *item;
|
||||
|
||||
item = G_OBJECT (g_object_get_data (G_OBJECT (row), "item"));
|
||||
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
edit_constraint (win, GTK_CONSTRAINT (item));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
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");
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, paned);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, open_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, save_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, add_child);
|
||||
gtk_widget_class_bind_template_callback (widget_class, add_guide);
|
||||
gtk_widget_class_bind_template_callback (widget_class, add_constraint);
|
||||
gtk_widget_class_bind_template_callback (widget_class, row_activated);
|
||||
}
|
||||
|
||||
static void
|
||||
row_edit (GtkButton *button,
|
||||
ConstraintEditorWindow *win)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GObject *item;
|
||||
|
||||
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
|
||||
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
edit_constraint (win, GTK_CONSTRAINT (item));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
|
||||
}
|
||||
|
||||
static void
|
||||
mark_constraints_invalid (ConstraintEditorWindow *win,
|
||||
gpointer removed)
|
||||
{
|
||||
GtkWidget *child;
|
||||
GObject *item;
|
||||
|
||||
for (child = gtk_widget_get_first_child (win->list);
|
||||
child;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
item = (GObject *)g_object_get_data (G_OBJECT (child), "item");
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
{
|
||||
GtkConstraint *constraint = GTK_CONSTRAINT (item);
|
||||
|
||||
if (gtk_constraint_get_target (constraint) == (GtkConstraintTarget *)removed ||
|
||||
gtk_constraint_get_source (constraint) == (GtkConstraintTarget *)removed)
|
||||
{
|
||||
GtkWidget *button;
|
||||
button = (GtkWidget *)g_object_get_data (G_OBJECT (child), "edit");
|
||||
gtk_button_set_icon_name (GTK_BUTTON (button), "dialog-warning-symbolic");
|
||||
gtk_widget_set_tooltip_text (button, "Constraint is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
row_delete (GtkButton *button,
|
||||
ConstraintEditorWindow *win)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GObject *item;
|
||||
|
||||
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
|
||||
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view),
|
||||
GTK_CONSTRAINT (item));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
{
|
||||
mark_constraints_invalid (win, item);
|
||||
constraint_view_remove_guide (CONSTRAINT_VIEW (win->view),
|
||||
GTK_CONSTRAINT_GUIDE (item));
|
||||
}
|
||||
else if (GTK_IS_WIDGET (item))
|
||||
{
|
||||
mark_constraints_invalid (win, item);
|
||||
constraint_view_remove_child (CONSTRAINT_VIEW (win->view),
|
||||
GTK_WIDGET (item));
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_widget_func (gpointer item,
|
||||
gpointer user_data)
|
||||
{
|
||||
ConstraintEditorWindow *win = user_data;
|
||||
const char *name;
|
||||
char *freeme = NULL;
|
||||
GtkWidget *row, *box, *label, *button;
|
||||
|
||||
if (GTK_IS_WIDGET (item))
|
||||
name = gtk_widget_get_name (GTK_WIDGET (item));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
|
||||
else if (GTK_IS_CONSTRAINT (item))
|
||||
name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item));
|
||||
else
|
||||
name = "";
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref);
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
label = gtk_label_new (name);
|
||||
if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
g_object_bind_property (item, "name",
|
||||
label, "label",
|
||||
G_BINDING_DEFAULT);
|
||||
gtk_widget_set_margin_start (label, 10);
|
||||
gtk_widget_set_margin_end (label, 10);
|
||||
gtk_widget_set_margin_top (label, 10);
|
||||
gtk_widget_set_margin_bottom (label, 10);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
{
|
||||
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
|
||||
g_object_set_data (G_OBJECT (row), "edit", button);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
}
|
||||
else if (GTK_IS_WIDGET (item))
|
||||
{
|
||||
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
}
|
||||
|
||||
g_free (freeme);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_window_init (ConstraintEditorWindow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
gtk_list_box_bind_model (GTK_LIST_BOX (self->list),
|
||||
constraint_view_get_model (CONSTRAINT_VIEW (self->view)),
|
||||
create_widget_func,
|
||||
self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
ConstraintEditorWindow *
|
||||
constraint_editor_window_new (ConstraintEditorApplication *application)
|
||||
{
|
||||
return g_object_new (CONSTRAINT_EDITOR_WINDOW_TYPE,
|
||||
"application", application,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "constraint-editor-application.h"
|
||||
|
||||
|
||||
#define CONSTRAINT_EDITOR_WINDOW_TYPE (constraint_editor_window_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintEditorWindow, constraint_editor_window, CONSTRAINT, EDITOR_WINDOW, GtkApplicationWindow)
|
||||
|
||||
ConstraintEditorWindow * constraint_editor_window_new (ConstraintEditorApplication *application);
|
||||
|
||||
gboolean constraint_editor_window_load (ConstraintEditorWindow *self,
|
||||
GFile *file);
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ConstraintEditorWindow" parent="GtkApplicationWindow">
|
||||
<property name="title" translatable="yes">GTK Constraint Editor</property>
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
<property name="tooltip-text">Open ui file</property>
|
||||
<signal name="clicked" handler="open_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-save-symbolic</property>
|
||||
<property name="tooltip-text">Save to ui file</property>
|
||||
<signal name="clicked" handler="save_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="paned">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Add Child</property>
|
||||
<signal name="clicked" handler="add_child" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Add Guide</property>
|
||||
<signal name="clicked" handler="add_guide" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Add Constraint</property>
|
||||
<signal name="clicked" handler="add_constraint" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="list">
|
||||
<property name="show-separators">1</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<signal name="row-activated" handler="row_activated"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="ConstraintView" id="view">
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,680 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "constraint-editor.h"
|
||||
|
||||
struct _ConstraintEditor
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *grid;
|
||||
GtkWidget *target;
|
||||
GtkWidget *target_attr;
|
||||
GtkWidget *relation;
|
||||
GtkWidget *source;
|
||||
GtkWidget *source_attr;
|
||||
GtkWidget *multiplier;
|
||||
GtkWidget *constant;
|
||||
GtkWidget *strength;
|
||||
GtkWidget *preview;
|
||||
GtkWidget *button;
|
||||
|
||||
GtkConstraint *constraint;
|
||||
GListModel *model;
|
||||
|
||||
gboolean constructed;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_MODEL = 1,
|
||||
PROP_CONSTRAINT,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *pspecs[LAST_PROP];
|
||||
|
||||
enum {
|
||||
DONE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET);
|
||||
|
||||
static const char *
|
||||
get_target_name (GtkConstraintTarget *target)
|
||||
{
|
||||
if (target == NULL)
|
||||
return "super";
|
||||
else if (GTK_IS_WIDGET (target))
|
||||
return gtk_widget_get_name (GTK_WIDGET (target));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (target))
|
||||
return gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (target));
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_target_combo (GListModel *model,
|
||||
GtkWidget *combo,
|
||||
gboolean is_source)
|
||||
{
|
||||
int i;
|
||||
|
||||
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;
|
||||
|
||||
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
|
||||
|
||||
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
|
||||
g_object_unref (item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
get_target (GListModel *model,
|
||||
const char *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (id == NULL)
|
||||
return NULL;
|
||||
|
||||
if (strcmp ("super", id) == 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
GObject *item = g_list_model_get_object (model, i);
|
||||
g_object_unref (item);
|
||||
if (GTK_IS_CONSTRAINT (item))
|
||||
continue;
|
||||
else if (GTK_IS_WIDGET (item))
|
||||
{
|
||||
if (strcmp (id, gtk_widget_get_name (GTK_WIDGET (item))) == 0)
|
||||
return item;
|
||||
}
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (item))
|
||||
{
|
||||
if (strcmp (id, gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item))) == 0)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GtkConstraintAttribute
|
||||
get_target_attr (const char *id)
|
||||
{
|
||||
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);
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_attr_nick (GtkConstraintAttribute attr)
|
||||
{
|
||||
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
|
||||
GEnumValue *value = g_enum_get_value (class, attr);
|
||||
const char *nick = value->value_nick;
|
||||
g_type_class_unref (class);
|
||||
|
||||
return nick;
|
||||
}
|
||||
|
||||
static GtkConstraintRelation
|
||||
get_relation (const char *id)
|
||||
{
|
||||
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);
|
||||
|
||||
return relation;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_relation_nick (GtkConstraintRelation relation)
|
||||
{
|
||||
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
|
||||
GEnumValue *value = g_enum_get_value (class, relation);
|
||||
const char *nick = value->value_nick;
|
||||
g_type_class_unref (class);
|
||||
|
||||
return nick;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_relation_display_name (GtkConstraintRelation relation)
|
||||
{
|
||||
switch (relation)
|
||||
{
|
||||
case GTK_CONSTRAINT_RELATION_LE:
|
||||
return "≤";
|
||||
case GTK_CONSTRAINT_RELATION_EQ:
|
||||
return "=";
|
||||
case GTK_CONSTRAINT_RELATION_GE:
|
||||
return "≥";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static GtkConstraintStrength
|
||||
get_strength (const char *id)
|
||||
{
|
||||
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 *
|
||||
get_strength_nick (GtkConstraintStrength strength)
|
||||
{
|
||||
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
|
||||
GEnumValue *value = g_enum_get_value (class, strength);
|
||||
const char *nick = value->value_nick;
|
||||
g_type_class_unref (class);
|
||||
|
||||
return nick;
|
||||
}
|
||||
|
||||
void
|
||||
constraint_editor_serialize_constraint (GString *str,
|
||||
int indent,
|
||||
GtkConstraint *constraint)
|
||||
{
|
||||
const char *target;
|
||||
const char *target_attr;
|
||||
const char *relation;
|
||||
const char *source;
|
||||
const char *source_attr;
|
||||
double multiplier;
|
||||
double constant;
|
||||
const char *strength;
|
||||
|
||||
target = get_target_name (gtk_constraint_get_target (constraint));
|
||||
target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
|
||||
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
|
||||
source = get_target_name (gtk_constraint_get_source (constraint));
|
||||
source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
|
||||
multiplier = gtk_constraint_get_multiplier (constraint);
|
||||
constant = gtk_constraint_get_constant (constraint);
|
||||
strength = get_strength_nick (gtk_constraint_get_strength (constraint));
|
||||
|
||||
g_string_append_printf (str, "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n", indent, "", target, target_attr);
|
||||
g_string_append_printf (str, "%*s relation=\"%s\"\n", indent, "", relation);
|
||||
if (strcmp (source_attr, "none") != 0)
|
||||
{
|
||||
g_string_append_printf (str, "%*s source=\"%s\" source-attribute=\"%s\"\n", indent, "", source, source_attr);
|
||||
g_string_append_printf (str, "%*s multiplier=\"%g\"\n", indent, "", multiplier);
|
||||
}
|
||||
g_string_append_printf (str, "%*s constant=\"%g\"\n", indent, "", constant);
|
||||
g_string_append_printf (str, "%*s strength=\"%s\" />\n", indent, "", strength);
|
||||
}
|
||||
|
||||
static void
|
||||
create_constraint (GtkButton *button,
|
||||
ConstraintEditor *editor)
|
||||
{
|
||||
const char *id;
|
||||
gpointer target;
|
||||
GtkConstraintAttribute target_attr;
|
||||
gpointer source;
|
||||
GtkConstraintAttribute source_attr;
|
||||
GtkConstraintRelation relation;
|
||||
double multiplier;
|
||||
double constant;
|
||||
int strength;
|
||||
GtkConstraint *constraint;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
|
||||
strength = get_strength (id);
|
||||
|
||||
constraint = gtk_constraint_new (target, target_attr,
|
||||
relation,
|
||||
source, source_attr,
|
||||
multiplier,
|
||||
constant,
|
||||
strength);
|
||||
g_signal_emit (editor, signals[DONE], 0, constraint);
|
||||
g_object_unref (constraint);
|
||||
}
|
||||
|
||||
static void
|
||||
source_attr_changed (ConstraintEditor *editor)
|
||||
{
|
||||
const char *id;
|
||||
|
||||
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
|
||||
if (strcmp (id, "none") == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_sensitive (editor->source, TRUE);
|
||||
gtk_widget_set_sensitive (editor->multiplier, TRUE);
|
||||
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
constraint_editor_constraint_to_string (GtkConstraint *constraint)
|
||||
{
|
||||
GString *str;
|
||||
const char *name;
|
||||
const char *attr;
|
||||
const char *relation;
|
||||
double c, m;
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
name = get_target_name (gtk_constraint_get_target (constraint));
|
||||
attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
|
||||
relation = get_relation_display_name (gtk_constraint_get_relation (constraint));
|
||||
|
||||
if (name == NULL)
|
||||
name = "[ ]";
|
||||
|
||||
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
|
||||
|
||||
c = gtk_constraint_get_constant (constraint);
|
||||
|
||||
attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
|
||||
if (strcmp (attr, "none") != 0)
|
||||
{
|
||||
name = get_target_name (gtk_constraint_get_source (constraint));
|
||||
m = gtk_constraint_get_multiplier (constraint);
|
||||
|
||||
if (name == NULL)
|
||||
name = "[ ]";
|
||||
|
||||
g_string_append_printf (str, "%s.%s", name, attr);
|
||||
|
||||
if (m != 1.0)
|
||||
g_string_append_printf (str, " × %g", m);
|
||||
|
||||
if (c > 0.0)
|
||||
g_string_append_printf (str, " + %g", c);
|
||||
else if (c < 0.0)
|
||||
g_string_append_printf (str, " - %g", -c);
|
||||
}
|
||||
else
|
||||
g_string_append_printf (str, "%g", c);
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
update_preview (ConstraintEditor *editor)
|
||||
{
|
||||
GString *str;
|
||||
const char *name;
|
||||
const char *attr;
|
||||
char *relation;
|
||||
const char *multiplier;
|
||||
const char *constant;
|
||||
double c, m;
|
||||
|
||||
if (!editor->constructed)
|
||||
return;
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
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 = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
|
||||
if (strcmp (attr, "none") != 0)
|
||||
{
|
||||
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);
|
||||
|
||||
if (name == NULL)
|
||||
name = "[ ]";
|
||||
|
||||
g_string_append_printf (str, "%s.%s", name, attr);
|
||||
|
||||
if (m != 1.0)
|
||||
g_string_append_printf (str, " × %g", m);
|
||||
|
||||
if (c > 0.0)
|
||||
g_string_append_printf (str, " + %g", c);
|
||||
else if (c < 0.0)
|
||||
g_string_append_printf (str, " - %g", -c);
|
||||
}
|
||||
else
|
||||
g_string_append_printf (str, "%g", c);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (editor->preview), str->str);
|
||||
|
||||
g_string_free (str, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
update_button (ConstraintEditor *editor)
|
||||
{
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_init (ConstraintEditor *editor)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (editor));
|
||||
}
|
||||
|
||||
static void
|
||||
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)
|
||||
{
|
||||
GtkConstraintTarget *target;
|
||||
GtkConstraintAttribute attr;
|
||||
GtkConstraintRelation relation;
|
||||
GtkConstraintStrength strength;
|
||||
const char *nick;
|
||||
char *val;
|
||||
double multiplier;
|
||||
double constant;
|
||||
|
||||
target = gtk_constraint_get_target (editor->constraint);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), val);
|
||||
g_free (val);
|
||||
|
||||
constant = gtk_constraint_get_constant (editor->constraint);
|
||||
val = g_strdup_printf ("%g", constant);
|
||||
gtk_editable_set_text (GTK_EDITABLE (editor->constant), val);
|
||||
g_free (val);
|
||||
|
||||
strength = gtk_constraint_get_strength (editor->constraint);
|
||||
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_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");
|
||||
|
||||
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
|
||||
}
|
||||
|
||||
editor->constructed = TRUE;
|
||||
update_preview (editor);
|
||||
update_button (editor);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
self->model = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_CONSTRAINT:
|
||||
self->constraint = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_CONSTRAINT:
|
||||
g_value_set_object (value, self->constraint);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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);
|
||||
|
||||
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_class_init (ConstraintEditorClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->constructed = constraint_editor_constructed;
|
||||
object_class->dispose = constraint_editor_dispose;
|
||||
object_class->set_property = constraint_editor_set_property;
|
||||
object_class->get_property = constraint_editor_get_property;
|
||||
|
||||
pspecs[PROP_CONSTRAINT] =
|
||||
g_param_spec_object ("constraint", "constraint", "constraint",
|
||||
GTK_TYPE_CONSTRAINT,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
pspecs[PROP_MODEL] =
|
||||
g_param_spec_object ("model", "model", "model",
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
|
||||
|
||||
signals[DONE] =
|
||||
g_signal_new ("done",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
"/org/gtk/gtk4/constraint-editor/constraint-editor.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview);
|
||||
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_preview);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_button);
|
||||
gtk_widget_class_bind_template_callback (widget_class, create_constraint);
|
||||
gtk_widget_class_bind_template_callback (widget_class, source_attr_changed);
|
||||
}
|
||||
|
||||
ConstraintEditor *
|
||||
constraint_editor_new (GListModel *model,
|
||||
GtkConstraint *constraint)
|
||||
{
|
||||
return g_object_new (CONSTRAINT_EDITOR_TYPE,
|
||||
"model", model,
|
||||
"constraint", constraint,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
constraintview {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
constraintview .child {
|
||||
background: red;
|
||||
}
|
||||
|
||||
constraintview .guide {
|
||||
background: blue;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/gtk4/constraint-editor">
|
||||
<file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
|
||||
<file preprocess="xml-stripblanks">constraint-editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">guide-editor.ui</file>
|
||||
<file>constraint-editor.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define CONSTRAINT_EDITOR_TYPE (constraint_editor_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, GtkWidget)
|
||||
|
||||
ConstraintEditor * constraint_editor_new (GListModel *model,
|
||||
GtkConstraint *constraint);
|
||||
|
||||
void constraint_editor_serialize_constraint (GString *str,
|
||||
int indent,
|
||||
GtkConstraint *constraint);
|
||||
char *constraint_editor_constraint_to_string (GtkConstraint *constraint);
|
||||
@@ -1,167 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ConstraintEditor" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="row-spacing">10</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Target</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<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>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<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>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Relation</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="relation">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Source</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<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>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<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>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Multiplier</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="multiplier">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Constant</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">5</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="constant">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">5</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Strength</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="strength">
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="preview">
|
||||
<property name="xalign">0</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">7</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.44"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button">
|
||||
<property name="label">Create</property>
|
||||
<signal name="clicked" handler="create_constraint"/>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">8</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "constraint-view-child.h"
|
||||
|
||||
struct _ConstraintViewChild
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_NAME = 1,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec props[LAST_PROP];
|
||||
|
||||
G_DEFINE_TYPE (ConstraintViewChild, constraint_view_child, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
constraint_view_child_init (ConstraintViewChild *child)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_view_child_finalize (GObject *object)
|
||||
{
|
||||
ConstraintViewChild *child = CONSTRAINT_VIEW_CHILD (object);
|
||||
|
||||
g_free (child->name);
|
||||
|
||||
G_OBJECT_CLASS (constraint_view_child_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_view_child_set_property (GObject *object,
|
||||
|
||||
static void
|
||||
constraint_view_child_class_init (ConstraintViewChildClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = constraint_view_child_finalize;
|
||||
object_class->get_property = constraint_view_child_get_property;
|
||||
object_class->set_property = constraint_view_child_set_property;
|
||||
|
||||
props[PROP_NAME] =
|
||||
g_param_spec_string ("name", "name", "name",
|
||||
NULL,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, props);
|
||||
}
|
||||
|
||||
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
|
||||
|
||||
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
|
||||
|
||||
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
|
||||
|
||||
ConstraintViewWidget * constraint_view_widget_new (void);
|
||||
|
||||
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
|
||||
|
||||
ConstraintViewGuide * constraint_view_guide_new (void);
|
||||
|
||||
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
|
||||
|
||||
ConstraintViewGuide * constraint_view_constraint_new (void);
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
|
||||
|
||||
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
|
||||
|
||||
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
|
||||
|
||||
ConstraintViewWidget * constraint_view_widget_new (void);
|
||||
|
||||
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
|
||||
|
||||
ConstraintViewGuide * constraint_view_guide_new (void);
|
||||
|
||||
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
|
||||
|
||||
ConstraintViewGuide * constraint_view_constraint_new (void);
|
||||
@@ -1,345 +0,0 @@
|
||||
/* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "constraint-view.h"
|
||||
|
||||
struct _ConstraintView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GListModel *model;
|
||||
|
||||
GtkWidget *drag_widget;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
constraint_view_dispose (GObject *object)
|
||||
{
|
||||
ConstraintView *view = CONSTRAINT_VIEW (object);
|
||||
GtkWidget *child;
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL)
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
g_clear_object (&view->model);
|
||||
|
||||
G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_view_class_init (ConstraintViewClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = constraint_view_dispose;
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "constraintview");
|
||||
}
|
||||
|
||||
static void
|
||||
update_weak_position (ConstraintView *self,
|
||||
GtkWidget *child,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkLayoutManager *manager;
|
||||
GtkConstraint *constraint;
|
||||
|
||||
manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
|
||||
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "x-constraint");
|
||||
if (constraint)
|
||||
{
|
||||
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
constraint);
|
||||
g_object_set_data (G_OBJECT (child), "x-constraint", NULL);
|
||||
}
|
||||
if (x != -100)
|
||||
{
|
||||
constraint = gtk_constraint_new_constant (child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
x,
|
||||
GTK_CONSTRAINT_STRENGTH_WEAK);
|
||||
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
|
||||
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
constraint);
|
||||
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
|
||||
}
|
||||
|
||||
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "y-constraint");
|
||||
if (constraint)
|
||||
{
|
||||
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
constraint);
|
||||
g_object_set_data (G_OBJECT (child), "y-constraint", NULL);
|
||||
}
|
||||
if (y != -100)
|
||||
{
|
||||
constraint = gtk_constraint_new_constant (child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
y,
|
||||
GTK_CONSTRAINT_STRENGTH_WEAK);
|
||||
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
|
||||
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
constraint);
|
||||
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkGestureDrag *drag,
|
||||
double start_x,
|
||||
double start_y,
|
||||
ConstraintView *self)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_widget_pick (GTK_WIDGET (self), start_x, start_y, GTK_PICK_DEFAULT);
|
||||
|
||||
if (GTK_IS_LABEL (widget))
|
||||
{
|
||||
widget = gtk_widget_get_ancestor (widget, GTK_TYPE_FRAME);
|
||||
if (widget &&
|
||||
gtk_widget_get_parent (widget) == (GtkWidget *)self)
|
||||
{
|
||||
self->drag_widget = widget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_update (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
ConstraintView *self)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
if (!self->drag_widget)
|
||||
return;
|
||||
|
||||
gtk_gesture_drag_get_start_point (drag, &x, &y);
|
||||
update_weak_position (self, self->drag_widget, x + offset_x, y + offset_y);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
ConstraintView *self)
|
||||
{
|
||||
self->drag_widget = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
omit_internal (gpointer item, gpointer user_data)
|
||||
{
|
||||
if (g_object_get_data (G_OBJECT (item), "internal"))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_view_init (ConstraintView *self)
|
||||
{
|
||||
GtkLayoutManager *manager;
|
||||
GtkEventController *controller;
|
||||
GListStore *list;
|
||||
GListModel *all_children;
|
||||
GListModel *all_constraints;
|
||||
GListModel *guides;
|
||||
GListModel *children;
|
||||
GListModel *constraints;
|
||||
GtkFilter *filter;
|
||||
|
||||
manager = gtk_constraint_layout_new ();
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
|
||||
|
||||
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
|
||||
|
||||
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
|
||||
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
|
||||
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
|
||||
|
||||
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
|
||||
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
|
||||
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
|
||||
|
||||
list = g_list_store_new (G_TYPE_LIST_MODEL);
|
||||
g_list_store_append (list, children);
|
||||
g_list_store_append (list, guides);
|
||||
g_list_store_append (list, constraints);
|
||||
g_object_unref (children);
|
||||
g_object_unref (guides);
|
||||
g_object_unref (constraints);
|
||||
|
||||
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
|
||||
|
||||
controller = (GtkEventController *)gtk_gesture_drag_new ();
|
||||
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
|
||||
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
|
||||
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_end), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
}
|
||||
|
||||
ConstraintView *
|
||||
constraint_view_new (void)
|
||||
{
|
||||
return g_object_new (CONSTRAINT_VIEW_TYPE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_add_child (ConstraintView *view,
|
||||
const char *name)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (name);
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_widget_add_css_class (frame, "child");
|
||||
gtk_widget_set_name (frame, name);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), label);
|
||||
gtk_widget_set_parent (frame, GTK_WIDGET (view));
|
||||
|
||||
update_weak_position (view, frame, 100, 100);
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_remove_child (ConstraintView *view,
|
||||
GtkWidget *child)
|
||||
{
|
||||
update_weak_position (view, child, -100, -100);
|
||||
gtk_widget_unparent (child);
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_add_guide (ConstraintView *view,
|
||||
GtkConstraintGuide *guide)
|
||||
{
|
||||
GtkConstraintLayout *layout;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *label;
|
||||
const char *name;
|
||||
GtkConstraint *constraint;
|
||||
struct {
|
||||
const char *name;
|
||||
GtkConstraintAttribute attr;
|
||||
} names[] = {
|
||||
{ "left-constraint", GTK_CONSTRAINT_ATTRIBUTE_LEFT },
|
||||
{ "top-constraint", GTK_CONSTRAINT_ATTRIBUTE_TOP },
|
||||
{ "width-constraint", GTK_CONSTRAINT_ATTRIBUTE_WIDTH },
|
||||
{ "height-constraint", GTK_CONSTRAINT_ATTRIBUTE_HEIGHT },
|
||||
};
|
||||
int i;
|
||||
|
||||
name = gtk_constraint_guide_get_name (guide);
|
||||
label = gtk_label_new (name);
|
||||
g_object_bind_property (guide, "name",
|
||||
label, "label",
|
||||
G_BINDING_DEFAULT);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_widget_add_css_class (frame, "guide");
|
||||
g_object_set_data (G_OBJECT (frame), "internal", (char *)"yes");
|
||||
gtk_frame_set_child (GTK_FRAME (frame), label);
|
||||
gtk_widget_insert_after (frame, GTK_WIDGET (view), NULL);
|
||||
|
||||
g_object_set_data (G_OBJECT (guide), "frame", frame);
|
||||
|
||||
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
|
||||
gtk_constraint_layout_add_guide (layout, g_object_ref (guide));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
{
|
||||
constraint = gtk_constraint_new (frame,
|
||||
names[i].attr,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
guide,
|
||||
names[i].attr,
|
||||
1.0, 0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED);
|
||||
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
|
||||
gtk_constraint_layout_add_constraint (layout, constraint);
|
||||
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
|
||||
}
|
||||
|
||||
update_weak_position (view, frame, 150, 150);
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_remove_guide (ConstraintView *view,
|
||||
GtkConstraintGuide *guide)
|
||||
{
|
||||
GtkConstraintLayout *layout;
|
||||
GtkWidget *frame;
|
||||
GtkConstraint *constraint;
|
||||
const char *names[] = {
|
||||
"left-constraint",
|
||||
"top-constraint",
|
||||
"width-constraint",
|
||||
"height-constraint"
|
||||
};
|
||||
int i;
|
||||
|
||||
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
{
|
||||
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), names[i]);
|
||||
gtk_constraint_layout_remove_constraint (layout, constraint);
|
||||
}
|
||||
|
||||
frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame");
|
||||
update_weak_position (view, frame, -100, -100);
|
||||
gtk_widget_unparent (frame);
|
||||
|
||||
gtk_constraint_layout_remove_guide (layout, guide);
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_add_constraint (ConstraintView *view,
|
||||
GtkConstraint *constraint)
|
||||
{
|
||||
GtkLayoutManager *manager;
|
||||
|
||||
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
|
||||
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
g_object_ref (constraint));
|
||||
}
|
||||
|
||||
void
|
||||
constraint_view_remove_constraint (ConstraintView *view,
|
||||
GtkConstraint *constraint)
|
||||
{
|
||||
GtkLayoutManager *manager;
|
||||
|
||||
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
|
||||
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
|
||||
constraint);
|
||||
}
|
||||
|
||||
GListModel *
|
||||
constraint_view_get_model (ConstraintView *view)
|
||||
{
|
||||
return view->model;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
|
||||
|
||||
G_MODULE_EXPORT
|
||||
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
|
||||
|
||||
ConstraintView * constraint_view_new (void);
|
||||
|
||||
void constraint_view_add_child (ConstraintView *view,
|
||||
const char *name);
|
||||
void constraint_view_remove_child (ConstraintView *view,
|
||||
GtkWidget *child);
|
||||
void constraint_view_add_guide (ConstraintView *view,
|
||||
GtkConstraintGuide *guide);
|
||||
void constraint_view_remove_guide (ConstraintView *view,
|
||||
GtkConstraintGuide *guide);
|
||||
void constraint_view_guide_changed (ConstraintView *view,
|
||||
GtkConstraintGuide *guide);
|
||||
void constraint_view_add_constraint (ConstraintView *view,
|
||||
GtkConstraint *constraint);
|
||||
void constraint_view_remove_constraint (ConstraintView *view,
|
||||
GtkConstraint *constraint);
|
||||
GListModel * constraint_view_get_model (ConstraintView *view);
|
||||
@@ -1,355 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "guide-editor.h"
|
||||
|
||||
struct _GuideEditor
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *grid;
|
||||
GtkWidget *name;
|
||||
GtkWidget *min_width;
|
||||
GtkWidget *min_height;
|
||||
GtkWidget *nat_width;
|
||||
GtkWidget *nat_height;
|
||||
GtkWidget *max_width;
|
||||
GtkWidget *max_height;
|
||||
GtkWidget *strength;
|
||||
GtkWidget *button;
|
||||
|
||||
GtkConstraintGuide *guide;
|
||||
|
||||
gboolean constructed;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_GUIDE = 1,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *pspecs[LAST_PROP];
|
||||
|
||||
enum {
|
||||
DONE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
guide_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 GtkConstraintStrength
|
||||
get_strength (const char *id)
|
||||
{
|
||||
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 *
|
||||
get_strength_nick (GtkConstraintStrength strength)
|
||||
{
|
||||
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
|
||||
GEnumValue *value = g_enum_get_value (class, strength);
|
||||
const char *nick = value->value_nick;
|
||||
g_type_class_unref (class);
|
||||
|
||||
return nick;
|
||||
}
|
||||
|
||||
void
|
||||
guide_editor_serialize_guide (GString *str,
|
||||
int indent,
|
||||
GtkConstraintGuide *guide)
|
||||
{
|
||||
int min_width, min_height;
|
||||
int nat_width, nat_height;
|
||||
int max_width, max_height;
|
||||
const char *name;
|
||||
const char *strength;
|
||||
|
||||
gtk_constraint_guide_get_min_size (guide, &min_width, &min_height);
|
||||
gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height);
|
||||
gtk_constraint_guide_get_max_size (guide, &max_width, &max_height);
|
||||
name = gtk_constraint_guide_get_name (guide);
|
||||
strength = get_strength_nick (gtk_constraint_guide_get_strength (guide));
|
||||
|
||||
g_string_append_printf (str, "%*s<guide min-width=\"%d\" min-height=\"%d\"\n", indent, "", min_width, min_height);
|
||||
g_string_append_printf (str, "%*s nat-width=\"%d\" nat-height=\"%d\"\n", indent, "", nat_width, nat_height);
|
||||
g_string_append_printf (str, "%*s max-width=\"%d\" max-height=\"%d\"\n", indent, "", max_width, max_height);
|
||||
g_string_append_printf (str, "%*s name=\"%s\" strength=\"%s\" />\n", indent, "", name, strength);
|
||||
}
|
||||
|
||||
static void
|
||||
create_guide (GtkButton *button,
|
||||
GuideEditor *editor)
|
||||
{
|
||||
const char *id;
|
||||
int strength;
|
||||
const char *name;
|
||||
int w, h;
|
||||
GtkConstraintGuide *guide;
|
||||
|
||||
if (editor->guide)
|
||||
guide = g_object_ref (editor->guide);
|
||||
else
|
||||
guide = gtk_constraint_guide_new ();
|
||||
|
||||
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
|
||||
gtk_constraint_guide_set_name (guide, name);
|
||||
|
||||
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
|
||||
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
|
||||
gtk_constraint_guide_set_min_size (guide, w, h);
|
||||
|
||||
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width));
|
||||
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height));
|
||||
gtk_constraint_guide_set_nat_size (guide, w, h);
|
||||
|
||||
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width));
|
||||
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_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
|
||||
strength = get_strength (id);
|
||||
gtk_constraint_guide_set_strength (guide, strength);
|
||||
|
||||
g_signal_emit (editor, signals[DONE], 0, guide);
|
||||
g_object_unref (guide);
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_init (GuideEditor *editor)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (editor));
|
||||
}
|
||||
|
||||
static int guide_counter;
|
||||
|
||||
static int
|
||||
min_input (GtkSpinButton *spin_button,
|
||||
double *new_val)
|
||||
{
|
||||
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
|
||||
{
|
||||
*new_val = 0.0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
max_input (GtkSpinButton *spin_button,
|
||||
double *new_val)
|
||||
{
|
||||
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
|
||||
{
|
||||
*new_val = G_MAXINT;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
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)
|
||||
{
|
||||
GtkConstraintStrength strength;
|
||||
const char *nick;
|
||||
int w, h;
|
||||
|
||||
nick = gtk_constraint_guide_get_name (editor->guide);
|
||||
if (nick)
|
||||
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
|
||||
|
||||
gtk_constraint_guide_get_min_size (editor->guide, &w, &h);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
|
||||
|
||||
gtk_constraint_guide_get_nat_size (editor->guide, &w, &h);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h);
|
||||
|
||||
gtk_constraint_guide_get_max_size (editor->guide, &w, &h);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
|
||||
|
||||
strength = gtk_constraint_guide_get_strength (editor->guide);
|
||||
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
|
||||
{
|
||||
char *name;
|
||||
|
||||
guide_counter++;
|
||||
name = g_strdup_printf ("Guide %d", guide_counter);
|
||||
gtk_editable_set_text (GTK_EDITABLE (editor->name), name);
|
||||
g_free (name);
|
||||
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), 0.0);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0);
|
||||
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_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
|
||||
|
||||
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
|
||||
}
|
||||
|
||||
editor->constructed = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GuideEditor *self = GUIDE_EDITOR (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GUIDE:
|
||||
self->guide = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GuideEditor *self = GUIDE_EDITOR (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GUIDE:
|
||||
g_value_set_object (value, self->guide);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_dispose (GObject *object)
|
||||
{
|
||||
GuideEditor *self = (GuideEditor *)object;
|
||||
|
||||
g_clear_pointer (&self->grid, gtk_widget_unparent);
|
||||
g_clear_object (&self->guide);
|
||||
|
||||
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
guide_editor_class_init (GuideEditorClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->constructed = guide_editor_constructed;
|
||||
object_class->dispose = guide_editor_dispose;
|
||||
object_class->set_property = guide_editor_set_property;
|
||||
object_class->get_property = guide_editor_get_property;
|
||||
|
||||
pspecs[PROP_GUIDE] =
|
||||
g_param_spec_object ("guide", "guide", "guide",
|
||||
GTK_TYPE_CONSTRAINT_GUIDE,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
|
||||
|
||||
signals[DONE] =
|
||||
g_signal_new ("done",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT_GUIDE);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
"/org/gtk/gtk4/constraint-editor/guide-editor.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, name);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength);
|
||||
gtk_widget_class_bind_template_child (widget_class, GuideEditor, button);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, create_guide);
|
||||
}
|
||||
|
||||
GuideEditor *
|
||||
guide_editor_new (GtkConstraintGuide *guide)
|
||||
{
|
||||
return g_object_new (GUIDE_EDITOR_TYPE,
|
||||
"guide", guide,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GUIDE_EDITOR_TYPE (guide_editor_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget)
|
||||
|
||||
GuideEditor * guide_editor_new (GtkConstraintGuide *guide);
|
||||
|
||||
void guide_editor_serialize_guide (GString *str,
|
||||
int indent,
|
||||
GtkConstraintGuide *guide);
|
||||
@@ -1,191 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkAdjustment" id="min_width_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="min_height_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="nat_width_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="nat_height_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="max_width_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="max_height_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">2147483647</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<template class="GuideEditor" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="row-spacing">10</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Name</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="name">
|
||||
<property name="max-width-chars">20</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">Min Size</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="min_width">
|
||||
<property name="adjustment">min_width_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="min_height">
|
||||
<property name="adjustment">min_height_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Nat Size</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="nat_width">
|
||||
<property name="adjustment">nat_width_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="nat_height">
|
||||
<property name="adjustment">nat_height_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Max Size</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="max_width">
|
||||
<property name="adjustment">max_width_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="max_height">
|
||||
<property name="adjustment">max_height_adj</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Strength</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="strength">
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">4</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button">
|
||||
<property name="label">Create</property>
|
||||
<signal name="clicked" handler="create_guide"/>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">5</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <constraint-editor-application.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
return g_application_run (G_APPLICATION (constraint_editor_application_new ()), argc, argv);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
constraint_editor_sources = [
|
||||
'main.c',
|
||||
'constraint-editor-application.c',
|
||||
'constraint-editor-window.c',
|
||||
'constraint-view.c',
|
||||
'constraint-editor.c',
|
||||
'guide-editor.c',
|
||||
]
|
||||
|
||||
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
|
||||
'constraint-editor.gresource.xml',
|
||||
source_dir: '.',
|
||||
)
|
||||
|
||||
executable('gtk4-constraint-editor',
|
||||
sources: [ constraint_editor_sources, constraint_editor_resources, ],
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_dep,
|
||||
include_directories: confinc,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: false,
|
||||
)
|
||||
@@ -1,303 +0,0 @@
|
||||
#include "fontcolors.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
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;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontColorsClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FontColors, font_colors, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontColors *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
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->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
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_clear_object (&self->font_map);
|
||||
|
||||
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_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_colors (self);
|
||||
}
|
||||
|
||||
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_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_colors_get_reset_action (FontColors *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#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);
|
||||
GAction * font_colors_get_reset_action (FontColors *self);
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,257 +0,0 @@
|
||||
#include "fontcontrols.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_SIZE = 1,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#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);
|
||||
@@ -1,173 +0,0 @@
|
||||
<?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="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="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>
|
||||
@@ -1,43 +0,0 @@
|
||||
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;
|
||||
}
|
||||
plainview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
waterfallview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
styleview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
glyphsview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
infoview .content {
|
||||
padding: 20px;
|
||||
border-spacing: 10px;
|
||||
}
|
||||
gridview > child {
|
||||
padding: 0;
|
||||
}
|
||||
glyphview {
|
||||
padding: 0;
|
||||
border: 0.6px solid gray;
|
||||
}
|
||||
.viewcontrols {
|
||||
padding: 20px;
|
||||
border-spacing: 10px;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/fontexplorer">
|
||||
<file preprocess="xml-stripblanks">fontcolors.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontcontrols.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontfeatures.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontvariations.ui</file>
|
||||
<file preprocess="xml-stripblanks">glyphsview.ui</file>
|
||||
<file preprocess="xml-stripblanks">infoview.ui</file>
|
||||
<file preprocess="xml-stripblanks">plainview.ui</file>
|
||||
<file preprocess="xml-stripblanks">rangeedit.ui</file>
|
||||
<file preprocess="xml-stripblanks">samplechooser.ui</file>
|
||||
<file preprocess="xml-stripblanks">sampleeditor.ui</file>
|
||||
<file preprocess="xml-stripblanks">styleview.ui</file>
|
||||
<file preprocess="xml-stripblanks">waterfallview.ui</file>
|
||||
<file>fontexplorer.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@@ -1,186 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "fontexplorerapp.h"
|
||||
|
||||
#include <gtk/gtk.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_open (GApplication *app,
|
||||
GFile **files,
|
||||
int n_files,
|
||||
const char *hint)
|
||||
{
|
||||
FontExplorerWindow *win;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
|
||||
font_explorer_window_load (win, files[i]);
|
||||
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;
|
||||
G_APPLICATION_CLASS (class)->open = font_explorer_app_open;
|
||||
}
|
||||
|
||||
FontExplorerApp *
|
||||
font_explorer_app_new (void)
|
||||
{
|
||||
return g_object_new (FONT_EXPLORER_APP_TYPE,
|
||||
"application-id", "org.gtk.FontExplorer",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#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);
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "fontexplorerwin.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fontcolors.h"
|
||||
#include "fontcontrols.h"
|
||||
#include "fontexplorerapp.h"
|
||||
#include "fontfeatures.h"
|
||||
#include "fontvariations.h"
|
||||
#include "glyphsview.h"
|
||||
#include "infoview.h"
|
||||
#include "plainview.h"
|
||||
#include "samplechooser.h"
|
||||
#include "sampleeditor.h"
|
||||
#include "styleview.h"
|
||||
#include "waterfallview.h"
|
||||
|
||||
struct _FontExplorerWindow
|
||||
{
|
||||
GtkApplicationWindow parent;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
|
||||
GtkFontButton *fontbutton;
|
||||
GtkLabel *path;
|
||||
FontControls *controls;
|
||||
FontFeatures *features;
|
||||
FontVariations *variations;
|
||||
FontColors *colors;
|
||||
GtkStack *stack;
|
||||
GtkToggleButton *plain_toggle;
|
||||
GtkToggleButton *waterfall_toggle;
|
||||
GtkToggleButton *style_toggle;
|
||||
GtkToggleButton *glyphs_toggle;
|
||||
GtkToggleButton *info_toggle;
|
||||
GtkToggleButton *edit_toggle;
|
||||
};
|
||||
|
||||
struct _FontExplorerWindowClass
|
||||
{
|
||||
GtkApplicationWindowClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
G_DEFINE_TYPE(FontExplorerWindow, font_explorer_window, GTK_TYPE_APPLICATION_WINDOW);
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
g_action_activate (font_controls_get_reset_action (self->controls), NULL);
|
||||
g_action_activate (font_features_get_reset_action (self->features), NULL);
|
||||
g_action_activate (font_variations_get_reset_action (self->variations), NULL);
|
||||
g_action_activate (font_colors_get_reset_action (self->colors), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_reset (GSimpleAction *action,
|
||||
GParamSpec *pspec,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
gboolean enabled;
|
||||
GAction *reset_action;
|
||||
|
||||
enabled = g_action_get_enabled (font_controls_get_reset_action (self->controls)) ||
|
||||
g_action_get_enabled (font_features_get_reset_action (self->features)) ||
|
||||
g_action_get_enabled (font_variations_get_reset_action (self->variations)) ||
|
||||
g_action_get_enabled (font_colors_get_reset_action (self->colors));
|
||||
|
||||
reset_action = g_action_map_lookup_action (G_ACTION_MAP (self), "reset");
|
||||
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (reset_action), enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_init (FontExplorerWindow *self)
|
||||
{
|
||||
GSimpleAction *reset_action;
|
||||
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_signal_connect (reset_action, "activate", G_CALLBACK (reset), self);
|
||||
g_signal_connect (font_controls_get_reset_action (self->controls),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_variations_get_reset_action (self->variations),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_colors_get_reset_action (self->colors),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_features_get_reset_action (self->features),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
|
||||
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (reset_action));
|
||||
update_reset (NULL, NULL, self);
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (GtkToggleButton *button,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
if (gtk_toggle_button_get_active (self->edit_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "edit");
|
||||
else if (gtk_toggle_button_get_active (self->plain_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "plain");
|
||||
else if (gtk_toggle_button_get_active (self->waterfall_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "waterfall");
|
||||
else if (gtk_toggle_button_get_active (self->style_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "style");
|
||||
else if (gtk_toggle_button_get_active (self->glyphs_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "glyphs");
|
||||
else if (gtk_toggle_button_get_active (self->info_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "info");
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
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 *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
|
||||
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_COLORS_TYPE);
|
||||
g_type_ensure (FONT_CONTROLS_TYPE);
|
||||
g_type_ensure (FONT_FEATURES_TYPE);
|
||||
g_type_ensure (FONT_VARIATIONS_TYPE);
|
||||
g_type_ensure (GLYPHS_VIEW_TYPE);
|
||||
g_type_ensure (INFO_VIEW_TYPE);
|
||||
g_type_ensure (PLAIN_VIEW_TYPE);
|
||||
g_type_ensure (SAMPLE_CHOOSER_TYPE);
|
||||
g_type_ensure (SAMPLE_EDITOR_TYPE);
|
||||
g_type_ensure (STYLE_VIEW_TYPE);
|
||||
g_type_ensure (WATERFALL_VIEW_TYPE);
|
||||
|
||||
object_class->set_property = font_explorer_window_set_property;
|
||||
object_class->get_property = font_explorer_window_get_property;
|
||||
object_class->dispose = font_explorer_window_dispose;
|
||||
object_class->finalize = font_explorer_window_finalize;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
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/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, path);
|
||||
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, stack);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, plain_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, waterfall_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, style_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, glyphs_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, info_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, edit_toggle);
|
||||
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), update_view);
|
||||
}
|
||||
|
||||
FontExplorerWindow *
|
||||
font_explorer_window_new (FontExplorerApp *app)
|
||||
{
|
||||
return g_object_new (FONT_EXPLORER_WINDOW_TYPE, "application", app, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
font_explorer_window_load (FontExplorerWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
const char *path;
|
||||
Pango2FontMap *map;
|
||||
Pango2HbFace *face;
|
||||
Pango2FontDescription *desc;
|
||||
char *basename;
|
||||
|
||||
path = g_file_peek_path (file);
|
||||
basename = g_path_get_basename (path);
|
||||
|
||||
face = pango2_hb_face_new_from_file (path, 0, -2, NULL, NULL);
|
||||
desc = pango2_font_face_describe (PANGO2_FONT_FACE (face));
|
||||
|
||||
map = pango2_font_map_new ();
|
||||
pango2_font_map_add_face (map, PANGO2_FONT_FACE (face));
|
||||
pango2_font_map_set_fallback (map, pango2_font_map_get_default ());
|
||||
|
||||
g_set_object (&self->font_map, map);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_MAP]);
|
||||
|
||||
g_object_unref (map);
|
||||
|
||||
gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (self->fontbutton), desc);
|
||||
|
||||
gtk_widget_hide (GTK_WIDGET (self->fontbutton));
|
||||
gtk_widget_show (GTK_WIDGET (self->path));
|
||||
gtk_label_set_label (self->path, basename);
|
||||
|
||||
pango2_font_description_free (desc);
|
||||
g_free (basename);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#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);
|
||||
void font_explorer_window_load (FontExplorerWindow *self,
|
||||
GFile *file);
|
||||
@@ -1,252 +0,0 @@
|
||||
<?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="title">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="plain_toggle">
|
||||
<property name="label">Plain</property>
|
||||
<property name="active">1</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="waterfall_toggle">
|
||||
<property name="label">Waterfall</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="style_toggle">
|
||||
<property name="label">Styles</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<property name="sensitive" bind-source="styleview" bind-property="has-styles" bind-flags="sync-create"/>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="glyphs_toggle">
|
||||
<property name="label">Glyphs</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="info_toggle">
|
||||
<property name="label">Info</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
</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>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="edit_toggle">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Edit the sample</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</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="GtkLabel" id="path">
|
||||
<property name="visible">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontControls" id="controls">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="SampleChooser" id="samplechooser"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontVariations" id="variations">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontFeatures" id="features">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<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-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="hexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">plain</property>
|
||||
<property name="child">
|
||||
<object class="PlainView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<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="sampleeditor" 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>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">waterfall</property>
|
||||
<property name="child">
|
||||
<object class="WaterfallView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<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="sampleeditor" 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>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">style</property>
|
||||
<property name="child">
|
||||
<object class="StyleView" id="styleview">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<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="sampleeditor" 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>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">glyphs</property>
|
||||
<property name="child">
|
||||
<object class="GlyphsView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" 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>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">info</property>
|
||||
<property name="child">
|
||||
<object class="InfoView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="size" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">edit</property>
|
||||
<property name="child">
|
||||
<object class="SampleEditor" id="sampleeditor">
|
||||
<property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
|
||||
<property name="editing" bind-source="edit_toggle" bind-property="active" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,744 +0,0 @@
|
||||
#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_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
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;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontFeaturesClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontFeatures, font_features, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontFeatures *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
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_clear_object (&self->font_map);
|
||||
|
||||
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_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
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_LANGUAGE:
|
||||
self->lang = pango2_language_from_string (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_features (self);
|
||||
}
|
||||
|
||||
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_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
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_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_features_get_reset_action (FontFeatures *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#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);
|
||||
GAction * font_features_get_reset_action (FontFeatures *self);
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,508 +0,0 @@
|
||||
#include "fontvariations.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
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;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontVariationsClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontVariations, font_variations, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontVariations *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_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);
|
||||
|
||||
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_clear_object (&self->font_map);
|
||||
|
||||
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_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_variations (self);
|
||||
}
|
||||
|
||||
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_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
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_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_variations_get_reset_action (FontVariations *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#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);
|
||||
GAction * font_variations_get_reset_action (FontVariations *self);
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "glyphitem.h"
|
||||
|
||||
struct _GlyphItem {
|
||||
GObject parent;
|
||||
Pango2Font *font;
|
||||
hb_codepoint_t glyph;
|
||||
};
|
||||
|
||||
struct _GlyphItemClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GlyphItem, glyph_item, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
glyph_item_init (GlyphItem *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_item_finalize (GObject *object)
|
||||
{
|
||||
GlyphItem *item = GLYPH_ITEM (object);
|
||||
|
||||
g_object_unref (item->font);
|
||||
|
||||
G_OBJECT_CLASS (glyph_item_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_item_class_init (GlyphItemClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->finalize = glyph_item_finalize;
|
||||
}
|
||||
|
||||
GlyphItem *
|
||||
glyph_item_new (Pango2Font *font,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
GlyphItem *item = g_object_new (GLYPH_ITEM_TYPE, NULL);
|
||||
item->font = g_object_ref (font);
|
||||
item->glyph = glyph;
|
||||
return item;
|
||||
}
|
||||
|
||||
Pango2Font *
|
||||
glyph_item_get_font (GlyphItem *item)
|
||||
{
|
||||
return item->font;
|
||||
}
|
||||
|
||||
hb_codepoint_t
|
||||
glyph_item_get_glyph (GlyphItem *item)
|
||||
{
|
||||
return item->glyph;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GLYPH_ITEM_TYPE (glyph_item_get_type ())
|
||||
#define GLYPH_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_ITEM_TYPE, GlyphItem))
|
||||
|
||||
|
||||
typedef struct _GlyphItem GlyphItem;
|
||||
typedef struct _GlyphItemClass GlyphItemClass;
|
||||
|
||||
|
||||
GType glyph_item_get_type (void);
|
||||
GlyphItem * glyph_item_new (Pango2Font *font,
|
||||
hb_codepoint_t glyph);
|
||||
hb_codepoint_t glyph_item_get_glyph (GlyphItem *item);
|
||||
Pango2Font * glyph_item_get_font (GlyphItem *item);
|
||||
@@ -1,97 +0,0 @@
|
||||
#include "glyphmodel.h"
|
||||
|
||||
#include "glyphitem.h"
|
||||
|
||||
struct _GlyphModel {
|
||||
GObject parent;
|
||||
Pango2Font *font;
|
||||
unsigned int num_glyphs;
|
||||
GlyphItem **glyphs;
|
||||
};
|
||||
|
||||
struct _GlyphModelClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GType
|
||||
glyph_model_get_item_type (GListModel *model)
|
||||
{
|
||||
return GLYPH_ITEM_TYPE;
|
||||
}
|
||||
|
||||
static guint
|
||||
glyph_model_get_n_items (GListModel *model)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (model);
|
||||
|
||||
return self->num_glyphs;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
glyph_model_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (model);
|
||||
|
||||
if (position >= self->num_glyphs)
|
||||
return NULL;
|
||||
|
||||
if (self->glyphs[position] == NULL)
|
||||
self->glyphs[position] = glyph_item_new (self->font, position);
|
||||
|
||||
return g_object_ref (self->glyphs[position]);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_list_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = glyph_model_get_item_type;
|
||||
iface->get_n_items = glyph_model_get_n_items;
|
||||
iface->get_item = glyph_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GlyphModel, glyph_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, glyph_model_list_model_init))
|
||||
|
||||
static void
|
||||
glyph_model_init (GlyphModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_finalize (GObject *object)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (object);
|
||||
|
||||
g_object_unref (self->font);
|
||||
for (int i = 0; i < self->num_glyphs; i++)
|
||||
{
|
||||
if (self->glyphs[i])
|
||||
g_object_unref (self->glyphs[i]);
|
||||
}
|
||||
g_free (self->glyphs);
|
||||
|
||||
G_OBJECT_CLASS (glyph_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_class_init (GlyphModelClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->finalize = glyph_model_finalize;
|
||||
}
|
||||
|
||||
GlyphModel *
|
||||
glyph_model_new (Pango2Font *font)
|
||||
{
|
||||
GlyphModel *self;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
self = g_object_new (GLYPH_MODEL_TYPE, NULL);
|
||||
|
||||
self->font = g_object_ref (font);
|
||||
hb_face = pango2_hb_face_get_hb_face (PANGO2_HB_FACE (pango2_font_get_face (font)));
|
||||
self->num_glyphs = hb_face_get_glyph_count (hb_face);
|
||||
self->glyphs = g_new0 (GlyphItem *, self->num_glyphs);
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GLYPH_MODEL_TYPE (glyph_model_get_type ())
|
||||
#define GLYPH_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_MODEL_TYPE, GlyphModel))
|
||||
|
||||
|
||||
typedef struct _GlyphModel GlyphModel;
|
||||
typedef struct _GlyphModelClass GlyphModelClass;
|
||||
|
||||
|
||||
GType glyph_model_get_type (void);
|
||||
GlyphModel * glyph_model_new (Pango2Font *font);
|
||||
@@ -1,239 +0,0 @@
|
||||
#include "glyphsview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_VARIATIONS,
|
||||
PROP_PALETTE,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _GlyphsView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
GtkGridView *glyphs;
|
||||
|
||||
Pango2FontDescription *font_desc;
|
||||
char *variations;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
};
|
||||
|
||||
struct _GlyphsViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GlyphsView, glyphs_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
glyphs_view_init (GlyphsView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->variations = g_strdup ("");
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), GLYPHS_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (glyphs_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_finalize (GObject *object)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (glyphs_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static Pango2Font *
|
||||
get_font (GlyphsView *self,
|
||||
int size)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2FontDescription *desc;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, size);
|
||||
font = pango2_context_load_font (context, desc);
|
||||
pango2_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
update_glyph_model (GlyphsView *self)
|
||||
{
|
||||
Pango2Font *font = get_font (self, 60 * PANGO2_SCALE);
|
||||
GlyphModel *gm;
|
||||
GtkSelectionModel *model;
|
||||
|
||||
gm = glyph_model_new (font);
|
||||
model = GTK_SELECTION_MODEL (gtk_no_selection_new (G_LIST_MODEL (gm)));
|
||||
gtk_grid_view_set_model (self->glyphs, model);
|
||||
g_object_unref (model);
|
||||
g_object_unref (font);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_glyph (GtkSignalListItemFactory *factory,
|
||||
GObject *listitem)
|
||||
{
|
||||
gtk_list_item_set_child (GTK_LIST_ITEM (listitem), GTK_WIDGET (glyph_view_new ()));
|
||||
}
|
||||
|
||||
static void
|
||||
bind_glyph (GtkSignalListItemFactory *factory,
|
||||
GObject *listitem,
|
||||
GlyphsView *self)
|
||||
{
|
||||
GlyphView *view;
|
||||
GObject *item;
|
||||
|
||||
view = GLYPH_VIEW (gtk_list_item_get_child (GTK_LIST_ITEM (listitem)));
|
||||
item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
|
||||
glyph_view_set_font (view, glyph_item_get_font (GLYPH_ITEM (item)));
|
||||
glyph_view_set_glyph (view, glyph_item_get_glyph (GLYPH_ITEM (item)));
|
||||
glyph_view_set_palette (view, self->palette_quark);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
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_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (g_value_get_string (value));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_glyph_model (self);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_class_init (GlyphsViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = glyphs_view_dispose;
|
||||
object_class->finalize = glyphs_view_finalize;
|
||||
object_class->get_property = glyphs_view_get_property;
|
||||
object_class->set_property = glyphs_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
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/glyphsview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), GlyphsView, glyphs);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup_glyph);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind_glyph);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "glyphsview");
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define GLYPHS_VIEW_TYPE (glyphs_view_get_type ())
|
||||
#define GLYPHS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPHS_VIEW_TYPE, GlyphsView))
|
||||
|
||||
|
||||
typedef struct _GlyphsView GlyphsView;
|
||||
typedef struct _GlyphsViewClass GlyphsViewClass;
|
||||
|
||||
|
||||
GType glyphs_view_get_type (void);
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GlyphsView" parent="GtkWidget">
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkGridView" id="glyphs">
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_glyph"/>
|
||||
<signal name="bind" handler="bind_glyph"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,321 +0,0 @@
|
||||
#include "glyphview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
struct _GlyphView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
Pango2Font *font;
|
||||
GQuark palette;
|
||||
int palette_index;
|
||||
hb_codepoint_t glyph;
|
||||
int n_layers;
|
||||
int layer;
|
||||
};
|
||||
|
||||
struct _GlyphViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GlyphView, glyph_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
click_cb (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GlyphView *self)
|
||||
{
|
||||
if (self->n_layers == 0)
|
||||
return;
|
||||
|
||||
self->layer++;
|
||||
|
||||
if (self->layer == self->n_layers)
|
||||
self->layer = -1;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_init (GlyphView *self)
|
||||
{
|
||||
GtkGesture *click;
|
||||
|
||||
self->n_layers = 0;
|
||||
self->layer = -1;
|
||||
|
||||
click = gtk_gesture_click_new ();
|
||||
g_signal_connect (click, "pressed", G_CALLBACK (click_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (click));
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_dispose (GObject *object)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font);
|
||||
|
||||
G_OBJECT_CLASS (glyph_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (widget);
|
||||
Pango2GlyphString *glyphs;
|
||||
Pango2Rectangle ink, logical;
|
||||
cairo_t *cr;
|
||||
int width, height;
|
||||
char name[80];
|
||||
|
||||
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
|
||||
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
glyphs = pango2_glyph_string_new ();
|
||||
pango2_glyph_string_set_size (glyphs, 1);
|
||||
|
||||
glyphs->glyphs[0].geometry.width = ink.width;
|
||||
glyphs->glyphs[0].geometry.x_offset = ink.x;
|
||||
glyphs->glyphs[0].geometry.y_offset = -ink.y;
|
||||
|
||||
if (self->layer == -1)
|
||||
{
|
||||
glyphs->glyphs[0].glyph = self->glyph;
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_face_t *face = hb_font_get_face (pango2_font_get_hb_font (self->font));
|
||||
hb_ot_color_layer_t *layers;
|
||||
unsigned int count;
|
||||
|
||||
layers = g_newa (hb_ot_color_layer_t, self->n_layers);
|
||||
count = self->n_layers;
|
||||
hb_ot_color_glyph_get_layers (face,
|
||||
self->glyph,
|
||||
0,
|
||||
&count,
|
||||
layers);
|
||||
glyphs->glyphs[0].glyph = layers[self->layer].glyph;
|
||||
if (layers[self->layer].color_index == 0xffff)
|
||||
{
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_color_t *colors;
|
||||
unsigned int n_colors;
|
||||
hb_color_t color;
|
||||
|
||||
n_colors = hb_ot_color_palette_get_colors (face,
|
||||
self->palette_index,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
colors = g_newa (hb_color_t, n_colors);
|
||||
hb_ot_color_palette_get_colors (face,
|
||||
self->palette_index,
|
||||
0,
|
||||
&n_colors,
|
||||
colors);
|
||||
color = colors[layers[self->layer].color_index];
|
||||
cairo_set_source_rgba (cr, hb_color_get_red (color)/255.,
|
||||
hb_color_get_green (color)/255.,
|
||||
hb_color_get_blue (color)/255.,
|
||||
hb_color_get_alpha (color)/255.);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_move_to (cr, (width - logical.width/1024.)/2, (height - logical.height/1024.)/2);
|
||||
pango2_cairo_show_color_glyph_string (cr, self->font, self->palette, glyphs);
|
||||
|
||||
{
|
||||
Pango2Layout *layout;
|
||||
Pango2FontDescription *desc;
|
||||
char gid[20];
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
g_snprintf (gid, sizeof (gid), "%d", self->glyph);
|
||||
layout = gtk_widget_create_pango_layout (widget, gid);
|
||||
desc = pango2_font_description_from_string ("Cantarell 8");
|
||||
pango2_layout_set_font_description (layout, desc);
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,0.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
|
||||
hb_font = pango2_font_get_hb_font (self->font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
if (hb_ot_layout_has_glyph_classes (hb_face))
|
||||
{
|
||||
hb_ot_layout_glyph_class_t class;
|
||||
const char *class_names[] = {
|
||||
NULL, "Base", "Ligature", "Mark", "Component"
|
||||
};
|
||||
int w, h;
|
||||
|
||||
class = hb_ot_layout_get_glyph_class (hb_face, self->glyph);
|
||||
|
||||
if (class != HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
|
||||
{
|
||||
pango2_layout_set_text (layout, class_names[class], -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
if (hb_font_get_glyph_name (hb_font, self->glyph, name, sizeof (name)))
|
||||
{
|
||||
int w, h;
|
||||
|
||||
pango2_layout_set_text (layout, name, -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, height - h/1024. - 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
if (self->n_layers > 0)
|
||||
{
|
||||
char buf[128];
|
||||
int w, h;
|
||||
|
||||
if (self->layer == -1)
|
||||
g_snprintf (buf, sizeof (buf), "%d Layers", self->n_layers);
|
||||
else
|
||||
g_snprintf (buf, sizeof (buf), "Layer %d", self->layer);
|
||||
|
||||
pango2_layout_set_text (layout, buf, -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, height - h/1024. - 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (widget);
|
||||
Pango2Rectangle ink, logical;
|
||||
|
||||
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = 2 * logical.width / PANGO2_SCALE;
|
||||
else
|
||||
*minimum = *natural = 2 * logical.height / PANGO2_SCALE;
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_class_init (GlyphViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = glyph_view_dispose;
|
||||
widget_class->snapshot = glyph_view_snapshot;
|
||||
widget_class->measure = glyph_view_measure;
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "glyphview");
|
||||
}
|
||||
|
||||
GlyphView *
|
||||
glyph_view_new (void)
|
||||
{
|
||||
return g_object_new (GLYPH_VIEW_TYPE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_font (GlyphView *self,
|
||||
Pango2Font *font)
|
||||
{
|
||||
if (g_set_object (&self->font, font))
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
find_palette_index_by_flag (hb_face_t *hbface,
|
||||
hb_ot_color_palette_flags_t flag)
|
||||
{
|
||||
unsigned int n_palettes;
|
||||
|
||||
n_palettes = hb_ot_color_palette_get_count (hbface);
|
||||
for (unsigned int i = 0; i < n_palettes; i++)
|
||||
{
|
||||
if (hb_ot_color_palette_get_flags (hbface, i) & flag)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_palette (GlyphView *self,
|
||||
GQuark palette)
|
||||
{
|
||||
if (self->palette == palette)
|
||||
return;
|
||||
|
||||
self->palette = palette;
|
||||
|
||||
if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DEFAULT))
|
||||
self->palette_index = 0;
|
||||
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_LIGHT))
|
||||
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND);
|
||||
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DARK))
|
||||
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND);
|
||||
else
|
||||
{
|
||||
const char *str = g_quark_to_string (palette);
|
||||
char *endp;
|
||||
if (g_str_has_prefix (str, "palette"))
|
||||
self->palette_index = g_ascii_strtoll (str + strlen ("palette"), &endp, 10);
|
||||
}
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_glyph (GlyphView *self,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
if (self->glyph == glyph)
|
||||
return;
|
||||
|
||||
self->glyph = glyph;
|
||||
self->n_layers = hb_ot_color_glyph_get_layers (hb_font_get_face (pango2_font_get_hb_font (self->font)), glyph, 0, NULL, NULL);
|
||||
self->layer = -1;
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define GLYPH_VIEW_TYPE (glyph_view_get_type ())
|
||||
#define GLYPH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_VIEW_TYPE, GlyphView))
|
||||
|
||||
|
||||
typedef struct _GlyphView GlyphView;
|
||||
typedef struct _GlyphViewClass GlyphViewClass;
|
||||
|
||||
|
||||
GType glyph_view_get_type (void);
|
||||
GlyphView * glyph_view_new (void);
|
||||
void glyph_view_set_font (GlyphView *view,
|
||||
Pango2Font *font);
|
||||
void glyph_view_set_palette (GlyphView *view,
|
||||
GQuark palette);
|
||||
void glyph_view_set_glyph (GlyphView *view,
|
||||
hb_codepoint_t glyph);
|
||||
@@ -1,423 +0,0 @@
|
||||
#include "infoview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_VARIATIONS,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _InfoView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkGrid *info;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
};
|
||||
|
||||
struct _InfoViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(InfoView, info_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
info_view_init (InfoView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->size = 12.;
|
||||
self->variations = g_strdup ("");
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), INFO_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (info_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_finalize (GObject *object)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
|
||||
G_OBJECT_CLASS (info_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static Pango2Font *
|
||||
get_font (InfoView *self,
|
||||
int size)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2FontDescription *desc;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, size);
|
||||
font = pango2_context_load_font (context, desc);
|
||||
pango2_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
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
|
||||
add_misc_line (InfoView *self,
|
||||
const char *title,
|
||||
const char *value,
|
||||
int row)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (title);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_START);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_grid_attach (self->info, label, 0, row, 1, 1);
|
||||
|
||||
label = gtk_label_new (value);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_END);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_START);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1);
|
||||
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
|
||||
gtk_label_set_width_chars (GTK_LABEL (label), 40);
|
||||
gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
|
||||
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||
gtk_grid_attach (self->info, label, 1, row, 1, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
add_info_line (InfoView *self,
|
||||
hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
char info[256];
|
||||
unsigned int len = sizeof (info);
|
||||
|
||||
if (hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, info) > 0)
|
||||
add_misc_line (self, title, info, row);
|
||||
}
|
||||
|
||||
static void
|
||||
add_metrics_line (InfoView *self,
|
||||
hb_font_t *font,
|
||||
hb_ot_metrics_tag_t metrics_tag,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
hb_position_t pos;
|
||||
|
||||
if (hb_ot_metrics_get_position (font, metrics_tag, &pos))
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
g_snprintf (buf, sizeof (buf), "%d", pos);
|
||||
add_misc_line (self, title, buf, row);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_style_line (InfoView *self,
|
||||
hb_font_t *font,
|
||||
hb_style_tag_t style_tag,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
float value;
|
||||
char buf[16];
|
||||
|
||||
value = hb_style_get_value (font, style_tag);
|
||||
g_snprintf (buf, sizeof (buf), "%.2f", value);
|
||||
add_misc_line (self, title, buf, row);
|
||||
}
|
||||
|
||||
static void
|
||||
update_info (InfoView *self)
|
||||
{
|
||||
GtkWidget *child;
|
||||
int size = pango2_font_description_get_size (self->font_desc);
|
||||
Pango2Font *pango_font = get_font (self, MAX (size, 10 * PANGO2_SCALE));
|
||||
hb_font_t *font1 = pango2_font_get_hb_font (pango_font);
|
||||
hb_face_t *face = hb_font_get_face (font1);
|
||||
hb_font_t *font = hb_font_create_sub_font (font1);
|
||||
int row = 0;
|
||||
char buf[128];
|
||||
unsigned int count;
|
||||
GString *s;
|
||||
hb_tag_t *tables;
|
||||
const char *path;
|
||||
|
||||
hb_font_set_scale (font, hb_face_get_upem (face), hb_face_get_upem (face));
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->info))) != NULL)
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("General Info"), 0, row++, 2, 1);
|
||||
|
||||
path = pango2_hb_face_get_file (PANGO2_HB_FACE (pango2_font_get_face (pango_font)));
|
||||
if (path)
|
||||
add_misc_line (self, "File ", path, row++);
|
||||
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FONT_FAMILY, "Font Family Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FONT_SUBFAMILY, "Font Subfamily Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_UNIQUE_ID, "Unique Font Identifier", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FULL_NAME, "Full Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_VERSION_STRING, "Version", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_POSTSCRIPT_NAME, "Postscript Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY, "Typographic Family Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, "Typographic Subfamily Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_MANUFACTURER, "Vendor ID", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_DESIGNER, "Designer", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_DESCRIPTION, "Description", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_COPYRIGHT, "Copyright", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Metrics"), 0, row++, 2, 1);
|
||||
g_snprintf (buf, sizeof (buf), "%d", hb_face_get_upem (face));
|
||||
add_misc_line (self, "Units per Em", buf, row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, "Ascender", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, "Descender", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, "Line Gap", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, "Caret Rise", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, "Caret Run", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, "Caret Offset", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_X_HEIGHT, "x Height", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_CAP_HEIGHT, "Cap Height", row++);
|
||||
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Strikeout Size", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Strikeout Offset", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Underline Size", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Underline Offset", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Style"), 0, row++, 2, 1);
|
||||
|
||||
add_style_line (self, font, HB_STYLE_TAG_ITALIC, "Italic", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_OPTICAL_SIZE, "Optical Size", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_SLANT_ANGLE, "Slant Angle", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_WIDTH, "Width", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_WEIGHT, "Weight", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Miscellaneous"), 0, row++, 2, 1);
|
||||
|
||||
count = hb_face_get_glyph_count (face);
|
||||
g_snprintf (buf, sizeof (buf), "%d", count);
|
||||
add_misc_line (self, "Glyph Count", buf, row++);
|
||||
|
||||
if (hb_ot_var_get_axis_count (face) > 0)
|
||||
{
|
||||
s = g_string_new ("");
|
||||
hb_ot_var_axis_info_t *axes;
|
||||
|
||||
axes = g_newa (hb_ot_var_axis_info_t, hb_ot_var_get_axis_count (face));
|
||||
count = hb_ot_var_get_axis_count (face);
|
||||
hb_ot_var_get_axis_infos (face, 0, &count, axes);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
char name[256];
|
||||
unsigned int len;
|
||||
|
||||
len = sizeof (buf);
|
||||
hb_ot_name_get_utf8 (face, axes[i].name_id, HB_LANGUAGE_INVALID, &len, name);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, name);
|
||||
}
|
||||
add_misc_line (self, "Axes", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
if (hb_ot_var_get_named_instance_count (face) > 0)
|
||||
{
|
||||
s = g_string_new ("");
|
||||
for (int i = 0; i < hb_ot_var_get_named_instance_count (face); i++)
|
||||
{
|
||||
hb_ot_name_id_t name_id;
|
||||
char name[256];
|
||||
unsigned int len;
|
||||
|
||||
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
|
||||
len = sizeof (buf);
|
||||
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, name);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, name);
|
||||
}
|
||||
add_misc_line (self, "Named Instances", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
s = g_string_new ("");
|
||||
count = hb_face_get_table_tags (face, 0, NULL, NULL);
|
||||
tables = g_newa (hb_tag_t, count);
|
||||
hb_face_get_table_tags (face, 0, &count, tables);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
memset (buf, 0, sizeof (buf));
|
||||
hb_tag_to_string (tables[i], buf);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
add_misc_line (self, "Tables", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
s = g_string_new ("");
|
||||
if (hb_ot_color_has_palettes (face))
|
||||
g_string_append_printf (s, "%s", "Palettes");
|
||||
if (hb_ot_color_has_layers (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "Layers");
|
||||
if (hb_ot_color_has_svg (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "SVG");
|
||||
if (hb_ot_color_has_png (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "PNG");
|
||||
if (s->len > 0)
|
||||
add_misc_line (self, "Color", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
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_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_info (self);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
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_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_class_init (InfoViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = info_view_dispose;
|
||||
object_class->finalize = info_view_finalize;
|
||||
object_class->get_property = info_view_get_property;
|
||||
object_class->set_property = info_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
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_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
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/infoview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), InfoView, info);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "infoview");
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define INFO_VIEW_TYPE (info_view_get_type ())
|
||||
#define INFO_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INFO_VIEW_TYPE, InfoView))
|
||||
|
||||
|
||||
typedef struct _InfoView InfoView;
|
||||
typedef struct _InfoViewClass InfoViewClass;
|
||||
|
||||
|
||||
GType info_view_get_type (void);
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="InfoView" parent="GtkWidget">
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="info">
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -1,334 +0,0 @@
|
||||
#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));
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#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
|
||||
@@ -1,9 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
fontexplorer_sources = [
|
||||
'fontcolors.c',
|
||||
'fontcontrols.c',
|
||||
'fontexplorerapp.c',
|
||||
'fontexplorerwin.c',
|
||||
'fontfeatures.c',
|
||||
'fontvariations.c',
|
||||
'glyphitem.c',
|
||||
'glyphmodel.c',
|
||||
'glyphsview.c',
|
||||
'glyphview.c',
|
||||
'infoview.c',
|
||||
'language-names.c',
|
||||
'main.c',
|
||||
'plainview.c',
|
||||
'rangeedit.c',
|
||||
'samplechooser.c',
|
||||
'sampleeditor.c',
|
||||
'styleview.c',
|
||||
'waterfallview.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,
|
||||
)
|
||||
@@ -1,343 +0,0 @@
|
||||
#include "plainview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
PROP_VARIATIONS,
|
||||
PROP_FEATURES,
|
||||
PROP_PALETTE,
|
||||
PROP_SAMPLE_TEXT,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _PlainView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkLabel *content;
|
||||
GtkScrolledWindow *swin;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
char *features;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
int letterspacing;
|
||||
float line_height;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
GtkCssProvider *bg_provider;
|
||||
char *sample_text;
|
||||
};
|
||||
|
||||
struct _PlainViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(PlainView, plain_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
plain_view_init (PlainView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
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->palette_quark = g_quark_from_string (self->palette);
|
||||
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
|
||||
plain_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), PLAIN_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (plain_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_finalize (GObject *object)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->features);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (plain_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (PlainView *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_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 (".content { 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
|
||||
plain_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
|
||||
break;
|
||||
|
||||
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));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
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
|
||||
plain_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_class_init (PlainViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = plain_view_dispose;
|
||||
object_class->finalize = plain_view_finalize;
|
||||
object_class->get_property = plain_view_get_property;
|
||||
object_class->set_property = plain_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
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);
|
||||
|
||||
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/plainview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, swin);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, content);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "plainview");
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define PLAIN_VIEW_TYPE (plain_view_get_type ())
|
||||
#define PLAIN_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLAIN_VIEW_TYPE, PlainView))
|
||||
|
||||
|
||||
typedef struct _PlainView PlainView;
|
||||
typedef struct _PlainViewClass PlainViewClass;
|
||||
|
||||
|
||||
GType plain_view_get_type (void);
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="PlainView" parent="GtkWidget">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="swin">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkLabel" id="content">
|
||||
<property name="label">Content</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="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user