Compare commits
380 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1675bfbc8 | |||
| 6d606b19be | |||
| 07019887be | |||
| 0d52772f68 | |||
| 269918b0f6 | |||
| 1bedfe3dcd | |||
| 1854f4d21a | |||
| 09d0f4289e | |||
| a227b4f69d | |||
| e881918fea | |||
| 06adb709a1 | |||
| 1a8db5f112 | |||
| 526f460d6b | |||
| 80b6a89a32 | |||
| 0c192288cd | |||
| d34035c22c | |||
| 1f7588087a | |||
| bef8d09040 | |||
| 6f1f1a7c89 | |||
| 4f5a2d7490 | |||
| 8a8e165560 | |||
| 0ec623da09 | |||
| 3b147ad630 | |||
| 615cf2a782 | |||
| f9725cc536 | |||
| 468863a8b9 | |||
| 95a3d3c26f | |||
| df1bca3027 | |||
| acf81a0377 | |||
| bf8fca391a | |||
| aa722dcfac | |||
| f5ccf63550 | |||
| 61f9b1d9e0 | |||
| aa8ba37a0f | |||
| 86c1493b4b | |||
| f58513e4dd | |||
| c816eee4d1 | |||
| 436fe18084 | |||
| 3ba2659860 | |||
| ffc5fdb9de | |||
| e88cf34642 | |||
| 5eb79b3b01 | |||
| cf793f94ac | |||
| ba405bfbf1 | |||
| 4b6223e07d | |||
| 8637ea8fb8 | |||
| ab8a32bc76 | |||
| 6aa38e6b39 | |||
| 46bef9b667 | |||
| 86862d56bd | |||
| 1e5c025a1e | |||
| 60f87f2a7d | |||
| 001903aeef | |||
| 3b04f5a963 | |||
| de29a01682 | |||
| bd3b88b276 | |||
| e7a9030fb5 | |||
| 98aca9e2cd | |||
| 6e8b23d485 | |||
| 05678d44ca | |||
| 7b4bc08254 | |||
| 3b81a9e529 | |||
| 6a0901c40e | |||
| a7b3a0c472 | |||
| 645eddf838 | |||
| ada1cc7dc5 | |||
| 042a3a1344 | |||
| 2542d913bc | |||
| fc619b9783 | |||
| 3c56f326fc | |||
| 4c81600fc9 | |||
| 68661b7291 | |||
| b6a2a8b0fc | |||
| d08802a2c3 | |||
| 759bf152d3 | |||
| 021bca4629 | |||
| f91995db06 | |||
| ad145e201b | |||
| 0bef169b32 | |||
| 5f40db5043 | |||
| afd398112b | |||
| 98591b383b | |||
| 319e75c73f | |||
| c80d5f89d8 | |||
| 8dd4f022c1 | |||
| ee42889790 | |||
| bd0f92fa8b | |||
| c438527e49 | |||
| dad4e1da22 | |||
| 52394b1520 | |||
| 3efd6c9a12 | |||
| 6d04869c85 | |||
| 5781a8c66a | |||
| 65813c3f19 | |||
| 33d5acf1db | |||
| d0d62ee0d6 | |||
| e359e0b146 | |||
| 4a633e4476 | |||
| 78c2fca48e | |||
| 9b93dcbbd8 | |||
| 5acdc8358e | |||
| 9ecd508b86 | |||
| 452eb951d7 | |||
| a6e665c6f3 | |||
| 19f2eddf46 | |||
| a79d427a4b | |||
| f9d794d315 | |||
| 75b96fa7cf | |||
| a5763a3de1 | |||
| 6c9206d46a | |||
| 918b07967c | |||
| 2f3aae002d | |||
| a1f9a45f17 | |||
| 57cf7e6fc2 | |||
| 5c817aef62 | |||
| b7c83ce45c | |||
| 8b13ea22be | |||
| a21b3c7337 | |||
| eb04db32e0 | |||
| faf0c8d1f9 | |||
| 2f91089b71 | |||
| b0a1b4f672 | |||
| 599baee1c4 | |||
| 51d645168f | |||
| 5991f4b6c9 | |||
| a41b9ebec7 | |||
| 50098ba75b | |||
| c804a3863e | |||
| a94a8857cc | |||
| 4b5ee6e45d | |||
| e30ef1989d | |||
| 288e8a46cf | |||
| db8d6e3d99 | |||
| 9d313b3264 | |||
| a28311883f | |||
| aa695ae1c2 | |||
| 42b017d073 | |||
| 0414c15537 | |||
| 98435e15dd | |||
| 7f63e426cc | |||
| 9e450370e8 | |||
| 5fe35cb0fd | |||
| 70f097ebd7 | |||
| 1f1641fdfc | |||
| dce77dc2a5 | |||
| 1500250116 | |||
| 8a5c2e771a | |||
| 419f4f87a4 | |||
| 0f848aace9 | |||
| c1111d9c4d | |||
| 614e043c94 | |||
| ee8ad62bb5 | |||
| ec6d102dc5 | |||
| c82cfa8b0c | |||
| ab41ef43d8 | |||
| aa913100ba | |||
| 0e256a6935 | |||
| 2559885415 | |||
| d9a79c0a2f | |||
| 268efbd5a6 | |||
| a14770a47d | |||
| d42f45bc5a | |||
| 87b108209e | |||
| 5ac2abc6d9 | |||
| 9c721bff1b | |||
| 78cae537a9 | |||
| 69cdeb6037 | |||
| 8d1f354d01 | |||
| c8928bf064 | |||
| 2b029af78f | |||
| 592bab384f | |||
| ffebe0c340 | |||
| 16ca8f75fd | |||
| 955762c5e8 | |||
| c49205c1e6 | |||
| fc67b5a8cf | |||
| ce1b970b46 | |||
| ceb77d6100 | |||
| 02579a1333 | |||
| 2f7fa10434 | |||
| 6be352f446 | |||
| 4d2be2e322 | |||
| d5c01098fd | |||
| d2bda8ea77 | |||
| c517e945de | |||
| e3a1a2e0c6 | |||
| b9c2a925e2 | |||
| 59238c6e73 | |||
| 652ab1ac72 | |||
| bdf879427c | |||
| 4058b80d56 | |||
| be949496ac | |||
| b57b12fdb7 | |||
| e64bb40d0b | |||
| c8d83b7a63 | |||
| 9539cc4a93 | |||
| 72cf304a86 | |||
| 67ad566188 | |||
| db46a8dd06 | |||
| 2611a996ff | |||
| 3e7618fef7 | |||
| 5b1b75b055 | |||
| f1612e36ee | |||
| bfd3d714b9 | |||
| 5a42ccc575 | |||
| b3b0321620 | |||
| e0deacd236 | |||
| f66172451d | |||
| e80238120e | |||
| 07cfdd8ca0 | |||
| ade7509b97 | |||
| 8d1956921d | |||
| 354fa6544a | |||
| 291c50202a | |||
| ce8faa2e90 | |||
| 50e4ca8593 | |||
| ddd5704c92 | |||
| 3ba6d2bd27 | |||
| cd9b730735 | |||
| f593f3da0a | |||
| e9d8bf96e0 | |||
| 6b3a612bbc | |||
| c742debea8 | |||
| cd60ec1576 | |||
| 95e6453823 | |||
| 7e0279b15c | |||
| 791f0d70ac | |||
| 0709dc7a6a | |||
| 15528599f4 | |||
| 031aab3ef6 | |||
| c990134e49 | |||
| 822508f33e | |||
| 358893aa84 | |||
| 344fac5aa7 | |||
| 27965d5fdc | |||
| c025bc5098 | |||
| 170bc0a8de | |||
| 891fd5c604 | |||
| 5b1cd335bb | |||
| eefb6a0dd4 | |||
| 9aaf54140f | |||
| c5786916f7 | |||
| b8e009eb05 | |||
| 256d226d4b | |||
| 7b3208092c | |||
| 1eb86d6394 | |||
| a0ca936e8d | |||
| de3c50a237 | |||
| 244ddea0ea | |||
| 6c94835f5d | |||
| 617566128d | |||
| 7bf772111c | |||
| 50e0893497 | |||
| 7459d430eb | |||
| 163616cc0a | |||
| e378dc4c28 | |||
| 4876028f29 | |||
| 22847563ce | |||
| 0996113d14 | |||
| f019e9d856 | |||
| 48b83d3e97 | |||
| c3211e32ae | |||
| c1790bf0d8 | |||
| 6690197673 | |||
| 384196efb1 | |||
| b801125797 | |||
| aecdd6f68f | |||
| 899cb44519 | |||
| 86175f043c | |||
| 74c6b8e9bc | |||
| d3347e64ba | |||
| 4c8081bafc | |||
| 5995e89a80 | |||
| b9bdbe9aae | |||
| c86789427d | |||
| 0852084884 | |||
| 96778fca92 | |||
| 0c53b608f9 | |||
| 27350ad71b | |||
| d9d220cfc9 | |||
| 2026256823 | |||
| 012baeb909 | |||
| 7249961aa4 | |||
| 3d77e526d6 | |||
| c4b2fe6ee5 | |||
| cea320af24 | |||
| a5bf0591ee | |||
| 22f5236943 | |||
| f84bcfbb97 | |||
| f36ee67226 | |||
| 615b8fc569 | |||
| ff3bb7f671 | |||
| 39e4e48fdc | |||
| 300a88922e | |||
| c003260d63 | |||
| 40c08954db | |||
| fd69b41748 | |||
| a2191c0a68 | |||
| c17451557f | |||
| b91dca9ad0 | |||
| 7586e535ff | |||
| 7859b88f19 | |||
| 7f7809f523 | |||
| b4c2d1dabb | |||
| 362e91c40b | |||
| acf6d47b6f | |||
| 0903ad48f0 | |||
| 46f8600b6a | |||
| fcb3638ac3 | |||
| e599b2548a | |||
| 98d14b4655 | |||
| 96f7e59832 | |||
| 061026f21f | |||
| 330e9a8424 | |||
| 1e47b1c610 | |||
| bf40b89b53 | |||
| 9f2dbf4fc5 | |||
| 235b0482dd | |||
| cbd332bc57 | |||
| fc8aa80e62 | |||
| 56404b7006 | |||
| 08d48201e9 | |||
| 76c4673944 | |||
| 0a31201c88 | |||
| afe94e303a | |||
| b004706009 | |||
| 129042425d | |||
| 81169d18c3 | |||
| cce6a603a6 | |||
| 1c6608f426 | |||
| fcdc5538cf | |||
| dd327bc8a6 | |||
| b878353f0b | |||
| 27d286eb7a | |||
| 01cf559d9d | |||
| 20fd760a52 | |||
| cca8ae04b6 | |||
| 60c45dac56 | |||
| 7bee4fa44b | |||
| 4c029af6cd | |||
| 1c6efea370 | |||
| 895dc94cc9 | |||
| 9f9479a50f | |||
| 13d559119f | |||
| 018388d321 | |||
| cf69d917c1 | |||
| 41599e5e90 | |||
| 1b2e69f6c0 | |||
| ee45869759 | |||
| 048fe84888 | |||
| 480031439f | |||
| dc9b145e27 | |||
| 0e27a49d1a | |||
| 4afd416840 | |||
| 25142abebf | |||
| 60d50bcb13 | |||
| 59f45aa30c | |||
| 14c32a7cf0 | |||
| 4c8e703803 | |||
| 8338e55549 | |||
| da72cfea40 | |||
| 0632e94e68 | |||
| 4a356ae331 | |||
| 4f4f2d169a | |||
| 577d520006 | |||
| 222d6f1db1 | |||
| 4ffa60be50 | |||
| 7da72d1295 | |||
| c9735e8ea9 | |||
| 8a7868d006 | |||
| c4e5242be0 | |||
| 935f7f19f3 | |||
| 5c9ae28937 | |||
| 8e27fc7f9b | |||
| e80d938ee5 | |||
| c87d1c2fb9 | |||
| c66d24b41a | |||
| 155b791d43 | |||
| 53acff167b | |||
| 96f63a6bf3 |
+16
-16
@@ -221,11 +221,11 @@ vs2017-x64:
|
||||
extends: .flatpak-defaults
|
||||
when: manual
|
||||
|
||||
# Only build Flatpak bundles automatically on master
|
||||
.flatpak-master:
|
||||
# Only build Flatpak bundles automatically on main
|
||||
.flatpak-main:
|
||||
extends: .flatpak-defaults
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
|
||||
flatpak-manual:demo:
|
||||
extends: .flatpak-manual
|
||||
@@ -233,8 +233,8 @@ flatpak-manual:demo:
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
|
||||
flatpak-master:demo:
|
||||
extends: .flatpak-master
|
||||
flatpak-main:demo:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
@@ -245,8 +245,8 @@ flatpak-manual:widget-factory:
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak-master:widget-factory:
|
||||
extends: .flatpak-master
|
||||
flatpak-main:widget-factory:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
@@ -257,8 +257,8 @@ flatpak-manual:icon-browser:
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
flatpak-master:icon-browser:
|
||||
extends: .flatpak-master
|
||||
flatpak-main:icon-browser:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
@@ -268,18 +268,18 @@ flatpak-master:icon-browser:
|
||||
# https://gitlab.gnome.org/GNOME/Initiatives/-/wikis/DevOps-with-Flatpak
|
||||
nightly demo:
|
||||
extends: '.publish_nightly'
|
||||
dependencies: ['flatpak-master:demo']
|
||||
needs: ['flatpak-master:demo']
|
||||
dependencies: ['flatpak-main:demo']
|
||||
needs: ['flatpak-main:demo']
|
||||
|
||||
nightly factory:
|
||||
extends: '.publish_nightly'
|
||||
dependencies: ['flatpak-master:widget-factory']
|
||||
needs: ['flatpak-master:widget-factory']
|
||||
dependencies: ['flatpak-main:widget-factory']
|
||||
needs: ['flatpak-main:widget-factory']
|
||||
|
||||
nightly icon-browser:
|
||||
extends: '.publish_nightly'
|
||||
dependencies: ['flatpak-master:icon-browser']
|
||||
needs: ['flatpak-master:icon-browser']
|
||||
dependencies: ['flatpak-main:icon-browser']
|
||||
needs: ['flatpak-main:icon-browser']
|
||||
|
||||
static-scan:
|
||||
image: $FEDORA_IMAGE
|
||||
@@ -346,4 +346,4 @@ publish-docs:
|
||||
- "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:
|
||||
- master
|
||||
- main
|
||||
|
||||
@@ -43,6 +43,6 @@ flatpak build-bundle \
|
||||
${appid}
|
||||
|
||||
# to be consumed by the nightly publish jobs
|
||||
if [[ $CI_COMMIT_BRANCH == master ]]; then
|
||||
if [[ $CI_COMMIT_BRANCH == main ]]; then
|
||||
tar cf repo.tar ${repodir}
|
||||
fi
|
||||
|
||||
@@ -268,7 +268,7 @@ aparser.add_argument('--job-id', metavar='ID',
|
||||
default=None)
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='master')
|
||||
default='main')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output HTML file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
|
||||
@@ -27,7 +27,7 @@ aparser.add_argument('--job-id', metavar='ID',
|
||||
default='Unknown')
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='master')
|
||||
default='main')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
# We need to add a new remote for the upstream master, since this script could
|
||||
# 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}..."
|
||||
@@ -16,7 +16,7 @@ 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/master` or `upstream/gtk-3-24`).
|
||||
# `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.
|
||||
@@ -36,7 +36,7 @@ exit_status=$?
|
||||
echo ""
|
||||
echo "Note that clang-format output is advisory and cannot always match the"
|
||||
echo "GTK coding style, documented at:"
|
||||
echo " https://gitlab.gnome.org/GNOME/gtk/blob/master/docs/CODING-STYLE"
|
||||
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."
|
||||
|
||||
@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
|
||||
fi
|
||||
pkg-config --modversion glib-2.0
|
||||
|
||||
if ! pkg-config --atleast-version=1.49.1 pango; then
|
||||
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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!--
|
||||
Please, read the CONTRIBUTING.md guide on how to file a new issue.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/master/CONTRIBUTING.md
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
## Steps to reproduce
|
||||
<!--
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!--
|
||||
Please, read the CONTRIBUTING.md guide on how to file a new issue.
|
||||
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/master/CONTRIBUTING.md
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
+1
-1
@@ -256,7 +256,7 @@ people committing to GTK to follow a few rules:
|
||||
0. Always write a meaningful commit message. Changes without a sufficient
|
||||
commit message will be reverted.
|
||||
|
||||
0. Never push to the `master` branch, or any stable branches, directly; you
|
||||
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
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
Overview of Changes
|
||||
===================
|
||||
|
||||
* Rename git `master` branch to `main`
|
||||
|
||||
Overview of Changes in 4.5.0
|
||||
============================
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
GTK — The GTK toolkit
|
||||
=====================
|
||||
|
||||
[](https://gitlab.gnome.org/GNOME/gtk/-/commits/master)
|
||||
[](https://gitlab.gnome.org/GNOME/gtk/-/commits/main)
|
||||
|
||||
General information
|
||||
-------------------
|
||||
@@ -40,7 +40,7 @@ Nightly documentation can be found at
|
||||
|
||||
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 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`
|
||||
@@ -116,6 +116,20 @@ 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
|
||||
```
|
||||
|
||||
How to report bugs
|
||||
------------------
|
||||
|
||||
|
||||
@@ -164,6 +164,21 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -177,7 +192,8 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -93,6 +93,21 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -106,7 +121,8 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -93,6 +93,21 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -106,7 +121,8 @@
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ do_cursors (GtkWidget *do_widget)
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/cursors/cursors.ui");
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_signal_connect (window, "destroy",
|
||||
@@ -34,9 +35,7 @@ do_cursors (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CURVE_TYPE_EDITOR (curve_editor_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (CurveEditor, curve_editor, CURVE, EDITOR, GtkWidget)
|
||||
|
||||
GtkWidget * curve_editor_new (void);
|
||||
|
||||
void curve_editor_set_edit (CurveEditor *self,
|
||||
gboolean edit);
|
||||
|
||||
void curve_editor_set_path (CurveEditor *self,
|
||||
GskPath *path);
|
||||
|
||||
GskPath * curve_editor_get_path (CurveEditor *self);
|
||||
|
||||
void curve_editor_set_stroke (CurveEditor *self,
|
||||
GskStroke *stroke);
|
||||
|
||||
const GskStroke * curve_editor_get_stroke (CurveEditor *self);
|
||||
|
||||
|
||||
void curve_editor_set_color (CurveEditor *self,
|
||||
GdkRGBA *color);
|
||||
|
||||
const GdkRGBA * curve_editor_get_color (CurveEditor *self);
|
||||
|
||||
gboolean curve_editor_get_show_outline (CurveEditor *self);
|
||||
|
||||
void curve_editor_set_show_outline (CurveEditor *self,
|
||||
gboolean show_outline);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,272 @@
|
||||
/* Path/Curve Editor
|
||||
*
|
||||
* This demo shows an elaborate curve editor that you would expect to find
|
||||
* in a vector graphics editor. It is built on top of GTK's path APIs.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "curve-editor.h"
|
||||
|
||||
|
||||
static GskPath *
|
||||
make_circle_path (void)
|
||||
{
|
||||
float w = 310;
|
||||
float h = 310;
|
||||
float cx = w / 2;
|
||||
float cy = h / 2;
|
||||
float pad = 20;
|
||||
float r = (w - 2 * pad) / 2;
|
||||
float k = 0.55228;
|
||||
float kr = k * r;
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_move_to (builder, cx, pad);
|
||||
gsk_path_builder_curve_to (builder, cx + kr, pad,
|
||||
w - pad, cy - kr,
|
||||
w - pad, cy);
|
||||
gsk_path_builder_curve_to (builder, w - pad, cy + kr,
|
||||
cx + kr, h - pad,
|
||||
cx, h - pad);
|
||||
gsk_path_builder_curve_to (builder, cx - kr, h - pad,
|
||||
pad, cy + kr,
|
||||
pad, cy);
|
||||
gsk_path_builder_curve_to (builder, pad, cy - kr,
|
||||
cx - kr, pad,
|
||||
cx, pad);
|
||||
gsk_path_builder_close (builder);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static void
|
||||
edit_changed (GtkToggleButton *button,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
curve_editor_set_edit (editor, gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GtkButton *button,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskPath *path;
|
||||
|
||||
path = make_circle_path ();
|
||||
curve_editor_set_path (editor, path);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
line_width_changed (GtkSpinButton *spin,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_width (stroke, gtk_spin_button_get_value (spin));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
cap_changed (GtkDropDown *combo,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_cap (stroke, (GskLineCap)gtk_drop_down_get_selected (combo));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
join_changed (GtkDropDown *combo,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_line_join (stroke, (GskLineJoin)gtk_drop_down_get_selected (combo));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
color_changed (GtkColorChooser *chooser,
|
||||
GParamSpec *pspec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_chooser_get_rgba (chooser, &color);
|
||||
curve_editor_set_color (editor, &color);
|
||||
}
|
||||
|
||||
static void
|
||||
stroke_toggled (GtkCheckButton *button,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
curve_editor_set_show_outline (editor, gtk_check_button_get_active (button));
|
||||
gtk_widget_queue_draw (GTK_WIDGET (editor));
|
||||
}
|
||||
|
||||
static void
|
||||
limit_changed (GtkSpinButton *spin,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_miter_limit (stroke, gtk_spin_button_get_value (spin));
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
}
|
||||
|
||||
static void
|
||||
dashes_changed (GtkEntry *entry,
|
||||
GParamSpec *spec,
|
||||
CurveEditor *editor)
|
||||
{
|
||||
const char *text;
|
||||
char **split;
|
||||
GArray *dash;
|
||||
GskStroke *stroke;
|
||||
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
||||
split = g_strsplit (text, " ", 0);
|
||||
|
||||
dash = g_array_new (FALSE, FALSE, sizeof (float));
|
||||
for (int i = 0; split[i] != NULL; i++)
|
||||
{
|
||||
double d;
|
||||
char *endp = 0;
|
||||
|
||||
d = g_strtod (split[i], &endp);
|
||||
if (*endp == '\0')
|
||||
g_array_append_vals (dash, (float[1]) { d }, 1);
|
||||
}
|
||||
|
||||
g_strfreev (split);
|
||||
|
||||
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
|
||||
gsk_stroke_set_dash (stroke, (const float *)dash->data, dash->len);
|
||||
curve_editor_set_stroke (editor, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
|
||||
g_array_free (dash, TRUE);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_curve (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
GtkWidget *demo;
|
||||
GtkWidget *edit_toggle;
|
||||
GtkWidget *reset_button;
|
||||
GtkWidget *titlebar;
|
||||
GtkWidget *stroke_toggle;
|
||||
GtkWidget *line_width_spin;
|
||||
GtkWidget *stroke_button;
|
||||
GtkWidget *popover;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *cap_combo;
|
||||
GtkWidget *join_combo;
|
||||
GtkWidget *color_button;
|
||||
GtkWidget *limit_spin;
|
||||
GtkWidget *dash_entry;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Curve Editor");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 310, 350);
|
||||
|
||||
edit_toggle = gtk_toggle_button_new ();
|
||||
gtk_button_set_icon_name (GTK_BUTTON (edit_toggle), "document-edit-symbolic");
|
||||
|
||||
reset_button = gtk_button_new_from_icon_name ("edit-undo-symbolic");
|
||||
|
||||
stroke_button = gtk_menu_button_new ();
|
||||
gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (stroke_button), "open-menu-symbolic");
|
||||
popover = gtk_popover_new ();
|
||||
gtk_menu_button_set_popover (GTK_MENU_BUTTON (stroke_button), popover);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
gtk_popover_set_child (GTK_POPOVER (popover), grid);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Color:"), 0, 0, 1, 1);
|
||||
color_button = gtk_color_button_new_with_rgba (&(GdkRGBA){ 0., 0., 0., 1.});
|
||||
gtk_grid_attach (GTK_GRID (grid), color_button, 1, 0, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line width:"), 0, 1, 1, 1);
|
||||
line_width_spin = gtk_spin_button_new_with_range (1, 20, 1);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), line_width_spin, 1, 1, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line cap:"), 0, 2, 1, 1);
|
||||
cap_combo = gtk_drop_down_new_from_strings ((const char *[]){"Butt", "Round", "Square", NULL});
|
||||
gtk_grid_attach (GTK_GRID (grid), cap_combo, 1, 2, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line join:"), 0, 3, 1, 1);
|
||||
join_combo = gtk_drop_down_new_from_strings ((const char *[]){"Miter", "Miter-clip", "Round", "Bevel", "Arcs", NULL});
|
||||
gtk_grid_attach (GTK_GRID (grid), join_combo, 1, 3, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Miter limit:"), 0, 4, 1, 1);
|
||||
limit_spin = gtk_spin_button_new_with_range (0, 10, 1);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (limit_spin), 1);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (limit_spin), 4);
|
||||
gtk_grid_attach (GTK_GRID (grid), limit_spin, 1, 4, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Dashes:"), 0, 5, 1, 1);
|
||||
dash_entry = gtk_entry_new ();
|
||||
gtk_grid_attach (GTK_GRID (grid), dash_entry, 1, 5, 1, 1);
|
||||
|
||||
stroke_toggle = gtk_check_button_new_with_label ("Show outline");
|
||||
gtk_grid_attach (GTK_GRID (grid), stroke_toggle, 1, 6, 1, 1);
|
||||
|
||||
titlebar = gtk_header_bar_new ();
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), edit_toggle);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), reset_button);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), stroke_button);
|
||||
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
|
||||
|
||||
demo = curve_editor_new ();
|
||||
|
||||
g_signal_connect (stroke_toggle, "toggled", G_CALLBACK (stroke_toggled), demo);
|
||||
g_signal_connect (edit_toggle, "notify::active", G_CALLBACK (edit_changed), demo);
|
||||
g_signal_connect (reset_button, "clicked", G_CALLBACK (reset), demo);
|
||||
g_signal_connect (cap_combo, "notify::selected", G_CALLBACK (cap_changed), demo);
|
||||
g_signal_connect (join_combo, "notify::selected", G_CALLBACK (join_changed), demo);
|
||||
g_signal_connect (color_button, "notify::rgba", G_CALLBACK (color_changed), demo);
|
||||
g_signal_connect (line_width_spin, "value-changed", G_CALLBACK (line_width_changed), demo);
|
||||
g_signal_connect (limit_spin, "value-changed", G_CALLBACK (limit_changed), demo);
|
||||
g_signal_connect (dash_entry, "notify::text", G_CALLBACK (dashes_changed), demo);
|
||||
|
||||
reset (NULL, CURVE_EDITOR (demo));
|
||||
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 6);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &(GdkRGBA) { 1, 0, 0, 1 });
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (cap_combo), GSK_LINE_CAP_ROUND);
|
||||
gtk_editable_set_text (GTK_EDITABLE (dash_entry), "0 8");
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), demo);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -249,6 +249,10 @@
|
||||
<gresource prefix="/video-player">
|
||||
<file>bbb.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/curve">
|
||||
<file>curve-editor.c</file>
|
||||
<file>curve-editor.h</file>
|
||||
</gresource>
|
||||
<gresource prefix="/sources">
|
||||
<file>application_demo.c</file>
|
||||
<file>assistant.c</file>
|
||||
@@ -266,6 +270,7 @@
|
||||
<file>css_pixbufs.c</file>
|
||||
<file>css_shadows.c</file>
|
||||
<file>cursors.c</file>
|
||||
<file>curve.c</file>
|
||||
<file>dialog.c</file>
|
||||
<file>drawingarea.c</file>
|
||||
<file>dropdown.c</file>
|
||||
@@ -286,6 +291,7 @@
|
||||
<file>gears.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>glyphs.c</file>
|
||||
<file>gltransition.c</file>
|
||||
<file>headerbar.c</file>
|
||||
<file>hypertext.c</file>
|
||||
@@ -324,6 +330,9 @@
|
||||
<file>paintable_symbolic.c</file>
|
||||
<file>panes.c</file>
|
||||
<file>password_entry.c</file>
|
||||
<file>path_fill.c</file>
|
||||
<file>path_maze.c</file>
|
||||
<file>path_text.c</file>
|
||||
<file>peg_solitaire.c</file>
|
||||
<file>pickers.c</file>
|
||||
<file>printing.c</file>
|
||||
@@ -408,6 +417,9 @@
|
||||
<gresource prefix="/fontrendering">
|
||||
<file>fontrendering.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/path_text">
|
||||
<file>path_text.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/Demo4">
|
||||
<file>icons/16x16/actions/application-exit.png</file>
|
||||
<file>icons/16x16/actions/document-new.png</file>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,8 @@
|
||||
* shows.
|
||||
*
|
||||
* We also demonstrate adding other things to a text view, such as
|
||||
* clickable icons.
|
||||
* clickable icons and widgets which can also replace a character
|
||||
* (try copying the ghost text).
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -113,7 +114,12 @@ show_page (GtkTextView *text_view,
|
||||
gtk_level_bar_set_value (GTK_LEVEL_BAR (child), 50);
|
||||
gtk_widget_set_size_request (child, 100, -1);
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
gtk_text_buffer_insert (buffer, &iter, ".", -1);
|
||||
gtk_text_buffer_insert (buffer, &iter, " and labels with ", -1);
|
||||
anchor = gtk_text_child_anchor_new_with_replacement ("👻");
|
||||
gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
|
||||
child = gtk_label_new ("ghost");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
gtk_text_buffer_insert (buffer, &iter, " text.", -1);
|
||||
}
|
||||
else if (page == 2)
|
||||
{
|
||||
|
||||
@@ -192,7 +192,7 @@ activate_about (GSimpleAction *action,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (s, "\tGTK\t%d.%d.%d\n",
|
||||
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
@@ -512,7 +512,7 @@ load_file (const char *demoname,
|
||||
|
||||
info_buffer = gtk_text_buffer_new (NULL);
|
||||
gtk_text_buffer_create_tag (info_buffer, "title",
|
||||
"font", "Sans 18",
|
||||
"size", 18 * 1024,
|
||||
"pixels-below-lines", 10,
|
||||
NULL);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ demos = files([
|
||||
'css_pixbufs.c',
|
||||
'css_shadows.c',
|
||||
'cursors.c',
|
||||
'curve.c',
|
||||
'dialog.c',
|
||||
'drawingarea.c',
|
||||
'dnd.c',
|
||||
@@ -34,6 +35,7 @@ demos = files([
|
||||
'gestures.c',
|
||||
'glarea.c',
|
||||
'gltransition.c',
|
||||
'glyphs.c',
|
||||
'headerbar.c',
|
||||
'hypertext.c',
|
||||
'iconscroll.c',
|
||||
@@ -70,6 +72,9 @@ demos = files([
|
||||
'paintable_symbolic.c',
|
||||
'panes.c',
|
||||
'password_entry.c',
|
||||
'path_fill.c',
|
||||
'path_maze.c',
|
||||
'path_text.c',
|
||||
'peg_solitaire.c',
|
||||
'pickers.c',
|
||||
'printing.c',
|
||||
@@ -128,6 +133,7 @@ extra_demo_sources = files([
|
||||
'script-names.c',
|
||||
'unicode-names.c',
|
||||
'suggestionentry.c',
|
||||
'curve-editor.c',
|
||||
])
|
||||
|
||||
if harfbuzz_dep.found() and pangoft_dep.found()
|
||||
@@ -140,7 +146,7 @@ if os_unix
|
||||
demos += files('pagesetup.c')
|
||||
endif
|
||||
|
||||
librsvg_dep = dependency('librsvg-2.0', version: '>= 2.46.0', required: false)
|
||||
librsvg_dep = dependency('librsvg-2.0', version: '>= 2.52.0', required: false)
|
||||
|
||||
if librsvg_dep.found()
|
||||
demos += files('paintable_svg.c')
|
||||
@@ -228,7 +234,9 @@ endif
|
||||
# Use a subset of compiler flags
|
||||
demo_cflags = []
|
||||
foreach flag: common_cflags
|
||||
if flag not in ['-Werror=missing-prototypes', '-Werror=missing-declarations', '-fvisibility=hidden']
|
||||
if flag not in ['-Werror=missing-prototypes', '-Wmissing-prototypes',
|
||||
'-Werror=missing-declarations', '-Wmissing-declarations',
|
||||
'-fvisibility=hidden']
|
||||
demo_cflags += flag
|
||||
endif
|
||||
endforeach
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/* Path/Text Fill
|
||||
*
|
||||
* This demo shows how to use PangoCairo to draw text with more than
|
||||
* just a single color.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
#include "gsk/gskpathdashprivate.h"
|
||||
|
||||
#define GTK_TYPE_PATH_PAINTABLE (gtk_path_paintable_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkPathPaintable, gtk_path_paintable, GTK, PATH_PAINTABLE, GObject)
|
||||
|
||||
struct _GtkPathPaintable
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GskPath *path;
|
||||
GdkPaintable *background;
|
||||
};
|
||||
|
||||
struct _GtkPathPaintableClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static int
|
||||
gtk_path_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return MAX (gdk_paintable_get_intrinsic_width (self->background), self->width);
|
||||
else
|
||||
return self->width;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_path_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return MAX (gdk_paintable_get_intrinsic_height (self->background), self->height);
|
||||
else
|
||||
return self->height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
#if 0
|
||||
gtk_snapshot_push_fill (snapshot, self->path, GSK_FILL_RULE_WINDING);
|
||||
#else
|
||||
GskStroke *stroke = gsk_stroke_new (2.0);
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
#endif
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (width, height),
|
||||
(GskColorStop[8]) {
|
||||
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
|
||||
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
|
||||
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
|
||||
},
|
||||
8);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
gtk_path_paintable_get_flags (GdkPaintable *paintable)
|
||||
{
|
||||
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
|
||||
|
||||
if (self->background)
|
||||
return gdk_paintable_get_flags (self->background);
|
||||
else
|
||||
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->get_intrinsic_width = gtk_path_paintable_get_intrinsic_width;
|
||||
iface->get_intrinsic_height = gtk_path_paintable_get_intrinsic_height;
|
||||
iface->snapshot = gtk_path_paintable_snapshot;
|
||||
iface->get_flags = gtk_path_paintable_get_flags;
|
||||
}
|
||||
|
||||
/* When defining the GType, we need to implement the GdkPaintable interface */
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkPathPaintable, gtk_path_paintable, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_path_paintable_paintable_init))
|
||||
|
||||
/* Here's the boilerplate for the GObject declaration.
|
||||
* We don't need to do anything special here, because we keep no
|
||||
* data of our own.
|
||||
*/
|
||||
static void
|
||||
gtk_path_paintable_class_init (GtkPathPaintableClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_paintable_init (GtkPathPaintable *self)
|
||||
{
|
||||
}
|
||||
|
||||
/* And finally, we add a simple constructor.
|
||||
* It is declared in the header so that the other examples
|
||||
* can use it.
|
||||
*/
|
||||
GdkPaintable *
|
||||
gtk_path_paintable_new (GskPath *path,
|
||||
GdkPaintable *background,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkPathPaintable *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_PATH_PAINTABLE, NULL);
|
||||
self->path = path;
|
||||
self->background = background;
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
|
||||
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
|
||||
}
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
return GDK_PAINTABLE (self);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_path_paintable_set_path (GtkPathPaintable *self,
|
||||
GskPath *path)
|
||||
{
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
self->path = gsk_path_ref (path);
|
||||
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_hexagon (GtkWidget *widget)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_move_to (builder, 120, 0);
|
||||
gsk_path_builder_line_to (builder, 360, 0);
|
||||
gsk_path_builder_line_to (builder, 480, 208);
|
||||
gsk_path_builder_line_to (builder, 360, 416);
|
||||
gsk_path_builder_line_to (builder, 120, 416);
|
||||
gsk_path_builder_line_to (builder, 0, 208);
|
||||
gsk_path_builder_close (builder);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_path_from_text (GtkWidget *widget)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoFontDescription *desc;
|
||||
GskPathBuilder *builder;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "Pango power!\nPango power!\nPango power!");
|
||||
desc = pango_font_description_from_string ("sans bold 36");
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_add_layout (builder, layout);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
build_path (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskPathBuilder *builder = user_data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (builder);
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CURVE:
|
||||
gsk_path_builder_curve_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, weight);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
update_path (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer measure)
|
||||
{
|
||||
float progress = gdk_frame_clock_get_frame_time (frame_clock) % (60 * G_USEC_PER_SEC) / (float) (30 * G_USEC_PER_SEC);
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path;
|
||||
graphene_point_t pos;
|
||||
graphene_vec2_t tangent;
|
||||
GskStroke *stroke;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_segment (builder,
|
||||
measure,
|
||||
#if 1
|
||||
0.0, gsk_path_measure_get_length (measure));
|
||||
#else
|
||||
progress > 1 ? (progress - 1) * gsk_path_measure_get_length (measure) : 0.0,
|
||||
(progress < 1 ? progress : 1.0) * gsk_path_measure_get_length (measure));
|
||||
#endif
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
stroke = gsk_stroke_new (1);
|
||||
gsk_stroke_set_dash (stroke, (float[2]) { 10, 5 }, 2);
|
||||
gsk_stroke_set_dash_offset (stroke, - (gdk_frame_clock_get_frame_time (frame_clock) % G_USEC_PER_SEC) * 15. / G_USEC_PER_SEC);
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_dash (path, stroke, 0.2, build_path, builder);
|
||||
gsk_path_unref (path);
|
||||
|
||||
gsk_path_measure_get_point (measure,
|
||||
(progress > 1 ? (progress - 1) : progress) * gsk_path_measure_get_length (measure),
|
||||
&pos,
|
||||
&tangent);
|
||||
gsk_path_builder_move_to (builder, pos.x + 5 * graphene_vec2_get_x (&tangent), pos.y + 5 * graphene_vec2_get_y (&tangent));
|
||||
gsk_path_builder_line_to (builder, pos.x + 3 * graphene_vec2_get_y (&tangent), pos.y + 3 * graphene_vec2_get_x (&tangent));
|
||||
gsk_path_builder_line_to (builder, pos.x - 3 * graphene_vec2_get_y (&tangent), pos.y - 3 * graphene_vec2_get_x (&tangent));
|
||||
gsk_path_builder_close (builder);
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_path_paintable_set_path (GTK_PATH_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget))),
|
||||
path);
|
||||
gsk_path_unref (path);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_fill (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *picture;
|
||||
GdkPaintable *paintable;
|
||||
GtkMediaStream *stream;
|
||||
GskPath *path;
|
||||
graphene_rect_t bounds;
|
||||
GskPathMeasure *measure;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
#if 0
|
||||
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
#else
|
||||
stream = gtk_nuclear_media_stream_new ();
|
||||
#endif
|
||||
gtk_media_stream_play (stream);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
|
||||
path = create_hexagon (window);
|
||||
path = create_path_from_text (window);
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
|
||||
paintable = gtk_path_paintable_new (path,
|
||||
GDK_PAINTABLE (stream),
|
||||
bounds.origin.x + bounds.size.width,
|
||||
bounds.origin.y + bounds.size.height);
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
measure = gsk_path_measure_new (path);
|
||||
gtk_widget_add_tick_callback (picture, update_path, measure, (GDestroyNotify) gsk_path_measure_unref);
|
||||
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (picture), FALSE);
|
||||
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
|
||||
g_object_unref (paintable);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/* Path/Maze
|
||||
* #Keywords: game, mouse
|
||||
*
|
||||
* This demo shows how to use a GskPath to create a maze and use
|
||||
* gsk_path_measure_get_closest_point() to check the mouse stays
|
||||
* on the path.
|
||||
*
|
||||
* It also shows off the performance of GskPath (or not) as this
|
||||
* is a rather complex path.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
#define MAZE_GRID_SIZE 20
|
||||
#define MAZE_STROKE_SIZE_ACTIVE (MAZE_GRID_SIZE - 4)
|
||||
#define MAZE_STROKE_SIZE_INACTIVE (MAZE_GRID_SIZE - 12)
|
||||
#define MAZE_WIDTH 31
|
||||
#define MAZE_HEIGHT 21
|
||||
|
||||
#define GTK_TYPE_MAZE (gtk_maze_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkMaze, gtk_maze, GTK, MAZE, GtkWidget)
|
||||
|
||||
struct _GtkMaze
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GskPath *path;
|
||||
GskPathMeasure *measure;
|
||||
GdkPaintable *background;
|
||||
|
||||
gboolean active;
|
||||
};
|
||||
|
||||
struct _GtkMazeClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkMaze, gtk_maze, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_maze_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = self->width;
|
||||
else
|
||||
*minimum = *natural = self->height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_snapshot (GtkWidget *widget,
|
||||
GdkSnapshot *snapshot)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (widget);
|
||||
double width = gtk_widget_get_width (widget);
|
||||
double height = gtk_widget_get_height (widget);
|
||||
GskStroke *stroke;
|
||||
|
||||
stroke = gsk_stroke_new (MAZE_STROKE_SIZE_INACTIVE);
|
||||
if (self->active)
|
||||
gsk_stroke_set_line_width (stroke, MAZE_STROKE_SIZE_ACTIVE);
|
||||
gsk_stroke_set_line_join (stroke, GSK_LINE_JOIN_ROUND);
|
||||
gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND);
|
||||
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
|
||||
if (self->background)
|
||||
{
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (width, height),
|
||||
(GskColorStop[8]) {
|
||||
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
|
||||
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
|
||||
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
|
||||
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
|
||||
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
|
||||
},
|
||||
8);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_dispose (GObject *object)
|
||||
{
|
||||
GtkMaze *self = GTK_MAZE (object);
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_matched (self->background, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
|
||||
g_clear_object (&self->background);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_maze_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_class_init (GtkMazeClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_maze_dispose;
|
||||
|
||||
widget_class->measure = gtk_maze_measure;
|
||||
widget_class->snapshot = gtk_maze_snapshot;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkMaze *self)
|
||||
{
|
||||
if (!self->active)
|
||||
return;
|
||||
|
||||
if (gsk_path_measure_get_closest_point (self->measure, &GRAPHENE_POINT_INIT (x, y), NULL) <= MAZE_STROKE_SIZE_ACTIVE / 2.0f)
|
||||
return;
|
||||
|
||||
self->active = FALSE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_leave (GtkEventControllerMotion *controller,
|
||||
GtkMaze *self)
|
||||
{
|
||||
if (!self->active)
|
||||
{
|
||||
self->active = TRUE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_init (GtkMaze *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->active = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_maze_set_path (GtkMaze *self,
|
||||
GskPath *path)
|
||||
{
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
g_clear_pointer (&self->measure, gsk_path_measure_unref);
|
||||
self->path = gsk_path_ref (path);
|
||||
self->measure = gsk_path_measure_new (path);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_maze_new (GskPath *path,
|
||||
GdkPaintable *background,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkMaze *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_MAZE, NULL);
|
||||
|
||||
gtk_maze_set_path (self, path);
|
||||
gsk_path_unref (path);
|
||||
self->background = background;
|
||||
if (self->background)
|
||||
{
|
||||
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gtk_widget_queue_draw), self);
|
||||
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gtk_widget_queue_resize), self);
|
||||
}
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
static void
|
||||
add_point_to_maze (GtkBitset *maze,
|
||||
GskPathBuilder *builder,
|
||||
guint x,
|
||||
guint y)
|
||||
{
|
||||
gboolean set[4] = { };
|
||||
guint dir;
|
||||
|
||||
gtk_bitset_add (maze, y * MAZE_WIDTH + x);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
set[0] = set[0] || x == 0 || gtk_bitset_contains (maze, y * MAZE_WIDTH + x - 1);
|
||||
set[1] = set[1] || y == 0 || gtk_bitset_contains (maze, (y - 1) * MAZE_WIDTH + x);
|
||||
set[2] = set[2] || x + 1 == MAZE_WIDTH || gtk_bitset_contains (maze, y * MAZE_WIDTH + x + 1);
|
||||
set[3] = set[3] || y + 1 == MAZE_HEIGHT || gtk_bitset_contains (maze, (y + 1) * MAZE_WIDTH + x);
|
||||
|
||||
if (set[0] && set[1] && set[2] && set[3])
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
dir = g_random_int_range (0, 4);
|
||||
}
|
||||
while (set[dir]);
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x - 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x - 1, y);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y - 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y - 1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 1.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x + 1, y);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 1.5) * MAZE_GRID_SIZE);
|
||||
add_point_to_maze (maze, builder, x, y + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
create_path_for_maze (GtkWidget *widget)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GtkBitset *maze;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
maze = gtk_bitset_new_empty ();
|
||||
/* make sure the outer lines are unreachable:
|
||||
* Set the full range, then remove the center again. */
|
||||
gtk_bitset_add_range (maze, 0, MAZE_WIDTH * MAZE_HEIGHT);
|
||||
gtk_bitset_remove_rectangle (maze, MAZE_WIDTH + 1, MAZE_WIDTH - 2, MAZE_HEIGHT - 2, MAZE_WIDTH);
|
||||
|
||||
/* Fill the maze */
|
||||
add_point_to_maze (maze, builder, MAZE_WIDTH / 2, MAZE_HEIGHT / 2);
|
||||
|
||||
/* Add start and stop lines */
|
||||
gsk_path_builder_move_to (builder, 1.5 * MAZE_GRID_SIZE, -0.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, 1.5 * MAZE_GRID_SIZE, 1.5 * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_move_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT - 1.5) * MAZE_GRID_SIZE);
|
||||
gsk_path_builder_line_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT + 0.5) * MAZE_GRID_SIZE);
|
||||
|
||||
|
||||
gtk_bitset_unref (maze);
|
||||
|
||||
return gsk_path_builder_free_to_path (builder);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_maze (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *maze;
|
||||
GtkMediaStream *stream;
|
||||
GskPath *path;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Follow the maze with the mouse");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
#if 0
|
||||
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
#else
|
||||
stream = gtk_nuclear_media_stream_new ();
|
||||
#endif
|
||||
gtk_media_stream_play (stream);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
|
||||
path = create_path_for_maze (window);
|
||||
|
||||
maze = gtk_maze_new (path,
|
||||
GDK_PAINTABLE (stream),
|
||||
MAZE_WIDTH * MAZE_GRID_SIZE,
|
||||
MAZE_HEIGHT * MAZE_GRID_SIZE);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), maze);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -0,0 +1,594 @@
|
||||
/* Path/Curved Text
|
||||
*
|
||||
* This demo shows how to use GskPath to animate a path along another path.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GTK_TYPE_PATH_WIDGET (gtk_path_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkPathWidget, gtk_path_widget, GTK, PATH_WIDGET, GtkWidget)
|
||||
|
||||
#define POINT_SIZE 8
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TEXT,
|
||||
PROP_EDITABLE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
struct _GtkPathWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
char *text;
|
||||
gboolean editable;
|
||||
|
||||
graphene_point_t points[4];
|
||||
|
||||
guint active_point;
|
||||
float line_closest;
|
||||
|
||||
GskPath *line_path;
|
||||
GskPathMeasure *line_measure;
|
||||
GskPath *text_path;
|
||||
|
||||
GdkPaintable *background;
|
||||
};
|
||||
|
||||
struct _GtkPathWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
G_DEFINE_TYPE (GtkPathWidget, gtk_path_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static GskPath *
|
||||
create_path_from_text (GtkWidget *widget,
|
||||
const char *text)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
cairo_path_t *path;
|
||||
PangoLayout *layout;
|
||||
PangoFontDescription *desc;
|
||||
GskPath *result;
|
||||
|
||||
surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, text);
|
||||
desc = pango_font_description_from_string ("sans bold 36");
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
cairo_move_to (cr, 0, - pango_layout_get_baseline (layout) / (double) PANGO_SCALE);
|
||||
pango_cairo_layout_path (cr, layout);
|
||||
path = cairo_copy_path_flat (cr);
|
||||
result = gsk_path_new_from_cairo (path);
|
||||
|
||||
cairo_path_destroy (path);
|
||||
g_object_unref (layout);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskPathMeasure *measure;
|
||||
GskPathBuilder *builder;
|
||||
double scale;
|
||||
} GtkPathTransform;
|
||||
|
||||
static void
|
||||
gtk_path_transform_point (GskPathMeasure *measure,
|
||||
const graphene_point_t *pt,
|
||||
float scale,
|
||||
graphene_point_t *res)
|
||||
{
|
||||
graphene_vec2_t tangent;
|
||||
|
||||
gsk_path_measure_get_point (measure, pt->x * scale, res, &tangent);
|
||||
|
||||
res->x -= pt->y * scale * graphene_vec2_get_y (&tangent);
|
||||
res->y += pt->y * scale * graphene_vec2_get_x (&tangent);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_path_transform_op (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPathTransform *transform = data;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
{
|
||||
graphene_point_t res;
|
||||
gtk_path_transform_point (transform->measure, &pts[0], transform->scale, &res);
|
||||
gsk_path_builder_move_to (transform->builder, res.x, res.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_LINE:
|
||||
{
|
||||
graphene_point_t res;
|
||||
gtk_path_transform_point (transform->measure, &pts[1], transform->scale, &res);
|
||||
gsk_path_builder_line_to (transform->builder, res.x, res.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CURVE:
|
||||
{
|
||||
graphene_point_t res[3];
|
||||
gtk_path_transform_point (transform->measure, &pts[1], transform->scale, &res[0]);
|
||||
gtk_path_transform_point (transform->measure, &pts[2], transform->scale, &res[1]);
|
||||
gtk_path_transform_point (transform->measure, &pts[3], transform->scale, &res[2]);
|
||||
gsk_path_builder_curve_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CONIC:
|
||||
{
|
||||
graphene_point_t res[2];
|
||||
gtk_path_transform_point (transform->measure, &pts[1], transform->scale, &res[0]);
|
||||
gtk_path_transform_point (transform->measure, &pts[2], transform->scale, &res[1]);
|
||||
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, weight);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_PATH_CLOSE:
|
||||
gsk_path_builder_close (transform->builder);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
gtk_path_transform (GskPathMeasure *measure,
|
||||
GskPath *path)
|
||||
{
|
||||
GtkPathTransform transform = { measure, gsk_path_builder_new () };
|
||||
graphene_rect_t bounds;
|
||||
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
if (bounds.origin.x + bounds.size.width > 0)
|
||||
transform.scale = gsk_path_measure_get_length (measure) / (bounds.origin.x + bounds.size.width);
|
||||
else
|
||||
transform.scale = 1.0f;
|
||||
|
||||
gsk_path_foreach (path, GSK_PATH_FOREACH_ALLOW_CURVE, gtk_path_transform_op, &transform);
|
||||
|
||||
return gsk_path_builder_free_to_path (transform.builder);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_clear_text_path (GtkPathWidget *self)
|
||||
{
|
||||
g_clear_pointer (&self->text_path, gsk_path_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_clear_paths (GtkPathWidget *self)
|
||||
{
|
||||
gtk_path_widget_clear_text_path (self);
|
||||
|
||||
g_clear_pointer (&self->line_path, gsk_path_unref);
|
||||
g_clear_pointer (&self->line_measure, gsk_path_measure_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_create_text_path (GtkPathWidget *self)
|
||||
{
|
||||
GskPath *path;
|
||||
|
||||
gtk_path_widget_clear_text_path (self);
|
||||
|
||||
if (self->line_measure == NULL)
|
||||
return;
|
||||
|
||||
path = create_path_from_text (GTK_WIDGET (self), self->text);
|
||||
self->text_path = gtk_path_transform (self->line_measure, path);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_create_paths (GtkPathWidget *self)
|
||||
{
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
GskPathBuilder *builder;
|
||||
|
||||
gtk_path_widget_clear_paths (self);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_move_to (builder,
|
||||
self->points[0].x * width, self->points[0].y * height);
|
||||
gsk_path_builder_curve_to (builder,
|
||||
self->points[1].x * width, self->points[1].y * height,
|
||||
self->points[2].x * width, self->points[2].y * height,
|
||||
self->points[3].x * width, self->points[3].y * height);
|
||||
self->line_path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
self->line_measure = gsk_path_measure_new (self->line_path);
|
||||
|
||||
gtk_path_widget_create_text_path (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_path_widget_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
|
||||
double width = gtk_widget_get_width (widget);
|
||||
double height = gtk_widget_get_height (widget);
|
||||
GskPath *path;
|
||||
GskStroke *stroke;
|
||||
gsize i;
|
||||
|
||||
/* frosted glass the background */
|
||||
gtk_snapshot_push_blur (snapshot, 100);
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 0.5 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
/* draw the text */
|
||||
if (self->text_path)
|
||||
{
|
||||
gtk_snapshot_push_fill (snapshot, self->text_path, GSK_FILL_RULE_WINDING);
|
||||
gdk_paintable_snapshot (self->background, snapshot, width, height);
|
||||
|
||||
/* ... with an emboss effect */
|
||||
stroke = gsk_stroke_new (2.0);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(1, 1));
|
||||
gtk_snapshot_push_stroke (snapshot, self->text_path, stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 0.2 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
if (self->editable && self->line_path)
|
||||
{
|
||||
/* draw the control line */
|
||||
stroke = gsk_stroke_new (1.0);
|
||||
gtk_snapshot_push_stroke (snapshot, self->line_path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
if (self->line_closest >= 0)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
graphene_point_t closest;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_measure_get_point (self->line_measure, self->line_closest, &closest, NULL);
|
||||
gsk_path_builder_add_circle (builder, &closest, POINT_SIZE);
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
if (self->editable && self->line_path)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
/* draw the points */
|
||||
builder = gsk_path_builder_new ();
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), POINT_SIZE);
|
||||
}
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
stroke = gsk_stroke_new (1.0);
|
||||
gtk_snapshot_push_stroke (snapshot, path, stroke);
|
||||
gsk_stroke_free (stroke);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_text (GtkPathWidget *self,
|
||||
const char *text)
|
||||
{
|
||||
if (g_strcmp0 (self->text, text) == 0)
|
||||
return;
|
||||
|
||||
g_free (self->text);
|
||||
self->text = g_strdup (text);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_editable (GtkPathWidget *self,
|
||||
gboolean editable)
|
||||
{
|
||||
if (self->editable == editable)
|
||||
return;
|
||||
|
||||
self->editable = editable;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EDITABLE]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TEXT:
|
||||
gtk_path_widget_set_text (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE:
|
||||
gtk_path_widget_set_editable (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, self->text);
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE:
|
||||
g_value_set_boolean (value, self->editable);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_dispose (GObject *object)
|
||||
{
|
||||
GtkPathWidget *self = GTK_PATH_WIDGET (object);
|
||||
|
||||
gtk_path_widget_clear_paths (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_path_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_class_init (GtkPathWidgetClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_path_widget_dispose;
|
||||
object_class->set_property = gtk_path_widget_set_property;
|
||||
object_class->get_property = gtk_path_widget_get_property;
|
||||
|
||||
widget_class->size_allocate = gtk_path_widget_allocate;
|
||||
widget_class->snapshot = gtk_path_widget_snapshot;
|
||||
|
||||
properties[PROP_TEXT] =
|
||||
g_param_spec_string ("text",
|
||||
"text",
|
||||
"Text transformed along a path",
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_EDITABLE] =
|
||||
g_param_spec_boolean ("editable",
|
||||
"editable",
|
||||
"If the path can be edited by the user",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkGestureDrag *gesture,
|
||||
double x,
|
||||
double y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
graphene_point_t mouse = GRAPHENE_POINT_INIT (x, y);
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (graphene_point_distance (&GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), &mouse, NULL, NULL) <= POINT_SIZE)
|
||||
{
|
||||
self->active_point = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 4)
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_update (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
double width = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
double height = gtk_widget_get_height (GTK_WIDGET (self));
|
||||
double start_x, start_y;
|
||||
|
||||
gtk_gesture_drag_get_start_point (drag, &start_x, &start_y);
|
||||
|
||||
self->points[self->active_point] = GRAPHENE_POINT_INIT ((start_x + offset_x) / width,
|
||||
(start_y + offset_y) / height);
|
||||
self->points[self->active_point].x = CLAMP (self->points[self->active_point].x, 0, 1);
|
||||
self->points[self->active_point].y = CLAMP (self->points[self->active_point].y, 0, 1);
|
||||
|
||||
gtk_path_widget_create_paths (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
gsk_path_measure_get_closest_point_full (self->line_measure,
|
||||
&GRAPHENE_POINT_INIT (x, y),
|
||||
INFINITY,
|
||||
NULL, NULL,
|
||||
&self->line_closest,
|
||||
NULL);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_leave (GtkEventControllerMotion *controller,
|
||||
GtkPathWidget *self)
|
||||
{
|
||||
self->line_closest = -1;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_path_widget_init (GtkPathWidget *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (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_update), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
|
||||
g_signal_connect (controller, "enter", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
|
||||
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->line_closest = -1;
|
||||
|
||||
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
|
||||
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
|
||||
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);
|
||||
self->points[3] = GRAPHENE_POINT_INIT (0.9, 0.9);
|
||||
|
||||
self->background = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
|
||||
|
||||
gtk_path_widget_set_text (self, "It's almost working");
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_path_widget_new (void)
|
||||
{
|
||||
GtkPathWidget *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_PATH_WIDGET, NULL);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_path_text (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
|
||||
g_type_ensure (GTK_TYPE_PATH_WIDGET);
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/path_text/path_text.ui");
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="title" translatable="yes">Text along a Path</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="edit-toggle">
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkRevealer">
|
||||
<property name="reveal-child" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="text">
|
||||
<property name="text">Through the looking glass</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPathWidget" id="view">
|
||||
<property name="editable" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
|
||||
<property name="text" bind-source="text" bind-property="text" bind-flags="sync-create"></property>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="vexpand">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -47,22 +47,24 @@ static int
|
||||
svg_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
SvgPaintable *self = SVG_PAINTABLE (paintable);
|
||||
RsvgDimensionData data;
|
||||
double width;
|
||||
|
||||
rsvg_handle_get_dimensions (self->handle, &data);
|
||||
if (!rsvg_handle_get_intrinsic_size_in_pixels (self->handle, &width, NULL))
|
||||
return 0;
|
||||
|
||||
return data.width;
|
||||
return ceil (width);
|
||||
}
|
||||
|
||||
static int
|
||||
svg_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
SvgPaintable *self = SVG_PAINTABLE (paintable);
|
||||
RsvgDimensionData data;
|
||||
double height;
|
||||
|
||||
rsvg_handle_get_dimensions (self->handle, &data);
|
||||
if (!rsvg_handle_get_intrinsic_size_in_pixels (self->handle, NULL, &height))
|
||||
return 0;
|
||||
|
||||
return data.height;
|
||||
return ceil (height);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+11
-5
@@ -1,6 +1,11 @@
|
||||
/* Text View/Tabs
|
||||
*
|
||||
* GtkTextView can position text at fixed positions, using tabs.
|
||||
* Tabs can specify alignment, and also allow aligning numbers
|
||||
* on the decimal point.
|
||||
*
|
||||
* The example here has three tabs, with left, numeric and right
|
||||
* alignment.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -22,7 +27,7 @@ do_tabs (GtkWidget *do_widget)
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Tabs");
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 330, 330);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 330, 130);
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
@@ -35,17 +40,18 @@ do_tabs (GtkWidget *do_widget)
|
||||
|
||||
tabs = pango_tab_array_new (3, TRUE);
|
||||
pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, 0);
|
||||
pango_tab_array_set_tab (tabs, 1, PANGO_TAB_LEFT, 100);
|
||||
pango_tab_array_set_tab (tabs, 2, PANGO_TAB_LEFT, 200);
|
||||
pango_tab_array_set_tab (tabs, 1, PANGO_TAB_DECIMAL, 150);
|
||||
pango_tab_array_set_decimal_point (tabs, 1, '.');
|
||||
pango_tab_array_set_tab (tabs, 2, PANGO_TAB_RIGHT, 290);
|
||||
gtk_text_view_set_tabs (GTK_TEXT_VIEW (view), tabs);
|
||||
pango_tab_array_free (tabs);
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
gtk_text_buffer_set_text (buffer, "one\ttwo\tthree\nfour\tfive\tsix\nseven\teight\tnine", -1);
|
||||
gtk_text_buffer_set_text (buffer, "one\t2.0\tthree\nfour\t5.555\tsix\nseven\t88.88\tnine", -1);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), view);
|
||||
|
||||
@@ -72,7 +72,7 @@ about_activated (GSimpleAction *action,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (s, "\tGTK\t%d.%d.%d\n",
|
||||
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
@@ -79,7 +79,7 @@ activate_about (GSimpleAction *action,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (s, "\tGTK\t%d.%d.%d\n",
|
||||
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
@@ -336,12 +336,39 @@ text_view_query_tooltip_cb (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_bytes (NodeEditorWindow *self,
|
||||
GBytes *bytes);
|
||||
|
||||
static void
|
||||
load_error (NodeEditorWindow *self,
|
||||
const char *error_message)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
GtkSnapshot *snapshot;
|
||||
GskRenderNode *node;
|
||||
GBytes *bytes;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), error_message);
|
||||
pango_layout_set_width (layout, 300 * PANGO_SCALE);
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA) { 0.7, 0.13, 0.13, 1.0 });
|
||||
node = gtk_snapshot_free_to_node (snapshot);
|
||||
bytes = gsk_render_node_serialize (node);
|
||||
|
||||
load_bytes (self, bytes);
|
||||
|
||||
gsk_render_node_unref (node);
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_bytes (NodeEditorWindow *self,
|
||||
GBytes *bytes)
|
||||
{
|
||||
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
|
||||
{
|
||||
load_error (self, "Invalid UTF-8");
|
||||
g_bytes_unref (bytes);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -359,11 +386,16 @@ static gboolean
|
||||
load_file_contents (NodeEditorWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GBytes *bytes;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||
if (bytes == NULL)
|
||||
return FALSE;
|
||||
{
|
||||
load_error (self, error->message);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return load_bytes (self, bytes);
|
||||
}
|
||||
@@ -473,17 +505,18 @@ node_editor_window_load (NodeEditorWindow *self,
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_object (&self->file_monitor);
|
||||
|
||||
if (!load_file_contents (self, file))
|
||||
return FALSE;
|
||||
|
||||
g_clear_object (&self->file_monitor);
|
||||
self->file_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
|
||||
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("couldn't monitor file: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_clear_object (&self->file_monitor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -161,9 +161,10 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned">
|
||||
<property name="shrink-start-child">false</property>
|
||||
<property name="shrink-end-child">false</property>
|
||||
<property name="position">400</property>
|
||||
<child>
|
||||
<property name="start-child">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="hexpand">1</property>
|
||||
@@ -184,8 +185,8 @@
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
</property>
|
||||
<property name="end-child">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
@@ -231,7 +232,7 @@
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
||||
@@ -42,7 +42,7 @@ update_statusbar (void)
|
||||
const char *print_str;
|
||||
|
||||
gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 0);
|
||||
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (buffer,
|
||||
&iter,
|
||||
gtk_text_buffer_get_insert (buffer));
|
||||
@@ -56,7 +56,7 @@ update_statusbar (void)
|
||||
GtkPrintOperation *op = active_prints->data;
|
||||
print_str = gtk_print_operation_get_status_string (op);
|
||||
}
|
||||
|
||||
|
||||
msg = g_strdup_printf ("%d, %d%s %s",
|
||||
row, col,
|
||||
file_changed?" - Modified":"",
|
||||
@@ -188,10 +188,10 @@ save_file (GFile *save_filename)
|
||||
"Error saving to file %s:\n%s",
|
||||
display_name,
|
||||
error->message);
|
||||
|
||||
|
||||
g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (error_dialog);
|
||||
|
||||
|
||||
g_error_free (error);
|
||||
g_object_unref (info);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ begin_print (GtkPrintOperation *operation,
|
||||
pango_font_description_free (desc);
|
||||
|
||||
pango_layout_set_width (print_data->layout, width * PANGO_SCALE);
|
||||
|
||||
|
||||
pango_layout_set_text (print_data->layout, print_data->text, -1);
|
||||
|
||||
num_lines = pango_layout_get_line_count (print_data->layout);
|
||||
@@ -241,7 +241,7 @@ begin_print (GtkPrintOperation *operation,
|
||||
{
|
||||
PangoRectangle ink_rect, logical_rect;
|
||||
double line_height;
|
||||
|
||||
|
||||
layout_line = pango_layout_get_line (print_data->layout, line);
|
||||
pango_layout_line_get_extents (layout_line, &ink_rect, &logical_rect);
|
||||
|
||||
@@ -258,7 +258,7 @@ begin_print (GtkPrintOperation *operation,
|
||||
|
||||
page_breaks = g_list_reverse (page_breaks);
|
||||
gtk_print_operation_set_n_pages (operation, g_list_length (page_breaks) + 1);
|
||||
|
||||
|
||||
print_data->page_breaks = page_breaks;
|
||||
}
|
||||
|
||||
@@ -287,11 +287,11 @@ draw_page (GtkPrintOperation *operation,
|
||||
end = pango_layout_get_line_count (print_data->layout);
|
||||
else
|
||||
end = GPOINTER_TO_INT (pagebreak->data);
|
||||
|
||||
|
||||
cr = gtk_print_context_get_cairo_context (context);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
|
||||
i = 0;
|
||||
start_pos = 0;
|
||||
iter = pango_layout_get_iter (print_data->layout);
|
||||
@@ -307,12 +307,12 @@ draw_page (GtkPrintOperation *operation,
|
||||
|
||||
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
|
||||
baseline = pango_layout_iter_get_baseline (iter);
|
||||
|
||||
|
||||
if (i == start)
|
||||
start_pos = logical_rect.y / 1024.0;
|
||||
|
||||
|
||||
cairo_move_to (cr, logical_rect.x / 1024.0, baseline / 1024.0 - start_pos);
|
||||
|
||||
|
||||
pango_cairo_show_layout_line (cr, line);
|
||||
}
|
||||
i++;
|
||||
@@ -383,9 +383,9 @@ print_done (GtkPrintOperation *op,
|
||||
{
|
||||
|
||||
GtkWidget *error_dialog;
|
||||
|
||||
|
||||
gtk_print_operation_get_error (op, &error);
|
||||
|
||||
|
||||
error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
@@ -405,13 +405,13 @@ print_done (GtkPrintOperation *op,
|
||||
g_free (print_data->text);
|
||||
g_free (print_data->font);
|
||||
g_free (print_data);
|
||||
|
||||
|
||||
if (!gtk_print_operation_is_finished (op))
|
||||
{
|
||||
g_object_ref (op);
|
||||
active_prints = g_list_append (active_prints, op);
|
||||
update_statusbar ();
|
||||
|
||||
|
||||
/* This ref is unref:ed when we get the final state change */
|
||||
g_signal_connect (op, "status_changed",
|
||||
G_CALLBACK (status_changed_cb), NULL);
|
||||
@@ -628,7 +628,7 @@ activate_about (GSimpleAction *action,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (sysinfo, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (sysinfo, "\tGTK\t%d.%d.%d\n",
|
||||
g_string_append_printf (sysinfo, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
@@ -78,6 +78,21 @@ change_theme_state (GSimpleAction *action,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
change_fullscreen (GSimpleAction *action,
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWindow *window = user_data;
|
||||
|
||||
if (g_variant_get_boolean (state))
|
||||
gtk_window_fullscreen (window);
|
||||
else
|
||||
gtk_window_unfullscreen (window);
|
||||
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static GtkWidget *page_stack;
|
||||
|
||||
static void
|
||||
@@ -283,7 +298,7 @@ activate_about (GSimpleAction *action,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (s, "\tGTK\t%d.%d.%d\n",
|
||||
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
@@ -384,7 +399,7 @@ print_operation_done (GtkPrintOperation *op,
|
||||
g_clear_error (&error);
|
||||
break;
|
||||
case GTK_PRINT_OPERATION_RESULT_APPLY:
|
||||
break;
|
||||
break;
|
||||
case GTK_PRINT_OPERATION_RESULT_CANCEL:
|
||||
g_print ("Printing was canceled\n");
|
||||
break;
|
||||
@@ -2012,11 +2027,12 @@ activate (GApplication *app)
|
||||
GMenuModel *model;
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "dark", NULL, NULL, "false", change_dark_state },
|
||||
{ "theme", NULL, "s", "'current'", change_theme_state },
|
||||
{ "theme", NULL, "s", "'current'", change_theme_state },
|
||||
{ "transition", NULL, NULL, "true", change_transition_state },
|
||||
{ "search", activate_search, NULL, NULL, NULL },
|
||||
{ "delete", activate_delete, NULL, NULL, NULL },
|
||||
{ "busy", get_busy, NULL, NULL, NULL },
|
||||
{ "fullscreen", NULL, NULL, "false", change_fullscreen },
|
||||
{ "background", activate_background, NULL, NULL, NULL },
|
||||
{ "open", activate_open, NULL, NULL, NULL },
|
||||
{ "record", activate_record, NULL, NULL, NULL },
|
||||
@@ -2182,7 +2198,7 @@ activate (GApplication *app)
|
||||
g_object_set_data (G_OBJECT (window), "searchbar", widget);
|
||||
|
||||
widget = (GtkWidget *)gtk_builder_get_object (builder, "infobar");
|
||||
g_signal_connect (widget, "response", G_CALLBACK (info_bar_response), NULL);
|
||||
g_signal_connect (widget, "response", G_CALLBACK (info_bar_response), NULL);
|
||||
g_object_set_data (G_OBJECT (window), "infobar", widget);
|
||||
|
||||
dialog = (GtkWidget *)gtk_builder_get_object (builder, "info_dialog");
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
<attribute name="label" translatable="yes">Get Busy</attribute>
|
||||
<attribute name="action">win.busy</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Fullscreen</attribute>
|
||||
<attribute name="action">win.fullscreen</attribute>
|
||||
</item>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">Style</attribute>
|
||||
<section>
|
||||
@@ -2923,7 +2927,7 @@ microphone-sensitivity-medium-symbolic</property>
|
||||
<property name="resizable">0</property>
|
||||
<property name="modal">1</property>
|
||||
<property name="text" translatable="1">Do something?</property>
|
||||
<property name="secondary-text" translatable="1">If you do something,
|
||||
<property name="secondary-text" translatable="1">If you don't do something,
|
||||
bad things might happen.</property>
|
||||
<property name="hide-on-close">1</property>
|
||||
<child type="action">
|
||||
|
||||
@@ -3,6 +3,7 @@ version = "@version@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/gtk/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/gdk4/"
|
||||
authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
|
||||
@@ -33,7 +33,7 @@ calls to different backends, and error out on unsupported windowing systems:
|
||||
else
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (GTK_IS_WAYLAND_DISPLAY (display))
|
||||
if (GDK_IS_WAYLAND_DISPLAY (display))
|
||||
{
|
||||
// make Wayland-specific calls here
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ calls to different backends, and error out on unsupported windowing systems:
|
||||
#endif
|
||||
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (GTK_IS_WAYLAND_DISPLAY (display))
|
||||
if (GDK_IS_WAYLAND_DISPLAY (display))
|
||||
{
|
||||
// make Wayland-specific calls here
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ calls to different backends, and error out on unsupported windowing systems:
|
||||
else
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (GTK_IS_WAYLAND_DISPLAY (display))
|
||||
if (GDK_IS_WAYLAND_DISPLAY (display))
|
||||
{
|
||||
// make Wayland-specific calls here
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ version = "@version@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/gtk/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/gsk4/"
|
||||
authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
|
||||
@@ -3,6 +3,7 @@ version = "@version@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/gtk/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/gtk4/"
|
||||
authors = "GTK Development Team"
|
||||
logo_url = "gtk-logo.svg"
|
||||
license = "LGPL-2.1-or-later"
|
||||
|
||||
@@ -315,7 +315,7 @@ have been added to `GdkDisplay`.
|
||||
|
||||
The root window is an X11-centric concept that is no longer exposed in the
|
||||
backend-neutral GDK API. If you need to interact with the X11 root window,
|
||||
you can use [method@GdkX11.Display.get_xrootwindow] to get its XID.
|
||||
you can use [`method@GdkX11.Display.get_xrootwindow`] to get its XID.
|
||||
|
||||
### Stop using `GdkVisual`
|
||||
|
||||
@@ -333,9 +333,9 @@ had replacements in GTK 3 and were deprecated in favor of `GdkSeat`.
|
||||
|
||||
In GTK 4, the two roles of a standalone toplevel window and of a popup that
|
||||
is placed relative to a parent window have been separated out into two
|
||||
interfaces, [class@Gdk.Toplevel] and [class@Gdk.Popup]. Surfaces
|
||||
implementing these interfaces are created with [ctor@Gdk.Surface.new_toplevel]
|
||||
and [ctor@Gdk.Surface.new_popup], respectively, and they are presented on
|
||||
interfaces, [iface@Gdk.Toplevel] and [iface@Gdk.Popup]. Surfaces
|
||||
implementing these interfaces are created with [`ctor@Gdk.Surface.new_toplevel`]
|
||||
and [`ctor@Gdk.Surface.new_popup`], respectively, and they are presented on
|
||||
screen using [method@Gdk.Toplevel.present] and [method@Gdk.Popup.present].
|
||||
The `present()` functions take parameters in the form of an auxiliary layout
|
||||
struct, [struct@Gdk.PopupLayout] or [struct@Gdk.ToplevelLayout].
|
||||
@@ -362,9 +362,9 @@ windows, you you will have to use Xlib apis.
|
||||
|
||||
A number of minor API cleanups have happened in `GdkSurface`
|
||||
as well. For example, `gdk_surface_input_shape_combine_region()`
|
||||
has been renamed to [method@Gdk.Surface.set_input_region], and
|
||||
has been renamed to [`method@Gdk.Surface.set_input_region`], and
|
||||
`gdk_surface_begin_resize_drag()` has been renamed to
|
||||
[method@Gdk.Toplevel.begin_resize].
|
||||
[`method@Gdk.Toplevel.begin_resize`].
|
||||
|
||||
### The "iconified" window state has been renamed to "minimized"
|
||||
|
||||
@@ -388,7 +388,7 @@ have accessors that you will have to use.
|
||||
|
||||
Event compression is always enabled in GTK 4, for both motion and
|
||||
scroll events. If you need to see the uncoalesced motion or scroll
|
||||
history, use [method@Gdk.Event.get_history] on the latest event.
|
||||
history, use [`method@Gdk.Event.get_history`] on the latest event.
|
||||
|
||||
### Stop using grabs
|
||||
|
||||
@@ -410,8 +410,8 @@ have been removed. Update your code accordingly.
|
||||
Any APIs that deal with global (or root) coordinates have been
|
||||
removed in GTK 4, since not all backends support them. You should
|
||||
replace your use of such APIs with surface-relative equivalents.
|
||||
Examples of this are `gdk_surface_get_origin()`, `gdk_surface_move()`
|
||||
or `gdk_event_get_root_coords()`.
|
||||
Examples of such removed APIs are `gdk_window_get_origin()`,
|
||||
`gdk_window_move()` or `gdk_event_get_root_coords()`.
|
||||
|
||||
### Adapt to `GdkKeymap` API changes
|
||||
|
||||
@@ -1054,7 +1054,7 @@ Observing widget contents and widget size is now done by using the
|
||||
|
||||
### Monitor handling has changed
|
||||
|
||||
Instead of a monitor number, [class@Gdk.Monitor] is now used throughout.
|
||||
Instead of a monitor number, [class@Gdk.Monitor] is now used throughout.
|
||||
[method@Gdk.Display.get_monitors] returns the list of monitors that can be queried
|
||||
or observed for monitors to pass to APIs like [method@Gtk.Window.fullscreen_on_monitor].
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ the question you have, this list is a good place to start.
|
||||
(most of it about GTK 2.x and 3.x, but still somewhat applicable). This
|
||||
reference manual also contains a introductory
|
||||
[Getting Started](#gtk-getting-started) part.
|
||||
|
||||
|
||||
More documentation ranging from whitepapers to online books can be found at
|
||||
the [GNOME developer's site](https://developer.gnome.org). After studying these
|
||||
materials you should be well prepared to come back to this reference manual for details.
|
||||
@@ -93,11 +93,11 @@ the question you have, this list is a good place to start.
|
||||
|
||||
`gi18n.h` provides the following shorthand macros for convenience.
|
||||
Conventionally, people define macros as follows for convenience:
|
||||
|
||||
|
||||
#define _(x) gettext (x)
|
||||
#define N_(x) x
|
||||
#define C_(ctx,x) pgettext (ctx, x)
|
||||
|
||||
|
||||
You use `N_()` (N stands for no-op) to mark a string for translation in
|
||||
a location where a function call to gettext() is not allowed, such as
|
||||
in an array initializer. You eventually have to call gettext() on the
|
||||
@@ -205,14 +205,14 @@ the question you have, this list is a good place to start.
|
||||
Here is an example showing the three approaches using the copyright
|
||||
sign © which has Unicode and ISO-8859-1 codepoint 169 and is represented
|
||||
in UTF-8 by the two bytes 194, 169, or `"\302\251"` as a string literal:
|
||||
|
||||
|
||||
g_print ("direct UTF-8: ©");
|
||||
g_print ("escaped UTF-8: \302\251");
|
||||
text = g_convert ("runtime conversion: ©", -1,
|
||||
"ISO-8859-1", "UTF-8", NULL, NULL, NULL);
|
||||
g_print (text);
|
||||
g_free (text);
|
||||
|
||||
|
||||
If you are using gettext() to localize your application, you need
|
||||
to call bind_textdomain_codeset() to ensure that translated strings
|
||||
are returned in UTF-8 encoding.
|
||||
@@ -432,10 +432,10 @@ the question you have, this list is a good place to start.
|
||||
|
||||
26. How do I associate some data with a row in the tree?
|
||||
|
||||
Remember that the [class@Gtk.TreeModel] columns don't necessarily have to be
|
||||
Remember that the [iface@Gtk.TreeModel] columns don't necessarily have to be
|
||||
displayed. So you can put non-user-visible data in your model just
|
||||
like any other data, and retrieve it with [method@Gtk.TreeModel.get].
|
||||
See the [tree widget overview](#TreeWidget).
|
||||
See the [tree widget overview](#TreeWidget).
|
||||
|
||||
27. How do I put an image and some text in the same column?
|
||||
|
||||
@@ -447,7 +447,7 @@ the question you have, this list is a good place to start.
|
||||
28. I can set data easily on my [class@Gtk.TreeStore] or [class@Gtk.ListStore] models using
|
||||
[method@Gtk.ListStore.set] and [method@Gtk.TreeStore.set], but can't read it back?
|
||||
|
||||
Both the [class@Gtk.TreeStore] and the [class@Gtk.ListStore] implement the [class@Gtk.TreeModel]
|
||||
Both the [class@Gtk.TreeStore] and the [class@Gtk.ListStore] implement the [iface@Gtk.TreeModel]
|
||||
interface. As a consequence, you can use any function this interface
|
||||
implements. The easiest way to read a set of data back is to use
|
||||
[method@Gtk.TreeModel.get].
|
||||
|
||||
@@ -133,7 +133,7 @@ gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider,
|
||||
"textview {"
|
||||
" font: 15 serif;"
|
||||
" font: 15px serif;"
|
||||
" color: green;"
|
||||
"}",
|
||||
-1);
|
||||
@@ -149,9 +149,9 @@ gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 30);
|
||||
tag = gtk_text_buffer_create_tag (buffer, "blue_foreground",
|
||||
"foreground", "blue",
|
||||
NULL);
|
||||
gtk_text_buffer_get_iter_at_offset (buffer, &start, 7);
|
||||
gtk_text_buffer_get_iter_at_offset (buffer, &end, 12);
|
||||
gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
|
||||
gtk_text_buffer_get_iter_at_offset (buffer, &start, 7);
|
||||
gtk_text_buffer_get_iter_at_offset (buffer, &end, 12);
|
||||
gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
|
||||
```
|
||||
|
||||
The `gtk4-demo` application that comes with
|
||||
|
||||
+29
-25
@@ -1438,31 +1438,6 @@ describe_egl_config (EGLDisplay egl_display,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*<private>
|
||||
* gdk_display_get_egl_display:
|
||||
* @self: a display
|
||||
*
|
||||
* Retrieves the EGL display connection object for the given GDK display.
|
||||
*
|
||||
* This function returns `NULL` if GL is not supported or GDK is using
|
||||
* a different OpenGL framework than EGL.
|
||||
*
|
||||
* Returns: (nullable): the EGL display object
|
||||
*/
|
||||
gpointer
|
||||
gdk_display_get_egl_display (GdkDisplay *self)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL);
|
||||
|
||||
if (!priv->egl_display &&
|
||||
!gdk_display_prepare_gl (self, NULL))
|
||||
return NULL;
|
||||
|
||||
return priv->egl_display;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gdk_display_get_egl_config (GdkDisplay *self)
|
||||
{
|
||||
@@ -1789,6 +1764,35 @@ gdk_display_init_egl (GdkDisplay *self,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*<private>
|
||||
* gdk_display_get_egl_display:
|
||||
* @self: a display
|
||||
*
|
||||
* Retrieves the EGL display connection object for the given GDK display.
|
||||
*
|
||||
* This function returns `NULL` if GL is not supported or GDK is using
|
||||
* a different OpenGL framework than EGL.
|
||||
*
|
||||
* Returns: (nullable): the EGL display object
|
||||
*/
|
||||
gpointer
|
||||
gdk_display_get_egl_display (GdkDisplay *self)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL);
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (!priv->egl_display &&
|
||||
!gdk_display_prepare_gl (self, NULL))
|
||||
return NULL;
|
||||
|
||||
return priv->egl_display;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
GdkDebugFlags
|
||||
gdk_display_get_debug_flags (GdkDisplay *display)
|
||||
{
|
||||
|
||||
@@ -105,7 +105,7 @@ struct _GdkDeleteEvent
|
||||
* GdkMotionEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) set during the motion
|
||||
* event. See [enum@Gdk.ModifierType]
|
||||
* event. See [flags@Gdk.ModifierType]
|
||||
* @x: the x coordinate of the pointer relative to the surface.
|
||||
* @y: the y coordinate of the pointer relative to the surface.
|
||||
* @axes: @x, @y translated to the axes of @device, or %NULL if @device is
|
||||
@@ -132,7 +132,7 @@ struct _GdkMotionEvent
|
||||
* GdkButtonEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @button: the button which was pressed or released, numbered from 1 to 5.
|
||||
* Normally button 1 is the left mouse button, 2 is the middle button,
|
||||
* and 3 is the right button. On 2-button mice, the middle button can
|
||||
@@ -162,7 +162,7 @@ struct _GdkButtonEvent
|
||||
* GdkTouchEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @x: the x coordinate of the pointer relative to the surface
|
||||
* @y: the y coordinate of the pointer relative to the surface
|
||||
* @axes: @x, @y translated to the axes of the event's device, or %NULL
|
||||
@@ -200,7 +200,7 @@ struct _GdkTouchEvent
|
||||
* @y: the y coordinate of the pointer relative to the surface.
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @direction: the direction to scroll to (one of %GDK_SCROLL_UP,
|
||||
* %GDK_SCROLL_DOWN, %GDK_SCROLL_LEFT, %GDK_SCROLL_RIGHT or
|
||||
* %GDK_SCROLL_SMOOTH).
|
||||
@@ -256,7 +256,7 @@ typedef struct {
|
||||
* GdkKeyEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @keycode: the raw code of the key that was pressed or released.
|
||||
* @translated: the result of translating @keycode. First with the full
|
||||
* @state, then while ignoring Caps Lock.
|
||||
@@ -277,7 +277,7 @@ struct _GdkKeyEvent
|
||||
* GdkCrossingEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @mode: the crossing mode (%GDK_CROSSING_NORMAL, %GDK_CROSSING_GRAB,
|
||||
* %GDK_CROSSING_UNGRAB, %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB or
|
||||
* %GDK_CROSSING_STATE_CHANGED). %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB,
|
||||
@@ -383,7 +383,7 @@ struct _GdkDNDEvent
|
||||
* GdkTouchpadEvent:
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See [enum@Gdk.ModifierType]
|
||||
* buttons. See [flags@Gdk.ModifierType]
|
||||
* @phase: (type GdkTouchpadGesturePhase): the current phase of the gesture
|
||||
* @n_fingers: The number of fingers triggering the pinch
|
||||
* @time: the time of the event in milliseconds
|
||||
|
||||
+3
-3
@@ -58,8 +58,8 @@
|
||||
* It’s a low-level object, used to implement high-level objects
|
||||
* such as [class@Gtk.Window] or [class@Gtk.Dialog] in GTK.
|
||||
*
|
||||
* The surfaces you see in practice are either [class@Gdk.Toplevel] or
|
||||
* [class@Gdk.Popup], and those interfaces provide much of the required
|
||||
* The surfaces you see in practice are either [iface@Gdk.Toplevel] or
|
||||
* [iface@Gdk.Popup], and those interfaces provide much of the required
|
||||
* API to interact with these surfaces. Other, more specialized surface
|
||||
* types exist, but you will rarely interact with them directly.
|
||||
*/
|
||||
@@ -2099,7 +2099,7 @@ gdk_surface_get_root_coords (GdkSurface *surface,
|
||||
*root_y = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GDK_SURFACE_GET_CLASS (surface)->get_root_coords (surface, x, y, root_x, root_y);
|
||||
}
|
||||
|
||||
|
||||
+1
-44
@@ -28,8 +28,7 @@
|
||||
* `GdkPixbuf`, or a Cairo surface, or other pixel data.
|
||||
*
|
||||
* The ownership of the pixel data is transferred to the `GdkTexture`
|
||||
* instance; you can only make a copy of it, via [method@Gdk.Texture.download]
|
||||
* or [method@Gdk.Texture.download_float].
|
||||
* instance; you can only make a copy of it, via [method@Gdk.Texture.download].
|
||||
*
|
||||
* `GdkTexture` is an immutable object: That means you cannot change
|
||||
* anything about it other than increasing the reference count via
|
||||
@@ -743,48 +742,6 @@ gdk_texture_download (GdkTexture *texture,
|
||||
stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_texture_download_float:
|
||||
* @texture: a `GdkTexture`
|
||||
* @data: (array): pointer to enough memory to be filled with the
|
||||
* downloaded data of @texture
|
||||
* @stride: rowstride in elements, will usually be equal to
|
||||
* gdk_texture_get_width() * 4
|
||||
*
|
||||
* Downloads the @texture into local memory in a high dynamic range format.
|
||||
*
|
||||
* This may be an expensive operation, as the actual texture data
|
||||
* may reside on a GPU or on a remote display server and because the data
|
||||
* may need to be upsampled if it was not already available in this
|
||||
* format.
|
||||
*
|
||||
* You may want to use [method@Gdk.Texture.download] instead if you don't
|
||||
* need high dynamic range support.
|
||||
*
|
||||
* The data format of the downloaded data is equivalent to
|
||||
* GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, so every downloaded
|
||||
* pixel requires 16 bytes of memory.
|
||||
*
|
||||
* Note that the caller is responsible to provide sufficiently
|
||||
* aligned memory to access the resulting data directly as floats.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
void
|
||||
gdk_texture_download_float (GdkTexture *texture,
|
||||
float *data,
|
||||
gsize stride)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_TEXTURE (texture));
|
||||
g_return_if_fail (data != NULL);
|
||||
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
|
||||
|
||||
gdk_texture_do_download (texture,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
(guchar *) data,
|
||||
stride);
|
||||
}
|
||||
|
||||
GdkMemoryFormat
|
||||
gdk_texture_get_format (GdkTexture *self)
|
||||
{
|
||||
|
||||
@@ -727,6 +727,13 @@ gdk_toplevel_begin_move (GdkToplevel *toplevel,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_toplevel_titlebar_gesture:
|
||||
* @toplevel: a `GdkToplevel`
|
||||
* @gesture: a `GdkTitlebarGesture`
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
gboolean
|
||||
gdk_toplevel_titlebar_gesture (GdkToplevel *toplevel,
|
||||
GdkTitlebarGesture gesture)
|
||||
|
||||
@@ -115,6 +115,14 @@ typedef enum
|
||||
GDK_TOPLEVEL_STATE_LEFT_RESIZABLE = 1 << 15
|
||||
} GdkToplevelState;
|
||||
|
||||
/**
|
||||
* GdkTitlebarGesture:
|
||||
* @GDK_TITLEBAR_GESTURE_DOUBLE_CLICK:
|
||||
* @GDK_TITLEBAR_GESTURE_RIGHT_CLICK:
|
||||
* @GDK_TITLEBAR_GESTURE_MIDDLE_CLICK:
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GDK_TITLEBAR_GESTURE_DOUBLE_CLICK = 1,
|
||||
|
||||
@@ -251,7 +251,7 @@ gdk_load_png (GBytes *bytes,
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
_("Unsupportd color type %u in png image"), color_type);
|
||||
_("Unsupported color type %u in png image"), color_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -3606,6 +3606,10 @@ tablet_tool_handle_proximity_out (void *data,
|
||||
g_object_unref (tablet->pointer_info.focus);
|
||||
tablet->pointer_info.focus = NULL;
|
||||
|
||||
tablet->pointer_info.button_modifiers &=
|
||||
~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
|
||||
GDK_BUTTON4_MASK | GDK_BUTTON5_MASK);
|
||||
|
||||
gdk_device_update_tool (tablet->stylus_device, NULL);
|
||||
g_clear_object (&tablet->pointer_info.cursor);
|
||||
}
|
||||
@@ -3621,7 +3625,6 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
|
||||
GdkEventType evtype,
|
||||
guint button)
|
||||
{
|
||||
GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
|
||||
GdkEvent *event;
|
||||
|
||||
event = gdk_button_event_new (evtype,
|
||||
@@ -3629,7 +3632,7 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
|
||||
tablet->logical_device,
|
||||
tablet->current_tool->tool,
|
||||
tablet->pointer_info.time,
|
||||
device_get_modifiers (seat->logical_pointer),
|
||||
device_get_modifiers (tablet->logical_device),
|
||||
button,
|
||||
tablet->pointer_info.surface_x,
|
||||
tablet->pointer_info.surface_y,
|
||||
|
||||
@@ -104,8 +104,6 @@ struct _GdkWaylandSurface
|
||||
|
||||
struct gtk_surface1 *gtk_surface;
|
||||
struct wl_egl_window *egl_window;
|
||||
struct zxdg_exported_v1 *xdg_exported;
|
||||
struct org_kde_kwin_server_decoration *server_decoration;
|
||||
} display_server;
|
||||
|
||||
struct wl_event_queue *event_queue;
|
||||
@@ -224,17 +222,8 @@ struct _GdkWaylandSurface
|
||||
|
||||
int state_freeze_count;
|
||||
|
||||
struct {
|
||||
GdkWaylandToplevelExported callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_func;
|
||||
} exported;
|
||||
|
||||
struct zxdg_imported_v1 *imported_transient_for;
|
||||
GHashTable *shortcuts_inhibitors;
|
||||
|
||||
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
|
||||
size_t idle_inhibitor_refcount;
|
||||
};
|
||||
|
||||
typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
|
||||
@@ -250,6 +239,18 @@ struct _GdkWaylandToplevel
|
||||
GdkWaylandSurface parent_instance;
|
||||
|
||||
GdkWaylandToplevel *transient_for;
|
||||
|
||||
struct org_kde_kwin_server_decoration *server_decoration;
|
||||
struct zxdg_exported_v1 *xdg_exported;
|
||||
|
||||
struct {
|
||||
GdkWaylandToplevelExported callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_func;
|
||||
} exported;
|
||||
|
||||
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
|
||||
size_t idle_inhibitor_refcount;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -329,7 +330,7 @@ static void update_popup_layout_state (GdkSurface *surface,
|
||||
int height,
|
||||
GdkPopupLayout *layout);
|
||||
|
||||
static gboolean gdk_wayland_surface_is_exported (GdkWaylandSurface *impl);
|
||||
static gboolean gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel);
|
||||
|
||||
static void configure_toplevel_geometry (GdkSurface *surface);
|
||||
|
||||
@@ -988,9 +989,6 @@ gdk_wayland_surface_finalize (GObject *object)
|
||||
|
||||
impl = GDK_WAYLAND_SURFACE (object);
|
||||
|
||||
if (gdk_wayland_surface_is_exported (impl))
|
||||
gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (impl));
|
||||
|
||||
g_free (impl->title);
|
||||
|
||||
g_free (impl->application.application_id);
|
||||
@@ -1028,8 +1026,7 @@ is_realized_popup (GdkWaylandSurface *impl)
|
||||
impl->display_server.zxdg_popup_v6);
|
||||
}
|
||||
|
||||
static void gdk_wayland_surface_show (GdkSurface *surface,
|
||||
gboolean already_mapped);
|
||||
static void gdk_wayland_surface_show (GdkSurface *surface);
|
||||
static void gdk_wayland_surface_hide (GdkSurface *surface);
|
||||
|
||||
static void
|
||||
@@ -1062,7 +1059,7 @@ gdk_wayland_surface_maybe_resize (GdkSurface *surface,
|
||||
gdk_wayland_surface_update_size (surface, width, height, scale);
|
||||
|
||||
if (is_xdg_popup && is_visible && !impl->initial_configure_received)
|
||||
gdk_wayland_surface_show (surface, FALSE);
|
||||
gdk_wayland_surface_show (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2238,57 +2235,62 @@ void
|
||||
gdk_wayland_toplevel_announce_csd (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
GdkWaylandToplevel *toplevel_wayland;
|
||||
|
||||
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
|
||||
toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
if (!display_wayland->server_decoration_manager)
|
||||
return;
|
||||
impl->display_server.server_decoration =
|
||||
org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
|
||||
impl->display_server.wl_surface);
|
||||
if (impl->display_server.server_decoration)
|
||||
org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
|
||||
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
|
||||
toplevel_wayland->server_decoration =
|
||||
org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
|
||||
gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
|
||||
if (toplevel_wayland->server_decoration)
|
||||
org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
|
||||
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
GdkWaylandToplevel *toplevel_wayland;
|
||||
|
||||
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
|
||||
toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
if (!display_wayland->server_decoration_manager)
|
||||
return;
|
||||
impl->display_server.server_decoration =
|
||||
org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
|
||||
impl->display_server.wl_surface);
|
||||
if (impl->display_server.server_decoration)
|
||||
org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
|
||||
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
toplevel_wayland->server_decoration =
|
||||
org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
|
||||
gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
|
||||
if (toplevel_wayland->server_decoration)
|
||||
org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
|
||||
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
GdkWaylandToplevel *wayland_toplevel;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
|
||||
wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
if (!display_wayland->idle_inhibit_manager)
|
||||
return FALSE;
|
||||
|
||||
if (!impl->idle_inhibitor)
|
||||
if (!wayland_toplevel->idle_inhibitor)
|
||||
{
|
||||
g_assert (impl->idle_inhibitor_refcount == 0);
|
||||
impl->idle_inhibitor =
|
||||
zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
|
||||
impl->display_server.wl_surface);
|
||||
g_assert (wayland_toplevel->idle_inhibitor &&
|
||||
wayland_toplevel->idle_inhibitor_refcount > 0);
|
||||
|
||||
wayland_toplevel->idle_inhibitor =
|
||||
zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
|
||||
gdk_wayland_surface_get_wl_surface (GDK_SURFACE (wayland_toplevel)));
|
||||
}
|
||||
++impl->idle_inhibitor_refcount;
|
||||
++wayland_toplevel->idle_inhibitor_refcount;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2296,14 +2298,19 @@ gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
|
||||
void
|
||||
gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
GdkWaylandToplevel *wayland_toplevel;
|
||||
|
||||
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
|
||||
wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
g_assert (impl->idle_inhibitor && impl->idle_inhibitor_refcount > 0);
|
||||
g_assert (wayland_toplevel->idle_inhibitor &&
|
||||
wayland_toplevel->idle_inhibitor_refcount > 0);
|
||||
|
||||
if (--impl->idle_inhibitor_refcount == 0)
|
||||
g_clear_pointer (&impl->idle_inhibitor, zwp_idle_inhibitor_v1_destroy);
|
||||
if (--wayland_toplevel->idle_inhibitor_refcount == 0)
|
||||
{
|
||||
g_clear_pointer (&wayland_toplevel->idle_inhibitor,
|
||||
zwp_idle_inhibitor_v1_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2850,8 +2857,7 @@ gdk_wayland_surface_map_toplevel (GdkSurface *surface)
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_show (GdkSurface *surface,
|
||||
gboolean already_mapped)
|
||||
gdk_wayland_surface_show (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
@@ -4420,13 +4426,13 @@ xdg_exported_handle (void *data,
|
||||
const char *handle)
|
||||
{
|
||||
GdkToplevel *toplevel = data;
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
impl->exported.callback (toplevel, handle, impl->exported.user_data);
|
||||
if (impl->exported.destroy_func)
|
||||
wayland_toplevel->exported.callback (toplevel, handle, wayland_toplevel->exported.user_data);
|
||||
if (wayland_toplevel->exported.destroy_func)
|
||||
{
|
||||
g_clear_pointer (&impl->exported.user_data,
|
||||
impl->exported.destroy_func);
|
||||
g_clear_pointer (&wayland_toplevel->exported.user_data,
|
||||
wayland_toplevel->exported.destroy_func);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4450,9 +4456,9 @@ static const struct zxdg_exported_v1_listener xdg_exported_listener = {
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
gdk_wayland_surface_is_exported (GdkWaylandSurface *impl)
|
||||
gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel)
|
||||
{
|
||||
return !!impl->display_server.xdg_exported;
|
||||
return !!wayland_toplevel->xdg_exported;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4489,7 +4495,8 @@ gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_func)
|
||||
{
|
||||
GdkWaylandSurface *impl;
|
||||
GdkWaylandToplevel *wayland_toplevel;
|
||||
GdkSurface *surface;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
|
||||
struct zxdg_exported_v1 *xdg_exported;
|
||||
@@ -4497,10 +4504,11 @@ gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
|
||||
|
||||
impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
surface = GDK_SURFACE (toplevel);
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
g_return_val_if_fail (!impl->display_server.xdg_exported, FALSE);
|
||||
g_return_val_if_fail (!wayland_toplevel->xdg_exported, FALSE);
|
||||
|
||||
if (!display_wayland->xdg_exporter)
|
||||
{
|
||||
@@ -4508,14 +4516,16 @@ gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
|
||||
impl->display_server.wl_surface);
|
||||
zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener, impl);
|
||||
xdg_exported =
|
||||
zxdg_exporter_v1_export (display_wayland->xdg_exporter,
|
||||
gdk_wayland_surface_get_wl_surface (surface));
|
||||
zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener,
|
||||
wayland_toplevel);
|
||||
|
||||
impl->display_server.xdg_exported = xdg_exported;
|
||||
impl->exported.callback = callback;
|
||||
impl->exported.user_data = user_data;
|
||||
impl->exported.destroy_func = destroy_func;
|
||||
wayland_toplevel->xdg_exported = xdg_exported;
|
||||
wayland_toplevel->exported.callback = callback;
|
||||
wayland_toplevel->exported.user_data = user_data;
|
||||
wayland_toplevel->exported.destroy_func = destroy_func;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -4536,20 +4546,20 @@ gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
|
||||
void
|
||||
gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandSurface *impl;
|
||||
GdkWaylandToplevel *wayland_toplevel;
|
||||
|
||||
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
|
||||
|
||||
impl = GDK_WAYLAND_SURFACE (toplevel);
|
||||
wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
g_return_if_fail (impl->display_server.xdg_exported);
|
||||
g_return_if_fail (wayland_toplevel->xdg_exported);
|
||||
|
||||
g_clear_pointer (&impl->display_server.xdg_exported,
|
||||
g_clear_pointer (&wayland_toplevel->xdg_exported,
|
||||
zxdg_exported_v1_destroy);
|
||||
if (impl->exported.destroy_func)
|
||||
if (wayland_toplevel->exported.destroy_func)
|
||||
{
|
||||
g_clear_pointer (&impl->exported.user_data,
|
||||
impl->exported.destroy_func);
|
||||
g_clear_pointer (&wayland_toplevel->exported.user_data,
|
||||
wayland_toplevel->exported.destroy_func);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4925,6 +4935,21 @@ gdk_wayland_toplevel_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_toplevel_finalize (GObject *object)
|
||||
{
|
||||
GdkWaylandToplevel *wayland_toplevel;
|
||||
|
||||
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (object));
|
||||
|
||||
wayland_toplevel = GDK_WAYLAND_TOPLEVEL (object);
|
||||
|
||||
if (gdk_wayland_toplevel_is_exported (wayland_toplevel))
|
||||
gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (wayland_toplevel));
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_toplevel_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class)
|
||||
{
|
||||
@@ -4932,6 +4957,7 @@ gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class)
|
||||
|
||||
object_class->get_property = gdk_wayland_toplevel_get_property;
|
||||
object_class->set_property = gdk_wayland_toplevel_set_property;
|
||||
object_class->finalize = gdk_wayland_toplevel_finalize;
|
||||
|
||||
gdk_toplevel_install_properties (object_class, 1);
|
||||
}
|
||||
@@ -4977,7 +5003,7 @@ gdk_wayland_toplevel_present (GdkToplevel *toplevel,
|
||||
g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref);
|
||||
impl->toplevel.layout = gdk_toplevel_layout_copy (layout);
|
||||
|
||||
gdk_wayland_surface_show (surface, FALSE);
|
||||
gdk_wayland_surface_show (surface);
|
||||
|
||||
if (!pending_configure)
|
||||
{
|
||||
@@ -5125,7 +5151,7 @@ gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface,
|
||||
GdkSurface *surface = GDK_SURFACE (drag_surface);
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
gdk_wayland_surface_show (surface, FALSE);
|
||||
gdk_wayland_surface_show (surface);
|
||||
|
||||
impl->next_layout.configured_width = width;
|
||||
impl->next_layout.configured_height = height;
|
||||
|
||||
@@ -100,15 +100,6 @@ gdk_device_win32_query_state (GdkDevice *device,
|
||||
if (win_y)
|
||||
*win_y = point.y / scale;
|
||||
|
||||
if (window)
|
||||
{
|
||||
if (win_x)
|
||||
*win_x += _gdk_offset_x;
|
||||
|
||||
if (win_y)
|
||||
*win_y += _gdk_offset_y;
|
||||
}
|
||||
|
||||
if (hwnd && child_window)
|
||||
{
|
||||
hwndc = ChildWindowFromPoint (hwnd, point);
|
||||
|
||||
@@ -91,15 +91,6 @@ gdk_device_winpointer_query_state (GdkDevice *device,
|
||||
if (win_y)
|
||||
*win_y = point.y / scale;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
if (win_x)
|
||||
*win_x += _gdk_offset_x;
|
||||
|
||||
if (win_y)
|
||||
*win_y += _gdk_offset_y;
|
||||
}
|
||||
|
||||
if (hwnd && child_window)
|
||||
{
|
||||
hwndc = ChildWindowFromPoint (hwnd, point);
|
||||
|
||||
@@ -99,15 +99,6 @@ gdk_device_wintab_query_state (GdkDevice *device,
|
||||
if (win_y)
|
||||
*win_y = point.y / scale;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
if (win_x)
|
||||
*win_x += _gdk_offset_x;
|
||||
|
||||
if (win_y)
|
||||
*win_y += _gdk_offset_y;
|
||||
}
|
||||
|
||||
if (hwnd && child_window)
|
||||
{
|
||||
hwndc = ChildWindowFromPoint (hwnd, point);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <dwmapi.h>
|
||||
|
||||
#include "gdkwin32langnotification.h"
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
# include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
@@ -645,14 +645,6 @@ gdk_win32_display_dispose (GObject *object)
|
||||
{
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (object);
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
if (display_win32->egl_disp != EGL_NO_DISPLAY)
|
||||
{
|
||||
eglTerminate (display_win32->egl_disp);
|
||||
display_win32->egl_disp = EGL_NO_DISPLAY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (display_win32->hwnd != NULL)
|
||||
{
|
||||
if (display_win32->dummy_context_wgl.hglrc != NULL)
|
||||
@@ -1146,23 +1138,54 @@ gdk_win32_display_get_setting (GdkDisplay *display,
|
||||
return _gdk_win32_get_setting (name, value);
|
||||
}
|
||||
|
||||
#ifndef EGL_PLATFORM_ANGLE_ANGLE
|
||||
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
gdk_win32_display_init_gl_backend (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
|
||||
/* No env vars set, do the regular GL initialization, first WGL and then EGL,
|
||||
if (display_win32->dummy_context_wgl.hdc == NULL)
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
|
||||
|
||||
/*
|
||||
* No env vars set, do the regular GL initialization, first WGL and then EGL,
|
||||
* as WGL is the more tried-and-tested configuration.
|
||||
*/
|
||||
|
||||
result = gdk_win32_display_init_wgl (display, error);
|
||||
#ifdef HAVE_EGL
|
||||
/*
|
||||
* Disable defaulting to EGL for now, since shaders need to be fixed for
|
||||
* usage against libANGLE EGL. EGL is used more as a compatibility layer
|
||||
* on Windows rather than being a native citizen on Windows
|
||||
*/
|
||||
if (_gdk_debug_flags & GDK_DEBUG_GL_EGL)
|
||||
result = gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
display_win32->dummy_context_wgl.hdc,
|
||||
FALSE,
|
||||
error);
|
||||
#endif
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
if (!result)
|
||||
{
|
||||
g_clear_error (error);
|
||||
result = gdk_win32_display_init_egl (display, error);
|
||||
result = gdk_win32_display_init_wgl (display, error);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (!result)
|
||||
{
|
||||
g_clear_error (error);
|
||||
result = gdk_display_init_egl (display,
|
||||
EGL_PLATFORM_ANGLE_ANGLE,
|
||||
display_win32->dummy_context_wgl.hdc,
|
||||
TRUE,
|
||||
error);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1179,13 +1202,12 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
if (!gdk_win32_display_init_gl_backend (display, error))
|
||||
return NULL;
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
if (display_win32->egl_disp)
|
||||
gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL, "display", display, NULL);
|
||||
else
|
||||
#endif
|
||||
if (display_win32->wgl_pixel_format != 0)
|
||||
gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL, "display", display, NULL);
|
||||
#ifdef HAVE_EGL
|
||||
else if (gdk_display_get_egl_display (display))
|
||||
gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL, "display", display, NULL);
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (gl_context != NULL, NULL);
|
||||
|
||||
@@ -1203,23 +1225,9 @@ gdk_win32_display_init_gl (GdkDisplay *display,
|
||||
gpointer
|
||||
gdk_win32_display_get_egl_display (GdkDisplay *display)
|
||||
{
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
GdkWin32Display *display_win32;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WIN32_DISPLAY (display), NULL);
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
|
||||
if (display_win32->wgl_pixel_format != 0)
|
||||
return NULL;
|
||||
|
||||
return display_win32->egl_disp;
|
||||
#else
|
||||
/* no EGL support */
|
||||
return NULL;
|
||||
#endif
|
||||
return gdk_display_get_egl_display (display);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "gdkwin32screen.h"
|
||||
#include "gdkwin32cursor.h"
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
# include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
@@ -135,14 +135,6 @@ struct _GdkWin32Display
|
||||
int wgl_pixel_format;
|
||||
guint gl_version;
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
/* EGL (Angle) Items */
|
||||
guint egl_version;
|
||||
EGLDisplay egl_disp;
|
||||
EGLConfig egl_config;
|
||||
HDC hdc_egl_temp;
|
||||
#endif
|
||||
|
||||
GListModel *monitors;
|
||||
|
||||
guint hasWglARBCreateContext : 1;
|
||||
@@ -151,7 +143,7 @@ struct _GdkWin32Display
|
||||
guint hasWglARBPixelFormat : 1;
|
||||
guint hasWglARBmultisample : 1;
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
guint hasEglKHRCreateContext : 1;
|
||||
guint hasEglSurfacelessContext : 1;
|
||||
EGLint egl_min_swap_interval;
|
||||
|
||||
@@ -2082,8 +2082,8 @@ gdk_dnd_handle_motion_event (GdkDrag *drag,
|
||||
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id,
|
||||
WM_MOUSEMOVE,
|
||||
key_state,
|
||||
MAKELPARAM (x_root * drag_win32->scale - _gdk_offset_x,
|
||||
y_root * drag_win32->scale - _gdk_offset_y)));
|
||||
MAKELPARAM (x_root * drag_win32->scale,
|
||||
y_root * drag_win32->scale)));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -425,14 +425,9 @@ set_source_actions_helper (GdkDrop *drop,
|
||||
return actions;
|
||||
}
|
||||
|
||||
/* Utility function to translate win32 screen coordinates to
|
||||
* client coordinates (i.e. relative to the surface origin)
|
||||
*
|
||||
* Note that input is expected to be:
|
||||
* a) NOT scaled by dpi_scale
|
||||
* b) NOT translated by the GDK screen offset (gdk_offset_x / y)
|
||||
*
|
||||
* This utility function preserves subpixel precision
|
||||
/* Utility function to translate screen coordinates to surface-relative
|
||||
* coordinates. This routine only works with pixel values that aren't
|
||||
* scaled by any GDK DPI scale factor.
|
||||
*/
|
||||
static void
|
||||
unscaled_screen_to_client (GdkSurface* surface,
|
||||
@@ -514,8 +509,8 @@ idroptarget_dragenter (LPDROPTARGET This,
|
||||
grfKeyState);
|
||||
|
||||
set_data_object (&ctx->data_object, pDataObj);
|
||||
pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
|
||||
pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
|
||||
pt_x = pt.x / drop_win32->scale;
|
||||
pt_y = pt.y / drop_win32->scale;
|
||||
|
||||
unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
|
||||
x /= drop_win32->scale;
|
||||
@@ -554,8 +549,8 @@ idroptarget_dragover (LPDROPTARGET This,
|
||||
{
|
||||
drop_target_context *ctx = (drop_target_context *) This;
|
||||
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop);
|
||||
int pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
|
||||
int pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
|
||||
int pt_x = pt.x / drop_win32->scale;
|
||||
int pt_y = pt.y / drop_win32->scale;
|
||||
GdkDragAction source_actions;
|
||||
GdkDragAction dest_actions;
|
||||
|
||||
@@ -624,8 +619,6 @@ idroptarget_drop (LPDROPTARGET This,
|
||||
{
|
||||
drop_target_context *ctx = (drop_target_context *) This;
|
||||
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop);
|
||||
int pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
|
||||
int pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
GdkDragAction dest_action;
|
||||
|
||||
@@ -1291,13 +1291,12 @@ make_crossing_event (GdkDevice *physical_device,
|
||||
}
|
||||
|
||||
/* Acquires actual client area size of the underlying native window.
|
||||
* Rectangle is in GDK screen coordinates (_gdk_offset_* is added).
|
||||
* Returns FALSE if configure events should be inhibited,
|
||||
* TRUE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
_gdk_win32_get_window_rect (GdkSurface *window,
|
||||
RECT *rect)
|
||||
RECT *rect)
|
||||
{
|
||||
RECT client_rect;
|
||||
POINT point;
|
||||
@@ -1312,11 +1311,7 @@ _gdk_win32_get_window_rect (GdkSurface *window,
|
||||
|
||||
/* top level windows need screen coords */
|
||||
if (GDK_IS_TOPLEVEL (window))
|
||||
{
|
||||
ClientToScreen (hwnd, &point);
|
||||
point.x += _gdk_offset_x * impl->surface_scale;
|
||||
point.y += _gdk_offset_y * impl->surface_scale;
|
||||
}
|
||||
ClientToScreen (hwnd, &point);
|
||||
|
||||
rect->left = point.x;
|
||||
rect->top = point.y;
|
||||
@@ -2410,15 +2405,15 @@ gdk_event_translate (MSG *msg,
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
|
||||
/* If we haven't moved, don't create any GDK event. Windows
|
||||
* sends WM_MOUSEMOVE messages after a new window is shows under
|
||||
* sends WM_MOUSEMOVE messages after a new window is shown under
|
||||
* the mouse, even if the mouse hasn't moved. This disturbs gtk.
|
||||
*/
|
||||
if ((msg->pt.x + _gdk_offset_x) / impl->surface_scale == current_root_x &&
|
||||
(msg->pt.y + _gdk_offset_y) / impl->surface_scale == current_root_y)
|
||||
break;
|
||||
if (msg->pt.x / impl->surface_scale == current_root_x &&
|
||||
msg->pt.y / impl->surface_scale == current_root_y)
|
||||
break;
|
||||
|
||||
current_root_x = (msg->pt.x + _gdk_offset_x) / impl->surface_scale;
|
||||
current_root_y = (msg->pt.y + _gdk_offset_y) / impl->surface_scale;
|
||||
current_root_x = msg->pt.x / impl->surface_scale;
|
||||
current_root_y = msg->pt.y / impl->surface_scale;
|
||||
|
||||
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
|
||||
gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
|
||||
|
||||
@@ -53,30 +53,6 @@ typedef struct _GdkWin32GLContextClass GdkWin32GLContextEGLClass;
|
||||
|
||||
G_DEFINE_TYPE (GdkWin32GLContextEGL, gdk_win32_gl_context_egl, GDK_TYPE_WIN32_GL_CONTEXT)
|
||||
|
||||
static void
|
||||
gdk_win32_gl_context_egl_dispose (GObject *gobject)
|
||||
{
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
|
||||
GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (gobject);
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
|
||||
if (display_win32 != NULL)
|
||||
{
|
||||
if (eglGetCurrentContext () == context_egl->egl_context)
|
||||
eglMakeCurrent(display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
|
||||
GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context"));
|
||||
|
||||
eglDestroyContext (display_win32->egl_disp,
|
||||
context_egl->egl_context);
|
||||
context_egl->egl_context = EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gdk_win32_gl_context_egl_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_egl_force_redraw (GdkSurface *surface)
|
||||
{
|
||||
@@ -109,7 +85,7 @@ gdk_win32_gl_context_egl_end_frame (GdkDrawContext *draw_context,
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
||||
GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
cairo_rectangle_int_t whole_window;
|
||||
EGLSurface egl_surface;
|
||||
|
||||
@@ -122,7 +98,7 @@ gdk_win32_gl_context_egl_end_frame (GdkDrawContext *draw_context,
|
||||
gdk_surface_get_height (surface)
|
||||
};
|
||||
|
||||
egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, FALSE);
|
||||
egl_surface = gdk_surface_get_egl_surface (surface);
|
||||
|
||||
if (is_egl_force_redraw (surface))
|
||||
{
|
||||
@@ -135,338 +111,7 @@ gdk_win32_gl_context_egl_end_frame (GdkDrawContext *draw_context,
|
||||
reset_egl_force_redraw (surface);
|
||||
}
|
||||
|
||||
eglSwapBuffers (display_win32->egl_disp, egl_surface);
|
||||
}
|
||||
|
||||
#ifndef EGL_PLATFORM_ANGLE_ANGLE
|
||||
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
|
||||
#endif
|
||||
|
||||
#ifndef EGL_PLATFORM_ANGLE_TYPE_ANGLE
|
||||
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
|
||||
#endif
|
||||
|
||||
#ifndef EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
|
||||
#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
|
||||
#endif
|
||||
|
||||
static EGLDisplay
|
||||
gdk_win32_get_egl_display (GdkWin32Display *display)
|
||||
{
|
||||
EGLDisplay disp;
|
||||
|
||||
if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
|
||||
{
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
|
||||
if (getPlatformDisplay)
|
||||
{
|
||||
EGLint disp_attr[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE};
|
||||
|
||||
disp = getPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE, display->hdc_egl_temp, disp_attr);
|
||||
|
||||
if (disp != EGL_NO_DISPLAY)
|
||||
return disp;
|
||||
}
|
||||
}
|
||||
|
||||
return eglGetDisplay (display->hdc_egl_temp);
|
||||
}
|
||||
|
||||
#define MAX_EGL_ATTRS 30
|
||||
|
||||
static gboolean
|
||||
find_eglconfig_for_window (GdkWin32Display *display,
|
||||
EGLConfig *egl_config_out,
|
||||
EGLint *min_swap_interval_out,
|
||||
GError **error)
|
||||
{
|
||||
EGLint attrs[MAX_EGL_ATTRS];
|
||||
EGLint count;
|
||||
EGLConfig *configs, chosen_config;
|
||||
|
||||
int i = 0;
|
||||
|
||||
EGLDisplay egl_disp = display->egl_disp;
|
||||
|
||||
attrs[i++] = EGL_CONFORMANT;
|
||||
attrs[i++] = EGL_OPENGL_ES2_BIT;
|
||||
attrs[i++] = EGL_SURFACE_TYPE;
|
||||
attrs[i++] = EGL_WINDOW_BIT;
|
||||
|
||||
attrs[i++] = EGL_COLOR_BUFFER_TYPE;
|
||||
attrs[i++] = EGL_RGB_BUFFER;
|
||||
|
||||
attrs[i++] = EGL_RED_SIZE;
|
||||
attrs[i++] = 1;
|
||||
attrs[i++] = EGL_GREEN_SIZE;
|
||||
attrs[i++] = 1;
|
||||
attrs[i++] = EGL_BLUE_SIZE;
|
||||
attrs[i++] = 1;
|
||||
attrs[i++] = EGL_ALPHA_SIZE;
|
||||
attrs[i++] = 1;
|
||||
|
||||
attrs[i++] = EGL_NONE;
|
||||
g_assert (i < MAX_EGL_ATTRS);
|
||||
|
||||
if (!eglChooseConfig (display->egl_disp, attrs, NULL, 0, &count) || count < 1)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
_("No available configurations for the given pixel format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
configs = g_new (EGLConfig, count);
|
||||
|
||||
if (!eglChooseConfig (display->egl_disp, attrs, configs, count, &count) || count < 1)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
_("No available configurations for the given pixel format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Pick first valid configuration i guess? */
|
||||
chosen_config = configs[0];
|
||||
|
||||
if (!eglGetConfigAttrib (display->egl_disp, chosen_config,
|
||||
EGL_MIN_SWAP_INTERVAL, min_swap_interval_out))
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
"Could not retrieve the minimum swap interval");
|
||||
g_free (configs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (egl_config_out != NULL)
|
||||
*egl_config_out = chosen_config;
|
||||
|
||||
g_free (configs);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_win32_display_init_egl (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
int best_idx = 0;
|
||||
EGLDisplay egl_disp;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
|
||||
return FALSE;
|
||||
|
||||
if (display_win32->egl_disp != EGL_NO_DISPLAY)
|
||||
return TRUE;
|
||||
|
||||
egl_disp = gdk_win32_get_egl_display (display_win32);
|
||||
|
||||
if (egl_disp == EGL_NO_DISPLAY)
|
||||
return FALSE;
|
||||
|
||||
if (!eglInitialize (egl_disp, NULL, NULL))
|
||||
{
|
||||
eglTerminate (egl_disp);
|
||||
egl_disp = EGL_NO_DISPLAY;
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
_("No GL implementation is available"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
display_win32->egl_disp = egl_disp;
|
||||
display_win32->egl_version = epoxy_egl_version (egl_disp);
|
||||
|
||||
eglBindAPI (EGL_OPENGL_ES_API);
|
||||
|
||||
display_win32->hasEglSurfacelessContext =
|
||||
epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context");
|
||||
|
||||
GDK_NOTE (OPENGL,
|
||||
g_print ("EGL API version %d.%d found\n"
|
||||
" - Vendor: %s\n"
|
||||
" - Checked extensions:\n"
|
||||
"\t* EGL_KHR_surfaceless_context: %s\n",
|
||||
display_win32->egl_version / 10,
|
||||
display_win32->egl_version % 10,
|
||||
eglQueryString (display_win32->egl_disp, EGL_VENDOR),
|
||||
display_win32->hasEglSurfacelessContext ? "yes" : "no"));
|
||||
|
||||
return find_eglconfig_for_window (display_win32, &display_win32->egl_config,
|
||||
&display_win32->egl_min_swap_interval, error);
|
||||
}
|
||||
|
||||
#define N_EGL_ATTRS 16
|
||||
|
||||
static EGLContext
|
||||
create_egl_context (EGLDisplay display,
|
||||
EGLConfig config,
|
||||
GdkGLContext *share,
|
||||
int flags,
|
||||
int major,
|
||||
int minor,
|
||||
gboolean *is_legacy)
|
||||
{
|
||||
EGLContext ctx;
|
||||
EGLint context_attribs[N_EGL_ATTRS];
|
||||
int i = 0;
|
||||
|
||||
/* ANGLE does not support the GL_OES_vertex_array_object extension, so we need to use ES3 directly */
|
||||
context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
|
||||
context_attribs[i++] = 3;
|
||||
|
||||
/* Specify the flags */
|
||||
context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
|
||||
context_attribs[i++] = flags;
|
||||
|
||||
context_attribs[i++] = EGL_NONE;
|
||||
g_assert (i < N_EGL_ATTRS);
|
||||
|
||||
ctx = eglCreateContext (display,
|
||||
config,
|
||||
share != NULL ? GDK_WIN32_GL_CONTEXT_EGL (share)->egl_context
|
||||
: EGL_NO_CONTEXT,
|
||||
context_attribs);
|
||||
|
||||
if (ctx != EGL_NO_CONTEXT)
|
||||
GDK_NOTE (OPENGL, g_message ("Created EGL context[%p]", ctx));
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_win32_gl_context_egl_realize (GdkGLContext *context,
|
||||
GError **error)
|
||||
{
|
||||
GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
|
||||
|
||||
gboolean debug_bit, compat_bit, legacy_bit;
|
||||
gboolean use_es = FALSE;
|
||||
EGLContext egl_context;
|
||||
EGLContext ctx;
|
||||
|
||||
/* request flags and specific versions for core (3.2+) WGL context */
|
||||
int flags = 0;
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
GdkGLContext *share = gdk_display_get_gl_context (display);
|
||||
|
||||
gdk_gl_context_get_required_version (context, &major, &minor);
|
||||
debug_bit = gdk_gl_context_get_debug_enabled (context);
|
||||
compat_bit = gdk_gl_context_get_forward_compatible (context);
|
||||
|
||||
/*
|
||||
* A legacy context cannot be shared with core profile ones, so this means we
|
||||
* must stick to a legacy context if the shared context is a legacy context
|
||||
*/
|
||||
|
||||
/* if GDK_GL_LEGACY is set, we default to a legacy context */
|
||||
legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ?
|
||||
TRUE :
|
||||
share != NULL && gdk_gl_context_is_legacy (share);
|
||||
|
||||
use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
|
||||
(share != NULL && gdk_gl_context_get_use_es (share));
|
||||
|
||||
if (debug_bit)
|
||||
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||
if (compat_bit)
|
||||
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||
|
||||
GDK_NOTE (OPENGL, g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s)",
|
||||
major, minor,
|
||||
debug_bit ? "yes" : "no",
|
||||
compat_bit ? "yes" : "no",
|
||||
legacy_bit ? "yes" : "no"));
|
||||
|
||||
ctx = create_egl_context (display_win32->egl_disp,
|
||||
display_win32->egl_config,
|
||||
share,
|
||||
flags,
|
||||
major,
|
||||
minor,
|
||||
&legacy_bit);
|
||||
|
||||
if (ctx == EGL_NO_CONTEXT)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
_("Unable to create a GL context"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GDK_NOTE (OPENGL, g_print ("Created EGL context[%p]\n", ctx));
|
||||
|
||||
context_egl->egl_context = ctx;
|
||||
|
||||
/* We are using GLES here */
|
||||
gdk_gl_context_set_use_es (context, TRUE);
|
||||
|
||||
/* Ensure that any other context is created with a legacy bit set */
|
||||
gdk_gl_context_set_is_legacy (context, legacy_bit);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_win32_gl_context_egl_clear_current (GdkGLContext *context)
|
||||
{
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
|
||||
if (display_win32->egl_disp != EGL_NO_DISPLAY)
|
||||
return eglMakeCurrent (display_win32->egl_disp,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_win32_gl_context_egl_make_current (GdkGLContext *context,
|
||||
gboolean surfaceless)
|
||||
{
|
||||
GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
GdkSurface *surface;
|
||||
|
||||
gboolean do_frame_sync = FALSE;
|
||||
|
||||
EGLSurface egl_surface;
|
||||
|
||||
surface = gdk_gl_context_get_surface (context);
|
||||
|
||||
if (!surfaceless)
|
||||
egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, FALSE);
|
||||
else
|
||||
{
|
||||
if (display_win32->hasEglSurfacelessContext)
|
||||
egl_surface = EGL_NO_SURFACE;
|
||||
else
|
||||
egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, TRUE);
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent (display_win32->egl_disp,
|
||||
egl_surface,
|
||||
egl_surface,
|
||||
context_egl->egl_context))
|
||||
return FALSE;
|
||||
|
||||
if (display_win32->egl_min_swap_interval == 0)
|
||||
eglSwapInterval (display_win32->egl_disp, 0);
|
||||
else
|
||||
g_debug ("Can't disable GL swap interval");
|
||||
|
||||
return TRUE;
|
||||
eglSwapBuffers (gdk_display_get_egl_display (display), egl_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -484,18 +129,11 @@ gdk_win32_gl_context_egl_class_init (GdkWin32GLContextClass *klass)
|
||||
{
|
||||
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS(klass);
|
||||
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
context_class->backend_type = GDK_GL_EGL;
|
||||
|
||||
context_class->realize = gdk_win32_gl_context_egl_realize;
|
||||
context_class->make_current = gdk_win32_gl_context_egl_make_current;
|
||||
context_class->clear_current = gdk_win32_gl_context_egl_clear_current;
|
||||
|
||||
draw_context_class->begin_frame = gdk_win32_gl_context_egl_begin_frame;
|
||||
draw_context_class->end_frame = gdk_win32_gl_context_egl_end_frame;
|
||||
|
||||
gobject_class->dispose = gdk_win32_gl_context_egl_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -226,9 +226,6 @@ gdk_init_dummy_wgl_context (GdkWin32Display *display_win32)
|
||||
gboolean set_pixel_format_result = FALSE;
|
||||
int best_idx = 0;
|
||||
|
||||
if (display_win32->dummy_context_wgl.hdc == NULL)
|
||||
display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
|
||||
|
||||
memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
|
||||
|
||||
best_idx = get_wgl_pfd (display_win32->dummy_context_wgl.hdc, &pfd, NULL);
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <cairo.h>
|
||||
#include <epoxy/wgl.h>
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
# include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/wgl.h>
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
# include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
GdkDisplay *_gdk_display = NULL;
|
||||
GdkDeviceManagerWin32 *_gdk_device_manager = NULL;
|
||||
|
||||
int _gdk_offset_x, _gdk_offset_y;
|
||||
|
||||
HDC _gdk_display_hdc;
|
||||
HINSTANCE _gdk_dll_hinstance;
|
||||
HINSTANCE _gdk_app_hmodule;
|
||||
|
||||
@@ -563,7 +563,7 @@ enum_monitor (HMONITOR hmonitor,
|
||||
GdkWin32Monitor *w32mon;
|
||||
GdkMonitor *mon;
|
||||
GdkRectangle rect;
|
||||
guint scale;
|
||||
int scale;
|
||||
|
||||
memset (&dd_monitor, 0, sizeof (dd_monitor));
|
||||
dd_monitor.cb = sizeof (dd_monitor);
|
||||
@@ -673,9 +673,6 @@ enum_monitor (HMONITOR hmonitor,
|
||||
HMONITOR hmonitor;
|
||||
POINT pt;
|
||||
|
||||
/* Not subtracting _gdk_offset_x and _gdk_offset_y because they will only
|
||||
* be added later on, in _gdk_win32_display_get_monitor_list().
|
||||
*/
|
||||
pt.x = w32mon->work_rect.x + w32mon->work_rect.width / 2;
|
||||
pt.y = w32mon->work_rect.y + w32mon->work_rect.height / 2;
|
||||
hmonitor = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
|
||||
@@ -772,45 +769,6 @@ _gdk_win32_display_get_monitor_list (GdkWin32Display *win32_display)
|
||||
prune_monitors (&data);
|
||||
}
|
||||
|
||||
_gdk_offset_x = G_MININT;
|
||||
_gdk_offset_y = G_MININT;
|
||||
|
||||
for (i = 0; i < data.monitors->len; i++)
|
||||
{
|
||||
GdkWin32Monitor *m;
|
||||
GdkRectangle rect;
|
||||
|
||||
m = g_ptr_array_index (data.monitors, i);
|
||||
|
||||
/* Calculate offset */
|
||||
gdk_monitor_get_geometry (GDK_MONITOR (m), &rect);
|
||||
_gdk_offset_x = MAX (_gdk_offset_x, -rect.x);
|
||||
_gdk_offset_y = MAX (_gdk_offset_y, -rect.y);
|
||||
}
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Multi-monitor offset: (%d,%d)\n",
|
||||
_gdk_offset_x, _gdk_offset_y));
|
||||
|
||||
/* Translate monitor coords into GDK coordinate space */
|
||||
for (i = 0; i < data.monitors->len; i++)
|
||||
{
|
||||
GdkWin32Monitor *m;
|
||||
GdkRectangle rect;
|
||||
|
||||
m = g_ptr_array_index (data.monitors, i);
|
||||
|
||||
gdk_monitor_get_geometry (GDK_MONITOR (m), &rect);
|
||||
rect.x += _gdk_offset_x;
|
||||
rect.y += _gdk_offset_y;
|
||||
gdk_monitor_set_geometry (GDK_MONITOR (m), &rect);
|
||||
|
||||
m->work_rect.x += _gdk_offset_x;
|
||||
m->work_rect.y += _gdk_offset_y;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@%+d%+d\n", i,
|
||||
rect.width, rect.height, rect.x, rect.y));
|
||||
}
|
||||
|
||||
return data.monitors;
|
||||
}
|
||||
|
||||
|
||||
@@ -258,13 +258,6 @@ extern GdkDisplay *_gdk_display;
|
||||
|
||||
extern GdkDeviceManagerWin32 *_gdk_device_manager;
|
||||
|
||||
/* Offsets to add to Windows coordinates (which are relative to the
|
||||
* primary monitor's origin, and thus might be negative for monitors
|
||||
* to the left and/or above the primary monitor) to get GDK
|
||||
* coordinates, which should be non-negative on the whole screen.
|
||||
*/
|
||||
extern int _gdk_offset_x, _gdk_offset_y;
|
||||
|
||||
extern HDC _gdk_display_hdc;
|
||||
extern HINSTANCE _gdk_dll_hinstance;
|
||||
extern HINSTANCE _gdk_app_hmodule;
|
||||
|
||||
+55
-135
@@ -473,7 +473,6 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
wchar_t *wtitle;
|
||||
int window_width, window_height;
|
||||
int window_x, window_y;
|
||||
int offset_x = 0, offset_y = 0;
|
||||
int real_x = 0, real_y = 0;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
@@ -528,8 +527,6 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
dwExStyle = 0;
|
||||
owner = NULL;
|
||||
|
||||
offset_x = _gdk_offset_x;
|
||||
offset_y = _gdk_offset_y;
|
||||
/* MSDN: We need WS_CLIPCHILDREN and WS_CLIPSIBLINGS for GL Context Creation */
|
||||
dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||
|
||||
@@ -561,8 +558,8 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
|
||||
AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
|
||||
|
||||
real_x = (x - offset_x) * impl->surface_scale;
|
||||
real_y = (y - offset_y) * impl->surface_scale;
|
||||
real_x = x * impl->surface_scale;
|
||||
real_y = y * impl->surface_scale;
|
||||
|
||||
if (surface_type == GDK_SURFACE_TOPLEVEL)
|
||||
{
|
||||
@@ -627,8 +624,8 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
|
||||
title,
|
||||
window_width, window_height,
|
||||
surface->x - offset_x,
|
||||
surface->y - offset_y,
|
||||
surface->x,
|
||||
surface->y,
|
||||
owner,
|
||||
hwndNew));
|
||||
|
||||
@@ -641,6 +638,7 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gdk_surface_set_egl_native_window (surface, (void *) impl->handle);
|
||||
if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
|
||||
gdk_winpointer_initialize_surface (surface);
|
||||
|
||||
@@ -688,22 +686,6 @@ gdk_win32_surface_destroy (GdkSurface *window,
|
||||
gdk_win32_surface_set_transient_for (child, NULL);
|
||||
}
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (window));
|
||||
|
||||
/* Get rid of any EGLSurfaces that we might have created */
|
||||
if (surface->egl_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface (display->egl_disp, surface->egl_surface);
|
||||
surface->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
if (surface->egl_dummy_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface (display->egl_disp, surface->egl_dummy_surface);
|
||||
surface->egl_dummy_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove ourself from our transient owner */
|
||||
if (surface->transient_owner != NULL)
|
||||
{
|
||||
@@ -712,6 +694,7 @@ gdk_win32_surface_destroy (GdkSurface *window,
|
||||
|
||||
if (!foreign_destroy)
|
||||
{
|
||||
gdk_surface_set_egl_native_window (window, NULL);
|
||||
window->destroyed = TRUE;
|
||||
DestroyWindow (GDK_SURFACE_HWND (window));
|
||||
}
|
||||
@@ -864,8 +847,8 @@ show_window_internal (GdkSurface *window,
|
||||
{
|
||||
GdkSurface *owner = surface->transient_owner;
|
||||
/* Center on transient parent */
|
||||
center_on_rect.left = (owner->x - _gdk_offset_x) * surface->surface_scale;
|
||||
center_on_rect.top = (owner->y - _gdk_offset_y) * surface->surface_scale;
|
||||
center_on_rect.left = owner->x * surface->surface_scale;
|
||||
center_on_rect.top = owner->y * surface->surface_scale;
|
||||
center_on_rect.right = center_on_rect.left + owner->width * surface->surface_scale;
|
||||
center_on_rect.bottom = center_on_rect.top + owner->height * surface->surface_scale;
|
||||
|
||||
@@ -1047,13 +1030,13 @@ gdk_win32_surface_do_move (GdkSurface *window,
|
||||
GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
|
||||
"NOACTIVATE|NOSIZE|NOZORDER)\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
(x - _gdk_offset_x) * impl->surface_scale,
|
||||
(y - _gdk_offset_y) * impl->surface_scale));
|
||||
x * impl->surface_scale,
|
||||
y * impl->surface_scale));
|
||||
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
SWP_NOZORDER_SPECIFIED,
|
||||
(x - _gdk_offset_x) * impl->surface_scale,
|
||||
(y - _gdk_offset_y) * impl->surface_scale,
|
||||
x * impl->surface_scale,
|
||||
y * impl->surface_scale,
|
||||
0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
|
||||
}
|
||||
@@ -1133,15 +1116,15 @@ gdk_win32_surface_do_move_resize (GdkSurface *window,
|
||||
GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
|
||||
"NOACTIVATE|NOZORDER)\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
(x - _gdk_offset_x) * impl->surface_scale,
|
||||
(y - _gdk_offset_y) * impl->surface_scale,
|
||||
x * impl->surface_scale,
|
||||
y * impl->surface_scale,
|
||||
outer_rect.right - outer_rect.left,
|
||||
outer_rect.bottom - outer_rect.top));
|
||||
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
SWP_NOZORDER_SPECIFIED,
|
||||
(x - _gdk_offset_x) * impl->surface_scale,
|
||||
(y - _gdk_offset_y) * impl->surface_scale,
|
||||
x * impl->surface_scale,
|
||||
y * impl->surface_scale,
|
||||
outer_rect.right - outer_rect.left,
|
||||
outer_rect.bottom - outer_rect.top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER));
|
||||
@@ -1681,14 +1664,6 @@ gdk_win32_surface_get_geometry (GdkSurface *window,
|
||||
|
||||
rect.right = pt.x;
|
||||
rect.bottom = pt.y;
|
||||
|
||||
if (parent == NULL)
|
||||
{
|
||||
rect.left += _gdk_offset_x * impl->surface_scale;
|
||||
rect.top += _gdk_offset_y * impl->surface_scale;
|
||||
rect.right += _gdk_offset_x * impl->surface_scale;
|
||||
rect.bottom += _gdk_offset_y * impl->surface_scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (x)
|
||||
@@ -1727,16 +1702,16 @@ gdk_win32_surface_get_root_coords (GdkSurface *window,
|
||||
ty = pt.y;
|
||||
|
||||
if (root_x)
|
||||
*root_x = (tx + _gdk_offset_x) / impl->surface_scale;
|
||||
*root_x = tx / impl->surface_scale;
|
||||
if (root_y)
|
||||
*root_y = (ty + _gdk_offset_y) / impl->surface_scale;
|
||||
*root_y = ty / impl->surface_scale;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_root_coords: %p: %+d%+d %+d%+d\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
x * impl->surface_scale,
|
||||
y * impl->surface_scale,
|
||||
(tx + _gdk_offset_x) / impl->surface_scale,
|
||||
(ty + _gdk_offset_y) / impl->surface_scale));
|
||||
tx / impl->surface_scale,
|
||||
ty / impl->surface_scale));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -2302,95 +2277,87 @@ stash_window (GdkSurface *window,
|
||||
}
|
||||
|
||||
static void
|
||||
snap_up (GdkSurface *window)
|
||||
snap_up (GdkSurface *surface)
|
||||
{
|
||||
SHORT maxysize;
|
||||
int x, y;
|
||||
int width, height;
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
|
||||
|
||||
stash_window (window, impl);
|
||||
stash_window (surface, impl);
|
||||
|
||||
maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->surface_scale;
|
||||
x = y = 0;
|
||||
width = gdk_surface_get_width (window);
|
||||
width = gdk_surface_get_width (surface);
|
||||
|
||||
y = 0;
|
||||
height = maxysize;
|
||||
|
||||
x = x - impl->shadow.left;
|
||||
y = y - impl->shadow.top;
|
||||
x = surface->x - impl->shadow.left / impl->surface_scale;
|
||||
y = y - impl->shadow.top / impl->surface_scale;
|
||||
width += impl->shadow_x;
|
||||
height += impl->shadow_y;
|
||||
|
||||
/* XXX: FIXME, AeroSnap snap_up() not really working well,
|
||||
*
|
||||
* * The snap_up() puts the window at the top left corner.
|
||||
* * Without the following call, the height maximizes but we see a spew of
|
||||
* "GdkToplevelSize: geometry size (x,y) exceeds bounds" warnings
|
||||
*/
|
||||
compute_toplevel_size (window, TRUE, &width, &height);
|
||||
|
||||
gdk_win32_surface_move_resize (window, x, y, width, height);
|
||||
gdk_win32_surface_move_resize (surface, x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
snap_left (GdkSurface *window,
|
||||
snap_left (GdkSurface *surface,
|
||||
GdkMonitor *monitor,
|
||||
GdkMonitor *snap_monitor)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
|
||||
|
||||
gdk_win32_monitor_get_workarea (snap_monitor, &rect);
|
||||
|
||||
stash_window (window, impl);
|
||||
stash_window (surface, impl);
|
||||
|
||||
rect.width = rect.width / 2;
|
||||
|
||||
rect.x = rect.x - impl->shadow.left;
|
||||
rect.y = rect.y - impl->shadow.top;
|
||||
rect.x = rect.x - impl->shadow.left / impl->surface_scale;
|
||||
rect.y = rect.y - impl->shadow.top / impl->surface_scale;
|
||||
rect.width = rect.width + impl->shadow_x;
|
||||
rect.height = rect.height + impl->shadow_y;
|
||||
|
||||
gdk_win32_surface_move_resize (window,
|
||||
gdk_win32_surface_move_resize (surface,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
}
|
||||
|
||||
static void
|
||||
snap_right (GdkSurface *window,
|
||||
snap_right (GdkSurface *surface,
|
||||
GdkMonitor *monitor,
|
||||
GdkMonitor *snap_monitor)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
impl = GDK_WIN32_SURFACE (window);
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
|
||||
|
||||
gdk_win32_monitor_get_workarea (snap_monitor, &rect);
|
||||
|
||||
stash_window (window, impl);
|
||||
stash_window (surface, impl);
|
||||
|
||||
rect.width = rect.width / 2;
|
||||
rect.x += rect.width;
|
||||
|
||||
rect.x = rect.x - impl->shadow.left;
|
||||
rect.y = rect.y - impl->shadow.top;
|
||||
rect.x = rect.x - impl->shadow.left / impl->surface_scale;
|
||||
rect.y = rect.y - impl->shadow.top / impl->surface_scale;
|
||||
rect.width = rect.width + impl->shadow_x;
|
||||
rect.height = rect.height + impl->shadow_y;
|
||||
|
||||
gdk_win32_surface_move_resize (window,
|
||||
gdk_win32_surface_move_resize (surface,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
}
|
||||
@@ -2883,8 +2850,8 @@ redraw_indicator (gpointer user_data)
|
||||
|
||||
last_draw = draw_indicator (context, context->draw_timestamp);
|
||||
|
||||
window_position.x = (context->indicator_window_rect.x - _gdk_offset_x) * impl->surface_scale;
|
||||
window_position.y = (context->indicator_window_rect.y - _gdk_offset_y) * impl->surface_scale;
|
||||
window_position.x = context->indicator_window_rect.x * impl->surface_scale;
|
||||
window_position.y = context->indicator_window_rect.y * impl->surface_scale;
|
||||
window_size.cx = context->indicator_window_rect.width * impl->surface_scale;
|
||||
window_size.cy = context->indicator_window_rect.height * impl->surface_scale;
|
||||
|
||||
@@ -3021,6 +2988,7 @@ update_fullup_indicator (GdkSurface *window,
|
||||
to.height = gdk_surface_get_height (window);
|
||||
|
||||
to.y = 0;
|
||||
to.x = window->x;
|
||||
to.height = maxysize;
|
||||
from = context->indicator_target;
|
||||
|
||||
@@ -3173,6 +3141,7 @@ start_indicator (GdkSurface *window,
|
||||
end_size.height = workarea.height;
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_STATE_FULLUP:
|
||||
start_size.x = end_size.x = window->x;
|
||||
end_size.y = 0;
|
||||
end_size.height = maxysize;
|
||||
break;
|
||||
@@ -3575,8 +3544,8 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
|
||||
placement.rcNormalPosition.right - placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
|
||||
placement.rcNormalPosition.left + _gdk_offset_x * impl->surface_scale,
|
||||
placement.rcNormalPosition.top + _gdk_offset_y * impl->surface_scale));
|
||||
placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.top));
|
||||
|
||||
unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
|
||||
unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
|
||||
@@ -3587,40 +3556,36 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
if (offsetx * impl->surface_scale < (shadow_unmax_width / 2) &&
|
||||
offsety * impl->surface_scale < (shadow_unmax_height / 2))
|
||||
{
|
||||
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
|
||||
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top) * impl->surface_scale;
|
||||
placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
|
||||
|
||||
if (left_half)
|
||||
{
|
||||
placement.rcNormalPosition.left = (root_x - offsetx + impl->shadow.left - _gdk_offset_x) * impl->surface_scale;
|
||||
placement.rcNormalPosition.left = (root_x - offsetx + impl->shadow.left) * impl->surface_scale;
|
||||
placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
placement.rcNormalPosition.right = (root_x + offsetx + impl->shadow.right - _gdk_offset_x) * impl->surface_scale;
|
||||
placement.rcNormalPosition.right = (root_x + offsetx + impl->shadow.right) * impl->surface_scale;
|
||||
placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
placement.rcNormalPosition.left = (root_x * impl->surface_scale) -
|
||||
(unmax_width / 2) -
|
||||
(_gdk_offset_x * impl->surface_scale);
|
||||
placement.rcNormalPosition.left = root_x * impl->surface_scale - unmax_width / 2;
|
||||
|
||||
if (offsety * impl->surface_scale < shadow_unmax_height / 2)
|
||||
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
|
||||
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top) * impl->surface_scale;
|
||||
else
|
||||
placement.rcNormalPosition.top = (root_y * impl->surface_scale) -
|
||||
(unmax_height / 2) -
|
||||
(_gdk_offset_y * impl->surface_scale);
|
||||
placement.rcNormalPosition.top = root_y * impl->surface_scale - unmax_height / 2;
|
||||
|
||||
placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
|
||||
placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
|
||||
}
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Unmaximized window will be at %ld : %ld\n",
|
||||
placement.rcNormalPosition.left + _gdk_offset_x * impl->surface_scale,
|
||||
placement.rcNormalPosition.top + _gdk_offset_y * impl->surface_scale));
|
||||
placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.top));
|
||||
|
||||
API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
|
||||
}
|
||||
@@ -3678,7 +3643,7 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
* the titlebar is, if any.
|
||||
*/
|
||||
root_y = wy + wheight / 2;
|
||||
SetCursorPos (root_x - _gdk_offset_x, root_y - _gdk_offset_y);
|
||||
SetCursorPos (root_x, root_y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3799,12 +3764,6 @@ gdk_win32_get_window_size_and_position_from_client_rect (GdkSurface *window,
|
||||
/* Turn client area into window area */
|
||||
_gdk_win32_adjust_client_rect (window, window_rect);
|
||||
|
||||
/* Convert GDK screen coordinates to W32 desktop coordinates */
|
||||
window_rect->left -= _gdk_offset_x * impl->surface_scale;
|
||||
window_rect->right -= _gdk_offset_x * impl->surface_scale;
|
||||
window_rect->top -= _gdk_offset_y * impl->surface_scale;
|
||||
window_rect->bottom -= _gdk_offset_y * impl->surface_scale;
|
||||
|
||||
window_position->x = window_rect->left;
|
||||
window_position->y = window_rect->top;
|
||||
window_size->cx = window_rect->right - window_rect->left;
|
||||
@@ -5053,39 +5012,6 @@ gdk_win32_drag_surface_iface_init (GdkDragSurfaceInterface *iface)
|
||||
iface->present = gdk_win32_drag_surface_present;
|
||||
}
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
EGLSurface
|
||||
gdk_win32_surface_get_egl_surface (GdkSurface *surface,
|
||||
EGLConfig config,
|
||||
gboolean is_dummy)
|
||||
{
|
||||
GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface));
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
if (is_dummy)
|
||||
{
|
||||
if (impl->egl_dummy_surface == EGL_NO_SURFACE)
|
||||
{
|
||||
EGLint attribs[] = {EGL_WIDTH, 1, EGL_WIDTH, 1, EGL_NONE};
|
||||
impl->egl_dummy_surface = eglCreatePbufferSurface (display->egl_disp,
|
||||
config,
|
||||
attribs);
|
||||
}
|
||||
return impl->egl_dummy_surface;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (impl->egl_surface == EGL_NO_SURFACE)
|
||||
impl->egl_surface = eglCreateWindowSurface (display->egl_disp,
|
||||
config,
|
||||
GDK_SURFACE_HWND (surface),
|
||||
NULL);
|
||||
|
||||
return impl->egl_surface;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
|
||||
@@ -5100,12 +5026,6 @@ gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
|
||||
/* Turn client area into window area */
|
||||
_gdk_win32_adjust_client_rect (surface, &window_rect);
|
||||
|
||||
/* Convert GDK screen coordinates to W32 desktop coordinates */
|
||||
window_rect.left -= _gdk_offset_x * impl->surface_scale;
|
||||
window_rect.right -= _gdk_offset_x * impl->surface_scale;
|
||||
window_rect.top -= _gdk_offset_y * impl->surface_scale;
|
||||
window_rect.bottom -= _gdk_offset_y * impl->surface_scale;
|
||||
|
||||
*return_window_rect = window_rect;
|
||||
}
|
||||
|
||||
@@ -5170,7 +5090,7 @@ _gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface)
|
||||
* as we need to re-acquire the EGL surfaces that we rendered to upload to Cairo explicitly,
|
||||
* using gdk_window_invalidate_rect (), when we maximize or restore or use aerosnap
|
||||
*/
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
|
||||
{
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
# include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
@@ -338,9 +338,7 @@ struct _GdkWin32Surface
|
||||
RECT configured_rect;
|
||||
} next_layout;
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
EGLSurface egl_surface;
|
||||
EGLSurface egl_dummy_surface;
|
||||
#ifdef HAVE_EGL
|
||||
guint egl_force_redraw_all : 1;
|
||||
#endif
|
||||
};
|
||||
@@ -373,7 +371,7 @@ void gdk_win32_surface_move_resize (GdkSurface *window,
|
||||
RECT
|
||||
gdk_win32_surface_handle_queued_move_resize (GdkDrawContext *draw_context);
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
#ifdef HAVE_EGL
|
||||
EGLSurface gdk_win32_surface_get_egl_surface (GdkSurface *surface,
|
||||
EGLConfig config,
|
||||
gboolean is_dummy);
|
||||
|
||||
@@ -46,10 +46,7 @@ gdk_win32_public_headers = files([
|
||||
|
||||
install_headers(gdk_win32_public_headers, 'gdkwin32.h', subdir: 'gtk-4.0/gdk/win32/')
|
||||
|
||||
GDK_WIN32_EGL_CFLAGS = []
|
||||
|
||||
if have_egl
|
||||
GDK_WIN32_EGL_CFLAGS = ['-DGDK_WIN32_ENABLE_EGL']
|
||||
gdk_win32_sources += ['gdkglcontext-win32-egl.c']
|
||||
endif
|
||||
|
||||
@@ -67,6 +64,6 @@ libgdk_win32 = static_library('gdk-win32',
|
||||
'-DINSIDE_GDK_WIN32',
|
||||
'-D_WIN32_WINNT=0x0601',
|
||||
'-DWINVER=0x0601',
|
||||
] + GDK_WIN32_EGL_CFLAGS,
|
||||
],
|
||||
dependencies: [ gdk_deps, gdk_win32_deps ],
|
||||
)
|
||||
|
||||
+10
-1
@@ -492,9 +492,18 @@ init_randr15 (GdkX11Screen *x11_screen)
|
||||
|
||||
if (output_info->crtc)
|
||||
{
|
||||
XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
|
||||
XRRCrtcInfo *crtc;
|
||||
int j;
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources,
|
||||
output_info->crtc);
|
||||
if (gdk_x11_display_error_trap_pop (display))
|
||||
{
|
||||
XRRFreeOutputInfo (output_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < resources->nmode; j++)
|
||||
{
|
||||
XRRModeInfo *xmode = &resources->modes[j];
|
||||
|
||||
@@ -269,6 +269,8 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
|
||||
default:
|
||||
|
||||
@@ -855,6 +857,8 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
default:
|
||||
break; /* Fallback */
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ snapshot_uniforms (GskGLUniformState *state,
|
||||
{
|
||||
const GskGLUniformMapping *mapping = &program->mappings[i];
|
||||
|
||||
if (!mapping->info.initial && mapping->location > -1)
|
||||
if (!mapping->info.initial && mapping->info.format && mapping->location > -1)
|
||||
{
|
||||
uniform[count].location = mapping->location;
|
||||
uniform[count].info = mapping->info;
|
||||
|
||||
+20
-9
@@ -28,10 +28,11 @@
|
||||
#include "gskglcompilerprivate.h"
|
||||
#include "gskglprogramprivate.h"
|
||||
|
||||
#define SHADER_VERSION_GLES 100
|
||||
#define SHADER_VERSION_GL2_LEGACY 110
|
||||
#define SHADER_VERSION_GL3_LEGACY 130
|
||||
#define SHADER_VERSION_GL3 150
|
||||
#define SHADER_VERSION_GLES "100"
|
||||
#define SHADER_VERSION_GLES3 "300 es"
|
||||
#define SHADER_VERSION_GL2_LEGACY "110"
|
||||
#define SHADER_VERSION_GL3_LEGACY "130"
|
||||
#define SHADER_VERSION_GL3 "150"
|
||||
|
||||
struct _GskGLCompiler
|
||||
{
|
||||
@@ -49,7 +50,7 @@ struct _GskGLCompiler
|
||||
|
||||
GArray *attrib_locations;
|
||||
|
||||
int glsl_version;
|
||||
const char *glsl_version;
|
||||
|
||||
guint gl3 : 1;
|
||||
guint gles : 1;
|
||||
@@ -98,7 +99,7 @@ gsk_gl_compiler_class_init (GskGLCompilerClass *klass)
|
||||
static void
|
||||
gsk_gl_compiler_init (GskGLCompiler *self)
|
||||
{
|
||||
self->glsl_version = 150;
|
||||
self->glsl_version = "150";
|
||||
self->attrib_locations = g_array_new (FALSE, FALSE, sizeof (GskGLProgramAttrib));
|
||||
self->all_preamble = g_bytes_ref (empty_bytes);
|
||||
self->vertex_preamble = g_bytes_ref (empty_bytes);
|
||||
@@ -127,8 +128,18 @@ gsk_gl_compiler_new (GskGLDriver *driver,
|
||||
|
||||
if (gdk_gl_context_get_use_es (context))
|
||||
{
|
||||
self->glsl_version = SHADER_VERSION_GLES;
|
||||
self->gles = TRUE;
|
||||
int maj, min;
|
||||
|
||||
/* for OpenGL/ES 3.0+, use "300 es" as our shader version */
|
||||
gdk_gl_context_get_version (context, &maj, &min);
|
||||
|
||||
if (maj >= 3)
|
||||
self->glsl_version = SHADER_VERSION_GLES3;
|
||||
else
|
||||
{
|
||||
self->glsl_version = SHADER_VERSION_GLES;
|
||||
self->gles = TRUE;
|
||||
}
|
||||
}
|
||||
else if (gdk_gl_context_is_legacy (context))
|
||||
{
|
||||
@@ -546,7 +557,7 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
|
||||
gsk_gl_command_queue_make_current (self->driver->command_queue);
|
||||
|
||||
g_snprintf (version, sizeof version, "#version %d\n", self->glsl_version);
|
||||
g_snprintf (version, sizeof version, "#version %s\n", self->glsl_version);
|
||||
|
||||
if (self->debug_shaders)
|
||||
debug = "#define GSK_DEBUG 1\n";
|
||||
|
||||
+91
-110
@@ -32,6 +32,7 @@
|
||||
#include "gskglcommandqueueprivate.h"
|
||||
#include "gskglcompilerprivate.h"
|
||||
#include "gskglglyphlibraryprivate.h"
|
||||
#include "gskglglyphylibraryprivate.h"
|
||||
#include "gskgliconlibraryprivate.h"
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskglshadowlibraryprivate.h"
|
||||
@@ -44,9 +45,6 @@
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#define ATLAS_SIZE 512
|
||||
#define MAX_OLD_RATIO 0.5
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
static guint
|
||||
@@ -156,50 +154,6 @@ gsk_gl_driver_collect_unused_textures (GskGLDriver *self,
|
||||
return collected;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_texture_atlas_free (GskGLTextureAtlas *atlas)
|
||||
{
|
||||
if (atlas->texture_id != 0)
|
||||
{
|
||||
glDeleteTextures (1, &atlas->texture_id);
|
||||
atlas->texture_id = 0;
|
||||
}
|
||||
|
||||
g_clear_pointer (&atlas->nodes, g_free);
|
||||
g_slice_free (GskGLTextureAtlas, atlas);
|
||||
}
|
||||
|
||||
GskGLTextureAtlas *
|
||||
gsk_gl_driver_create_atlas (GskGLDriver *self)
|
||||
{
|
||||
GskGLTextureAtlas *atlas;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL);
|
||||
|
||||
atlas = g_slice_new0 (GskGLTextureAtlas);
|
||||
atlas->width = ATLAS_SIZE;
|
||||
atlas->height = ATLAS_SIZE;
|
||||
/* TODO: We might want to change the strategy about the amount of
|
||||
* nodes here? stb_rect_pack.h says width is optimal. */
|
||||
atlas->nodes = g_malloc0_n (atlas->width, sizeof (struct stbrp_node));
|
||||
stbrp_init_target (&atlas->context, atlas->width, atlas->height, atlas->nodes, atlas->width);
|
||||
atlas->texture_id = gsk_gl_command_queue_create_texture (self->command_queue,
|
||||
atlas->width,
|
||||
atlas->height,
|
||||
GL_RGBA8,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR);
|
||||
|
||||
gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
|
||||
GL_TEXTURE, atlas->texture_id,
|
||||
"Texture atlas %d",
|
||||
atlas->texture_id);
|
||||
|
||||
g_ptr_array_add (self->atlases, atlas);
|
||||
|
||||
return atlas;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_program (gpointer data)
|
||||
{
|
||||
@@ -226,6 +180,29 @@ gsk_gl_driver_shader_weak_cb (gpointer data,
|
||||
g_hash_table_remove (self->shader_cache, where_object_was);
|
||||
}
|
||||
|
||||
G_GNUC_NULL_TERMINATED static inline GBytes *
|
||||
join_sources (GBytes *first_bytes,
|
||||
...)
|
||||
{
|
||||
GByteArray *byte_array = g_byte_array_new ();
|
||||
GBytes *bytes = first_bytes;
|
||||
va_list args;
|
||||
|
||||
va_start (args, first_bytes);
|
||||
while (bytes != NULL)
|
||||
{
|
||||
gsize len;
|
||||
const guint8 *data = g_bytes_get_data (bytes, &len);
|
||||
if (len > 0)
|
||||
g_byte_array_append (byte_array, data, len);
|
||||
g_bytes_unref (bytes);
|
||||
bytes = va_arg (args, GBytes *);
|
||||
}
|
||||
va_end (args);
|
||||
|
||||
return g_byte_array_free_to_bytes (byte_array);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_dispose (GObject *object)
|
||||
{
|
||||
@@ -235,6 +212,10 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
g_assert (self->in_frame == FALSE);
|
||||
|
||||
#define GSK_GL_NO_UNIFORMS
|
||||
#define GSK_GL_SHADER_RESOURCE(name)
|
||||
#define GSK_GL_SHADER_STRING(str)
|
||||
#define GSK_GL_SHADER_SINGLE(name)
|
||||
#define GSK_GL_SHADER_JOINED(kind, ...)
|
||||
#define GSK_GL_ADD_UNIFORM(pos, KEY, name)
|
||||
#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \
|
||||
GSK_GL_DELETE_PROGRAM(name); \
|
||||
@@ -248,6 +229,10 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
} G_STMT_END;
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_NO_UNIFORMS
|
||||
#undef GSK_GL_SHADER_RESOURCE
|
||||
#undef GSK_GL_SHADER_STRING
|
||||
#undef GSK_GL_SHADER_SINGLE
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
|
||||
@@ -289,11 +274,11 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
g_assert (!self->texture_id_to_key || g_hash_table_size (self->texture_id_to_key) == 0);
|
||||
g_assert (!self->key_to_texture_id|| g_hash_table_size (self->key_to_texture_id) == 0);
|
||||
|
||||
g_clear_object (&self->glyphs);
|
||||
g_clear_object (&self->icons);
|
||||
g_clear_object (&self->shadows);
|
||||
g_clear_object (&self->glyphs_library);
|
||||
g_clear_object (&self->glyphy_library);
|
||||
g_clear_object (&self->icons_library);
|
||||
g_clear_object (&self->shadows_library);
|
||||
|
||||
g_clear_pointer (&self->atlases, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->autorelease_framebuffers, g_array_unref);
|
||||
g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref);
|
||||
g_clear_pointer (&self->textures, g_hash_table_unref);
|
||||
@@ -330,7 +315,6 @@ gsk_gl_driver_init (GskGLDriver *self)
|
||||
self->shader_cache = g_hash_table_new_full (NULL, NULL, NULL, remove_program);
|
||||
self->texture_pool = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
self->render_targets = g_ptr_array_new ();
|
||||
self->atlases = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -348,14 +332,14 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
|
||||
/* Setup preambles that are shared by all shaders */
|
||||
gsk_gl_compiler_set_preamble_from_resource (compiler,
|
||||
GSK_GL_COMPILER_ALL,
|
||||
"/org/gtk/libgsk/gl/preamble.glsl");
|
||||
GSK_GL_COMPILER_ALL,
|
||||
"/org/gtk/libgsk/gl/preamble.glsl");
|
||||
gsk_gl_compiler_set_preamble_from_resource (compiler,
|
||||
GSK_GL_COMPILER_VERTEX,
|
||||
"/org/gtk/libgsk/gl/preamble.vs.glsl");
|
||||
GSK_GL_COMPILER_VERTEX,
|
||||
"/org/gtk/libgsk/gl/preamble.vs.glsl");
|
||||
gsk_gl_compiler_set_preamble_from_resource (compiler,
|
||||
GSK_GL_COMPILER_FRAGMENT,
|
||||
"/org/gtk/libgsk/gl/preamble.fs.glsl");
|
||||
GSK_GL_COMPILER_FRAGMENT,
|
||||
"/org/gtk/libgsk/gl/preamble.fs.glsl");
|
||||
|
||||
/* Setup attributes that are provided via VBO */
|
||||
gsk_gl_compiler_bind_attribute (compiler, "aPosition", 0);
|
||||
@@ -365,10 +349,28 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
|
||||
/* Use XMacros to register all of our programs and their uniforms */
|
||||
#define GSK_GL_NO_UNIFORMS
|
||||
#define GSK_GL_SHADER_RESOURCE(name) \
|
||||
g_bytes_ref(g_resources_lookup_data("/org/gtk/libgsk/gl/" name, 0, NULL))
|
||||
#define GSK_GL_SHADER_STRING(str) \
|
||||
g_bytes_new_static(str, strlen(str))
|
||||
#define GSK_GL_SHADER_SINGLE(bytes) \
|
||||
G_STMT_START { \
|
||||
GBytes *b = bytes; \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_ALL, b); \
|
||||
g_bytes_unref (b); \
|
||||
} G_STMT_END;
|
||||
#define GSK_GL_SHADER_JOINED(kind, ...) \
|
||||
G_STMT_START { \
|
||||
GBytes *bytes = join_sources(__VA_ARGS__); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_##kind, bytes); \
|
||||
g_bytes_unref (bytes); \
|
||||
} G_STMT_END;
|
||||
#define GSK_GL_ADD_UNIFORM(pos, KEY, name) \
|
||||
gsk_gl_program_add_uniform (program, #name, UNIFORM_##KEY);
|
||||
#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \
|
||||
gsk_gl_compiler_set_source_from_resource (compiler, GSK_GL_COMPILER_ALL, resource); \
|
||||
#define GSK_GL_DEFINE_PROGRAM(name, sources, uniforms) \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \
|
||||
sources \
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name, uniforms, "");
|
||||
@@ -401,6 +403,11 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
#undef GSK_GL_DEFINE_PROGRAM_CLIP
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_SHADER_SINGLE
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
#undef GSK_GL_SHADER_RESOURCE
|
||||
#undef GSK_GL_SHADER_STRING
|
||||
#undef GSK_GL_NO_UNIFORMS
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
@@ -456,9 +463,10 @@ gsk_gl_driver_new (GskGLCommandQueue *command_queue,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->glyphs = gsk_gl_glyph_library_new (self);
|
||||
self->icons = gsk_gl_icon_library_new (self);
|
||||
self->shadows = gsk_gl_shadow_library_new (self);
|
||||
self->glyphs_library = gsk_gl_glyph_library_new (self);
|
||||
self->glyphy_library = gsk_gl_glyphy_library_new (self);
|
||||
self->icons_library = gsk_gl_icon_library_new (self);
|
||||
self->shadows_library = gsk_gl_shadow_library_new (self);
|
||||
|
||||
gdk_profiler_end_mark (before, "create GskGLDriver", NULL);
|
||||
|
||||
@@ -518,37 +526,6 @@ failure:
|
||||
return g_steal_pointer (&driver);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
gsk_gl_driver_compact_atlases (GskGLDriver *self)
|
||||
{
|
||||
GPtrArray *removed = NULL;
|
||||
|
||||
g_assert (GSK_IS_GL_DRIVER (self));
|
||||
|
||||
for (guint i = self->atlases->len; i > 0; i--)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1);
|
||||
|
||||
if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
|
||||
{
|
||||
GSK_NOTE (GLYPH_CACHE,
|
||||
g_message ("Dropping atlas %d (%g.2%% old)", i,
|
||||
100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)));
|
||||
if (removed == NULL)
|
||||
removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free);
|
||||
g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
GSK_NOTE (GLYPH_CACHE, {
|
||||
static guint timestamp;
|
||||
if (timestamp++ % 60 == 0)
|
||||
g_message ("%d atlases", self->atlases->len);
|
||||
});
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_begin_frame:
|
||||
* @self: a `GskGLDriver`
|
||||
@@ -565,7 +542,6 @@ gsk_gl_driver_begin_frame (GskGLDriver *self,
|
||||
GskGLCommandQueue *command_queue)
|
||||
{
|
||||
gint64 last_frame_id;
|
||||
GPtrArray *removed;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue));
|
||||
@@ -580,19 +556,16 @@ gsk_gl_driver_begin_frame (GskGLDriver *self,
|
||||
|
||||
gsk_gl_command_queue_begin_frame (self->command_queue);
|
||||
|
||||
/* Compact atlases with too many freed pixels */
|
||||
removed = gsk_gl_driver_compact_atlases (self);
|
||||
|
||||
/* Mark unused pixel regions of the atlases */
|
||||
gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons),
|
||||
self->current_frame_id,
|
||||
removed);
|
||||
gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs),
|
||||
self->current_frame_id,
|
||||
removed);
|
||||
gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons_library),
|
||||
self->current_frame_id);
|
||||
gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs_library),
|
||||
self->current_frame_id);
|
||||
gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphy_library),
|
||||
self->current_frame_id);
|
||||
|
||||
/* Cleanup old shadows */
|
||||
gsk_gl_shadow_library_begin_frame (self->shadows);
|
||||
gsk_gl_shadow_library_begin_frame (self->shadows_library);
|
||||
|
||||
/* Remove all textures that are from a previous frame or are no
|
||||
* longer used by linked GdkTexture. We do this at the beginning
|
||||
@@ -600,9 +573,6 @@ gsk_gl_driver_begin_frame (GskGLDriver *self,
|
||||
* we block on any resources while delivering our frames.
|
||||
*/
|
||||
gsk_gl_driver_collect_unused_textures (self, last_frame_id - 1);
|
||||
|
||||
/* Now free atlas textures */
|
||||
g_clear_pointer (&removed, g_ptr_array_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1182,14 +1152,23 @@ void
|
||||
gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
const char *directory)
|
||||
{
|
||||
GPtrArray *atlases;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
|
||||
if (directory == NULL)
|
||||
directory = ".";
|
||||
|
||||
for (guint i = 0; i < self->atlases->len; i++)
|
||||
#define copy_atlases(dst, library) \
|
||||
g_ptr_array_extend(dst, GSK_GL_TEXTURE_LIBRARY(library)->atlases, NULL, NULL)
|
||||
atlases = g_ptr_array_new ();
|
||||
copy_atlases (atlases, self->glyphs_library);
|
||||
copy_atlases (atlases, self->icons_library);
|
||||
#undef copy_atlases
|
||||
|
||||
for (guint i = 0; i < atlases->len; i++)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (atlases, i);
|
||||
char *filename = g_strdup_printf ("%s%sframe-%d-atlas-%d.png",
|
||||
directory,
|
||||
G_DIR_SEPARATOR_S,
|
||||
@@ -1198,6 +1177,8 @@ gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
write_atlas_to_png (self, atlas, filename);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
g_ptr_array_unref (atlases);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -100,17 +100,16 @@ struct _GskGLDriver
|
||||
GskGLCommandQueue *shared_command_queue;
|
||||
GskGLCommandQueue *command_queue;
|
||||
|
||||
GskGLGlyphLibrary *glyphs;
|
||||
GskGLIconLibrary *icons;
|
||||
GskGLShadowLibrary *shadows;
|
||||
GskGLGlyphLibrary *glyphs_library;
|
||||
GskGLGlyphyLibrary *glyphy_library;
|
||||
GskGLIconLibrary *icons_library;
|
||||
GskGLShadowLibrary *shadows_library;
|
||||
|
||||
GArray *texture_pool;
|
||||
GHashTable *textures;
|
||||
GHashTable *key_to_texture_id;
|
||||
GHashTable *texture_id_to_key;
|
||||
|
||||
GPtrArray *atlases;
|
||||
|
||||
GHashTable *shader_cache;
|
||||
|
||||
GArray *autorelease_framebuffers;
|
||||
@@ -184,7 +183,6 @@ void gsk_gl_driver_add_texture_slices (GskGLDriver *s
|
||||
GskGLProgram * gsk_gl_driver_lookup_shader (GskGLDriver *self,
|
||||
GskGLShader *shader,
|
||||
GError **error);
|
||||
GskGLTextureAtlas * gsk_gl_driver_create_atlas (GskGLDriver *self);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
void gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
|
||||
+65
-19
@@ -84,15 +84,64 @@ gsk_gl_glyph_value_free (gpointer data)
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyph_library_begin_frame (GskGLTextureLibrary *library,
|
||||
gint64 frame_id,
|
||||
GPtrArray *removed_atlases)
|
||||
gsk_gl_glyph_library_clear_cache (GskGLTextureLibrary *library)
|
||||
{
|
||||
GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)library;
|
||||
|
||||
g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
|
||||
|
||||
memset (self->front, 0, sizeof self->front);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self,
|
||||
GskGLTextureAtlas *atlas)
|
||||
{
|
||||
gboolean packed G_GNUC_UNUSED;
|
||||
int x, y;
|
||||
guint gl_format;
|
||||
guint gl_type;
|
||||
guint8 pixel_data[4 * 3 * 3];
|
||||
|
||||
g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
|
||||
g_assert (atlas != NULL);
|
||||
|
||||
/* Insert a single pixel at 0,0 for use in coloring */
|
||||
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
"Initializing Atlas");
|
||||
|
||||
packed = gsk_gl_texture_library_allocate (self, atlas, 3, 3, &x, &y);
|
||||
g_assert (packed);
|
||||
g_assert (x == 0 && y == 0);
|
||||
|
||||
memset (pixel_data, 255, sizeof pixel_data);
|
||||
|
||||
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
|
||||
{
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_format = GL_BGRA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
0, 0,
|
||||
3, 3,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
|
||||
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
|
||||
|
||||
self->driver->command_queue->n_uploads++;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gsk_gl_glyph_library_finalize (GObject *object)
|
||||
{
|
||||
@@ -111,7 +160,8 @@ gsk_gl_glyph_library_class_init (GskGLGlyphLibraryClass *klass)
|
||||
|
||||
object_class->finalize = gsk_gl_glyph_library_finalize;
|
||||
|
||||
library_class->begin_frame = gsk_gl_glyph_library_begin_frame;
|
||||
library_class->clear_cache = gsk_gl_glyph_library_clear_cache;
|
||||
library_class->init_atlas = gsk_gl_glyph_library_init_atlas;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -161,25 +211,27 @@ gsk_gl_glyph_library_create_surface (GskGLGlyphLibrary *self,
|
||||
|
||||
static void
|
||||
render_glyph (cairo_surface_t *surface,
|
||||
const cairo_scaled_font_t *scaled_font,
|
||||
const GskGLGlyphKey *key,
|
||||
const GskGLGlyphValue *value)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cairo_glyph_t glyph;
|
||||
PangoGlyphString glyph_string;
|
||||
PangoGlyphInfo glyph_info;
|
||||
|
||||
g_assert (surface != NULL);
|
||||
g_assert (scaled_font != NULL);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_scaled_font (cr, scaled_font);
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 1);
|
||||
|
||||
glyph.index = key->glyph;
|
||||
glyph.x = 0.25 * key->xshift - value->ink_rect.x;
|
||||
glyph.y = 0.25 * key->yshift - value->ink_rect.y;
|
||||
glyph_info.glyph = key->glyph;
|
||||
glyph_info.geometry.width = value->ink_rect.width * 1024;
|
||||
glyph_info.geometry.x_offset = 0.25 * key->xshift - value->ink_rect.x * 1024;
|
||||
glyph_info.geometry.y_offset = 0.25 * key->yshift - value->ink_rect.y * 1024;
|
||||
|
||||
cairo_show_glyphs (cr, &glyph, 1);
|
||||
glyph_string.num_glyphs = 1;
|
||||
glyph_string.glyphs = &glyph_info;
|
||||
|
||||
pango_cairo_show_glyph_string (cr, key->font, &glyph_string);
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_flush (surface);
|
||||
@@ -198,7 +250,6 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
|
||||
{
|
||||
GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self;
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
cairo_surface_t *surface;
|
||||
guchar *pixel_data;
|
||||
guchar *free_data = NULL;
|
||||
@@ -211,11 +262,6 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
|
||||
g_assert (key != NULL);
|
||||
g_assert (value != NULL);
|
||||
|
||||
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->font);
|
||||
if G_UNLIKELY (scaled_font == NULL ||
|
||||
cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
|
||||
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
@@ -223,7 +269,7 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
|
||||
key->glyph);
|
||||
|
||||
surface = gsk_gl_glyph_library_create_surface (self, stride, width, height, uwidth, uheight);
|
||||
render_glyph (surface, scaled_font, key, value);
|
||||
render_glyph (surface, key, value);
|
||||
|
||||
texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value);
|
||||
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
/* gskglglyphylibrary.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/* Some of the glyphy cache is based upon the original glyphy code.
|
||||
* It's license is provided below.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012 Google, Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
|
||||
#include "gskglcommandqueueprivate.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglglyphylibraryprivate.h"
|
||||
|
||||
#include "gskpath.h"
|
||||
|
||||
#include <glyphy.h>
|
||||
|
||||
#define TOLERANCE (1/2048.)
|
||||
#define MIN_FONT_SIZE 14
|
||||
#define GRID_SIZE 20 /* Per EM */
|
||||
#define ENLIGHTEN_MAX .01 /* Per EM */
|
||||
#define EMBOLDEN_MAX .024 /* Per EM */
|
||||
#define ITEM_W 64
|
||||
#define ITEM_H_QUANTUM 8
|
||||
|
||||
G_DEFINE_TYPE (GskGLGlyphyLibrary, gsk_gl_glyphy_library, GSK_TYPE_GL_TEXTURE_LIBRARY)
|
||||
|
||||
GskGLGlyphyLibrary *
|
||||
gsk_gl_glyphy_library_new (GskGLDriver *driver)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
|
||||
|
||||
return g_object_new (GSK_TYPE_GL_GLYPHY_LIBRARY,
|
||||
"driver", driver,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static guint
|
||||
gsk_gl_glyphy_key_hash (gconstpointer data)
|
||||
{
|
||||
const GskGLGlyphyKey *key = data;
|
||||
|
||||
/* malloc()'d pointers already guarantee 3 bits from the LSB on 64-bit and
|
||||
* 2 bits from the LSB on 32-bit. Shift by enough to give us 256 entries
|
||||
* in our front cache for the glyph since languages will naturally cluster
|
||||
* for us.
|
||||
*/
|
||||
|
||||
return (key->font << 8) ^ key->glyph;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_glyphy_key_equal (gconstpointer v1,
|
||||
gconstpointer v2)
|
||||
{
|
||||
return memcmp (v1, v2, sizeof (GskGLGlyphyKey)) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_key_free (gpointer data)
|
||||
{
|
||||
GskGLGlyphyKey *key = data;
|
||||
|
||||
g_slice_free (GskGLGlyphyKey, key);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_value_free (gpointer data)
|
||||
{
|
||||
g_slice_free (GskGLGlyphyValue, data);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_library_clear_cache (GskGLTextureLibrary *library)
|
||||
{
|
||||
GskGLGlyphyLibrary *self = (GskGLGlyphyLibrary *)library;
|
||||
|
||||
g_assert (GSK_IS_GL_GLYPHY_LIBRARY (self));
|
||||
|
||||
memset (self->front, 0, sizeof self->front);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_library_init_atlas (GskGLTextureLibrary *library,
|
||||
GskGLTextureAtlas *atlas)
|
||||
{
|
||||
g_assert (GSK_IS_GL_GLYPHY_LIBRARY (library));
|
||||
g_assert (atlas != NULL);
|
||||
|
||||
atlas->cursor_x = 0;
|
||||
atlas->cursor_y = 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_glyphy_library_allocate (GskGLTextureLibrary *library,
|
||||
GskGLTextureAtlas *atlas,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
GskGLGlyphyLibrary *self = (GskGLGlyphyLibrary *)library;
|
||||
int cursor_save_x;
|
||||
int cursor_save_y;
|
||||
|
||||
g_assert (GSK_IS_GL_GLYPHY_LIBRARY (self));
|
||||
g_assert (atlas != NULL);
|
||||
|
||||
cursor_save_x = atlas->cursor_x;
|
||||
cursor_save_y = atlas->cursor_y;
|
||||
|
||||
if ((height & (self->item_h_q-1)) != 0)
|
||||
height = (height + self->item_h_q - 1) & ~(self->item_h_q - 1);
|
||||
|
||||
/* Require allocations in columns of 64 and rows of 8 */
|
||||
g_assert (width == self->item_w);
|
||||
g_assert ((height % self->item_h_q) == 0);
|
||||
|
||||
if (atlas->cursor_y + height > atlas->height)
|
||||
{
|
||||
/* Go to next column */
|
||||
atlas->cursor_x += self->item_w;
|
||||
atlas->cursor_y = 0;
|
||||
}
|
||||
|
||||
if (atlas->cursor_x + width <= atlas->width &&
|
||||
atlas->cursor_y + height <= atlas->height)
|
||||
{
|
||||
*out_x = atlas->cursor_x;
|
||||
*out_y = atlas->cursor_y;
|
||||
atlas->cursor_y += height;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
atlas->cursor_x = cursor_save_x;
|
||||
atlas->cursor_y = cursor_save_y;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_library_finalize (GObject *object)
|
||||
{
|
||||
GskGLGlyphyLibrary *self = (GskGLGlyphyLibrary *)object;
|
||||
|
||||
g_clear_pointer (&self->acc, glyphy_arc_accumulator_destroy);
|
||||
g_clear_pointer (&self->acc_endpoints, g_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_glyphy_library_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
GQuark quark_glyphy_font_key;
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_library_class_init (GskGLGlyphyLibraryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GskGLTextureLibraryClass *library_class = GSK_GL_TEXTURE_LIBRARY_CLASS (klass);
|
||||
|
||||
quark_glyphy_font_key = g_quark_from_static_string ("glyphy-font-key");
|
||||
|
||||
object_class->finalize = gsk_gl_glyphy_library_finalize;
|
||||
|
||||
library_class->allocate = gsk_gl_glyphy_library_allocate;
|
||||
library_class->clear_cache = gsk_gl_glyphy_library_clear_cache;
|
||||
library_class->init_atlas = gsk_gl_glyphy_library_init_atlas;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_glyphy_library_init (GskGLGlyphyLibrary *self)
|
||||
{
|
||||
GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self;
|
||||
|
||||
tl->max_entry_size = 0;
|
||||
tl->max_frame_age = 512;
|
||||
tl->atlas_width = 2048;
|
||||
tl->atlas_height = 1024;
|
||||
gsk_gl_texture_library_set_funcs (tl,
|
||||
gsk_gl_glyphy_key_hash,
|
||||
gsk_gl_glyphy_key_equal,
|
||||
gsk_gl_glyphy_key_free,
|
||||
gsk_gl_glyphy_value_free);
|
||||
|
||||
self->acc = glyphy_arc_accumulator_create ();
|
||||
self->acc_endpoints = g_array_new (FALSE, FALSE, sizeof (glyphy_arc_endpoint_t));
|
||||
self->item_w = ITEM_W;
|
||||
self->item_h_q = ITEM_H_QUANTUM;
|
||||
}
|
||||
|
||||
static glyphy_bool_t
|
||||
accumulate_endpoint (glyphy_arc_endpoint_t *endpoint,
|
||||
GArray *endpoints)
|
||||
{
|
||||
g_array_append_vals (endpoints, endpoint, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
move_to (hb_draw_funcs_t *dfuncs,
|
||||
GskPathBuilder *builder,
|
||||
hb_draw_state_t *st,
|
||||
float x,
|
||||
float y,
|
||||
void *data)
|
||||
{
|
||||
gsk_path_builder_move_to (builder, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
line_to (hb_draw_funcs_t *dfuncs,
|
||||
GskPathBuilder *builder,
|
||||
hb_draw_state_t *st,
|
||||
float x,
|
||||
float y,
|
||||
void *data)
|
||||
{
|
||||
gsk_path_builder_line_to (builder, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
cubic_to (hb_draw_funcs_t *dfuncs,
|
||||
GskPathBuilder *builder,
|
||||
hb_draw_state_t *st,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3,
|
||||
void *data)
|
||||
{
|
||||
gsk_path_builder_curve_to (builder, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
static void
|
||||
close_path (hb_draw_funcs_t *dfuncs,
|
||||
GskPathBuilder *builder,
|
||||
hb_draw_state_t *st,
|
||||
void *data)
|
||||
{
|
||||
gsk_path_builder_close (builder);
|
||||
}
|
||||
|
||||
static hb_draw_funcs_t *
|
||||
gsk_path_get_draw_funcs (void)
|
||||
{
|
||||
static hb_draw_funcs_t *funcs = NULL;
|
||||
|
||||
if (!funcs)
|
||||
{
|
||||
funcs = hb_draw_funcs_create ();
|
||||
|
||||
hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, NULL, NULL);
|
||||
hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, NULL, NULL);
|
||||
hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
|
||||
hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, NULL, NULL);
|
||||
|
||||
hb_draw_funcs_make_immutable (funcs);
|
||||
}
|
||||
|
||||
return funcs;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
acc_callback (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data)
|
||||
{
|
||||
glyphy_arc_accumulator_t *acc = user_data;
|
||||
glyphy_point_t p0, p1, p2, p3;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GSK_PATH_MOVE:
|
||||
p0.x = pts[0].x; p0.y = pts[0].y;
|
||||
glyphy_arc_accumulator_move_to (acc, &p0);
|
||||
break;
|
||||
case GSK_PATH_CLOSE:
|
||||
glyphy_arc_accumulator_close_path (acc);
|
||||
break;
|
||||
case GSK_PATH_LINE:
|
||||
p1.x = pts[1].x; p1.y = pts[1].y;
|
||||
glyphy_arc_accumulator_line_to (acc, &p1);
|
||||
break;
|
||||
case GSK_PATH_CURVE:
|
||||
p1.x = pts[1].x; p1.y = pts[1].y;
|
||||
p2.x = pts[2].x; p2.y = pts[2].y;
|
||||
p3.x = pts[3].x; p3.y = pts[3].y;
|
||||
glyphy_arc_accumulator_cubic_to (acc, &p1, &p2, &p3);
|
||||
break;
|
||||
case GSK_PATH_CONIC:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
encode_glyph (GskGLGlyphyLibrary *self,
|
||||
hb_font_t *font,
|
||||
unsigned int glyph_index,
|
||||
double tolerance_per_em,
|
||||
glyphy_rgba_t *buffer,
|
||||
guint buffer_len,
|
||||
guint *output_len,
|
||||
guint *nominal_width,
|
||||
guint *nominal_height,
|
||||
glyphy_extents_t *extents)
|
||||
{
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
guint upem = hb_face_get_upem (face);
|
||||
double tolerance = upem * tolerance_per_em;
|
||||
double faraway = (double)upem / (MIN_FONT_SIZE * M_SQRT2);
|
||||
double unit_size = (double) upem / GRID_SIZE;
|
||||
double enlighten_max = (double) upem * ENLIGHTEN_MAX;
|
||||
double embolden_max = (double) upem * EMBOLDEN_MAX;
|
||||
double avg_fetch_achieved;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path, *simplified;
|
||||
|
||||
self->acc_endpoints->len = 0;
|
||||
|
||||
glyphy_arc_accumulator_reset (self->acc);
|
||||
glyphy_arc_accumulator_set_tolerance (self->acc, tolerance);
|
||||
glyphy_arc_accumulator_set_callback (self->acc,
|
||||
(glyphy_arc_endpoint_accumulator_callback_t)accumulate_endpoint,
|
||||
self->acc_endpoints);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
hb_font_get_glyph_shape (font, glyph_index, gsk_path_get_draw_funcs (), builder);
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
simplified = gsk_path_simplify (path);
|
||||
|
||||
gsk_path_foreach (simplified, GSK_PATH_FOREACH_ALLOW_CURVE, acc_callback, self->acc);
|
||||
gsk_path_unref (simplified);
|
||||
gsk_path_unref (path);
|
||||
|
||||
if (!glyphy_arc_accumulator_successful (self->acc))
|
||||
return FALSE;
|
||||
|
||||
g_assert (glyphy_arc_accumulator_get_error (self->acc) <= tolerance);
|
||||
|
||||
if (self->acc_endpoints->len > 0)
|
||||
glyphy_outline_winding_from_even_odd ((gpointer)self->acc_endpoints->data,
|
||||
self->acc_endpoints->len,
|
||||
FALSE);
|
||||
|
||||
if (!glyphy_arc_list_encode_blob2 ((gpointer)self->acc_endpoints->data,
|
||||
self->acc_endpoints->len,
|
||||
buffer,
|
||||
buffer_len,
|
||||
faraway,
|
||||
unit_size,
|
||||
enlighten_max,
|
||||
embolden_max,
|
||||
&avg_fetch_achieved,
|
||||
output_len,
|
||||
nominal_width,
|
||||
nominal_height,
|
||||
extents))
|
||||
return FALSE;
|
||||
|
||||
glyphy_extents_scale (extents, 1./upem, 1./upem);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline hb_font_t *
|
||||
get_nominal_size_hb_font (PangoFont *font)
|
||||
{
|
||||
hb_font_t *hbfont;
|
||||
const float *coords;
|
||||
unsigned int length;
|
||||
|
||||
hbfont = (hb_font_t *) g_object_get_data ((GObject *)font, "glyph-nominal-size-font");
|
||||
if (hbfont == NULL)
|
||||
{
|
||||
hbfont = hb_font_create (hb_font_get_face (pango_font_get_hb_font (font)));
|
||||
coords = hb_font_get_var_coords_design (pango_font_get_hb_font (font), &length);
|
||||
if (length > 0)
|
||||
hb_font_set_var_coords_design (hbfont, coords, length);
|
||||
|
||||
g_object_set_data_full ((GObject *)font, "glyphy-nominal-size-font",
|
||||
hbfont, (GDestroyNotify)hb_font_destroy);
|
||||
}
|
||||
|
||||
return hbfont;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_glyphy_library_add (GskGLGlyphyLibrary *self,
|
||||
GskGLGlyphyKey *key,
|
||||
PangoFont *font,
|
||||
const GskGLGlyphyValue **out_value)
|
||||
{
|
||||
static glyphy_rgba_t buffer[4096 * 16];
|
||||
GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self;
|
||||
GskGLGlyphyValue *value;
|
||||
glyphy_extents_t extents;
|
||||
hb_font_t *hbfont;
|
||||
guint packed_x;
|
||||
guint packed_y;
|
||||
guint nominal_w, nominal_h;
|
||||
guint output_len = 0;
|
||||
guint texture_id;
|
||||
guint width, height;
|
||||
|
||||
g_assert (GSK_IS_GL_GLYPHY_LIBRARY (self));
|
||||
g_assert (key != NULL);
|
||||
g_assert (font != NULL);
|
||||
g_assert (out_value != NULL);
|
||||
|
||||
hbfont = get_nominal_size_hb_font (font);
|
||||
|
||||
/* Convert the glyph to a list of arcs */
|
||||
if (!encode_glyph (self, hbfont, key->glyph, TOLERANCE,
|
||||
buffer, sizeof buffer, &output_len,
|
||||
&nominal_w, &nominal_h, &extents))
|
||||
return FALSE;
|
||||
|
||||
/* Allocate space for list within atlas */
|
||||
width = self->item_w;
|
||||
height = (output_len + width - 1) / width;
|
||||
value = gsk_gl_texture_library_pack (tl, key, sizeof *value,
|
||||
width, height, 0,
|
||||
&packed_x, &packed_y);
|
||||
|
||||
g_assert (packed_x % ITEM_W == 0);
|
||||
g_assert (packed_y % ITEM_H_QUANTUM == 0);
|
||||
|
||||
/* Make sure we found space to pack */
|
||||
texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value);
|
||||
if (texture_id == 0)
|
||||
return FALSE;
|
||||
|
||||
if (!glyphy_extents_is_empty (&extents))
|
||||
{
|
||||
/* Connect the texture for data upload */
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
g_assert (width > 0);
|
||||
g_assert (height > 0);
|
||||
|
||||
/* Upload the arc list */
|
||||
if (width * height == output_len)
|
||||
{
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y,
|
||||
width, height,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y,
|
||||
width, height - 1,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buffer);
|
||||
/* Upload the last row separately */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + height - 1,
|
||||
output_len - (width * (height - 1)), 1,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buffer + (width * (height - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
value->extents.min_x = extents.min_x;
|
||||
value->extents.min_y = extents.min_y;
|
||||
value->extents.max_x = extents.max_x;
|
||||
value->extents.max_y = extents.max_y;
|
||||
value->nominal_w = nominal_w;
|
||||
value->nominal_h = nominal_h;
|
||||
value->atlas_x = packed_x / self->item_w;
|
||||
value->atlas_y = packed_y / self->item_h_q;
|
||||
|
||||
*out_value = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/* gskglglyphylibraryprivate.h
|
||||
*
|
||||
* Copyright 2020-2022 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef __GSK_GL_GLYPHY_LIBRARY_PRIVATE_H__
|
||||
#define __GSK_GL_GLYPHY_LIBRARY_PRIVATE_H__
|
||||
|
||||
#include <glyphy.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
#include "gskgltexturelibraryprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_GLYPHY_LIBRARY (gsk_gl_glyphy_library_get_type())
|
||||
|
||||
typedef guint FontKey;
|
||||
|
||||
extern GQuark quark_glyphy_font_key;
|
||||
|
||||
static inline FontKey
|
||||
gsk_gl_glyphy_library_get_font_key (PangoFont *font)
|
||||
{
|
||||
FontKey key;
|
||||
|
||||
key = (FontKey) GPOINTER_TO_UINT (g_object_get_qdata ((GObject *)font, quark_glyphy_font_key));
|
||||
if (key == 0)
|
||||
{
|
||||
PangoFontDescription *desc = pango_font_describe (font);
|
||||
pango_font_description_set_size (desc, 10 * PANGO_SCALE);
|
||||
key = (FontKey) pango_font_description_hash (desc);
|
||||
pango_font_description_free (desc);
|
||||
g_object_set_qdata ((GObject *)font, quark_glyphy_font_key, GUINT_TO_POINTER (key));
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static inline float
|
||||
gsk_gl_glyphy_library_get_font_scale (PangoFont *font)
|
||||
{
|
||||
hb_font_t *hbfont;
|
||||
int x_scale, y_scale;
|
||||
|
||||
hbfont = pango_font_get_hb_font (font);
|
||||
hb_font_get_scale (hbfont, &x_scale, &y_scale);
|
||||
|
||||
return MAX (x_scale, y_scale) / 1000.0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct _GskGLGlyphyKey
|
||||
{
|
||||
FontKey font;
|
||||
PangoGlyph glyph;
|
||||
} GskGLGlyphyKey;
|
||||
|
||||
typedef struct _GskGLGlyphyValue
|
||||
{
|
||||
GskGLTextureAtlasEntry entry;
|
||||
struct {
|
||||
float min_x;
|
||||
float min_y;
|
||||
float max_x;
|
||||
float max_y;
|
||||
} extents;
|
||||
guint nominal_w;
|
||||
guint nominal_h;
|
||||
guint atlas_x;
|
||||
guint atlas_y;
|
||||
} GskGLGlyphyValue;
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskGLGlyphyLibrary, gsk_gl_glyphy_library, GSK, GL_GLYPHY_LIBRARY, GskGLTextureLibrary)
|
||||
|
||||
struct _GskGLGlyphyLibrary
|
||||
{
|
||||
GskGLTextureLibrary parent_instance;
|
||||
glyphy_arc_accumulator_t *acc;
|
||||
GArray *acc_endpoints;
|
||||
guint item_w;
|
||||
guint item_h_q;
|
||||
struct {
|
||||
GskGLGlyphyKey key;
|
||||
const GskGLGlyphyValue *value;
|
||||
} front[256];
|
||||
};
|
||||
|
||||
GskGLGlyphyLibrary *gsk_gl_glyphy_library_new (GskGLDriver *driver);
|
||||
gboolean gsk_gl_glyphy_library_add (GskGLGlyphyLibrary *self,
|
||||
GskGLGlyphyKey *key,
|
||||
PangoFont *font,
|
||||
const GskGLGlyphyValue **out_value);
|
||||
|
||||
static inline guint
|
||||
gsk_gl_glyphy_library_lookup_or_add (GskGLGlyphyLibrary *self,
|
||||
const GskGLGlyphyKey *key,
|
||||
PangoFont *font,
|
||||
const GskGLGlyphyValue **out_value)
|
||||
{
|
||||
GskGLTextureAtlasEntry *entry;
|
||||
guint front_index = key->glyph & 0xFF;
|
||||
|
||||
if (memcmp (key, &self->front[front_index], sizeof *key) == 0)
|
||||
{
|
||||
*out_value = self->front[front_index].value;
|
||||
}
|
||||
else if (gsk_gl_texture_library_lookup ((GskGLTextureLibrary *)self, key, &entry))
|
||||
{
|
||||
*out_value = (GskGLGlyphyValue *)entry;
|
||||
self->front[front_index].key = *key;
|
||||
self->front[front_index].value = *out_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
GskGLGlyphyKey *k = g_slice_copy (sizeof *key, key);
|
||||
gsk_gl_glyphy_library_add (self, k, font, out_value);
|
||||
self->front[front_index].key = *key;
|
||||
self->front[front_index].value = *out_value;
|
||||
}
|
||||
|
||||
return GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (*out_value);
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_GLYPHY_LIBRARY_PRIVATE_H__ */
|
||||
+34
-16
@@ -1,71 +1,71 @@
|
||||
GSK_GL_DEFINE_PROGRAM (blend,
|
||||
"/org/gtk/libgsk/gl/blend.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blend.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, BLEND_SOURCE2, u_source2)
|
||||
GSK_GL_ADD_UNIFORM (2, BLEND_MODE, u_mode))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (blit,
|
||||
"/org/gtk/libgsk/gl/blit.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blit.glsl")),
|
||||
GSK_GL_NO_UNIFORMS)
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (blur,
|
||||
"/org/gtk/libgsk/gl/blur.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blur.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, BLUR_RADIUS, u_blur_radius)
|
||||
GSK_GL_ADD_UNIFORM (2, BLUR_SIZE, u_blur_size)
|
||||
GSK_GL_ADD_UNIFORM (3, BLUR_DIR, u_blur_dir))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (border,
|
||||
"/org/gtk/libgsk/gl/border.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("border.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, BORDER_WIDTHS, u_widths)
|
||||
GSK_GL_ADD_UNIFORM (2, BORDER_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (color,
|
||||
"/org/gtk/libgsk/gl/color.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color.glsl")),
|
||||
GSK_GL_NO_UNIFORMS)
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (coloring,
|
||||
"/org/gtk/libgsk/gl/coloring.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("coloring.glsl")),
|
||||
GSK_GL_NO_UNIFORMS)
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (color_matrix,
|
||||
"/org/gtk/libgsk/gl/color_matrix.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color_matrix.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, COLOR_MATRIX_COLOR_MATRIX, u_color_matrix)
|
||||
GSK_GL_ADD_UNIFORM (2, COLOR_MATRIX_COLOR_OFFSET, u_color_offset))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (conic_gradient,
|
||||
"/org/gtk/libgsk/gl/conic_gradient.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("conic_gradient.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, CONIC_GRADIENT_COLOR_STOPS, u_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (2, CONIC_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (3, CONIC_GRADIENT_GEOMETRY, u_geometry))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (cross_fade,
|
||||
"/org/gtk/libgsk/gl/cross_fade.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("cross_fade.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress)
|
||||
GSK_GL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (filled_border,
|
||||
"/org/gtk/libgsk/gl/filled_border.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("filled_border.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, FILLED_BORDER_WIDTHS, u_widths)
|
||||
GSK_GL_ADD_UNIFORM (2, FILLED_BORDER_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (inset_shadow,
|
||||
"/org/gtk/libgsk/gl/inset_shadow.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("inset_shadow.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, INSET_SHADOW_SPREAD, u_spread)
|
||||
GSK_GL_ADD_UNIFORM (2, INSET_SHADOW_OFFSET, u_offset)
|
||||
GSK_GL_ADD_UNIFORM (3, INSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (linear_gradient,
|
||||
"/org/gtk/libgsk/gl/linear_gradient.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("linear_gradient.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, LINEAR_GRADIENT_COLOR_STOPS, u_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (2, LINEAR_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
|
||||
GSK_GL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (outset_shadow,
|
||||
"/org/gtk/libgsk/gl/outset_shadow.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (radial_gradient,
|
||||
"/org/gtk/libgsk/gl/radial_gradient.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("radial_gradient.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, RADIAL_GRADIENT_COLOR_STOPS, u_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (2, RADIAL_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
|
||||
GSK_GL_ADD_UNIFORM (3, RADIAL_GRADIENT_REPEAT, u_repeat)
|
||||
@@ -73,12 +73,30 @@ GSK_GL_DEFINE_PROGRAM (radial_gradient,
|
||||
GSK_GL_ADD_UNIFORM (5, RADIAL_GRADIENT_GEOMETRY, u_geometry))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (repeat,
|
||||
"/org/gtk/libgsk/gl/repeat.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("repeat.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, REPEAT_CHILD_BOUNDS, u_child_bounds)
|
||||
GSK_GL_ADD_UNIFORM (2, REPEAT_TEXTURE_RECT, u_texture_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
|
||||
"/org/gtk/libgsk/gl/unblurred_outset_shadow.glsl",
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("unblurred_outset_shadow.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
|
||||
GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
|
||||
GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (glyphy,
|
||||
GSK_GL_SHADER_JOINED (VERTEX,
|
||||
GSK_GL_SHADER_RESOURCE ("glyphy.vs.glsl"),
|
||||
NULL)
|
||||
GSK_GL_SHADER_JOINED (FRAGMENT,
|
||||
GSK_GL_SHADER_RESOURCE ("glyphy.atlas.glsl"),
|
||||
GSK_GL_SHADER_STRING (glyphy_common_shader_source ()),
|
||||
GSK_GL_SHADER_STRING ("#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"),
|
||||
GSK_GL_SHADER_STRING (glyphy_sdf_shader_source ()),
|
||||
GSK_GL_SHADER_RESOURCE ("glyphy.fs.glsl"),
|
||||
NULL),
|
||||
GSK_GL_ADD_UNIFORM (0, GLYPHY_CONTRAST, u_contrast)
|
||||
GSK_GL_ADD_UNIFORM (1, GLYPHY_GAMMA_ADJUST, u_gamma_adjust)
|
||||
GSK_GL_ADD_UNIFORM (2, GLYPHY_OUTLINE_THICKNESS, u_outline_thickness)
|
||||
GSK_GL_ADD_UNIFORM (3, GLYPHY_OUTLINE, u_outline)
|
||||
GSK_GL_ADD_UNIFORM (4, GLYPHY_BOLDNESS, u_boldness)
|
||||
GSK_GL_ADD_UNIFORM (6, GLYPHY_ATLAS_INFO, u_atlas_info))
|
||||
|
||||
+271
-9
@@ -33,10 +33,12 @@
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <pango/pangofc-font.h>
|
||||
|
||||
#include "gskglcommandqueueprivate.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglglyphlibraryprivate.h"
|
||||
#include "gskglglyphylibraryprivate.h"
|
||||
#include "gskgliconlibraryprivate.h"
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskglrenderjobprivate.h"
|
||||
@@ -2455,7 +2457,9 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
|
||||
scaled_outline.corner[i].height *= scale_y;
|
||||
}
|
||||
|
||||
cached_tid = gsk_gl_shadow_library_lookup (job->driver->shadows, &scaled_outline, blur_radius);
|
||||
cached_tid = gsk_gl_shadow_library_lookup (job->driver->shadows_library,
|
||||
&scaled_outline,
|
||||
blur_radius);
|
||||
|
||||
if (cached_tid == 0)
|
||||
{
|
||||
@@ -2517,7 +2521,7 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
|
||||
blur_radius * scale_x,
|
||||
blur_radius * scale_y);
|
||||
|
||||
gsk_gl_shadow_library_insert (job->driver->shadows,
|
||||
gsk_gl_shadow_library_insert (job->driver->shadows_library,
|
||||
&scaled_outline,
|
||||
blur_radius,
|
||||
blurred_texture_id);
|
||||
@@ -2927,10 +2931,10 @@ compute_phase_and_pos (float value, float *pos)
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
const GdkRGBA *color,
|
||||
gboolean force_color)
|
||||
gsk_gl_render_job_visit_text_node_legacy (GskGLRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
const GdkRGBA *color,
|
||||
gboolean force_color)
|
||||
{
|
||||
const PangoFont *font = gsk_text_node_get_font (node);
|
||||
const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL);
|
||||
@@ -2939,7 +2943,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
|
||||
guint num_glyphs = gsk_text_node_get_num_glyphs (node);
|
||||
float x = offset->x + job->offset_x;
|
||||
float y = offset->y + job->offset_y;
|
||||
GskGLGlyphLibrary *library = job->driver->glyphs;
|
||||
GskGLGlyphLibrary *library = job->driver->glyphs_library;
|
||||
GskGLCommandBatch *batch;
|
||||
int x_position = 0;
|
||||
GskGLGlyphKey lookup;
|
||||
@@ -3065,6 +3069,259 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
|
||||
gsk_gl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float g16hi;
|
||||
float g16lo;
|
||||
} EncodedGlyph;
|
||||
|
||||
static inline unsigned int
|
||||
glyph_encode (guint atlas_x , /* 7 bits */
|
||||
guint atlas_y, /* 7 bits */
|
||||
guint corner_x, /* 1 bit */
|
||||
guint corner_y, /* 1 bit */
|
||||
guint nominal_w, /* 6 bits */
|
||||
guint nominal_h) /* 6 bits */
|
||||
{
|
||||
guint x, y;
|
||||
|
||||
g_assert (0 == (atlas_x & ~0x7F));
|
||||
g_assert (0 == (atlas_y & ~0x7F));
|
||||
g_assert (0 == (corner_x & ~1));
|
||||
g_assert (0 == (corner_y & ~1));
|
||||
g_assert (0 == (nominal_w & ~0x3F));
|
||||
g_assert (0 == (nominal_h & ~0x3F));
|
||||
|
||||
x = (((atlas_x << 6) | nominal_w) << 1) | corner_x;
|
||||
y = (((atlas_y << 6) | nominal_h) << 1) | corner_y;
|
||||
|
||||
return (x << 16) | y;
|
||||
}
|
||||
|
||||
static inline void
|
||||
encoded_glyph_init (EncodedGlyph *eg,
|
||||
float x,
|
||||
float y,
|
||||
guint corner_x,
|
||||
guint corner_y,
|
||||
const GskGLGlyphyValue *gi)
|
||||
{
|
||||
guint encoded = glyph_encode (gi->atlas_x, gi->atlas_y, corner_x, corner_y, gi->nominal_w, gi->nominal_h);
|
||||
|
||||
eg->x = x;
|
||||
eg->y = y;
|
||||
eg->g16hi = encoded >> 16;
|
||||
eg->g16lo = encoded & 0xFFFF;
|
||||
}
|
||||
|
||||
static inline void
|
||||
add_encoded_glyph (GskGLDrawVertex *vertices,
|
||||
const EncodedGlyph *eg,
|
||||
const guint16 c[4])
|
||||
{
|
||||
*vertices = (GskGLDrawVertex) { .position = { eg->x, eg->y}, .uv = { eg->g16hi, eg->g16lo}, .color = { c[0], c[1], c[2], c[3] } };
|
||||
}
|
||||
|
||||
static void
|
||||
get_synthetic_font_params (PangoFont *font,
|
||||
gboolean *embolden,
|
||||
PangoMatrix *matrix)
|
||||
{
|
||||
*embolden = FALSE;
|
||||
|
||||
if (PANGO_IS_FC_FONT (font))
|
||||
{
|
||||
FcPattern *pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font));
|
||||
FcBool b;
|
||||
FcMatrix mat;
|
||||
FcMatrix *m;
|
||||
|
||||
if (FcPatternGetBool (pattern, FC_EMBOLDEN, 0, &b) == FcResultMatch)
|
||||
*embolden = b;
|
||||
|
||||
FcMatrixInit (&mat);
|
||||
for (int i = 0; FcPatternGetMatrix (pattern, FC_MATRIX, i, &m) == FcResultMatch; i++)
|
||||
FcMatrixMultiply (&mat, &mat, m);
|
||||
|
||||
matrix->xx = mat.xx;
|
||||
matrix->xy = mat.xy;
|
||||
matrix->yx = mat.yx;
|
||||
matrix->yy = mat.yy;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_gl_render_job_visit_text_node_glyphy (GskGLRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
const graphene_point_t *offset;
|
||||
const PangoGlyphInfo *glyphs;
|
||||
const PangoGlyphInfo *gi;
|
||||
GskGLGlyphyLibrary *library;
|
||||
GskGLCommandBatch *batch;
|
||||
PangoFont *font;
|
||||
GskGLDrawVertex *vertices;
|
||||
const guint16 *c;
|
||||
GskGLGlyphyKey lookup;
|
||||
guint16 cc[4];
|
||||
float x;
|
||||
float y;
|
||||
guint last_texture = 0;
|
||||
guint num_glyphs;
|
||||
guint used = 0;
|
||||
guint i;
|
||||
int x_position = 0;
|
||||
float font_scale;
|
||||
gboolean embolden;
|
||||
PangoMatrix matrix = PANGO_MATRIX_INIT;
|
||||
|
||||
#define GRID_SIZE 20
|
||||
|
||||
g_assert (!gsk_text_node_has_color_glyphs (node));
|
||||
|
||||
if (!(num_glyphs = gsk_text_node_get_num_glyphs (node)))
|
||||
return;
|
||||
|
||||
if (RGBA_IS_CLEAR (color))
|
||||
return;
|
||||
|
||||
font = (PangoFont *)gsk_text_node_get_font (node);
|
||||
get_synthetic_font_params (font, &embolden, &matrix);
|
||||
|
||||
glyphs = gsk_text_node_get_glyphs (node, NULL);
|
||||
library = job->driver->glyphy_library;
|
||||
offset = gsk_text_node_get_offset (node);
|
||||
x = offset->x + job->offset_x;
|
||||
y = offset->y + job->offset_y;
|
||||
|
||||
rgba_to_half (color, cc);
|
||||
c = cc;
|
||||
|
||||
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, glyphy));
|
||||
|
||||
batch = gsk_gl_command_queue_get_batch (job->command_queue);
|
||||
vertices = gsk_gl_command_queue_add_n_vertices (job->command_queue, num_glyphs);
|
||||
|
||||
lookup.font = gsk_gl_glyphy_library_get_font_key (font);
|
||||
font_scale = gsk_gl_glyphy_library_get_font_scale (font);
|
||||
|
||||
for (i = 0, gi = glyphs; i < num_glyphs; i++, gi++)
|
||||
{
|
||||
const GskGLGlyphyValue *glyph;
|
||||
float cx = 0, cy = 0;
|
||||
guint texture_id;
|
||||
|
||||
lookup.glyph = gi->glyph;
|
||||
texture_id = gsk_gl_glyphy_library_lookup_or_add (library, &lookup, font, &glyph);
|
||||
|
||||
if G_UNLIKELY (texture_id == 0)
|
||||
continue;
|
||||
|
||||
if G_UNLIKELY (last_texture != texture_id || batch->draw.vbo_count + GSK_GL_N_VERTICES > 0xffff)
|
||||
{
|
||||
if G_LIKELY (last_texture != 0)
|
||||
{
|
||||
guint vbo_offset = batch->draw.vbo_offset + batch->draw.vbo_count;
|
||||
|
||||
/* Since we have batched added our VBO vertices to avoid repeated
|
||||
* calls to the buffer, we need to manually tweak the vbo offset
|
||||
* of the new batch as otherwise it will point at the end of our
|
||||
* vbo array.
|
||||
*/
|
||||
gsk_gl_render_job_split_draw (job);
|
||||
batch = gsk_gl_command_queue_get_batch (job->command_queue);
|
||||
batch->draw.vbo_offset = vbo_offset;
|
||||
}
|
||||
|
||||
gsk_gl_program_set_uniform4i (job->current_program,
|
||||
UNIFORM_GLYPHY_ATLAS_INFO, 0,
|
||||
GSK_GL_TEXTURE_LIBRARY (library)->atlas_width,
|
||||
GSK_GL_TEXTURE_LIBRARY (library)->atlas_height,
|
||||
library->item_w,
|
||||
library->item_h_q);
|
||||
gsk_gl_program_set_uniform_texture (job->current_program,
|
||||
UNIFORM_SHARED_SOURCE, 0,
|
||||
GL_TEXTURE_2D,
|
||||
GL_TEXTURE0,
|
||||
texture_id);
|
||||
gsk_gl_program_set_uniform1f (job->current_program,
|
||||
UNIFORM_GLYPHY_GAMMA_ADJUST, 0,
|
||||
1.0);
|
||||
gsk_gl_program_set_uniform1f (job->current_program,
|
||||
UNIFORM_GLYPHY_CONTRAST, 0,
|
||||
1.0);
|
||||
|
||||
/* 0.0208 is the value used by freetype for synthetic emboldening */
|
||||
gsk_gl_program_set_uniform1f (job->current_program,
|
||||
UNIFORM_GLYPHY_BOLDNESS, 0,
|
||||
embolden ? 0.0208 * GRID_SIZE : 0.0);
|
||||
|
||||
#if 0
|
||||
gsk_gl_program_set_uniform1f (job->current_program,
|
||||
UNIFORM_GLYPHY_OUTLINE_THICKNESS, 0,
|
||||
1.0);
|
||||
gsk_gl_program_set_uniform1f (job->current_program,
|
||||
UNIFORM_GLYPHY_OUTLINE, 0,
|
||||
1.0);
|
||||
#endif
|
||||
|
||||
last_texture = texture_id;
|
||||
}
|
||||
|
||||
cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
if G_UNLIKELY (gi->geometry.y_offset != 0)
|
||||
cy = (float)(gi->geometry.y_offset) / PANGO_SCALE;
|
||||
|
||||
x_position += gi->geometry.width;
|
||||
|
||||
EncodedGlyph encoded[4];
|
||||
#define ENCODE_CORNER(_cx, _cy) \
|
||||
G_STMT_START { \
|
||||
float _dx = _cx * (glyph->extents.max_x - glyph->extents.min_x); \
|
||||
float _dy = _cy * (glyph->extents.max_y - glyph->extents.min_y); \
|
||||
float _vx = x + cx + font_scale * (glyph->extents.min_x + matrix.xx * _dx + matrix.xy * _dy); \
|
||||
float _vy = y + cy - font_scale * (glyph->extents.min_y + matrix.yx * _dx + matrix.yy * _dy); \
|
||||
encoded_glyph_init (&encoded[_cx * 2 + _cy], _vx, _vy, _cx, _cy, glyph); \
|
||||
} G_STMT_END
|
||||
ENCODE_CORNER (0, 0);
|
||||
ENCODE_CORNER (0, 1);
|
||||
ENCODE_CORNER (1, 0);
|
||||
ENCODE_CORNER (1, 1);
|
||||
#undef ENCODE_CORNER
|
||||
|
||||
add_encoded_glyph (vertices++, &encoded[0], c);
|
||||
add_encoded_glyph (vertices++, &encoded[1], c);
|
||||
add_encoded_glyph (vertices++, &encoded[2], c);
|
||||
|
||||
add_encoded_glyph (vertices++, &encoded[1], c);
|
||||
add_encoded_glyph (vertices++, &encoded[2], c);
|
||||
add_encoded_glyph (vertices++, &encoded[3], c);
|
||||
|
||||
batch->draw.vbo_count += GSK_GL_N_VERTICES;
|
||||
used++;
|
||||
}
|
||||
|
||||
if (used != num_glyphs)
|
||||
gsk_gl_command_queue_retract_n_vertices (job->command_queue, num_glyphs - used);
|
||||
|
||||
gsk_gl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
const GdkRGBA *color,
|
||||
gboolean force_color)
|
||||
{
|
||||
if (!gsk_text_node_has_color_glyphs (node))
|
||||
gsk_gl_render_job_visit_text_node_glyphy (job, node, color);
|
||||
else
|
||||
gsk_gl_render_job_visit_text_node_legacy (job, node, color, force_color);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
@@ -3442,14 +3699,14 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
GdkTexture *texture,
|
||||
GskGLRenderOffscreen *offscreen)
|
||||
{
|
||||
if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons,
|
||||
if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
texture->width,
|
||||
texture->height) &&
|
||||
!GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
const GskGLIconData *icon_data;
|
||||
|
||||
gsk_gl_icon_library_lookup_or_add (job->driver->icons, texture, &icon_data);
|
||||
gsk_gl_icon_library_lookup_or_add (job->driver->icons_library, texture, &icon_data);
|
||||
offscreen->texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data);
|
||||
memcpy (&offscreen->area, &icon_data->entry.area, sizeof offscreen->area);
|
||||
}
|
||||
@@ -3767,6 +4024,11 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
|
||||
gsk_gl_render_job_visit_as_fallback (job, node);
|
||||
break;
|
||||
|
||||
case GSK_FILL_NODE:
|
||||
case GSK_STROKE_NODE:
|
||||
gsk_gl_render_job_visit_as_fallback (job, node);
|
||||
break;
|
||||
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
struct _GskGLShadowLibrary
|
||||
{
|
||||
GObject parent_instance;
|
||||
GObject parent_instance;
|
||||
GskGLDriver *driver;
|
||||
GArray *shadows;
|
||||
GArray *shadows;
|
||||
};
|
||||
|
||||
typedef struct _Shadow
|
||||
|
||||
+312
-158
@@ -27,7 +27,10 @@
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskgltexturelibraryprivate.h"
|
||||
|
||||
#define MAX_FRAME_AGE 60
|
||||
#define DEFAULT_MAX_FRAME_AGE 60
|
||||
#define DEFAULT_ATLAS_WIDTH 512
|
||||
#define DEFAULT_ATLAS_HEIGHT 512
|
||||
#define MAX_OLD_RATIO 0.5
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GskGLTextureLibrary, gsk_gl_texture_library, G_TYPE_OBJECT)
|
||||
|
||||
@@ -39,6 +42,143 @@ enum {
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
gsk_gl_texture_atlas_free (GskGLTextureAtlas *atlas)
|
||||
{
|
||||
if (atlas->texture_id != 0)
|
||||
{
|
||||
glDeleteTextures (1, &atlas->texture_id);
|
||||
atlas->texture_id = 0;
|
||||
}
|
||||
|
||||
g_clear_pointer (&atlas->nodes, g_free);
|
||||
g_slice_free (GskGLTextureAtlas, atlas);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_texture_library_real_compact (GskGLTextureLibrary *self,
|
||||
gint64 frame_id)
|
||||
{
|
||||
GPtrArray *removed = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gboolean periodic_scan;
|
||||
|
||||
g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
|
||||
periodic_scan = (self->max_frame_age > 0 &&
|
||||
(frame_id % self->max_frame_age) == 0);
|
||||
|
||||
for (guint i = self->atlases->len; i > 0; i--)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1);
|
||||
|
||||
if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
|
||||
{
|
||||
GSK_NOTE (GLYPH_CACHE,
|
||||
g_message ("Dropping atlas %d (%g.2%% old)", i,
|
||||
100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)));
|
||||
if (removed == NULL)
|
||||
removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free);
|
||||
g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (periodic_scan || removed != NULL)
|
||||
{
|
||||
GskGLTextureAtlasEntry *entry;
|
||||
GHashTableIter iter;
|
||||
guint dropped = 0;
|
||||
guint atlased = 0;
|
||||
|
||||
g_hash_table_iter_init (&iter, self->hash_table);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry))
|
||||
{
|
||||
if (entry->is_atlased)
|
||||
{
|
||||
if (removed && g_ptr_array_find (removed, entry->atlas, NULL))
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
}
|
||||
else if (periodic_scan)
|
||||
{
|
||||
gsk_gl_texture_atlas_entry_mark_unused (entry);
|
||||
entry->accessed = FALSE;
|
||||
if (entry->is_atlased)
|
||||
atlased++;
|
||||
}
|
||||
}
|
||||
else if (!entry->accessed)
|
||||
{
|
||||
gsk_gl_driver_release_texture (self->driver, entry->texture);
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
GSK_NOTE (GLYPH_CACHE, g_message ("%s: Dropped %d individual items",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
dropped);
|
||||
g_message ("%s: %d items cached (%d atlased, %d individually)",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
g_hash_table_size (self->hash_table),
|
||||
atlased,
|
||||
g_hash_table_size (self->hash_table) - atlased));
|
||||
|
||||
if (dropped > 0)
|
||||
gsk_gl_texture_library_clear_cache (self);
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
g_clear_pointer (&removed, g_ptr_array_unref);
|
||||
}
|
||||
|
||||
GSK_NOTE (GLYPH_CACHE, {
|
||||
static gint64 last_message;
|
||||
gint64 now = g_get_monotonic_time ();
|
||||
if (now - last_message > G_USEC_PER_SEC)
|
||||
{
|
||||
last_message = now;
|
||||
g_message ("%s contains %d atlases",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
self->atlases->len);
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_texture_library_real_allocate (GskGLTextureLibrary *self,
|
||||
GskGLTextureAtlas *atlas,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
stbrp_rect rect;
|
||||
|
||||
g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
g_assert (atlas != NULL);
|
||||
g_assert (width > 0);
|
||||
g_assert (height > 0);
|
||||
g_assert (out_x != NULL);
|
||||
g_assert (out_y != NULL);
|
||||
|
||||
rect.w = width;
|
||||
rect.h = height;
|
||||
|
||||
stbrp_pack_rects (&atlas->context, &rect, 1);
|
||||
|
||||
if (rect.was_packed)
|
||||
{
|
||||
*out_x = rect.x;
|
||||
*out_y = rect.y;
|
||||
}
|
||||
|
||||
return rect.was_packed;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_texture_library_constructed (GObject *object)
|
||||
{
|
||||
@@ -52,6 +192,7 @@ gsk_gl_texture_library_dispose (GObject *object)
|
||||
{
|
||||
GskGLTextureLibrary *self = (GskGLTextureLibrary *)object;
|
||||
|
||||
g_clear_pointer (&self->atlases, g_ptr_array_unref);
|
||||
g_clear_object (&self->driver);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_texture_library_parent_class)->dispose (object);
|
||||
@@ -105,6 +246,9 @@ gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass)
|
||||
object_class->get_property = gsk_gl_texture_library_get_property;
|
||||
object_class->set_property = gsk_gl_texture_library_set_property;
|
||||
|
||||
klass->compact = gsk_gl_texture_library_real_compact;
|
||||
klass->allocate = gsk_gl_texture_library_real_allocate;
|
||||
|
||||
properties [PROP_DRIVER] =
|
||||
g_param_spec_object ("driver",
|
||||
"Driver",
|
||||
@@ -118,6 +262,10 @@ gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass)
|
||||
static void
|
||||
gsk_gl_texture_library_init (GskGLTextureLibrary *self)
|
||||
{
|
||||
self->max_frame_age = DEFAULT_MAX_FRAME_AGE;
|
||||
self->atlas_width = DEFAULT_ATLAS_WIDTH;
|
||||
self->atlas_height = DEFAULT_ATLAS_HEIGHT;
|
||||
self->atlases = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -136,78 +284,14 @@ gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self,
|
||||
|
||||
void
|
||||
gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self,
|
||||
gint64 frame_id,
|
||||
GPtrArray *removed_atlases)
|
||||
gint64 frame_id)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
|
||||
gsk_gl_texture_library_compact (self, frame_id);
|
||||
|
||||
if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame)
|
||||
GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id, removed_atlases);
|
||||
|
||||
if (removed_atlases != NULL)
|
||||
{
|
||||
GskGLTextureAtlasEntry *entry;
|
||||
guint dropped = 0;
|
||||
|
||||
g_hash_table_iter_init (&iter, self->hash_table);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry))
|
||||
{
|
||||
if (entry->is_atlased)
|
||||
{
|
||||
for (guint i = 0; i < removed_atlases->len; i++)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (removed_atlases, i);
|
||||
|
||||
if (atlas == entry->atlas)
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSK_NOTE (GLYPH_CACHE,
|
||||
if (dropped > 0)
|
||||
g_message ("%s: Dropped %d items",
|
||||
G_OBJECT_TYPE_NAME (self), dropped));
|
||||
}
|
||||
|
||||
if (frame_id % MAX_FRAME_AGE == 0)
|
||||
{
|
||||
GskGLTextureAtlasEntry *entry;
|
||||
int atlased = 0;
|
||||
int dropped = 0;
|
||||
|
||||
g_hash_table_iter_init (&iter, self->hash_table);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry))
|
||||
{
|
||||
if (!entry->is_atlased && !entry->accessed)
|
||||
{
|
||||
gsk_gl_driver_release_texture (self->driver, entry->texture);
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
gsk_gl_texture_atlas_entry_mark_unused (entry);
|
||||
entry->accessed = FALSE;
|
||||
if (entry->is_atlased)
|
||||
atlased++;
|
||||
}
|
||||
|
||||
GSK_NOTE (GLYPH_CACHE, g_message ("%s: Dropped %d individual items",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
dropped);
|
||||
g_message ("%s: %d items cached (%d atlased, %d individually)",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
g_hash_table_size (self->hash_table),
|
||||
atlased,
|
||||
g_hash_table_size (self->hash_table) - atlased));
|
||||
}
|
||||
GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id);
|
||||
}
|
||||
|
||||
static GskGLTexture *
|
||||
@@ -234,90 +318,29 @@ gsk_gl_texture_library_pack_one (GskGLTextureLibrary *self,
|
||||
return texture;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
stbrp_rect rect;
|
||||
|
||||
rect.w = width;
|
||||
rect.h = height;
|
||||
|
||||
stbrp_pack_rects (&self->context, &rect, 1);
|
||||
|
||||
if (rect.was_packed)
|
||||
{
|
||||
*out_x = rect.x;
|
||||
*out_y = rect.y;
|
||||
}
|
||||
|
||||
return rect.was_packed;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_texture_atlas_initialize (GskGLDriver *driver,
|
||||
GskGLTextureAtlas *atlas)
|
||||
{
|
||||
/* Insert a single pixel at 0,0 for use in coloring */
|
||||
|
||||
gboolean packed G_GNUC_UNUSED;
|
||||
int x, y;
|
||||
guint gl_format;
|
||||
guint gl_type;
|
||||
guint8 pixel_data[4 * 3 * 3];
|
||||
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
"Initializing Atlas");
|
||||
|
||||
packed = gsk_gl_texture_atlas_pack (atlas, 3, 3, &x, &y);
|
||||
g_assert (packed);
|
||||
g_assert (x == 0 && y == 0);
|
||||
|
||||
memset (pixel_data, 255, sizeof pixel_data);
|
||||
|
||||
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
|
||||
{
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_format = GL_BGRA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
0, 0,
|
||||
3, 3,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
|
||||
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
|
||||
|
||||
driver->command_queue->n_uploads++;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_texture_atlases_pack (GskGLDriver *driver,
|
||||
int width,
|
||||
int height,
|
||||
GskGLTextureAtlas **out_atlas,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
gsk_gl_texture_library_pack_any_atlas (GskGLTextureLibrary *self,
|
||||
int width,
|
||||
int height,
|
||||
GskGLTextureAtlas **out_atlas,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = NULL;
|
||||
int x, y;
|
||||
|
||||
for (guint i = 0; i < driver->atlases->len; i++)
|
||||
{
|
||||
atlas = g_ptr_array_index (driver->atlases, i);
|
||||
g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
g_assert (width > 0);
|
||||
g_assert (height > 0);
|
||||
g_assert (out_atlas != NULL);
|
||||
g_assert (out_x != NULL);
|
||||
g_assert (out_y != NULL);
|
||||
|
||||
if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
|
||||
for (guint i = 0; i < self->atlases->len; i++)
|
||||
{
|
||||
atlas = g_ptr_array_index (self->atlases, i);
|
||||
|
||||
if (gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y))
|
||||
break;
|
||||
|
||||
atlas = NULL;
|
||||
@@ -326,12 +349,10 @@ gsk_gl_texture_atlases_pack (GskGLDriver *driver,
|
||||
if (atlas == NULL)
|
||||
{
|
||||
/* No atlas has enough space, so create a new one... */
|
||||
atlas = gsk_gl_driver_create_atlas (driver);
|
||||
|
||||
gsk_gl_texture_atlas_initialize (driver, atlas);
|
||||
atlas = gsk_gl_texture_library_acquire_atlas (self);
|
||||
|
||||
/* Pack it onto that one, which surely has enough space... */
|
||||
if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
|
||||
if (!gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y))
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
@@ -380,17 +401,19 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
|
||||
*out_packed_x = 0;
|
||||
*out_packed_y = 0;
|
||||
}
|
||||
else if (width <= self->max_entry_size && height <= self->max_entry_size)
|
||||
else if (self->max_entry_size == 0 ||
|
||||
(width <= self->max_entry_size &&
|
||||
height <= self->max_entry_size))
|
||||
{
|
||||
int packed_x;
|
||||
int packed_y;
|
||||
|
||||
gsk_gl_texture_atlases_pack (self->driver,
|
||||
padding + width + padding,
|
||||
padding + height + padding,
|
||||
&atlas,
|
||||
&packed_x,
|
||||
&packed_y);
|
||||
gsk_gl_texture_library_pack_any_atlas (self,
|
||||
padding + width + padding,
|
||||
padding + height + padding,
|
||||
&atlas,
|
||||
&packed_x,
|
||||
&packed_y);
|
||||
|
||||
entry->atlas = atlas;
|
||||
entry->is_atlased = TRUE;
|
||||
@@ -424,3 +447,134 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* gsk_gl_texture_library_clear_cache:
|
||||
*
|
||||
* Clear the front cache if the texture library is using one. For
|
||||
* example the glyph cache would drop it's front cache to force
|
||||
* next lookups to fall through to the GHashTable key lookup.
|
||||
*/
|
||||
void
|
||||
gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
|
||||
if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache)
|
||||
GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* gsk_gl_texture_library_compact:
|
||||
*
|
||||
* Requests that the texture library compact it's altases. That
|
||||
* generally means to traverse them to look for unused pixels over
|
||||
* a certain threshold and release them if necessary.
|
||||
*
|
||||
* Returns: %TRUE if any compaction occurred.
|
||||
*/
|
||||
gboolean
|
||||
gsk_gl_texture_library_compact (GskGLTextureLibrary *self,
|
||||
gint64 frame_id)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), FALSE);
|
||||
|
||||
if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact)
|
||||
return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact (self, frame_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_library_reset (GskGLTextureLibrary *self)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
|
||||
gsk_gl_texture_library_clear_cache (self);
|
||||
|
||||
g_hash_table_remove_all (self->hash_table);
|
||||
|
||||
if (self->atlases->len)
|
||||
g_ptr_array_remove_range (self->atlases, 0, self->atlases->len);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
|
||||
if (width <= 0)
|
||||
width = DEFAULT_ATLAS_WIDTH;
|
||||
|
||||
if (height <= 0)
|
||||
height = DEFAULT_ATLAS_HEIGHT;
|
||||
|
||||
self->atlas_height = height;
|
||||
self->atlas_width = width;
|
||||
|
||||
gsk_gl_texture_library_reset (self);
|
||||
}
|
||||
|
||||
/*
|
||||
* gsk_gl_texture_library_acquire_atlas:
|
||||
*
|
||||
* Allocates a new texture atlas based on the current size
|
||||
* and format requirements.
|
||||
*/
|
||||
GskGLTextureAtlas *
|
||||
gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self)
|
||||
{
|
||||
GskGLTextureAtlas *atlas;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), NULL);
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self->driver), NULL);
|
||||
g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->driver->command_queue), NULL);
|
||||
g_return_val_if_fail (self->atlas_width > 0, NULL);
|
||||
g_return_val_if_fail (self->atlas_height > 0, NULL);
|
||||
|
||||
atlas = g_slice_new0 (GskGLTextureAtlas);
|
||||
atlas->width = self->atlas_width;
|
||||
atlas->height = self->atlas_height;
|
||||
/* TODO: We might want to change the strategy about the amount of
|
||||
* nodes here? stb_rect_pack.h says width is optimal. */
|
||||
atlas->nodes = g_malloc0_n (atlas->width, sizeof (struct stbrp_node));
|
||||
stbrp_init_target (&atlas->context, atlas->width, atlas->height, atlas->nodes, atlas->width);
|
||||
atlas->texture_id = gsk_gl_command_queue_create_texture (self->driver->command_queue,
|
||||
atlas->width,
|
||||
atlas->height,
|
||||
GL_RGBA8,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR);
|
||||
|
||||
gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
|
||||
GL_TEXTURE, atlas->texture_id,
|
||||
"Texture atlas %d",
|
||||
atlas->texture_id);
|
||||
|
||||
g_ptr_array_add (self->atlases, atlas);
|
||||
|
||||
if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas)
|
||||
GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas (self, atlas);
|
||||
|
||||
return atlas;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_texture_library_allocate (GskGLTextureLibrary *self,
|
||||
GskGLTextureAtlas *atlas,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
|
||||
g_assert (atlas != NULL);
|
||||
g_assert (width > 0);
|
||||
g_assert (height > 0);
|
||||
g_assert (out_x != NULL);
|
||||
g_assert (out_y != NULL);
|
||||
|
||||
return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->allocate (self, atlas, width, height, out_x, out_y);
|
||||
}
|
||||
|
||||
@@ -37,9 +37,14 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GskGLTextureAtlas
|
||||
{
|
||||
/* Used by Glyph/Icons */
|
||||
struct stbrp_context context;
|
||||
struct stbrp_node *nodes;
|
||||
|
||||
/* Used by Glyphy */
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
@@ -49,8 +54,6 @@ typedef struct _GskGLTextureAtlas
|
||||
* But are now unused.
|
||||
*/
|
||||
int unused_pixels;
|
||||
|
||||
void *user_data;
|
||||
} GskGLTextureAtlas;
|
||||
|
||||
typedef struct _GskGLTextureAtlasEntry
|
||||
@@ -89,40 +92,67 @@ typedef struct _GskGLTextureAtlasEntry
|
||||
|
||||
typedef struct _GskGLTextureLibrary
|
||||
{
|
||||
GObject parent_instance;
|
||||
GObject parent_instance;
|
||||
GskGLDriver *driver;
|
||||
GHashTable *hash_table;
|
||||
guint max_entry_size;
|
||||
GPtrArray *atlases;
|
||||
GHashTable *hash_table;
|
||||
guint max_entry_size;
|
||||
guint max_frame_age;
|
||||
guint atlas_width;
|
||||
guint atlas_height;
|
||||
} GskGLTextureLibrary;
|
||||
|
||||
typedef struct _GskGLTextureLibraryClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*begin_frame) (GskGLTextureLibrary *library,
|
||||
gint64 frame_id,
|
||||
GPtrArray *removed_atlases);
|
||||
void (*begin_frame) (GskGLTextureLibrary *library,
|
||||
gint64 frame_id);
|
||||
gboolean (*compact) (GskGLTextureLibrary *library,
|
||||
gint64 frame_id);
|
||||
void (*clear_cache) (GskGLTextureLibrary *library);
|
||||
void (*init_atlas) (GskGLTextureLibrary *library,
|
||||
GskGLTextureAtlas *atlas);
|
||||
gboolean (*allocate) (GskGLTextureLibrary *library,
|
||||
GskGLTextureAtlas *atlas,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y);
|
||||
} GskGLTextureLibraryClass;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskGLTextureLibrary, g_object_unref)
|
||||
|
||||
GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST;
|
||||
void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self,
|
||||
GHashFunc hash_func,
|
||||
GEqualFunc equal_func,
|
||||
GDestroyNotify key_destroy,
|
||||
GDestroyNotify value_destroy);
|
||||
void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self,
|
||||
gint64 frame_id,
|
||||
GPtrArray *removed_atlases);
|
||||
gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
|
||||
gpointer key,
|
||||
gsize valuelen,
|
||||
guint width,
|
||||
guint height,
|
||||
int padding,
|
||||
guint *out_packed_x,
|
||||
guint *out_packed_y);
|
||||
GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST;
|
||||
gboolean gsk_gl_texture_library_compact (GskGLTextureLibrary *self,
|
||||
gint64 frame_id);
|
||||
void gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self);
|
||||
void gsk_gl_texture_library_reset (GskGLTextureLibrary *self);
|
||||
void gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self,
|
||||
int width,
|
||||
int height);
|
||||
GskGLTextureAtlas *gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self);
|
||||
void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self,
|
||||
GHashFunc hash_func,
|
||||
GEqualFunc equal_func,
|
||||
GDestroyNotify key_destroy,
|
||||
GDestroyNotify value_destroy);
|
||||
void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self,
|
||||
gint64 frame_id);
|
||||
gboolean gsk_gl_texture_library_allocate (GskGLTextureLibrary *self,
|
||||
GskGLTextureAtlas *atlas,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y);
|
||||
gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
|
||||
gpointer key,
|
||||
gsize valuelen,
|
||||
guint width,
|
||||
guint height,
|
||||
int padding,
|
||||
guint *out_packed_x,
|
||||
guint *out_packed_y);
|
||||
|
||||
static inline void
|
||||
gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
|
||||
|
||||
@@ -37,6 +37,7 @@ typedef struct _GskGLCompiler GskGLCompiler;
|
||||
typedef struct _GskGLDrawVertex GskGLDrawVertex;
|
||||
typedef struct _GskGLRenderTarget GskGLRenderTarget;
|
||||
typedef struct _GskGLGlyphLibrary GskGLGlyphLibrary;
|
||||
typedef struct _GskGLGlyphyLibrary GskGLGlyphyLibrary;
|
||||
typedef struct _GskGLIconLibrary GskGLIconLibrary;
|
||||
typedef struct _GskGLProgram GskGLProgram;
|
||||
typedef struct _GskGLRenderJob GskGLRenderJob;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
uniform vec4 u_geometry;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec2 coord;
|
||||
_OUT_ vec2 coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
@@ -29,7 +29,7 @@ uniform highp int u_num_color_stops; // Why? Because it works like this.
|
||||
uniform vec4 u_geometry;
|
||||
uniform float u_color_stops[MAX_COLOR_STOPS * 5];
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec2 coord;
|
||||
_IN_ vec2 coord;
|
||||
|
||||
float get_offset(int index) {
|
||||
// u_color_stops[5 * index] makes Intel Windows driver crash.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
uniform ivec4 u_atlas_info;
|
||||
|
||||
#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos
|
||||
#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos
|
||||
#define GLYPHY_DEMO_EXTRA_ARGS , u_source, u_atlas_info, gi.atlas_pos
|
||||
|
||||
vec4
|
||||
glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)
|
||||
{
|
||||
ivec2 item_geom = _atlas_info.zw;
|
||||
vec2 pos = (vec2 (_atlas_pos.xy * item_geom +
|
||||
ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +
|
||||
+ vec2 (.5, .5)) / vec2(_atlas_info.xy);
|
||||
return GskTexture (_tex, pos);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// FRAGMENT_SHADER:
|
||||
// glyphy.fs.glsl
|
||||
|
||||
uniform float u_contrast;
|
||||
uniform float u_gamma_adjust;
|
||||
uniform float u_outline_thickness;
|
||||
uniform bool u_outline;
|
||||
uniform float u_boldness;
|
||||
|
||||
_IN_ vec4 v_glyph;
|
||||
_IN_ vec4 final_color;
|
||||
|
||||
#define SQRT2 1.4142135623730951
|
||||
#define SQRT2_INV 0.70710678118654757 /* 1 / sqrt(2.) */
|
||||
|
||||
struct glyph_info_t {
|
||||
ivec2 nominal_size;
|
||||
ivec2 atlas_pos;
|
||||
};
|
||||
|
||||
glyph_info_t
|
||||
glyph_info_decode (vec4 v)
|
||||
{
|
||||
glyph_info_t gi;
|
||||
gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;
|
||||
gi.atlas_pos = ivec2 (v_glyph.zw) / 256;
|
||||
return gi;
|
||||
}
|
||||
|
||||
float
|
||||
antialias (float d)
|
||||
{
|
||||
return smoothstep (-.75, +.75, d);
|
||||
}
|
||||
|
||||
void
|
||||
main()
|
||||
{
|
||||
vec2 p = v_glyph.xy;
|
||||
glyph_info_t gi = glyph_info_decode (v_glyph);
|
||||
|
||||
/* isotropic antialiasing */
|
||||
vec2 dpdx = dFdx (p);
|
||||
vec2 dpdy = dFdy (p);
|
||||
float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_INV;
|
||||
|
||||
float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
|
||||
gsdist -= u_boldness;
|
||||
float sdist = gsdist / m * u_contrast;
|
||||
|
||||
if (u_outline)
|
||||
sdist = abs (sdist) - u_outline_thickness * .5;
|
||||
|
||||
if (sdist > 1.)
|
||||
discard;
|
||||
|
||||
float alpha = antialias (-sdist);
|
||||
if (u_gamma_adjust != 1.)
|
||||
alpha = pow (alpha, 1./u_gamma_adjust);
|
||||
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// VERTEX_SHADER:
|
||||
// glyphy.vs.glsl
|
||||
|
||||
_OUT_ vec4 v_glyph;
|
||||
_OUT_ vec4 final_color;
|
||||
|
||||
vec4
|
||||
glyph_vertex_transcode (vec2 v)
|
||||
{
|
||||
ivec2 g = ivec2 (v);
|
||||
ivec2 corner = ivec2 (mod (v, 2.));
|
||||
g /= 2;
|
||||
ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));
|
||||
return vec4 (corner * nominal_size, g * 4);
|
||||
}
|
||||
|
||||
void
|
||||
main()
|
||||
{
|
||||
v_glyph = glyph_vertex_transcode(aUv);
|
||||
vUv = v_glyph.zw;
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
final_color = gsk_scaled_premultiply(aColor, u_alpha);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// linear_gradient.glsl
|
||||
uniform vec4 u_points;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec4 info;
|
||||
_OUT_ vec4 info;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
@@ -53,7 +53,7 @@ uniform highp int u_num_color_stops; // Why? Because it works like this.
|
||||
uniform float u_color_stops[MAX_COLOR_STOPS * 5];
|
||||
uniform bool u_repeat;
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec4 info;
|
||||
_IN_ vec4 info;
|
||||
|
||||
float get_offset(int index) {
|
||||
// u_color_stops[5 * index] makes Intel Windows driver crash.
|
||||
|
||||
@@ -5,12 +5,10 @@ precision highp float;
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
#define _OUT_ varying
|
||||
#define _IN_ varying
|
||||
#define _NOPERSPECTIVE_
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
|
||||
#else
|
||||
#define _OUT_ out
|
||||
#define _IN_ in
|
||||
#define _NOPERSPECTIVE_ noperspective
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
uniform vec4 u_geometry;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec2 coord;
|
||||
_OUT_ vec2 coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
@@ -32,7 +32,7 @@ uniform bool u_repeat;
|
||||
uniform vec2 u_range;
|
||||
uniform float u_color_stops[MAX_COLOR_STOPS * 5];
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec2 coord;
|
||||
_IN_ vec2 coord;
|
||||
|
||||
float get_offset(int index) {
|
||||
// u_color_stops[5 * index] makes Intel Windows driver crash.
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#ifndef __GI_SCANNER__
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskRenderer, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskRenderNode, gsk_render_node_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskTransform, gsk_transform_unref)
|
||||
|
||||
@@ -21,11 +21,15 @@
|
||||
#define __GSK_H_INSIDE__
|
||||
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gskglshader.h>
|
||||
#include <gsk/gskpath.h>
|
||||
#include <gsk/gskpathbuilder.h>
|
||||
#include <gsk/gskpathmeasure.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gskstroke.h>
|
||||
#include <gsk/gsktransform.h>
|
||||
#include <gsk/gskglshader.h>
|
||||
|
||||
#include <gsk/gskcairorenderer.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskboundingboxprivate.h"
|
||||
|
||||
GskBoundingBox *
|
||||
gsk_bounding_box_init (GskBoundingBox *self,
|
||||
const graphene_point_t *a,
|
||||
const graphene_point_t *b)
|
||||
{
|
||||
self->min.x = MIN (a->x, b->x);
|
||||
self->min.y = MIN (a->y, b->y);
|
||||
self->max.x = MAX (a->x, b->x);
|
||||
self->max.y = MAX (a->y, b->y);
|
||||
return self;
|
||||
}
|
||||
|
||||
GskBoundingBox *
|
||||
gsk_bounding_box_init_copy (GskBoundingBox *self,
|
||||
const GskBoundingBox *src)
|
||||
{
|
||||
self->min = src->min;
|
||||
self->max = src->max;
|
||||
return self;
|
||||
}
|
||||
|
||||
GskBoundingBox *
|
||||
gsk_bounding_box_init_from_rect (GskBoundingBox *self,
|
||||
const graphene_rect_t *bounds)
|
||||
{
|
||||
self->min = bounds->origin;
|
||||
self->max.x = bounds->origin.x + bounds->size.width;
|
||||
self->max.y = bounds->origin.y + bounds->size.height;
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_bounding_box_expand (GskBoundingBox *self,
|
||||
const graphene_point_t *p)
|
||||
{
|
||||
self->min.x = MIN (self->min.x, p->x);
|
||||
self->min.y = MIN (self->min.y, p->y);
|
||||
self->max.x = MAX (self->max.x, p->x);
|
||||
self->max.y = MAX (self->max.y, p->y);
|
||||
}
|
||||
|
||||
graphene_rect_t *
|
||||
gsk_bounding_box_to_rect (const GskBoundingBox *self,
|
||||
graphene_rect_t *rect)
|
||||
{
|
||||
rect->origin = self->min;
|
||||
rect->size.width = self->max.x - self->min.x;
|
||||
rect->size.height = self->max.y - self->min.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_bounding_box_contains_point (const GskBoundingBox *self,
|
||||
const graphene_point_t *p)
|
||||
{
|
||||
return self->min.x <= p->x && p->x <= self->max.x &&
|
||||
self->min.y <= p->y && p->y <= self->max.y;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_bounding_box_intersection (const GskBoundingBox *a,
|
||||
const GskBoundingBox *b,
|
||||
GskBoundingBox *res)
|
||||
{
|
||||
graphene_point_t min, max;
|
||||
|
||||
min.x = MAX (a->min.x, b->min.x);
|
||||
min.y = MAX (a->min.y, b->min.y);
|
||||
max.x = MIN (a->max.x, b->max.x);
|
||||
max.y = MIN (a->max.y, b->max.y);
|
||||
|
||||
if (res)
|
||||
gsk_bounding_box_init (res, &min, &max);
|
||||
|
||||
return min.x <= max.x && min.y <= max.y;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GskBoundingBox GskBoundingBox;
|
||||
|
||||
struct _GskBoundingBox {
|
||||
graphene_point_t min;
|
||||
graphene_point_t max;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskBoundingBox * gsk_bounding_box_init (GskBoundingBox *self,
|
||||
const graphene_point_t *a,
|
||||
const graphene_point_t *b);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskBoundingBox * gsk_bounding_box_init_copy (GskBoundingBox *self,
|
||||
const GskBoundingBox *src);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskBoundingBox * gsk_bounding_box_init_from_rect (GskBoundingBox *self,
|
||||
const graphene_rect_t *bounds);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_bounding_box_expand (GskBoundingBox *self,
|
||||
const graphene_point_t *p);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
graphene_rect_t *gsk_bounding_box_to_rect (const GskBoundingBox *self,
|
||||
graphene_rect_t *rect);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_bounding_box_contains_point (const GskBoundingBox *self,
|
||||
const graphene_point_t *p);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_bounding_box_intersection (const GskBoundingBox *a,
|
||||
const GskBoundingBox *b,
|
||||
GskBoundingBox *res);
|
||||
|
||||
G_END_DECLS
|
||||
+2099
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* 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: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GSK_CONTOUR_PRIVATE_H__
|
||||
#define __GSK_CONTOUR_PRIVATE_H__
|
||||
|
||||
#include <gskpath.h>
|
||||
|
||||
#include "gskpathopprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* A path is flat if it contains no cubic or conic segments.
|
||||
* A path is closed if all its contours end with a GSK_PATH_CLOSE
|
||||
* operation.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_FLAT,
|
||||
GSK_PATH_CLOSED
|
||||
} GskPathFlags;
|
||||
|
||||
typedef struct _GskContour GskContour;
|
||||
|
||||
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
|
||||
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||
float radius,
|
||||
float start_angle,
|
||||
float end_angle);
|
||||
GskContour * gsk_standard_contour_new (GskPathFlags flags,
|
||||
const graphene_point_t *points,
|
||||
gsize n_points,
|
||||
const gskpathop *ops,
|
||||
gsize n_ops,
|
||||
gssize offset);
|
||||
|
||||
void gsk_contour_copy (GskContour * dest,
|
||||
const GskContour *src);
|
||||
GskContour * gsk_contour_dup (const GskContour *src);
|
||||
|
||||
GskContour * gsk_contour_reverse (const GskContour *src);
|
||||
|
||||
gsize gsk_contour_get_size (const GskContour *self);
|
||||
GskPathFlags gsk_contour_get_flags (const GskContour *self);
|
||||
void gsk_contour_print (const GskContour *self,
|
||||
GString *string);
|
||||
gboolean gsk_contour_get_bounds (const GskContour *self,
|
||||
graphene_rect_t *bounds);
|
||||
gpointer gsk_contour_init_measure (const GskContour *self,
|
||||
float tolerance,
|
||||
float *out_length);
|
||||
void gsk_contour_free_measure (const GskContour *self,
|
||||
gpointer data);
|
||||
gboolean gsk_contour_foreach (const GskContour *self,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
void gsk_contour_get_start_end (const GskContour *self,
|
||||
graphene_point_t *start,
|
||||
graphene_point_t *end);
|
||||
void gsk_contour_get_point (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
graphene_point_t *pos,
|
||||
graphene_vec2_t *tangent);
|
||||
float gsk_contour_get_curvature (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
graphene_point_t *center);
|
||||
gboolean gsk_contour_get_closest_point (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float tolerance,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
float *out_distance,
|
||||
graphene_point_t *out_pos,
|
||||
float *out_offset,
|
||||
graphene_vec2_t *out_tangent);
|
||||
int gsk_contour_get_winding (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gpointer measure_data,
|
||||
gboolean emit_move_to,
|
||||
float start,
|
||||
float end);
|
||||
gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds);
|
||||
void gsk_contour_add_stroke (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
GskStroke *stroke);
|
||||
void gsk_contour_default_add_stroke (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
GskStroke *stroke);
|
||||
|
||||
void gsk_contour_offset (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
float distance,
|
||||
GskLineJoin line_join,
|
||||
float miter_limit);
|
||||
void gsk_contour_default_offset (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
float distance,
|
||||
GskLineJoin line_join,
|
||||
float miter_limit);
|
||||
|
||||
gboolean gsk_contour_is_convex (const GskContour *contour);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_CONTOUR_PRIVATE_H__ */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user