Compare commits
599 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 258233efa9 | |||
| 59bf76dce1 | |||
| 44a2a49f31 | |||
| 69bc42f444 | |||
| 269535c844 | |||
| c7f773f3e3 | |||
| c6da0c9a7a | |||
| d098cd5865 | |||
| 4dc8ab58a3 | |||
| 5680393f9d | |||
| aadcec3d1e | |||
| 5fd936beef | |||
| 563b80d434 | |||
| f4f0f0e6a0 | |||
| ba9b0c6f7d | |||
| 3ce3de98da | |||
| 1cd934e105 | |||
| dc1d3824a2 | |||
| 927e49ed86 | |||
| d55fc8b7b1 | |||
| e72d0a9118 | |||
| 8b14c8d0a8 | |||
| 913b4fcc49 | |||
| fb7d033953 | |||
| cfa440bbae | |||
| 7ac9fe3b60 | |||
| b0a8b7da63 | |||
| b2ff6e91cd | |||
| b4d906c464 | |||
| ae03caacc4 | |||
| ec22646210 | |||
| ba1644cba1 | |||
| d11bc68b27 | |||
| 5720e406b9 | |||
| b3f8f358b5 | |||
| e458ea2f3d | |||
| b6d8d3975e | |||
| 5e96129be1 | |||
| 0ef7d07880 | |||
| 545e95bb5c | |||
| ca76675a69 | |||
| 16d4ce4d03 | |||
| 58e273d056 | |||
| 1c14285dee | |||
| cd69570e78 | |||
| 52b9e4703b | |||
| d7193eaf8b | |||
| b52dea7a10 | |||
| 7bb5888272 | |||
| 4404afc9f3 | |||
| dadac6a9e1 | |||
| 210a06174d | |||
| f9a5a474f0 | |||
| c51f1fda28 | |||
| ea3d0c0f01 | |||
| 2c1198f6c2 | |||
| 9d3120cc1e | |||
| 66d3aa8101 | |||
| 0530637fef | |||
| 3d6bdb9af3 | |||
| 7e7c90961c | |||
| 3da9280a8a | |||
| ed17a8ddd7 | |||
| cd7e70680c | |||
| a80007ac12 | |||
| dc68d04c32 | |||
| bd95e16372 | |||
| c1e1e2da80 | |||
| ea8f1469c1 | |||
| 1d3aa9207c | |||
| b4f2a3416e | |||
| 3b46e2a558 | |||
| 480a04131c | |||
| 171a710a23 | |||
| 4f532a414c | |||
| 3f567781dd | |||
| 0397c8b628 | |||
| 3939824d11 | |||
| d7cafca118 | |||
| d10709c917 | |||
| e9d4823c57 | |||
| 06d764d046 | |||
| 325badc3eb | |||
| c665a1d5a5 | |||
| c7f1a275ac | |||
| a52989842e | |||
| 1df276f263 | |||
| 615f10f7c8 | |||
| 38cba6895a | |||
| e95e045898 | |||
| 1b730dcf31 | |||
| beb9ee6d4a | |||
| 8ce6d03c7b | |||
| 904202a636 | |||
| 7a0b6a3639 | |||
| b465e04ae2 | |||
| f67627875f | |||
| 8912dc226c | |||
| 12ac9f351e | |||
| c4b4e90f98 | |||
| fcf28ded42 | |||
| 1e69d248cb | |||
| c49b29fa53 | |||
| 024220aee8 | |||
| 1423265610 | |||
| 89c48a08a0 | |||
| c30968861f | |||
| a8ac6f833c | |||
| 271acaff53 | |||
| c35e0cba39 | |||
| 65240967e4 | |||
| a99bd2a422 | |||
| 3ec2d5fa38 | |||
| a0b5b39bbd | |||
| ab52862a5d | |||
| a350192ea2 | |||
| cb0d8d6d90 | |||
| 86ad3e8f2a | |||
| 8f29a0633b | |||
| 7601bca758 | |||
| 3bbfff9280 | |||
| 5b049364dc | |||
| 7997bdc5d7 | |||
| 04aebda1e9 | |||
| 77792b6475 | |||
| 5612e84551 | |||
| 462193ae26 | |||
| 80a90a084e | |||
| 2f29cb9e6f | |||
| 67fdfca3ba | |||
| 284d909347 | |||
| 43ef4d7b53 | |||
| 3ce45508e1 | |||
| 57efdcfbbe | |||
| df817bd118 | |||
| 82a1d4f280 | |||
| 80f2660838 | |||
| edd4d2918a | |||
| 320d272ec8 | |||
| 72d09d22e9 | |||
| a2a4603329 | |||
| 8de1ba2cc4 | |||
| 2644da106b | |||
| 4860410c4a | |||
| 4b3a94f382 | |||
| d67dacedba | |||
| e1feb1b712 | |||
| e8670c89ae | |||
| b4f918904c | |||
| aead150ce2 | |||
| fd47e57e4b | |||
| 1e129c1dd2 | |||
| e0a7d28339 | |||
| ad93806005 | |||
| 2b95a5daee | |||
| 0681c5d5bc | |||
| b19926c079 | |||
| 692ed4f994 | |||
| ad759307f8 | |||
| fb6adaaa62 | |||
| 58a4ae94e9 | |||
| 9df9087a13 | |||
| f8df527c68 | |||
| 71512cf9ad | |||
| 79cc8fb261 | |||
| 2831dbb110 | |||
| 933acb3682 | |||
| 574ebafa46 | |||
| 74dd05b45e | |||
| 3eb2cef421 | |||
| 94745241c2 | |||
| 538491efa1 | |||
| 6f8c4f873d | |||
| 7a4e9fa4d3 | |||
| f3c704b82e | |||
| a6a69dd567 | |||
| 8921c868a5 | |||
| 3f8598baa4 | |||
| b5fd7b3211 | |||
| e9fe9410e0 | |||
| 904fd5f1fc | |||
| f598836d6c | |||
| 5907ff694f | |||
| 7c020bfaaa | |||
| 2bd02d9185 | |||
| c0cf592336 | |||
| 12378f0afa | |||
| 5ea211bbb1 | |||
| c17c18f1ae | |||
| dbde7b68c0 | |||
| 95f06f6e75 | |||
| a26edd59d1 | |||
| dcd21e12cd | |||
| e5efc84eda | |||
| 8035969860 | |||
| e5f9bf2e9b | |||
| 0be4d31217 | |||
| eebb849760 | |||
| f92745aacf | |||
| 7aee30bfc2 | |||
| ef751bc809 | |||
| fe49f83982 | |||
| 059d9376da | |||
| 6466e53bfc | |||
| b7963a06ab | |||
| eeeefb40c7 | |||
| 97d8676b40 | |||
| 6e28d004ae | |||
| 8d7bf3ad0c | |||
| d76a0feef6 | |||
| 08a07d4ae5 | |||
| b42d99b37e | |||
| ea487b2233 | |||
| 40ae5c1319 | |||
| 8c9c3e4426 | |||
| d0f4fcb6fd | |||
| 4142d0a69a | |||
| b061821f24 | |||
| e0833e492c | |||
| 55faaf1aa1 | |||
| 7aa02b9e95 | |||
| c65c6ba11f | |||
| 359d874ddb | |||
| ade171a2ed | |||
| 1f1306a53b | |||
| ce3d5fcb0a | |||
| 28bd56454d | |||
| 75deff035b | |||
| 87ee7e31a4 | |||
| 5a3ecb9703 | |||
| e656f66720 | |||
| 0d47a6c970 | |||
| 39f8e1e137 | |||
| d7c2e5844b | |||
| edc4b2f7d0 | |||
| b3ba2961d2 | |||
| c2c1acc73e | |||
| c44728282c | |||
| 85a002bf9f | |||
| 6eba544ad4 | |||
| f610fbfc0e | |||
| 1e2d11cc62 | |||
| f1e24ca30a | |||
| 1787f04097 | |||
| 671f69c6ca | |||
| 7b51de6bbd | |||
| 45b909f2c5 | |||
| 0b4ee06f8e | |||
| 797739198f | |||
| 0c017ff109 | |||
| aad3686726 | |||
| fe7a2635d0 | |||
| 2834b38d2c | |||
| 29563a33ba | |||
| 5936d7f8f2 | |||
| 481a78eee7 | |||
| ac4134c298 | |||
| 145659af93 | |||
| 31b8e0f109 | |||
| 18199a3cef | |||
| 3194c39471 | |||
| 9d51a8f53a | |||
| c37c86a9bf | |||
| b4b30b4951 | |||
| 54830a2af3 | |||
| 9946dd2ab7 | |||
| 5028cb35bc | |||
| 48b569eae0 | |||
| 8099669466 | |||
| 1c465604d5 | |||
| 833442e1e2 | |||
| 1e39f999e3 | |||
| e31187e1cf | |||
| e457a7823c | |||
| 88c77eb7be | |||
| f57d337fac | |||
| 60b0f48fbc | |||
| 4c6d60ce2b | |||
| b4acf81609 | |||
| 62871400b1 | |||
| c4b3337569 | |||
| 45e6e0cd04 | |||
| 98dd53c2c3 | |||
| ad7eaf2bb8 | |||
| ef82f1799f | |||
| 1729da8a3e | |||
| a3ac3b61ef | |||
| 532a48aa92 | |||
| f3674688bf | |||
| dd6aa7b870 | |||
| 21d0e30903 | |||
| 3c73f70dae | |||
| 65fbd0af4e | |||
| 55b32c8a8f | |||
| bb0e964f56 | |||
| 0f4a6bfbf8 | |||
| 4e884b6056 | |||
| f252bbc02c | |||
| 9cbd3ac017 | |||
| 4bae7fb0fd | |||
| b98f5a0823 | |||
| 00c29e1fbe | |||
| de3e5be235 | |||
| ae3e6d1949 | |||
| 114efa83c6 | |||
| d15df65a9d | |||
| e0a1311e5b | |||
| 48e88c6ea4 | |||
| 50c63fc39a | |||
| 1ca5b41571 | |||
| cebf5ed46c | |||
| 1ca906008e | |||
| dd69c4e0f2 | |||
| cbb0d7ba69 | |||
| cbdb744c40 | |||
| 10fef2fbb4 | |||
| 8e2fb9c2be | |||
| f48ed12e78 | |||
| 66c0336ead | |||
| 0657a53940 | |||
| eecd5823d0 | |||
| 99b769706c | |||
| 39843ebb3f | |||
| 52bcf7fd46 | |||
| 43997fb550 | |||
| c59669d376 | |||
| ac97d2be0c | |||
| e9a67cc6d0 | |||
| 44655932c4 | |||
| 278f9a9eda | |||
| a28c7e8839 | |||
| 77c8d2df00 | |||
| aeca5858d8 | |||
| 89b96a864e | |||
| 26302cada5 | |||
| 42d064c62f | |||
| 273189fc1a | |||
| d51abaea2e | |||
| 248708c282 | |||
| 0e2748006a | |||
| e89bd7dfa2 | |||
| 2f6e998a27 | |||
| 7b7296410e | |||
| d90e2733ea | |||
| 19bf502fde | |||
| 2b8e30a8ed | |||
| 4ad8dcebd8 | |||
| a966b90e51 | |||
| 5b2a451e75 | |||
| 8105bde835 | |||
| 2329b62c14 | |||
| 1e1bed056f | |||
| a0d83bdfa7 | |||
| fa8190328d | |||
| d19cba429d | |||
| be2609a271 | |||
| 5bf009a203 | |||
| 93a89a371e | |||
| 60cb315be6 | |||
| 73728814b0 | |||
| d4098099dd | |||
| 57ef793e6d | |||
| 58cdd5139e | |||
| 2c84049769 | |||
| 29c700d1c7 | |||
| 0d7c987b1a | |||
| 03679d4342 | |||
| 1a4b60fb36 | |||
| 05b2ae0f31 | |||
| f211d71f74 | |||
| 691ab421fb | |||
| 9e3e9e83ef | |||
| a0056d5ca8 | |||
| f3e6d00db1 | |||
| e55df03fe2 | |||
| c8a13a2d8a | |||
| 6971e2923d | |||
| 231b76bdd1 | |||
| 57ba4048de | |||
| 545c5f18b2 | |||
| 5571217218 | |||
| b92c328425 | |||
| 8bdcff3320 | |||
| 9ffd88012d | |||
| 563fb97f90 | |||
| ee5708f543 | |||
| b7bf04fabd | |||
| b94b8ac38d | |||
| afd69db678 | |||
| f3834138f7 | |||
| 64b7c123cc | |||
| fcb780ee13 | |||
| 65b795b861 | |||
| 64d97b233b | |||
| db8474e5b1 | |||
| 5e8983883e | |||
| 59006e2e03 | |||
| b6acc31d44 | |||
| 6d0fe46cba | |||
| 05e752e096 | |||
| 2237009983 | |||
| 417ac4ab43 | |||
| 4495eaae84 | |||
| aba76fe8e9 | |||
| 867042f88f | |||
| 32ec7dec61 | |||
| d6161e09cd | |||
| 4b5fb5ec79 | |||
| 4f70f72349 | |||
| dd94129e27 | |||
| 63e5b827ed | |||
| 573c63973a | |||
| 1ce960c85b | |||
| d7a5dcba0b | |||
| a4b1c6b384 | |||
| 0edec9bcae | |||
| 7d12a843f2 | |||
| 867efe2e33 | |||
| a121bfa7ec | |||
| 02758cd48d | |||
| 005f932d13 | |||
| 4e8c06eb7a | |||
| ca9aa23619 | |||
| ae2c765ffd | |||
| ab9455ea1b | |||
| 89522e6923 | |||
| 506a4ddad5 | |||
| 272e4a0a9d | |||
| 16deffb48d | |||
| a60e951941 | |||
| 05306470b0 | |||
| 803a8cf333 | |||
| 3e5746356e | |||
| c9f1c56776 | |||
| fc026b95dd | |||
| 2bb97bc136 | |||
| d4d12171f4 | |||
| 21e484731a | |||
| b82a32676b | |||
| d7228ae025 | |||
| 04c02e9aec | |||
| d6945d81f0 | |||
| 6d6559f982 | |||
| b271db253f | |||
| eb9f95e9fa | |||
| d7a5723d66 | |||
| 72498b9e28 | |||
| b904fc6ee0 | |||
| 9622ba8a0d | |||
| 3b8d206143 | |||
| e027fc9272 | |||
| ba6c5ef201 | |||
| 6a8013735d | |||
| c3e72c4d7e | |||
| a6c47cb3ab | |||
| cc129e564a | |||
| 9fbcbc55d7 | |||
| 00a27c1e28 | |||
| f5f6597abc | |||
| fade0afbef | |||
| 0082675de8 | |||
| ed8e784879 | |||
| a4790b7eaa | |||
| ed434519d2 | |||
| 4ed4b4fd6a | |||
| 369cb702e4 | |||
| d246abd085 | |||
| 911627fa0b | |||
| ec576088bb | |||
| ab0b54db76 | |||
| fb51f8be9a | |||
| eb22c7c9c3 | |||
| 749ef4d71c | |||
| f6fae1dd09 | |||
| f21abba82f | |||
| bf222a9292 | |||
| 96e465b6d9 | |||
| 016de68ceb | |||
| d2178bcb94 | |||
| f40eb8a1fe | |||
| 9e0f43e8cb | |||
| 3e4d7250a0 | |||
| 4ebd14c045 | |||
| ca39b35e2f | |||
| a32fb5b849 | |||
| eed19c9269 | |||
| e2d691bdb1 | |||
| a73f961e65 | |||
| a7aed5af4b | |||
| 220a51e7cb | |||
| 6df28420d7 | |||
| 081b45399f | |||
| 0874a54708 | |||
| cd40ec2200 | |||
| 62b887e064 | |||
| ce9ce8a5bc | |||
| 2322f38bf9 | |||
| dcb6c9b4cf | |||
| afdeffd820 | |||
| 10439aaefe | |||
| d64467b334 | |||
| 099b967885 | |||
| d13cd9cb67 | |||
| 79b87cc543 | |||
| 3c2aceba63 | |||
| a01feae15b | |||
| b4d4f73d9f | |||
| c1de6219ed | |||
| b364827a5b | |||
| bbe362d015 | |||
| 08f32c6560 | |||
| b3c8c8e592 | |||
| ed36933232 | |||
| a90fc088f2 | |||
| ff6c4ed07e | |||
| 201f635559 | |||
| 59077e4843 | |||
| 3e6a473082 | |||
| 580d96620e | |||
| 61f50f2410 | |||
| 61b2f3c996 | |||
| ab30850aad | |||
| f5e04b59e9 | |||
| c67bcf09b9 | |||
| 5eba0bc932 | |||
| ff2ba52bc6 | |||
| a822d6fce9 | |||
| b749fe4270 | |||
| 933cb857cf | |||
| dde535bbdf | |||
| 71b36db88d | |||
| b5576397f7 | |||
| 4e86858405 | |||
| 14b21d78db | |||
| 35829a7272 | |||
| 0eb60fb03e | |||
| 94162197a1 | |||
| 877fffdd5e | |||
| 8669d31c30 | |||
| e76d17a786 | |||
| 5ab90f1a80 | |||
| 5b1fd111d1 | |||
| 5596feae9b | |||
| 8fb8303ba0 | |||
| 06e4c3c991 | |||
| f25f3b3c47 | |||
| 72ec8963d7 | |||
| 50d5666db0 | |||
| e06044530f | |||
| 7ce7e5503f | |||
| 0ba307995d | |||
| ce7956cd50 | |||
| d29b378fa0 | |||
| 1129febd7d | |||
| 47928b9e14 | |||
| 01f17836ac | |||
| 7e919aaaa5 | |||
| 03a6420c37 | |||
| 375fbd4e47 | |||
| 813957a92f | |||
| 36ed4c2a29 | |||
| 8e78b53378 | |||
| 76ed6cf9d8 | |||
| a8c6f222ed | |||
| c5afea0c6b | |||
| efa42a6932 | |||
| 5d1b2f627c | |||
| 8f6f980e49 | |||
| 25b3b90920 | |||
| 71762d3b28 | |||
| f15224926a | |||
| 1570c41efa | |||
| 5e0f2d7d20 | |||
| 88743ab975 | |||
| 6f15447633 | |||
| 85f6995511 | |||
| 4d59a00074 | |||
| 2dbb1509d8 | |||
| 101c927c40 | |||
| 6d3eb18578 | |||
| d301695ba1 | |||
| ca8008e2c9 | |||
| 0d7b4ecb14 | |||
| 9a541d9b91 | |||
| cdfde6673d | |||
| 7ef95734af | |||
| de17e3b525 | |||
| f8a971a7df | |||
| e1a7629a85 | |||
| 7d3b8b0d09 | |||
| fff2fabd7a | |||
| 73b45ec77e | |||
| 8f95a5980e | |||
| 87d33470ed | |||
| 002e48c469 | |||
| f33549da91 | |||
| 791da76ae1 | |||
| b7f9a5419f | |||
| 6cfa799ca1 |
@@ -0,0 +1 @@
|
||||
/subprojects/*/
|
||||
+2
-2
@@ -13,7 +13,7 @@ stages:
|
||||
- subprojects/pango/
|
||||
|
||||
fedora-x86_64:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
|
||||
stage: build
|
||||
script:
|
||||
- bash -x ./.gitlab-ci/test-docker.sh
|
||||
@@ -64,7 +64,7 @@ flatpak:widget-factory:
|
||||
<<: *flatpak-defaults
|
||||
|
||||
pages:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
|
||||
stage: deploy
|
||||
script:
|
||||
- meson -Ddocumentation=true _build .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM fedora:28
|
||||
FROM fedora:29
|
||||
|
||||
RUN dnf -y install \
|
||||
hicolor-icon-theme \
|
||||
@@ -33,6 +33,7 @@ RUN dnf -y install \
|
||||
iso-codes \
|
||||
itstool \
|
||||
json-glib-devel \
|
||||
lcov \
|
||||
libattr-devel \
|
||||
libepoxy-devel \
|
||||
libffi-devel \
|
||||
@@ -69,7 +70,7 @@ RUN dnf -y install \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf clean all
|
||||
|
||||
RUN pip3 install meson
|
||||
RUN pip3 install meson==0.49.0
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v1"
|
||||
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v2"
|
||||
|
||||
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
|
||||
--file "Dockerfile" .
|
||||
|
||||
+223
-22
@@ -1,31 +1,144 @@
|
||||
If you want to hack on the GTK+ project, you'll need to have the development
|
||||
tools appropriate for your operating system, including:
|
||||
# Contribution guidelines
|
||||
|
||||
Thank you for considering contributing to the GTK project!
|
||||
|
||||
These guidelines are meant for new contributors, regardless of their level
|
||||
of proficiency; following them allows the maintainers of the GTK project to
|
||||
more effectively evaluate your contribution, and provide prompt feedback to
|
||||
you. Additionally, by following these guidelines you clearly communicate
|
||||
that you respect the time and effort that the people developing GTK put into
|
||||
managing the project.
|
||||
|
||||
GTK is a complex free software GUI toolkit, and it would not exist without
|
||||
contributions from the free and open source software community. There are
|
||||
many things that we value:
|
||||
|
||||
- bug reporting and fixing
|
||||
- documentation and examples
|
||||
- tests
|
||||
- new features
|
||||
|
||||
Please, do not use the issue tracker for support questions. If you have
|
||||
questions on how to use GTK effectively, you can use:
|
||||
|
||||
- the `#gtk+` IRC channel on irc.gnome.org
|
||||
- the [gtk](https://mail.gnome.org/mailman/listinfo/gtk-list) mailing list,
|
||||
for general questions on GTK
|
||||
- the [gtk-app-devel](https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list)
|
||||
mailing list, for questions on application development with GTK
|
||||
- the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
|
||||
mailing list, for questions on developing GTK itself
|
||||
|
||||
You can also look at the GTK tag on [Stack
|
||||
Overflow](https://stackoverflow.com/questions/tagged/gtk).
|
||||
|
||||
The issue tracker is meant to be used for actionable issues only.
|
||||
|
||||
## How to report bugs
|
||||
|
||||
### Security issues
|
||||
|
||||
You should not open a new issue for security related questions.
|
||||
|
||||
When in doubt, send an email to the [security](mailto:security@gnome.org)
|
||||
mailing list.
|
||||
|
||||
### Bug reports
|
||||
|
||||
If you're reporting a bug make sure to list:
|
||||
|
||||
0. which version of GTK are you using?
|
||||
0. which operating system are you using?
|
||||
0. the necessary steps to reproduce the issue
|
||||
0. the expected outcome
|
||||
0. a description of the behavior; screenshots are also welcome
|
||||
0. a small, self-contained example exhibiting the behavior; if this
|
||||
is not available, try reproducing the issue using the GTK examples
|
||||
or interactive tests
|
||||
|
||||
If the issue includes a crash, you should also include:
|
||||
|
||||
0. the eventual warnings printed on the terminal
|
||||
0. a backtrace, obtained with tools such as GDB or LLDB
|
||||
|
||||
For small issues, such as:
|
||||
|
||||
- spelling/grammar fixes in the documentation
|
||||
- typo correction
|
||||
- comment clean ups
|
||||
- changes to metadata files (CI, `.gitignore`)
|
||||
- build system changes
|
||||
- source tree clean ups and reorganizations
|
||||
|
||||
You should directly open a merge request instead of filing a new issue.
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
Feature discussion can be open ended and require high bandwidth channels; if
|
||||
you are proposing a new feature on the issue tracker, make sure to make
|
||||
an actionable proposal, and list:
|
||||
|
||||
0. what you're trying to achieve
|
||||
0. prior art, in other toolkits or applications
|
||||
0. design and theming changes
|
||||
|
||||
If you're proposing the integration of new features it helps to have
|
||||
multiple applications using shared or similar code, especially if they have
|
||||
iterated over it various times.
|
||||
|
||||
Each feature should also come fully documented, and with tests.
|
||||
|
||||
## Your first contribution
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you want to contribute to the GTK project, you will need to have the
|
||||
development tools appropriate for your operating system, including:
|
||||
|
||||
- Python 3.x
|
||||
- Meson
|
||||
- Ninja
|
||||
- Gettext (19.7 or newer)
|
||||
- a C99 compatible compiler
|
||||
- a [C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
|
||||
|
||||
Up-to-date instructions about developing GNOME applications and libraries
|
||||
can be found here:
|
||||
can be found on [the GNOME Developer Center](https://developer.gnome.org).
|
||||
|
||||
* https://developer.gnome.org
|
||||
The GTK project uses GitLab for code hosting and for tracking issues. More
|
||||
information about using GitLab can be found [on the GNOME
|
||||
wiki](https://wiki.gnome.org/GitLab).
|
||||
|
||||
Information about using GitLab with GNOME can be found here:
|
||||
### Dependencies
|
||||
|
||||
* https://wiki.gnome.org/GitLab
|
||||
In order to get GTK from Git installed on your system, you need to have the
|
||||
required versions of all the software dependencies required by GTK; typically,
|
||||
this means a recent version of GLib, Cairo, Pango, and ATK, as well as the
|
||||
platform-specific dependencies for the windowing system you are using (Wayland,
|
||||
X11, Windows, or macOS).
|
||||
|
||||
In order to get Git GTK+ installed on your system, you need to have the
|
||||
required versions of all the GTK+ dependencies; typically, this means a
|
||||
recent version of GLib, Cairo, Pango, and ATK, as well as the platform
|
||||
specific dependencies for the windowing system you are using (Wayland, X11,
|
||||
Windows, or macOS).
|
||||
The core dependencies for GTK are:
|
||||
|
||||
- [GLib, GObject, and GIO](https://gitlab.gnome.org/GNOME/glib)
|
||||
- [Cairo](http://cairographics.org)
|
||||
- [Pango](https://gitlab.gnome.org/GNOME/pango)
|
||||
- [GdkPixbuf](https://gitlab.gnome.org/GNOME/gdk-pixbuf)
|
||||
- [Epoxy](https://github.com/anholt/libepoxy)
|
||||
- [ATK](https://gitlab.gnome.org/GNOME/atk)
|
||||
- [Graphene](https://github.com/ebassi/graphene)
|
||||
|
||||
GTK will attempt to download and build some of these dependencies if it
|
||||
cannot find them on your system.
|
||||
|
||||
Additionally, you may want to look at projects that create a development
|
||||
environment for you, like [jhbuild](https://wiki.gnome.org/HowDoI/Jhbuild)
|
||||
and [gvsbuild](https://github.com/wingtk/gvsbuild).
|
||||
|
||||
### Getting started
|
||||
|
||||
You should start by forking the GTK repository from the GitLab web UI, and
|
||||
cloning from your fork:
|
||||
|
||||
```ssh
|
||||
```sh
|
||||
$ git clone https://gitlab.gnome.org/yourusername/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
@@ -38,7 +151,7 @@ $ git clone git@gitlab.gnome.org:GNOME/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
|
||||
To compile the Git version of GTK+ on your system, you will need to
|
||||
To compile the Git version of GTK on your system, you will need to
|
||||
configure your build using Meson:
|
||||
|
||||
```sh
|
||||
@@ -47,11 +160,6 @@ $ cd _builddir
|
||||
$ ninja
|
||||
```
|
||||
|
||||
**Note**: For information about submitting patches and pushing changes
|
||||
to Git, see the `README.md` and `README.commits` files. In particular,
|
||||
don't, under any circumstances, push anything to Git before reading and
|
||||
understanding `README.commmits`.
|
||||
|
||||
Typically, you should work on your own branch:
|
||||
|
||||
```sh
|
||||
@@ -60,6 +168,99 @@ $ git checkout -b your-branch
|
||||
|
||||
Once you've finished working on the bug fix or feature, push the branch
|
||||
to the Git repository and open a new merge request, to let the GTK
|
||||
maintainers review your contribution. The [CODE-OWNERS](./docs-CODE-OWNERS)
|
||||
document contains the list of core contributors to GTK and the areas for
|
||||
which they are responsible.
|
||||
maintainers review your contribution.
|
||||
|
||||
### Code reviews
|
||||
|
||||
Each contribution is reviewed by the core developers of the GTK project.
|
||||
|
||||
The [CODE-OWNERS](./docs/CODE-OWNERS) document contains the list of core
|
||||
contributors to GTK and the areas for which they are responsible; you
|
||||
should ensure to receive their review and signoff on your changes.
|
||||
|
||||
### Commit messages
|
||||
|
||||
The expected format for git commit messages is as follows:
|
||||
|
||||
```plain
|
||||
Short explanation of the commit
|
||||
|
||||
Longer explanation explaining exactly what's changed, whether any
|
||||
external or private interfaces changed, what bugs were fixed (with bug
|
||||
tracker reference if applicable) and so forth. Be concise but not too
|
||||
brief.
|
||||
|
||||
Closes #1234
|
||||
```
|
||||
|
||||
- Always add a brief description of the commit to the _first_ line of
|
||||
the commit and terminate by two newlines (it will work without the
|
||||
second newline, but that is not nice for the interfaces).
|
||||
|
||||
- First line (the brief description) must only be one sentence and
|
||||
should start with a capital letter unless it starts with a lowercase
|
||||
symbol or identifier. Don't use a trailing period either. Don't exceed
|
||||
72 characters.
|
||||
|
||||
- The main description (the body) is normal prose and should use normal
|
||||
punctuation and capital letters where appropriate. Consider the commit
|
||||
message as an email sent to the developers (or yourself, six months
|
||||
down the line) detailing **why** you changed something. There's no need
|
||||
to specify the **how**: the changes can be inlined.
|
||||
|
||||
- When committing code on behalf of others use the `--author` option, e.g.
|
||||
`git commit -a --author "Joe Coder <joe@coder.org>"` and `--signoff`.
|
||||
|
||||
- If your commit is addressing an issue, use the
|
||||
[GitLab syntax](https://docs.gitlab.com/ce/user/project/issues/automatic_issue_closing.html)
|
||||
to automatically close the issue when merging the commit with the upstream
|
||||
repository:
|
||||
|
||||
```plain
|
||||
Closes #1234
|
||||
Fixes #1234
|
||||
Closes: https://gitlab.gnome.org/GNOME/gtk/issues/1234
|
||||
```
|
||||
|
||||
- If you have a merge request with multiple commits and none of them
|
||||
completely fixes an issue, you should add a reference to the issue in
|
||||
the commit message, e.g. `Bug: #1234`, and use the automatic issue
|
||||
closing syntax in the description of the merge request.
|
||||
|
||||
### Commit access to the GTK repository
|
||||
|
||||
GTK is part of the GNOME infrastructure. At the current time, any
|
||||
person with write access to the GNOME repository can merge changes to
|
||||
GTK. This is a good thing, in that it encourages many people to work
|
||||
on GTK, and progress can be made quickly. However, GTK is a fairly
|
||||
large and complicated project on which many other things depend, so to
|
||||
avoid unnecessary breakage, and to take advantage of the knowledge
|
||||
about GTK that has been built up over the years, we'd like to ask
|
||||
people committing to GTK to follow a few rules:
|
||||
|
||||
0. Ask first. If your changes are major, or could possibly break existing
|
||||
code, you should always ask. If your change is minor and you've been
|
||||
working on GTK for a while it probably isn't necessary to ask. But when
|
||||
in doubt, ask. Even if your change is correct, somebody may know a
|
||||
better way to do things. If you are making changes to GTK, you should
|
||||
be subscribed to the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
|
||||
mailing list; this is a good place to ask about intended changes.
|
||||
The `#gtk+` IRC channel on irc.gnome.org is also a good place to find GTK
|
||||
developers to discuss changes, but if you live outside of the EU/US time
|
||||
zones, an email to the gtk-devel mailing list is the most certain and
|
||||
preferred method.
|
||||
|
||||
0. Ask _first_.
|
||||
|
||||
0. Always write a meaningful commit message. Changes without a sufficient
|
||||
commit message will be reverted.
|
||||
|
||||
0. Never push to the `master` branch, or any stable branches, directly; you
|
||||
should always go through a merge request, to ensure that the code is
|
||||
tested on the CI infrastructure at the very least. A merge request is
|
||||
also the proper place to get a comprehensive code review from the core
|
||||
developers of GTK.
|
||||
|
||||
If you have been contributing to GTK for a while and you don't have commit
|
||||
access to the repository, you may ask to obtain it following the [GNOME account
|
||||
process](https://wiki.gnome.org/AccountsTeam/NewAccounts).
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
GTK+ is part of the GNOME git repository. At the current time, any
|
||||
person with write access to the GNOME repository, can make changes to
|
||||
GTK+. This is a good thing, in that it encourages many people to work
|
||||
on GTK+, and progress can be made quickly. However, GTK+ is a fairly
|
||||
large and complicated package that many other things depend on, so to
|
||||
avoid unnecessary breakage, and to take advantage of the knowledge
|
||||
about GTK+ that has been built up over the years, we'd like to ask
|
||||
people committing to GTK+ to follow a few rules:
|
||||
|
||||
0) Ask first. If your changes are major, or could possibly break existing
|
||||
code, you should always ask. If your change is minor and you've
|
||||
been working on GTK+ for a while it probably isn't necessary
|
||||
to ask. But when in doubt, ask. Even if your change is correct,
|
||||
somebody may know a better way to do things.
|
||||
|
||||
If you are making changes to GTK+, you should be subscribed
|
||||
to gtk-devel-list@gnome.org. (Subscription address:
|
||||
gtk-devel-list-request@gnome.org.) This is a good place to ask
|
||||
about intended changes.
|
||||
|
||||
#gtk+ on GIMPNet (irc.gimp.org, irc.us.gimp.org, irc.eu.gimp.org, ...)
|
||||
is also a good place to find GTK+ developers to discuss changes with,
|
||||
however, email to gtk-devel-list is the most certain and preferred
|
||||
method.
|
||||
|
||||
1) Ask _first_.
|
||||
|
||||
2) With git, we no longer maintain a ChangeLog file, but you are expected
|
||||
to produce a meaningful commit message. Changes without a sufficient
|
||||
commit message will be reverted. See below for the expected format
|
||||
of commit messages.
|
||||
|
||||
Notes:
|
||||
|
||||
* When developing larger features or complicated bug fixes, it is
|
||||
advisable to work in a branch in your own cloned GTK+ repository.
|
||||
You may even consider making your repository publically available
|
||||
so that others can easily test and review your changes.
|
||||
|
||||
* The expected format for git commit messages is as follows:
|
||||
|
||||
=== begin example commit ===
|
||||
Short explanation of the commit
|
||||
|
||||
Longer explanation explaining exactly what's changed, whether any
|
||||
external or private interfaces changed, what bugs were fixed (with bug
|
||||
tracker reference if applicable) and so forth. Be concise but not too brief.
|
||||
=== end example commit ===
|
||||
|
||||
- Always add a brief description of the commit to the _first_ line of
|
||||
the commit and terminate by two newlines (it will work without the
|
||||
second newline, but that is not nice for the interfaces).
|
||||
|
||||
- First line (the brief description) must only be one sentence and
|
||||
should start with a capital letter unless it starts with a lowercase
|
||||
symbol or identifier. Don't use a trailing period either. Don't exceed
|
||||
72 characters.
|
||||
|
||||
- The main description (the body) is normal prose and should use normal
|
||||
punctuation and capital letters where appropriate. Normally, for patches
|
||||
sent to a mailing list it's copied from there.
|
||||
|
||||
- When committing code on behalf of others use the --author option, e.g.
|
||||
git commit -a --author "Joe Coder <joe@coder.org>" and --signoff.
|
||||
|
||||
|
||||
Owen Taylor
|
||||
13 Aug 1998
|
||||
17 Apr 2001
|
||||
|
||||
Matthias Clasen
|
||||
31 Mar 2009
|
||||
@@ -31,6 +31,11 @@ Information about mailing lists can be found at
|
||||
|
||||
- http://www.gtk.org/mailing-lists.php
|
||||
|
||||
Nightly documentation can be found at
|
||||
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk/
|
||||
- Gdk: https://gnome.pages.gitlab.gnome.org/gtk/gdk/
|
||||
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk/
|
||||
|
||||
Building and installing
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk4-demo",
|
||||
"tags": ["devel", "development", "nightly"],
|
||||
"rename-desktop-file": "gtk4-demo.desktop",
|
||||
"rename-icon": "gtk4-demo",
|
||||
"desktop-file-name-prefix": "(Development) ",
|
||||
"finish-args": [
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk4-widget-factory",
|
||||
"tags": ["devel", "development", "nightly"],
|
||||
"rename-desktop-file": "gtk4-widget-factory.desktop",
|
||||
"rename-icon": "gtk4-widget-factory",
|
||||
"desktop-file-name-prefix": "(Development) ",
|
||||
"finish-args": [
|
||||
|
||||
@@ -455,13 +455,16 @@ demo_application_window_constructed (GObject *object)
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_size_allocate (GtkWidget *widget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline)
|
||||
demo_application_window_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
||||
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget, allocation,
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget,
|
||||
width,
|
||||
height,
|
||||
baseline);
|
||||
|
||||
if (!window->maximized && !window->fullscreen)
|
||||
|
||||
@@ -87,14 +87,14 @@ find_toplevel_at_pointer (GdkDisplay *display)
|
||||
return widget ? gtk_widget_get_toplevel (widget) : NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
release_event_cb (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gboolean *clicked)
|
||||
static void
|
||||
released_cb (GtkGestureMultiPress *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean *clicked)
|
||||
{
|
||||
if (gdk_event_get_event_type (event) == GDK_BUTTON_RELEASE)
|
||||
*clicked = TRUE;
|
||||
return TRUE;
|
||||
*clicked = TRUE;
|
||||
}
|
||||
|
||||
/* Asks the user to click on a window, then waits for them click
|
||||
@@ -132,10 +132,12 @@ query_for_toplevel (GdkDisplay *display,
|
||||
GDK_SEAT_CAPABILITY_ALL_POINTING,
|
||||
FALSE, cursor, NULL, NULL, NULL) == GDK_GRAB_SUCCESS)
|
||||
{
|
||||
GtkGesture *gesture = gtk_gesture_multi_press_new ();
|
||||
gboolean clicked = FALSE;
|
||||
|
||||
g_signal_connect (popup, "event",
|
||||
G_CALLBACK (release_event_cb), &clicked);
|
||||
g_signal_connect (gesture, "released",
|
||||
G_CALLBACK (released_cb), &clicked);
|
||||
gtk_widget_add_controller (popup, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
/* Process events until clicked is set by our button release event handler.
|
||||
* We pass in may_block=TRUE since we want to wait if there
|
||||
@@ -144,6 +146,8 @@ query_for_toplevel (GdkDisplay *display,
|
||||
while (!clicked)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gdk_seat_ungrab (gdk_device_get_seat (device));
|
||||
|
||||
toplevel = find_toplevel_at_pointer (display);
|
||||
if (toplevel == popup)
|
||||
toplevel = NULL;
|
||||
|
||||
@@ -144,7 +144,7 @@ create_capital_store (void)
|
||||
{ NULL, "Jackson" },
|
||||
{ NULL, "Jefferson City" },
|
||||
{ NULL, "Juneau" },
|
||||
{ "K - O" },
|
||||
{ "K - O", NULL },
|
||||
{ NULL, "Lansing" },
|
||||
{ NULL, "Lincoln" },
|
||||
{ NULL, "Little Rock" },
|
||||
@@ -154,7 +154,7 @@ create_capital_store (void)
|
||||
{ NULL, "Nashville" },
|
||||
{ NULL, "Oklahoma City" },
|
||||
{ NULL, "Olympia" },
|
||||
{ NULL, "P - S" },
|
||||
{ "P - S", NULL },
|
||||
{ NULL, "Phoenix" },
|
||||
{ NULL, "Pierre" },
|
||||
{ NULL, "Providence" },
|
||||
|
||||
@@ -161,7 +161,6 @@
|
||||
<file>editable_cells.c</file>
|
||||
<file>entry_buffer.c</file>
|
||||
<file>entry_completion.c</file>
|
||||
<file>event_axes.c</file>
|
||||
<file>expander.c</file>
|
||||
<file>filtermodel.c</file>
|
||||
<file>fishbowl.c</file>
|
||||
@@ -169,7 +168,6 @@
|
||||
<file>foreigndrawing.c</file>
|
||||
<file>font_features.c</file>
|
||||
<file>fontplane.c</file>
|
||||
<file>fontrendering.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>headerbar.c</file>
|
||||
@@ -263,7 +261,4 @@
|
||||
<gresource prefix="/dnd">
|
||||
<file>dnd.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/fontrendering">
|
||||
<file>fontrendering.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
@@ -1,666 +0,0 @@
|
||||
/* Touch and Drawing Tablets
|
||||
*
|
||||
* Demonstrates advanced handling of event information from exotic
|
||||
* input devices.
|
||||
*
|
||||
* On one hand, this snippet demonstrates management of drawing tablets,
|
||||
* those contain additional information for the pointer other than
|
||||
* X/Y coordinates. Tablet pads events are mapped to actions, which
|
||||
* are both defined and interpreted by the application.
|
||||
*
|
||||
* Input axes are dependent on hardware devices, on linux/unix you
|
||||
* can see the device axes through xinput list <device>. Each time
|
||||
* a different hardware device is used to move the pointer, the
|
||||
* master device will be updated to match the axes it provides,
|
||||
* these changes can be tracked through GdkDevice::changed, or
|
||||
* checking gdk_event_get_source_device().
|
||||
*
|
||||
* On the other hand, this demo handles basic multitouch events,
|
||||
* each event coming from an specific touchpoint will contain a
|
||||
* GdkEventSequence that's unique for its lifetime, so multiple
|
||||
* touchpoints can be tracked.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
typedef struct {
|
||||
GdkDevice *last_source;
|
||||
GdkDeviceTool *last_tool;
|
||||
gdouble *axes;
|
||||
GdkRGBA color;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
} AxesInfo;
|
||||
|
||||
typedef struct {
|
||||
GHashTable *pointer_info; /* GdkDevice -> AxesInfo */
|
||||
GHashTable *touch_info; /* GdkEventSequence -> AxesInfo */
|
||||
} EventData;
|
||||
|
||||
const gchar *colors[] = {
|
||||
"black",
|
||||
"orchid",
|
||||
"fuchsia",
|
||||
"indigo",
|
||||
"thistle",
|
||||
"sienna",
|
||||
"azure",
|
||||
"plum",
|
||||
"lime",
|
||||
"navy",
|
||||
"maroon",
|
||||
"burlywood"
|
||||
};
|
||||
|
||||
static GtkPadActionEntry pad_actions[] = {
|
||||
{ GTK_PAD_ACTION_BUTTON, 1, -1, N_("Nuclear strike"), "pad.nuke" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 2, -1, N_("Release siberian methane reserves"), "pad.heat" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 3, -1, N_("Release solar flare"), "pad.fry" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 4, -1, N_("De-stabilize Oort cloud"), "pad.fall" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 5, -1, N_("Ignite WR-104"), "pad.burst" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 6, -1, N_("Lart whoever asks about this button"), "pad.lart" },
|
||||
{ GTK_PAD_ACTION_RING, -1, -1, N_("Earth axial tilt"), "pad.tilt" },
|
||||
{ GTK_PAD_ACTION_STRIP, -1, -1, N_("Extent of weak nuclear force"), "pad.dissolve" },
|
||||
};
|
||||
|
||||
static const gchar *pad_action_results[] = {
|
||||
"☢",
|
||||
"♨",
|
||||
"☼",
|
||||
"☄",
|
||||
"⚡",
|
||||
"💫",
|
||||
"◑",
|
||||
"⚛"
|
||||
};
|
||||
|
||||
static guint cur_color = 0;
|
||||
static guint pad_action_timeout_id = 0;
|
||||
|
||||
static AxesInfo *
|
||||
axes_info_new (void)
|
||||
{
|
||||
AxesInfo *info;
|
||||
|
||||
info = g_new0 (AxesInfo, 1);
|
||||
gdk_rgba_parse (&info->color, colors[cur_color]);
|
||||
|
||||
cur_color = (cur_color + 1) % G_N_ELEMENTS (colors);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static EventData *
|
||||
event_data_new (void)
|
||||
{
|
||||
EventData *data;
|
||||
|
||||
data = g_new0 (EventData, 1);
|
||||
data->pointer_info = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) g_free);
|
||||
data->touch_info = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) g_free);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
event_data_free (EventData *data)
|
||||
{
|
||||
g_hash_table_destroy (data->pointer_info);
|
||||
g_hash_table_destroy (data->touch_info);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
update_axes_from_event (GdkEvent *event,
|
||||
EventData *data)
|
||||
{
|
||||
GdkDevice *device, *source_device;
|
||||
GdkEventSequence *sequence;
|
||||
GdkDeviceTool *tool;
|
||||
GdkEventType type;
|
||||
gdouble x, y;
|
||||
AxesInfo *info;
|
||||
|
||||
device = gdk_event_get_device (event);
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
sequence = gdk_event_get_event_sequence (event);
|
||||
tool = gdk_event_get_device_tool (event);
|
||||
type = gdk_event_get_event_type (event);
|
||||
|
||||
if (type == GDK_TOUCH_END ||
|
||||
type == GDK_TOUCH_CANCEL)
|
||||
{
|
||||
g_hash_table_remove (data->touch_info, sequence);
|
||||
return;
|
||||
}
|
||||
else if (type == GDK_LEAVE_NOTIFY)
|
||||
{
|
||||
g_hash_table_remove (data->pointer_info, device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!source_device)
|
||||
return;
|
||||
|
||||
if (!sequence)
|
||||
{
|
||||
info = g_hash_table_lookup (data->pointer_info, device);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
info = axes_info_new ();
|
||||
g_hash_table_insert (data->pointer_info, device, info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info = g_hash_table_lookup (data->touch_info, sequence);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
info = axes_info_new ();
|
||||
g_hash_table_insert (data->touch_info, sequence, info);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->last_source != source_device)
|
||||
info->last_source = source_device;
|
||||
|
||||
if (info->last_tool != tool)
|
||||
info->last_tool = tool;
|
||||
|
||||
g_clear_pointer (&info->axes, g_free);
|
||||
|
||||
if (type == GDK_TOUCH_BEGIN ||
|
||||
type == GDK_TOUCH_UPDATE)
|
||||
{
|
||||
gboolean emulating_pointer;
|
||||
|
||||
gdk_event_get_touch_emulating_pointer (event, &emulating_pointer);
|
||||
if (sequence && emulating_pointer)
|
||||
g_hash_table_remove (data->pointer_info, device);
|
||||
}
|
||||
if (type == GDK_MOTION_NOTIFY ||
|
||||
type == GDK_BUTTON_PRESS ||
|
||||
type == GDK_BUTTON_RELEASE)
|
||||
{
|
||||
gdouble *axes;
|
||||
guint n_axes;
|
||||
|
||||
gdk_event_get_axes (event, &axes, &n_axes);
|
||||
info->axes = g_memdup (axes, sizeof (double) * n_axes);
|
||||
}
|
||||
|
||||
if (gdk_event_get_coords (event, &x, &y))
|
||||
{
|
||||
info->x = x;
|
||||
info->y = y;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_cb (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
update_axes_from_event (event, user_data);
|
||||
gtk_widget_queue_draw (widget);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
render_arrow (cairo_t *cr,
|
||||
gdouble x_diff,
|
||||
gdouble y_diff,
|
||||
const gchar *label)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_new_path (cr);
|
||||
cairo_move_to (cr, 0, 0);
|
||||
cairo_line_to (cr, x_diff, y_diff);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_move_to (cr, x_diff, y_diff);
|
||||
cairo_show_text (cr, label);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_axes_info (cairo_t *cr,
|
||||
AxesInfo *info,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
gdouble pressure, tilt_x, tilt_y, distance, wheel, rotation, slider;
|
||||
GdkAxisFlags axes = gdk_device_get_axes (info->last_source);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_set_line_width (cr, 1);
|
||||
gdk_cairo_set_source_rgba (cr, &info->color);
|
||||
|
||||
cairo_move_to (cr, 0, info->y);
|
||||
cairo_line_to (cr, width, info->y);
|
||||
cairo_move_to (cr, info->x, 0);
|
||||
cairo_line_to (cr, info->x, height);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_translate (cr, info->x, info->y);
|
||||
|
||||
if (!info->axes)
|
||||
{
|
||||
cairo_restore (cr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_PRESSURE)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_PRESSURE,
|
||||
&pressure);
|
||||
|
||||
pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, 100);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, pressure, 1, 0, 0, pressure);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 1, 0);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
|
||||
cairo_arc (cr, 0, 0, 100, 0, 2 * G_PI);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_XTILT &&
|
||||
axes & GDK_AXIS_FLAG_YTILT)
|
||||
{
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_XTILT,
|
||||
&tilt_x);
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_YTILT,
|
||||
&tilt_y);
|
||||
|
||||
render_arrow (cr, tilt_x * 100, tilt_y * 100, "Tilt");
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_DISTANCE)
|
||||
{
|
||||
double dashes[] = { 5.0, 5.0 };
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_DISTANCE,
|
||||
&distance);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_move_to (cr, distance * 100, 0);
|
||||
|
||||
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
|
||||
cairo_set_dash (cr, dashes, 2, 0.0);
|
||||
cairo_arc (cr, 0, 0, distance * 100, 0, 2 * G_PI);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_move_to (cr, 0, -distance * 100);
|
||||
cairo_text_extents (cr, "Distance", &extents);
|
||||
cairo_rel_move_to (cr, -extents.width / 2, 0);
|
||||
cairo_show_text (cr, "Distance");
|
||||
|
||||
cairo_move_to (cr, 0, 0);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_WHEEL)
|
||||
{
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_WHEEL,
|
||||
&wheel);
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 10);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, 0, 0, 100, 0, wheel * 2 * G_PI);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_ROTATION)
|
||||
{
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_ROTATION,
|
||||
&rotation);
|
||||
rotation *= 2 * G_PI;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_rotate (cr, - G_PI / 2);
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_width (cr, 5);
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, 0, 0, 100, 0, rotation);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
if (axes & GDK_AXIS_FLAG_SLIDER)
|
||||
{
|
||||
cairo_pattern_t *pattern, *mask;
|
||||
|
||||
gdk_device_get_axis (info->last_source, info->axes, GDK_AXIS_SLIDER,
|
||||
&slider);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_move_to (cr, 0, -10);
|
||||
cairo_rel_line_to (cr, 0, -50);
|
||||
cairo_rel_line_to (cr, 10, 0);
|
||||
cairo_rel_line_to (cr, -5, 50);
|
||||
cairo_close_path (cr);
|
||||
|
||||
cairo_clip_preserve (cr);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, -10, 0, -60);
|
||||
cairo_pattern_add_color_stop_rgb (pattern, 0, 0, 1, 0);
|
||||
cairo_pattern_add_color_stop_rgb (pattern, 1, 1, 0, 0);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
mask = cairo_pattern_create_linear (0, -10, 0, -60);
|
||||
cairo_pattern_add_color_stop_rgba (mask, 0, 0, 0, 0, 1);
|
||||
cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 1);
|
||||
cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 0);
|
||||
cairo_pattern_add_color_stop_rgba (mask, 1, 0, 0, 0, 0);
|
||||
cairo_mask (cr, mask);
|
||||
cairo_pattern_destroy (mask);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
tool_type_to_string (GdkDeviceToolType tool_type)
|
||||
{
|
||||
switch (tool_type)
|
||||
{
|
||||
case GDK_DEVICE_TOOL_TYPE_PEN:
|
||||
return "Pen";
|
||||
case GDK_DEVICE_TOOL_TYPE_ERASER:
|
||||
return "Eraser";
|
||||
case GDK_DEVICE_TOOL_TYPE_BRUSH:
|
||||
return "Brush";
|
||||
case GDK_DEVICE_TOOL_TYPE_PENCIL:
|
||||
return "Pencil";
|
||||
case GDK_DEVICE_TOOL_TYPE_AIRBRUSH:
|
||||
return "Airbrush";
|
||||
case GDK_DEVICE_TOOL_TYPE_MOUSE:
|
||||
return "Mouse";
|
||||
case GDK_DEVICE_TOOL_TYPE_LENS:
|
||||
return "Lens cursor";
|
||||
case GDK_DEVICE_TOOL_TYPE_UNKNOWN:
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_device_info (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
GdkEventSequence *sequence,
|
||||
gint *y,
|
||||
AxesInfo *info)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
GString *string;
|
||||
gint height;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
string = g_string_new (NULL);
|
||||
g_string_append_printf (string, "Source: %s",
|
||||
gdk_device_get_name (info->last_source));
|
||||
|
||||
if (sequence)
|
||||
g_string_append_printf (string, "\nSequence: %d",
|
||||
GPOINTER_TO_UINT (sequence));
|
||||
|
||||
if (info->last_tool)
|
||||
{
|
||||
const gchar *tool_type;
|
||||
guint64 serial;
|
||||
|
||||
tool_type = tool_type_to_string (gdk_device_tool_get_tool_type (info->last_tool));
|
||||
serial = gdk_device_tool_get_serial (info->last_tool);
|
||||
g_string_append_printf (string, "\nTool: %s", tool_type);
|
||||
|
||||
if (serial != 0)
|
||||
g_string_append_printf (string, ", Serial: %" G_GINT64_MODIFIER "x", serial);
|
||||
}
|
||||
|
||||
cairo_move_to (cr, 10, *y);
|
||||
layout = gtk_widget_create_pango_layout (widget, string->str);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
cairo_stroke (cr);
|
||||
|
||||
pango_layout_get_pixel_size (layout, NULL, &height);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &info->color);
|
||||
cairo_set_line_width (cr, 10);
|
||||
cairo_move_to (cr, 0, *y);
|
||||
|
||||
*y = *y + height;
|
||||
cairo_line_to (cr, 0, *y);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
g_object_unref (layout);
|
||||
g_string_free (string, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cb (GtkDrawingArea *da,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (da);
|
||||
EventData *data = user_data;
|
||||
AxesInfo *info;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
gint y = 0;
|
||||
|
||||
/* Draw Abs info */
|
||||
g_hash_table_iter_init (&iter, data->pointer_info);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
{
|
||||
info = value;
|
||||
draw_axes_info (cr, info, width, height);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, data->touch_info);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
{
|
||||
info = value;
|
||||
draw_axes_info (cr, info, width, height);
|
||||
}
|
||||
|
||||
/* Draw name, color legend and misc data */
|
||||
g_hash_table_iter_init (&iter, data->pointer_info);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
{
|
||||
info = value;
|
||||
draw_device_info (widget, cr, NULL, &y, info);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, data->touch_info);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
info = value;
|
||||
draw_device_info (widget, cr, key, &y, info);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_label_text (GtkWidget *label,
|
||||
const gchar *text)
|
||||
{
|
||||
gchar *markup = NULL;
|
||||
|
||||
if (text)
|
||||
markup = g_strdup_printf ("<span font='48.0'>%s</span>", text);
|
||||
gtk_label_set_markup (GTK_LABEL (label), markup);
|
||||
g_free (markup);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
reset_label_text_timeout_cb (gpointer user_data)
|
||||
{
|
||||
GtkWidget *label = user_data;
|
||||
|
||||
update_label_text (label, NULL);
|
||||
pad_action_timeout_id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
update_label_and_timeout (GtkWidget *label,
|
||||
const gchar *text)
|
||||
{
|
||||
if (pad_action_timeout_id)
|
||||
g_source_remove (pad_action_timeout_id);
|
||||
|
||||
update_label_text (label, text);
|
||||
pad_action_timeout_id = g_timeout_add (200, reset_label_text_timeout_cb, label);
|
||||
}
|
||||
|
||||
static void
|
||||
on_action_activate (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *label = user_data;
|
||||
const gchar *result;
|
||||
gchar *str;
|
||||
|
||||
result = g_object_get_data (G_OBJECT (action), "action-result");
|
||||
|
||||
if (!parameter)
|
||||
update_label_and_timeout (label, result);
|
||||
else
|
||||
{
|
||||
str = g_strdup_printf ("%s %.2f", result, g_variant_get_double (parameter));
|
||||
update_label_and_timeout (label, str);
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_pad_controller (GtkWidget *window,
|
||||
GtkWidget *label)
|
||||
{
|
||||
GtkPadController *pad_controller;
|
||||
GSimpleActionGroup *action_group;
|
||||
GSimpleAction *action;
|
||||
gint i;
|
||||
|
||||
action_group = g_simple_action_group_new ();
|
||||
pad_controller = gtk_pad_controller_new (G_ACTION_GROUP (action_group),
|
||||
NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (pad_actions); i++)
|
||||
{
|
||||
if (pad_actions[i].type == GTK_PAD_ACTION_BUTTON)
|
||||
{
|
||||
action = g_simple_action_new (pad_actions[i].action_name, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
action = g_simple_action_new_stateful (pad_actions[i].action_name,
|
||||
G_VARIANT_TYPE_DOUBLE, NULL);
|
||||
}
|
||||
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (on_action_activate), label);
|
||||
g_object_set_data (G_OBJECT (action), "action-result",
|
||||
(gpointer) pad_action_results[i]);
|
||||
g_action_map_add_action (G_ACTION_MAP (action_group), G_ACTION (action));
|
||||
g_object_unref (action);
|
||||
}
|
||||
|
||||
gtk_pad_controller_set_action_entries (pad_controller, pad_actions,
|
||||
G_N_ELEMENTS (pad_actions));
|
||||
gtk_widget_add_controller (window, GTK_EVENT_CONTROLLER (pad_controller));
|
||||
|
||||
g_object_unref (action_group);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_event_axes (GtkWidget *toplevel)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
EventData *event_data;
|
||||
GtkWidget *label;
|
||||
GtkWidget *overlay;
|
||||
GtkWidget *da;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Touch and Drawing Tablets");
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
gtk_widget_set_support_multidevice (window, TRUE);
|
||||
|
||||
event_data = event_data_new ();
|
||||
g_object_set_data_full (G_OBJECT (window), "gtk-demo-event-data",
|
||||
event_data, (GDestroyNotify) event_data_free);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 400);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 400);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_cb, event_data, NULL);
|
||||
gtk_widget_set_can_focus (da, TRUE);
|
||||
gtk_widget_grab_focus (da);
|
||||
|
||||
g_signal_connect (da, "event",
|
||||
G_CALLBACK (event_cb), event_data);
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_START);
|
||||
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
|
||||
|
||||
overlay = gtk_overlay_new ();
|
||||
gtk_container_add (GTK_CONTAINER (window), overlay);
|
||||
gtk_container_add (GTK_CONTAINER (overlay), da);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), label);
|
||||
|
||||
init_pad_controller (da, label);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -134,7 +134,9 @@ static GtkWidget *
|
||||
create_video (void)
|
||||
{
|
||||
GtkMediaStream *stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
|
||||
GtkWidget *w = gtk_image_new_from_paintable (GDK_PAINTABLE (stream));
|
||||
GtkWidget *w = gtk_picture_new_for_paintable (GDK_PAINTABLE (stream));
|
||||
|
||||
gtk_widget_set_size_request (w, 64, 64);
|
||||
gtk_media_stream_set_loop (stream, TRUE);
|
||||
gtk_media_stream_play (stream);
|
||||
g_object_unref (stream);
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
/* Pango/Font Rendering
|
||||
*
|
||||
* Demonstrates variations in font rendering.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *font_button = NULL;
|
||||
static GtkWidget *entry = NULL;
|
||||
static GtkWidget *image = NULL;
|
||||
static GtkWidget *hinting = NULL;
|
||||
static GtkWidget *hint_metrics = NULL;
|
||||
static GtkWidget *up_button = NULL;
|
||||
static GtkWidget *down_button = NULL;
|
||||
static GtkWidget *text_radio = NULL;
|
||||
|
||||
static PangoContext *context;
|
||||
|
||||
static int scale = 10;
|
||||
|
||||
static void
|
||||
on_destroy (gpointer data)
|
||||
{
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
update_image (void)
|
||||
{
|
||||
const char *text;
|
||||
PangoFontDescription *desc;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle ink, logical;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *pixbuf2;
|
||||
const char *hint;
|
||||
cairo_font_options_t *fopt;
|
||||
cairo_hint_style_t hintstyle;
|
||||
cairo_hint_metrics_t hintmetrics;
|
||||
|
||||
if (!context)
|
||||
context = gtk_widget_create_pango_context (image);
|
||||
|
||||
text = gtk_entry_get_text (GTK_ENTRY (entry));
|
||||
desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (font_button));
|
||||
|
||||
fopt = cairo_font_options_copy (pango_cairo_context_get_font_options (context));
|
||||
|
||||
hint = gtk_combo_box_get_active_id (GTK_COMBO_BOX (hinting));
|
||||
if (strcmp (hint, "none") == 0)
|
||||
hintstyle = CAIRO_HINT_STYLE_NONE;
|
||||
else if (strcmp (hint, "slight") == 0)
|
||||
hintstyle = CAIRO_HINT_STYLE_SLIGHT;
|
||||
else if (strcmp (hint, "medium") == 0)
|
||||
hintstyle = CAIRO_HINT_STYLE_MEDIUM;
|
||||
else if (strcmp (hint, "full") == 0)
|
||||
hintstyle = CAIRO_HINT_STYLE_FULL;
|
||||
else
|
||||
hintstyle = CAIRO_HINT_STYLE_DEFAULT;
|
||||
cairo_font_options_set_hint_style (fopt, hintstyle);
|
||||
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (hint_metrics)))
|
||||
hintmetrics = CAIRO_HINT_METRICS_ON;
|
||||
else
|
||||
hintmetrics = CAIRO_HINT_METRICS_OFF;
|
||||
cairo_font_options_set_hint_metrics (fopt, hintmetrics);
|
||||
|
||||
pango_cairo_context_set_font_options (context, fopt);
|
||||
cairo_font_options_destroy (fopt);
|
||||
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (text_radio)))
|
||||
{
|
||||
layout = pango_layout_new (context);
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_layout_set_text (layout, text, -1);
|
||||
pango_layout_get_extents (layout, &ink, &logical);
|
||||
|
||||
pango_extents_to_pixels (&logical, NULL);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
MAX(1,logical.width),
|
||||
MAX(1,logical.height));
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
cairo_destroy (cr);
|
||||
g_object_unref (layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
PangoLayoutIter *iter;
|
||||
PangoGlyphItem *run;
|
||||
PangoGlyphInfo *g;
|
||||
int i, j;
|
||||
|
||||
layout = pango_layout_new (context);
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_layout_set_text (layout, "aaaa", -1);
|
||||
pango_layout_get_extents (layout, &ink, &logical);
|
||||
pango_extents_to_pixels (&logical, NULL);
|
||||
|
||||
iter = pango_layout_get_iter (layout);
|
||||
run = pango_layout_iter_get_run (iter);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
MAX(1, logical.width) * 3 / 2,
|
||||
MAX(1, logical.height) * 4);
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g = &(run->glyphs->glyphs[i]);
|
||||
g->geometry.width = PANGO_UNITS_ROUND (g->geometry.width * 3 / 2);
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g = &(run->glyphs->glyphs[i]);
|
||||
g->geometry.x_offset = i * (PANGO_SCALE / 4);
|
||||
g->geometry.y_offset = j * (PANGO_SCALE / 4);
|
||||
}
|
||||
|
||||
cairo_move_to (cr, 0, j * logical.height);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
pango_layout_iter_free (iter);
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface));
|
||||
pixbuf2 = gdk_pixbuf_scale_simple (pixbuf, gdk_pixbuf_get_width (pixbuf) * scale, gdk_pixbuf_get_height (pixbuf) * scale, GDK_INTERP_NEAREST);
|
||||
|
||||
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
g_object_unref (pixbuf2);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
|
||||
static void
|
||||
update_buttons (void)
|
||||
{
|
||||
gtk_widget_set_sensitive (up_button, scale < 32);
|
||||
gtk_widget_set_sensitive (down_button, scale > 1);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_up (void)
|
||||
{
|
||||
scale += 1;
|
||||
update_buttons ();
|
||||
update_image ();
|
||||
}
|
||||
|
||||
static void
|
||||
scale_down (void)
|
||||
{
|
||||
scale -= 1;
|
||||
update_buttons ();
|
||||
update_image ();
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_fontrendering (GtkWidget *do_widget)
|
||||
{
|
||||
if (!window)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/fontrendering/fontrendering.ui");
|
||||
gtk_builder_connect_signals (builder, NULL);
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (on_destroy), NULL);
|
||||
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
|
||||
font_button = GTK_WIDGET (gtk_builder_get_object (builder, "font_button"));
|
||||
up_button = GTK_WIDGET (gtk_builder_get_object (builder, "up_button"));
|
||||
down_button = GTK_WIDGET (gtk_builder_get_object (builder, "down_button"));
|
||||
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
|
||||
image = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
|
||||
hinting = GTK_WIDGET (gtk_builder_get_object (builder, "hinting"));
|
||||
hint_metrics = GTK_WIDGET (gtk_builder_get_object (builder, "hint_metrics"));
|
||||
text_radio = GTK_WIDGET (gtk_builder_get_object (builder, "text_radio"));
|
||||
|
||||
g_signal_connect (up_button, "clicked", G_CALLBACK (scale_up), NULL);
|
||||
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
|
||||
update_image ();
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
{
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.94 -->
|
||||
<object class="GtkAdjustment" id="scale_adj">
|
||||
<property name="lower">0</property>
|
||||
<property name="value">0</property>
|
||||
<property name="upper">24</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">4</property>
|
||||
<property name="page-size">0</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="default-width">600</property>
|
||||
<property name="default-height">300</property>
|
||||
<property name="title">Font rendering</property>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="margin-top">10</property>
|
||||
<property name="row-spacing">10</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="label">Text</property>
|
||||
<property name="xalign">1</property>
|
||||
<style><class name="dim-label"/></style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry">
|
||||
<property name="text">Fonts render</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="label">Font</property>
|
||||
<property name="xalign">1</property>
|
||||
<style><class name="dim-label"/></style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFontButton" id="font_button">
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Hinting</property>
|
||||
<property name="xalign">1</property>
|
||||
<style><class name="dim-label"/></style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="hinting">
|
||||
<property name="active">0</property>
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item translatable="yes" id="none">None</item>
|
||||
<item translatable="yes" id="slight">Slight</item>
|
||||
<item translatable="yes" id="medium">Medium</item>
|
||||
<item translatable="yes" id="full">Full</item>
|
||||
</items>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">3</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="hint_metrics">
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Hint Metrics</property>
|
||||
<style><class name="dim-label"/></style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">3</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="up_button">
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<style><class name="circular"/></style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">4</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="down_button">
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<style><class name="circular"/></style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">4</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label"></property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">6</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<style><class name="linked"/></style>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="text_radio">
|
||||
<property name="draw-indicator">0</property>
|
||||
<property name="label">Text</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="grid_radio">
|
||||
<property name="draw-indicator">0</property>
|
||||
<property name="label">Grid</property>
|
||||
<property name="group">text_radio</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="width">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">automatic</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<property name="propagate-natural-height">1</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkPicture" id="image">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="keep-aspect-ratio">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">4</property>
|
||||
<property name="width">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -128,9 +128,10 @@ gtk_fishbowl_measure (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fishbowl_size_allocate (GtkWidget *widget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline)
|
||||
gtk_fishbowl_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
|
||||
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
|
||||
@@ -147,8 +148,8 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
|
||||
continue;
|
||||
|
||||
gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
|
||||
child_allocation.x = allocation->x + round (child->x * (allocation->width - child_requisition.width));
|
||||
child_allocation.y = allocation->y + round (child->y * (allocation->height - child_requisition.height));
|
||||
child_allocation.x = round (child->x * (width - child_requisition.width));
|
||||
child_allocation.y = round (child->y * (height - child_requisition.height));
|
||||
child_allocation.width = child_requisition.width;
|
||||
child_allocation.height = child_requisition.height;
|
||||
|
||||
|
||||
+29
-34
@@ -135,55 +135,42 @@ static void set_cursor_if_appropriate (GtkTextView *text_view,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
/* Links can also be activated by clicking or tapping.
|
||||
*/
|
||||
static gboolean
|
||||
event_cb (GtkWidget *text_view,
|
||||
GdkEvent *ev)
|
||||
static void
|
||||
released_cb (GtkGestureMultiPress *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkWidget *text_view)
|
||||
{
|
||||
GtkTextIter start, end, iter;
|
||||
GtkTextBuffer *buffer;
|
||||
gdouble ex, ey;
|
||||
int x, y;
|
||||
GdkEventType type;
|
||||
int tx, ty;
|
||||
|
||||
type = gdk_event_get_event_type (ev);
|
||||
if (gtk_gesture_single_get_button (GTK_GESTURE_SINGLE (gesture)) > 1)
|
||||
return;
|
||||
|
||||
gdk_event_get_coords (ev, &ex, &ey);
|
||||
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
|
||||
GTK_TEXT_WINDOW_WIDGET,
|
||||
ex, ey, &x, &y);
|
||||
|
||||
if (type == GDK_BUTTON_RELEASE)
|
||||
{
|
||||
guint button;
|
||||
|
||||
gdk_event_get_button (ev, &button);
|
||||
if (button != GDK_BUTTON_PRIMARY)
|
||||
return FALSE;
|
||||
}
|
||||
else if (type == GDK_MOTION_NOTIFY)
|
||||
{
|
||||
set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y);
|
||||
return FALSE;
|
||||
}
|
||||
else if (type == GDK_TOUCH_END)
|
||||
{
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
x, y, &tx, &ty);
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
|
||||
|
||||
/* we shouldn't follow a link if the user has selected something */
|
||||
gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
|
||||
if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
|
||||
return FALSE;
|
||||
return;
|
||||
|
||||
if (gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y))
|
||||
follow_if_link (text_view, &iter);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
static void
|
||||
motion_cb (GtkEventControllerMotion *controller,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkTextView *text_view)
|
||||
{
|
||||
set_cursor_if_appropriate (text_view, x, y);
|
||||
}
|
||||
|
||||
static gboolean hovering_over_link = FALSE;
|
||||
@@ -259,8 +246,16 @@ do_hypertext (GtkWidget *do_widget)
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed), view);
|
||||
gtk_widget_add_controller (view, controller);
|
||||
g_signal_connect (view, "event",
|
||||
G_CALLBACK (event_cb), NULL);
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_gesture_multi_press_new ());
|
||||
g_signal_connect (controller, "released",
|
||||
G_CALLBACK (released_cb), view);
|
||||
gtk_widget_add_controller (view, controller);
|
||||
|
||||
controller = gtk_event_controller_motion_new ();
|
||||
g_signal_connect (controller, "motion",
|
||||
G_CALLBACK (motion_cb), view);
|
||||
gtk_widget_add_controller (view, controller);
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
|
||||
|
||||
@@ -831,15 +831,14 @@ load_file (const gchar *demoname,
|
||||
/* Skipping blank lines */
|
||||
while (g_ascii_isspace (*p))
|
||||
p++;
|
||||
if (*p)
|
||||
{
|
||||
p = lines[i];
|
||||
state++;
|
||||
/* Fall through */
|
||||
}
|
||||
else
|
||||
|
||||
if (!*p)
|
||||
break;
|
||||
|
||||
p = lines[i];
|
||||
state++;
|
||||
/* Fall through */
|
||||
|
||||
case 3:
|
||||
/* Reading program body */
|
||||
gtk_text_buffer_insert (source_buffer, &start, p, -1);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkApplicationWindow" id="window">
|
||||
<style><class name="devel"/></style>
|
||||
<property name="default-width">800</property>
|
||||
<property name="default-height">600</property>
|
||||
<property name="title">GTK+ Demo</property>
|
||||
|
||||
@@ -22,11 +22,9 @@ demos = files([
|
||||
'editable_cells.c',
|
||||
'entry_buffer.c',
|
||||
'entry_completion.c',
|
||||
'event_axes.c',
|
||||
'expander.c',
|
||||
'filtermodel.c',
|
||||
'fishbowl.c',
|
||||
'fontrendering.c',
|
||||
'foreigndrawing.c',
|
||||
'gestures.c',
|
||||
'glarea.c',
|
||||
@@ -131,7 +129,7 @@ foreach icon_size: [ '16x16', '22x22', '24x24', '32x32', '48x48', '256x256', ]
|
||||
endforeach
|
||||
|
||||
# desktop file
|
||||
install_data('gtk4-demo.desktop', install_dir: gtk_applicationsdir)
|
||||
install_data('org.gtk.Demo.desktop', install_dir: gtk_applicationsdir)
|
||||
|
||||
# GSettings
|
||||
install_data('org.gtk.Demo.gschema.xml', install_dir: gtk_schemasdir)
|
||||
|
||||
+139
-10
@@ -3,14 +3,24 @@
|
||||
* Demonstrates practical handling of drawing tablets in a real world
|
||||
* usecase.
|
||||
*/
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
enum {
|
||||
COLOR_SET,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint area_signals[N_SIGNALS] = { 0, };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
GdkRGBA draw_color;
|
||||
GtkPadController *pad_controller;
|
||||
gdouble brush_size;
|
||||
} DrawingArea;
|
||||
|
||||
typedef struct
|
||||
@@ -18,8 +28,30 @@ typedef struct
|
||||
GtkWidgetClass parent_class;
|
||||
} DrawingAreaClass;
|
||||
|
||||
static GtkPadActionEntry pad_actions[] = {
|
||||
{ GTK_PAD_ACTION_BUTTON, 1, -1, N_("Black"), "pad.black" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 2, -1, N_("Pink"), "pad.pink" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 3, -1, N_("Green"), "pad.green" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 4, -1, N_("Red"), "pad.red" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 5, -1, N_("Purple"), "pad.purple" },
|
||||
{ GTK_PAD_ACTION_BUTTON, 6, -1, N_("Orange"), "pad.orange" },
|
||||
{ GTK_PAD_ACTION_STRIP, -1, -1, N_("Brush size"), "pad.brush_size" },
|
||||
};
|
||||
|
||||
static const gchar *pad_colors[] = {
|
||||
"black",
|
||||
"pink",
|
||||
"green",
|
||||
"red",
|
||||
"purple",
|
||||
"orange"
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (DrawingArea, drawing_area, GTK_TYPE_WIDGET)
|
||||
|
||||
static void drawing_area_set_color (DrawingArea *area,
|
||||
GdkRGBA *color);
|
||||
|
||||
static void
|
||||
drawing_area_ensure_surface (DrawingArea *area,
|
||||
gint width,
|
||||
@@ -52,15 +84,16 @@ drawing_area_ensure_surface (DrawingArea *area,
|
||||
}
|
||||
|
||||
static void
|
||||
drawing_area_size_allocate (GtkWidget *widget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline)
|
||||
drawing_area_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
DrawingArea *area = (DrawingArea *) widget;
|
||||
|
||||
drawing_area_ensure_surface (area, allocation->width, allocation->height);
|
||||
drawing_area_ensure_surface (area, width, height);
|
||||
|
||||
GTK_WIDGET_CLASS (drawing_area_parent_class)->size_allocate (widget, allocation, baseline);
|
||||
GTK_WIDGET_CLASS (drawing_area_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -115,6 +148,82 @@ drawing_area_snapshot (GtkWidget *widget,
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
on_pad_button_activate (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
DrawingArea *area)
|
||||
{
|
||||
const gchar *color = g_object_get_data (G_OBJECT (action), "color");
|
||||
GdkRGBA rgba;
|
||||
|
||||
gdk_rgba_parse (&rgba, color);
|
||||
drawing_area_set_color (area, &rgba);
|
||||
}
|
||||
|
||||
static void
|
||||
on_pad_knob_change (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
DrawingArea *area)
|
||||
{
|
||||
gdouble value = g_variant_get_double (parameter);
|
||||
|
||||
area->brush_size = value;
|
||||
}
|
||||
|
||||
static void
|
||||
drawing_area_hierarchy_changed (GtkWidget *widget,
|
||||
GtkWidget *previous_toplevel)
|
||||
{
|
||||
DrawingArea *area = (DrawingArea *) widget;
|
||||
GSimpleActionGroup *action_group;
|
||||
GSimpleAction *action;
|
||||
GtkWidget *toplevel;
|
||||
gint i;
|
||||
|
||||
if (previous_toplevel && area->pad_controller)
|
||||
{
|
||||
gtk_widget_remove_controller (previous_toplevel,
|
||||
GTK_EVENT_CONTROLLER (area->pad_controller));
|
||||
area->pad_controller = NULL;
|
||||
}
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (area));
|
||||
if (!GTK_IS_WINDOW (toplevel))
|
||||
return;
|
||||
|
||||
action_group = g_simple_action_group_new ();
|
||||
area->pad_controller = gtk_pad_controller_new (G_ACTION_GROUP (action_group),
|
||||
NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (pad_actions); i++)
|
||||
{
|
||||
if (pad_actions[i].type == GTK_PAD_ACTION_BUTTON)
|
||||
{
|
||||
action = g_simple_action_new (pad_actions[i].action_name, NULL);
|
||||
g_object_set_data (G_OBJECT (action), "color",
|
||||
(gpointer) pad_colors[i]);
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (on_pad_button_activate), area);
|
||||
}
|
||||
else
|
||||
{
|
||||
action = g_simple_action_new_stateful (pad_actions[i].action_name,
|
||||
G_VARIANT_TYPE_DOUBLE, NULL);
|
||||
g_signal_connect (action, "activate",
|
||||
G_CALLBACK (on_pad_knob_change), area);
|
||||
}
|
||||
|
||||
g_action_map_add_action (G_ACTION_MAP (action_group), G_ACTION (action));
|
||||
g_object_unref (action);
|
||||
}
|
||||
|
||||
gtk_pad_controller_set_action_entries (area->pad_controller, pad_actions,
|
||||
G_N_ELEMENTS (pad_actions));
|
||||
|
||||
gtk_widget_add_controller (toplevel,
|
||||
GTK_EVENT_CONTROLLER (area->pad_controller));
|
||||
}
|
||||
|
||||
static void
|
||||
drawing_area_class_init (DrawingAreaClass *klass)
|
||||
{
|
||||
@@ -124,6 +233,14 @@ drawing_area_class_init (DrawingAreaClass *klass)
|
||||
widget_class->snapshot = drawing_area_snapshot;
|
||||
widget_class->map = drawing_area_map;
|
||||
widget_class->unmap = drawing_area_unmap;
|
||||
widget_class->hierarchy_changed = drawing_area_hierarchy_changed;
|
||||
|
||||
area_signals[COLOR_SET] =
|
||||
g_signal_new ("color-set",
|
||||
G_TYPE_FROM_CLASS (widget_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, GDK_TYPE_RGBA);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -135,12 +252,12 @@ drawing_area_apply_stroke (DrawingArea *area,
|
||||
{
|
||||
if (gdk_device_tool_get_tool_type (tool) == GDK_DEVICE_TOOL_TYPE_ERASER)
|
||||
{
|
||||
cairo_set_line_width (area->cr, 10 * pressure);
|
||||
cairo_set_line_width (area->cr, 10 * pressure * area->brush_size);
|
||||
cairo_set_operator (area->cr, CAIRO_OPERATOR_DEST_OUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_line_width (area->cr, 4 * pressure);
|
||||
cairo_set_line_width (area->cr, 4 * pressure * area->brush_size);
|
||||
cairo_set_operator (area->cr, CAIRO_OPERATOR_SATURATE);
|
||||
}
|
||||
|
||||
@@ -148,8 +265,6 @@ drawing_area_apply_stroke (DrawingArea *area,
|
||||
area->draw_color.green, area->draw_color.blue,
|
||||
area->draw_color.alpha * pressure);
|
||||
|
||||
//cairo_set_source_rgba (area->cr, 0, 0, 0, pressure);
|
||||
|
||||
cairo_line_to (area->cr, x, y);
|
||||
cairo_stroke (area->cr);
|
||||
cairo_move_to (area->cr, x, y);
|
||||
@@ -225,11 +340,15 @@ drawing_area_new (void)
|
||||
return g_object_new (drawing_area_get_type (), NULL);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
drawing_area_set_color (DrawingArea *area,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
if (gdk_rgba_equal (&area->draw_color, color))
|
||||
return;
|
||||
|
||||
area->draw_color = *color;
|
||||
g_signal_emit (area, area_signals[COLOR_SET], 0, &area->draw_color);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -242,6 +361,14 @@ color_button_color_set (GtkColorButton *button,
|
||||
drawing_area_set_color (draw_area, &color);
|
||||
}
|
||||
|
||||
static void
|
||||
drawing_area_color_set (DrawingArea *area,
|
||||
GdkRGBA *color,
|
||||
GtkColorButton *button)
|
||||
{
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button), color);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_paint (GtkWidget *toplevel)
|
||||
{
|
||||
@@ -263,6 +390,8 @@ do_paint (GtkWidget *toplevel)
|
||||
colorbutton = gtk_color_button_new ();
|
||||
g_signal_connect (colorbutton, "color-set",
|
||||
G_CALLBACK (color_button_color_set), draw_area);
|
||||
g_signal_connect (draw_area, "color-set",
|
||||
G_CALLBACK (drawing_area_color_set), colorbutton);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (colorbutton),
|
||||
&(GdkRGBA) { 0, 0, 0, 1 });
|
||||
|
||||
|
||||
@@ -55,10 +55,11 @@ create_complex_popover (GtkWidget *parent,
|
||||
}
|
||||
|
||||
static void
|
||||
entry_size_allocate_cb (GtkEntry *entry,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline,
|
||||
gpointer user_data)
|
||||
entry_size_allocate_cb (GtkEntry *entry,
|
||||
int width,
|
||||
int height,
|
||||
int baseline,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkEntryIconPosition popover_pos;
|
||||
GtkPopover *popover = user_data;
|
||||
|
||||
@@ -26,17 +26,6 @@ changed_cb (GtkEditable *editable)
|
||||
g_message ("changed: %s", text);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_event_cb (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkSearchBar *bar)
|
||||
{
|
||||
if (gdk_event_get_event_type (event) == GDK_KEY_PRESS)
|
||||
return gtk_search_bar_handle_event (bar, event);
|
||||
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
static void
|
||||
search_changed (GtkSearchEntry *entry,
|
||||
GtkLabel *label)
|
||||
@@ -102,7 +91,7 @@ do_search_entry2 (GtkWidget *do_widget)
|
||||
gtk_box_pack_start (GTK_BOX (vbox), searchbar);
|
||||
|
||||
/* Hook the search bar to key presses */
|
||||
g_signal_connect (window, "event", G_CALLBACK (window_event_cb), searchbar);
|
||||
gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (searchbar), window);
|
||||
|
||||
/* Help */
|
||||
label = gtk_label_new ("Start Typing to search");
|
||||
|
||||
@@ -12,12 +12,10 @@ do_transparent (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *sw;
|
||||
GtkWidget *overlay;
|
||||
GtkWidget *button;
|
||||
GtkWidget *label;
|
||||
GtkWidget *box;
|
||||
GtkWidget *image;
|
||||
GtkWidget *picture;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
@@ -54,17 +52,8 @@ do_transparent (GtkWidget *do_widget)
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
|
||||
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (overlay), sw);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (sw), box);
|
||||
image = gtk_image_new_from_resource ("/transparent/portland-rose.jpg");
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (box), image);
|
||||
picture = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
|
||||
gtk_container_add (GTK_CONTAINER (overlay), picture);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -17,4 +17,4 @@ executable('gtk4-icon-browser',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true)
|
||||
|
||||
install_data('gtk4-icon-browser.desktop', install_dir: gtk_applicationsdir)
|
||||
install_data('org.gtk.IconBrowser.desktop', install_dir: gtk_applicationsdir)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<property name="child-model">store</property>
|
||||
</object>
|
||||
<template class="IconBrowserWindow" parent="GtkApplicationWindow">
|
||||
<style><class name="devel"/></style>
|
||||
<property name="title" translatable="yes">Icon Browser</property>
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<menu id="app-menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">About</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
<attribute name="accel"><Primary>q</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
@@ -13,7 +13,7 @@ executable('gtk4-widget-factory',
|
||||
install: true)
|
||||
|
||||
# desktop file
|
||||
install_data('gtk4-widget-factory.desktop', install_dir: gtk_applicationsdir)
|
||||
install_data('org.gtk.WidgetFactory.desktop', install_dir: gtk_applicationsdir)
|
||||
|
||||
# icons
|
||||
icontheme_dir = join_paths(gtk_datadir, 'icons/hicolor')
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
<gresource prefix="/org/gtk/WidgetFactory">
|
||||
<file>widget-factory.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/WidgetFactory/gtk">
|
||||
<file preprocess="xml-stripblanks">menus.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/WidgetFactory/gtk">
|
||||
<file preprocess="xml-stripblanks">help-overlay.ui</file>
|
||||
</gresource>
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
<attribute name="action">win.transition</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
|
||||
<attribute name="action">win.show-help-overlay</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About Widget Factory</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
<menu id="dinner_menu">
|
||||
<section>
|
||||
@@ -396,6 +406,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkApplicationWindow" id="window">
|
||||
<style><class name="devel"/></style>
|
||||
<property name="title">GTK+ Widget Factory</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="headerbar1">
|
||||
@@ -3583,4 +3594,4 @@ bad things might happen.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
</interface>
|
||||
|
||||
@@ -655,7 +655,6 @@ gdk_event_get_key_is_modifier
|
||||
gdk_event_get_pad_axis_value
|
||||
gdk_event_get_pad_button
|
||||
gdk_event_get_pad_group_mode
|
||||
gdk_event_get_string
|
||||
gdk_event_get_touch_emulating_pointer
|
||||
gdk_event_get_touchpad_angle_delta
|
||||
gdk_event_get_touchpad_deltas
|
||||
|
||||
+21
-21
@@ -44,7 +44,7 @@
|
||||
|
||||
<informalexample>
|
||||
<para>Create a new file with the following content named <filename>example-0.c.</filename></para>
|
||||
<programlisting><xi:include href="../../../../examples/window-default.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/window-default.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>
|
||||
@@ -153,7 +153,7 @@
|
||||
<example id="gtk-getting-started-hello-world">
|
||||
<title>Hello World in GTK+</title>
|
||||
<para>Create a new file with the following content named example-1.c.</para>
|
||||
<programlisting><xi:include href="../../../../examples/hello-world.c" parse="text">
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/hello-world.c" parse="text">
|
||||
<xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</example>
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
<example id="gtk-getting-started-grid-packing">
|
||||
<title>Packing buttons</title>
|
||||
<para>Create a new file with the following content named example-2.c.</para>
|
||||
<programlisting><xi:include href="../../../../examples/grid-packing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/grid-packing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
You can compile the program above with GCC using:
|
||||
@@ -257,9 +257,9 @@
|
||||
<example>
|
||||
<title>Packing buttons with GtkBuilder</title>
|
||||
<para>Create a new file with the following content named example-3.c.</para>
|
||||
<programlisting><xi:include href="../../../../examples/builder.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/builder.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<para>Create a new file with the following content named builder.ui.</para>
|
||||
<programlisting><xi:include href="../../../../examples/builder.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/builder.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
You can compile the program above with GCC using:
|
||||
@@ -346,7 +346,7 @@
|
||||
of our application class.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application1/main.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application1/main.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>All the application logic is in the application class, which
|
||||
@@ -364,7 +364,7 @@
|
||||
GIO <ulink url="https://developer.gnome.org/gio/2.36/GApplication.html#GApplication.description">documentation</ulink>.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application1/exampleapp.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleapp.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Another important class that is part of the application support
|
||||
@@ -373,7 +373,7 @@
|
||||
window.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application1/exampleappwin.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleappwin.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>As part of the initial setup of our application, we also
|
||||
@@ -388,7 +388,7 @@
|
||||
</informalfigure>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application1/exampleapp.desktop" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application1/org.gtk.exampleapp.desktop" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Note that <replaceable>@<!-- -->bindir@</replaceable> needs to be replaced
|
||||
@@ -420,7 +420,7 @@
|
||||
</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application2/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application2/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>To make use of this file in our application, we revisit
|
||||
@@ -460,7 +460,7 @@ example_app_window_class_init (ExampleAppWindowClass *class)
|
||||
</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application2/exampleapp.gresource.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application2/exampleapp.gresource.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>This file has to be converted into a C source file that will be
|
||||
@@ -599,7 +599,7 @@ example_app_window_open (ExampleAppWindow *win,
|
||||
in a ui file, and add it as a resource to our binary.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application4/app-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application4/app-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>To associate the app menu with the application, we have to call
|
||||
@@ -698,7 +698,7 @@ example_app_class_init (ExampleAppClass *class)
|
||||
GSettings requires a schema that describes our settings:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application5/org.gtk.exampleapp.gschema.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application5/org.gtk.exampleapp.gschema.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Before we can make use of this schema in our application,
|
||||
@@ -747,13 +747,13 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
<para>Lets start with the template.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application6/prefs.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application6/prefs.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Next comes the dialog subclass.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application6/exampleappprefs.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application6/exampleappprefs.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Now we revisit the <literal>preferences_activated(<!-- -->)</literal> function in our
|
||||
@@ -805,7 +805,7 @@ preferences_activated (GSimpleAction *action,
|
||||
to slide out the search bar below the header bar.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application7/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application7/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Implementing the search needs quite a few code changes that
|
||||
@@ -882,7 +882,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
which demonstrates #GtkMenuButton, #GtkRevealer and #GtkListBox.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application8/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application8/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>The code to populate the sidebar with buttons for the words
|
||||
@@ -893,7 +893,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
ui file.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application8/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application8/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>To connect the menuitem to the show-words setting, we use
|
||||
@@ -952,7 +952,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
triggers the show-lines action:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application9/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application9/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>To make this menu item do something, we create a property
|
||||
@@ -1012,7 +1012,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
be a direct child of the window, and set its type to be titlebar.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><xi:include href="../../../../examples/application10/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/application10/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>A small extra bonus of using a header bar is that we get
|
||||
@@ -1068,7 +1068,7 @@ example_app_window_init (ExampleAppWindow *win)
|
||||
<example id="gtk-getting-started-drawing">
|
||||
<title>Drawing in response to input</title>
|
||||
<para>Create a new file with the following content named example-4.c.</para>
|
||||
<programlisting><xi:include href="../../../../examples/drawing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
<programlisting><xi:include href="@SRC_DIR@/examples/drawing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
You can compile the program above with GCC using:
|
||||
@@ -41,6 +41,16 @@
|
||||
<xi:include href="visual_index.xml" />
|
||||
</chapter>
|
||||
|
||||
<chapter id="Lists">
|
||||
<title>GListModel support</title>
|
||||
<xi:include href="xml/gtkfilterlistmodel.xml" />
|
||||
<xi:include href="xml/gtkflattenlistmodel.xml" />
|
||||
<xi:include href="xml/gtkmaplistmodel.xml" />
|
||||
<xi:include href="xml/gtkslicelistmodel.xml" />
|
||||
<xi:include href="xml/gtksortlistmodel.xml" />
|
||||
<xi:include href="xml/gtktreelistmodel.xml" />
|
||||
</chapter>
|
||||
|
||||
<chapter id="Application">
|
||||
<title>Application support</title>
|
||||
<xi:include href="xml/gtkapplication.xml" />
|
||||
@@ -152,6 +162,7 @@
|
||||
<chapter id="TreeWidgetObjects">
|
||||
<title>Tree, List and Icon Grid Widgets</title>
|
||||
<xi:include href="xml/tree_widget.sgml" />
|
||||
<xi:include href="xml/treeview_tutorial.xml" />
|
||||
<xi:include href="xml/gtktreemodel.xml" />
|
||||
<xi:include href="xml/gtktreeselection.xml" />
|
||||
<xi:include href="xml/gtktreeviewcolumn.xml" />
|
||||
@@ -301,6 +312,7 @@
|
||||
<title>Gestures and event handling</title>
|
||||
<xi:include href="xml/gtkeventcontroller.xml" />
|
||||
<xi:include href="xml/gtkeventcontrollerkey.xml" />
|
||||
<xi:include href="xml/gtkeventcontrollerlegacy.xml" />
|
||||
<xi:include href="xml/gtkeventcontrollerscroll.xml" />
|
||||
<xi:include href="xml/gtkeventcontrollermotion.xml" />
|
||||
<xi:include href="xml/gtkgesture.xml" />
|
||||
|
||||
@@ -758,9 +758,6 @@ gtk_container_child_set_valist
|
||||
gtk_container_child_notify
|
||||
gtk_container_child_notify_by_pspec
|
||||
gtk_container_forall
|
||||
gtk_container_get_focus_chain
|
||||
gtk_container_set_focus_chain
|
||||
gtk_container_unset_focus_chain
|
||||
gtk_container_class_find_child_property
|
||||
gtk_container_class_install_child_property
|
||||
gtk_container_class_install_child_properties
|
||||
@@ -1242,6 +1239,26 @@ GTK_TYPE_FILE_FILTER
|
||||
gtk_file_filter_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkfilterlistmodel</FILE>
|
||||
<TITLE>GtkFilterListModel</TITLE>
|
||||
GtkFilterListModel
|
||||
gtk_filter_list_model_new
|
||||
gtk_filter_list_model_get_model
|
||||
gtk_filter_list_model_set_filter_func
|
||||
gtk_filter_list_model_has_filter
|
||||
gtk_filter_list_model_refilter
|
||||
<SUBSECTION Standard>
|
||||
GTK_FILTER_LIST_MODEL
|
||||
GTK_IS_FILTER_LIST_MODEL
|
||||
GTK_TYPE_FILTER_LIST_MODEL
|
||||
GTK_FILTER_LIST_MODEL_CLASS
|
||||
GTK_IS_FILTER_LIST_MODEL_CLASS
|
||||
GTK_FILTER_LIST_MODEL_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_filter_list_model_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkfixed</FILE>
|
||||
<TITLE>GtkFixed</TITLE>
|
||||
@@ -1262,6 +1279,24 @@ GtkFixedChild
|
||||
gtk_fixed_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkflattenlistmodel</FILE>
|
||||
<TITLE>GtkFlattenListModel</TITLE>
|
||||
GtkFlattenListModel
|
||||
gtk_flatten_list_model_new
|
||||
gtk_flatten_list_model_set_model
|
||||
gtk_flatten_list_model_get_model
|
||||
<SUBSECTION Standard>
|
||||
GTK_FLATTEN_LIST_MODEL
|
||||
GTK_IS_FLATTEN_LIST_MODEL
|
||||
GTK_TYPE_FLATTEN_LIST_MODEL
|
||||
GTK_FLATTEN_LIST_MODEL_CLASS
|
||||
GTK_IS_FLATTEN_LIST_MODEL_CLASS
|
||||
GTK_FLATTEN_LIST_MODEL_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_flatten_list_model_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkfontbutton</FILE>
|
||||
<TITLE>GtkFontButton</TITLE>
|
||||
@@ -1709,6 +1744,27 @@ GtkLinkButtonPrivate
|
||||
gtk_link_button_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkmaplistmodel</FILE>
|
||||
<TITLE>GtkMapListModel</TITLE>
|
||||
GtkMapListModel
|
||||
GtkMapListModelMapFunc
|
||||
gtk_map_list_model_new
|
||||
gtk_map_list_model_set_map_func
|
||||
gtk_map_list_model_set_model
|
||||
gtk_map_list_model_get_model
|
||||
gtk_map_list_model_has_map
|
||||
<SUBSECTION Standard>
|
||||
GTK_MAP_LIST_MODEL
|
||||
GTK_IS_MAP_LIST_MODEL
|
||||
GTK_TYPE_MAP_LIST_MODEL
|
||||
GTK_MAP_LIST_MODEL_CLASS
|
||||
GTK_IS_MAP_LIST_MODEL_CLASS
|
||||
GTK_MAP_LIST_MODEL_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_map_list_model_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkmenu</FILE>
|
||||
<TITLE>GtkMenu</TITLE>
|
||||
@@ -2537,6 +2593,51 @@ GtkSizeGroupPrivate
|
||||
gtk_size_group_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkslicelistmodel</FILE>
|
||||
<TITLE>GtkSliceListModel</TITLE>
|
||||
GtkSliceListModel
|
||||
gtk_slice_list_model_new
|
||||
gtk_slice_list_model_new_for_type
|
||||
gtk_slice_list_model_set_model
|
||||
gtk_slice_list_model_get_model
|
||||
gtk_slice_list_model_set_offset
|
||||
gtk_slice_list_model_get_offset
|
||||
gtk_slice_list_model_set_size
|
||||
gtk_slice_list_model_get_size
|
||||
<SUBSECTION Standard>
|
||||
GTK_SLICE_LIST_MODEL
|
||||
GTK_IS_SLICE_LIST_MODEL
|
||||
GTK_TYPE_SLICE_LIST_MODEL
|
||||
GTK_SLICE_LIST_MODEL_CLASS
|
||||
GTK_IS_SLICE_LIST_MODEL_CLASS
|
||||
GTK_SLICE_LIST_MODEL_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_slice_list_model_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtksortlistmodel</FILE>
|
||||
<TITLE>GtkSortListModel</TITLE>
|
||||
GtkSortListModel
|
||||
gtk_sort_list_model_new
|
||||
gtk_sort_list_model_new_for_type
|
||||
gtk_sort_list_model_set_sort_func
|
||||
gtk_sort_list_model_has_sort
|
||||
gtk_sort_list_model_set_model
|
||||
gtk_sort_list_model_get_model
|
||||
gtk_sort_list_model_resort
|
||||
<SUBSECTION Standard>
|
||||
GTK_SORT_LIST_MODEL
|
||||
GTK_IS_SORT_LIST_MODEL
|
||||
GTK_TYPE_SORT_LIST_MODEL
|
||||
GTK_SORT_LIST_MODEL_CLASS
|
||||
GTK_IS_SORT_LIST_MODEL_CLASS
|
||||
GTK_SORT_LIST_MODEL_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_sort_list_model_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkspinbutton</FILE>
|
||||
<TITLE>GtkSpinButton</TITLE>
|
||||
@@ -3271,6 +3372,49 @@ GTK_TOOLTIP
|
||||
gtk_tooltip_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtktreelistmodel</FILE>
|
||||
<TITLE>GtkTreeListModel</TITLE>
|
||||
GtkTreeListModel
|
||||
GtkTreeListRow
|
||||
GtkTreeListModelCreateModelFunc
|
||||
gtk_tree_list_model_new
|
||||
gtk_tree_list_model_get_model
|
||||
gtk_tree_list_model_get_passthrough
|
||||
gtk_tree_list_model_set_autoexpand
|
||||
gtk_tree_list_model_get_autoexpand
|
||||
gtk_tree_list_model_get_child_row
|
||||
gtk_tree_list_model_get_row
|
||||
|
||||
<SUBSECTION>
|
||||
gtk_tree_list_row_get_item
|
||||
gtk_tree_list_row_set_expanded
|
||||
gtk_tree_list_row_get_expanded
|
||||
gtk_tree_list_row_is_expandable
|
||||
gtk_tree_list_row_get_position
|
||||
gtk_tree_list_row_get_depth
|
||||
gtk_tree_list_row_get_children
|
||||
gtk_tree_list_row_get_parent
|
||||
gtk_tree_list_row_get_child_row
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TREE_LIST_MODEL
|
||||
GTK_IS_TREE_LIST_MODEL
|
||||
GTK_TYPE_TREE_LIST_MODEL
|
||||
GTK_TREE_LIST_MODEL_CLASS
|
||||
GTK_IS_TREE_LIST_MODEL_CLASS
|
||||
GTK_TREE_LIST_MODEL_GET_CLASS
|
||||
GTK_TREE_LIST_ROW
|
||||
GTK_IS_TREE_LIST_ROW
|
||||
GTK_TYPE_TREE_LIST_ROW
|
||||
GTK_TREE_LIST_ROW_CLASS
|
||||
GTK_IS_TREE_LIST_ROW_CLASS
|
||||
GTK_TREE_LIST_ROW_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_tree_list_model_get_type
|
||||
gtk_tree_list_row_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtktreemodel</FILE>
|
||||
<TITLE>GtkTreeModel</TITLE>
|
||||
@@ -4277,7 +4421,6 @@ gtk_widget_list_accel_closures
|
||||
gtk_widget_can_activate_accel
|
||||
gtk_widget_event
|
||||
gtk_widget_activate
|
||||
gtk_widget_intersect
|
||||
gtk_widget_is_focus
|
||||
gtk_widget_grab_focus
|
||||
gtk_widget_grab_default
|
||||
@@ -4460,6 +4603,10 @@ gtk_widget_class_bind_template_callback
|
||||
gtk_widget_class_bind_template_callback_full
|
||||
gtk_widget_class_set_connect_func
|
||||
|
||||
<SUBSECTION>
|
||||
gtk_widget_observe_children
|
||||
gtk_widget_observe_controllers
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_WIDGET
|
||||
GTK_IS_WIDGET
|
||||
@@ -4503,6 +4650,7 @@ gtk_window_set_destroy_with_parent
|
||||
gtk_window_set_display
|
||||
gtk_window_is_active
|
||||
gtk_window_is_maximized
|
||||
gtk_window_get_toplevels
|
||||
gtk_window_list_toplevels
|
||||
gtk_window_add_mnemonic
|
||||
gtk_window_remove_mnemonic
|
||||
@@ -6456,6 +6604,24 @@ GTK_GESTURE_SINGLE_GET_CLASS
|
||||
gtk_gesture_single_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkeventcontrollerlegacy</FILE>
|
||||
<TITLE>GtkEventControllerlegacy</TITLE>
|
||||
GtkEventControllerlegacy
|
||||
gtk_event_controller_legacy_new
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_EVENT_CONTROLLER_LEGACY
|
||||
GTK_EVENT_CONTROLLER_LEGACY
|
||||
GTK_EVENT_CONTROLLER_LEGACY_CLASS
|
||||
GTK_IS_EVENT_CONTROLLER_LEGACY
|
||||
GTK_IS_EVENT_CONTROLLER_LEGACY_CLASS
|
||||
GTK_EVENT_CONTROLLER_LEGACY_GET_CLASS
|
||||
|
||||
<SUBSECTION Private>
|
||||
gtk_event_controller_legacy_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkeventcontrollerscroll</FILE>
|
||||
<TITLE>GtkEventControllerScroll</TITLE>
|
||||
|
||||
@@ -54,6 +54,7 @@ gtk_entry_completion_get_type
|
||||
gtk_entry_get_type
|
||||
gtk_event_controller_get_type
|
||||
gtk_event_controller_key_get_type
|
||||
gtk_event_controller_legacy_get_type
|
||||
gtk_event_controller_motion_get_type
|
||||
gtk_event_controller_scroll_get_type
|
||||
gtk_expander_get_type
|
||||
|
||||
@@ -340,7 +340,6 @@ content_files = [
|
||||
'css-overview.xml',
|
||||
'css-properties.xml',
|
||||
'drawing-model.xml',
|
||||
'getting_started.xml',
|
||||
'glossary.xml',
|
||||
'gtk4-broadwayd.xml',
|
||||
'gtk4-builder-tool.xml',
|
||||
@@ -363,6 +362,7 @@ content_files = [
|
||||
'running.sgml',
|
||||
'text_widget.sgml',
|
||||
'tree_widget.sgml',
|
||||
'treeview_tutorial.xml',
|
||||
'visual_index.xml',
|
||||
'wayland.xml',
|
||||
'windows.sgml',
|
||||
@@ -372,7 +372,6 @@ content_files = [
|
||||
expand_content_files = [
|
||||
'compiling.sgml',
|
||||
'drawing-model.xml',
|
||||
'getting_started.xml',
|
||||
'glossary.xml',
|
||||
'input-handling.xml',
|
||||
'migrating-2to4.xml',
|
||||
@@ -380,9 +379,11 @@ expand_content_files = [
|
||||
'question_index.sgml',
|
||||
'text_widget.sgml',
|
||||
'tree_widget.sgml',
|
||||
'treeview_tutorial.xml',
|
||||
]
|
||||
|
||||
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
|
||||
configure_file(input: 'getting_started.xml.in', output: 'getting_started.xml', configuration: src_dir_conf)
|
||||
|
||||
types_conf = configuration_data()
|
||||
if os_win32
|
||||
|
||||
@@ -177,6 +177,22 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Set a proper app_id</title>
|
||||
<para>
|
||||
In GTK+4 we want the application's #GApplication
|
||||
'application-id' (and therefore the D-Bus name), the desktop
|
||||
file basename and Wayland's xdg-shell app_id to match. In
|
||||
order to achieve this with GTK+3 call g_set_prgname() with the same
|
||||
application id you passed to #GtkApplication. Rename your
|
||||
desktop files to match the application id if needed.
|
||||
</para>
|
||||
<para>
|
||||
The call to g_set_prgname() can be removed once you fully migrated
|
||||
to GTK+4.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -270,6 +286,14 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Stop using GtkEventBox</title>
|
||||
<para>
|
||||
GtkEventBox is no longer needed and has been removed.
|
||||
All widgets receive all events.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Adapt to GtkHeaderBar API changes</title>
|
||||
<para>
|
||||
@@ -319,6 +343,15 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Adapt to GtkWidget's size allocation changes</title>
|
||||
<para>
|
||||
The #GtkWidget::size-allocate signal now takes the baseline as an
|
||||
argument, so you no longer need to call gtk_widget_get_allocated_baseline()
|
||||
to get it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Switch to GtkWidget's children APIs</title>
|
||||
<para>
|
||||
@@ -399,6 +432,10 @@
|
||||
from ui files it run the command <command>gtk4-builder-tool simplify --replace</command>
|
||||
on them.
|
||||
</para>
|
||||
<para>
|
||||
The function gtk_widget_show_all(), the #GtkWidget::no-show-all property
|
||||
and its getter and setter have been removed in GTK+ 4, so you should stop using them.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
]>
|
||||
<refentry id="TreeView-tutorial">
|
||||
<refmeta>
|
||||
<refentrytitle>TreeView Tutorial</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GTK Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>TreeView Tutorial</refname>
|
||||
<refpurpose>A tutorial on the use of GtkTreeModel, GtkTreeView, and friends</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Overview</title>
|
||||
<para>GtkTreeView is a widget that displays single- or multi-columned
|
||||
lists and trees.</para>
|
||||
|
||||
<para>The purpose of this tutorial is not to provide an exhaustive
|
||||
documentation of #GtkTreeView - that is what the API documentation is
|
||||
for, which should be read alongside with this tutorial. The goal is
|
||||
rather to present an introduction to the most commonly-used aspects
|
||||
of #GtkTreeView, and to demonstrate how the various #GtkTreeView
|
||||
components and concepts work together. Furthermore, an attempt has
|
||||
been made to shed some light on custom tree models and custom cell
|
||||
renderers, which seem to be often-mentioned, but rarely
|
||||
explained.</para>
|
||||
|
||||
<para>Developers looking for a quick and dirty introduction that
|
||||
teaches them everything they need to know in less than five paragraphs
|
||||
will not find it here. In the author's experience, developers who do
|
||||
not understand how the tree view and the models work together will run
|
||||
into problems once they try to modify the given examples, whereas
|
||||
developers who have worked with other toolkits that employ the
|
||||
Model/View/Controller-design will find that the API reference provides
|
||||
all the information they need to know in more condensed form anyway.
|
||||
Those who disagree may jump straight to the working example code of
|
||||
course.</para>
|
||||
|
||||
<para>Please note that the code examples in the following sections do
|
||||
not necessarily demonstrate how GtkTreeView is used best in a particular
|
||||
situation. There are different ways to achieve the same result, and the
|
||||
examples merely show those different ways, so that developers are able
|
||||
to decide which one is most suitable for the task at hand.</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Components</title>
|
||||
|
||||
<para>The most important concept underlying #GtkTreeView is that of
|
||||
complete separation between data and how that data is displayed on
|
||||
the screen. This is commonly known as Model/View/Controller-design,
|
||||
or MVC. Data of various type (strings, numbers, images, etc.) is
|
||||
stored in a "model". The "view" is then told which data to display,
|
||||
where to display it, and how to display it. One of the advantages
|
||||
of this approach is that you can have multiple views that display
|
||||
the same data (a directory tree for example) in different ways, or
|
||||
in the same way multiple times, with only one copy of the underlying
|
||||
data. This avoids duplication of data and programming effort if the
|
||||
same data is re-used in different contexts. Also, when the data in
|
||||
the model is updated, all views automatically get updated as
|
||||
well.</para>
|
||||
|
||||
<para>So, while #GtkTreeModel is used to store data, there are other
|
||||
components that determine which data is displayed in the #GtkTreeView
|
||||
and how it is displayed. These components are #GtkTreeViewColumn and
|
||||
#GtkCellRenderer. A #GtkTreeView is made up of tree view columns.
|
||||
These are the columns that users perceive as columns. They have a
|
||||
clickable column header with a column title that can be hidden, and
|
||||
can be resized and sorted. Tree view columns do not display any data,
|
||||
they are only used as a device to represent the user-side of the tree
|
||||
view (sorting etc.) and serve as packing widgets for the components
|
||||
that do the actual rendering of data onto the screen, namely the
|
||||
#GtkCellRenderer family of objects. There are a number of different
|
||||
cell renderers that specialise in rendering certain data like
|
||||
strings, pixbufs, or toggle buttons. More on this later.</para>
|
||||
|
||||
<para>Cell renderers are packed into tree view columns to display data.
|
||||
A tree view column needs to contain at least one cell renderer, but can
|
||||
contain multiple cell renderers. For example, if one wanted to display
|
||||
a 'Filename' column where each filename has a little icon on the left
|
||||
indicating the file type, one would pack a GtkCellRendererPixbuf and a
|
||||
GtkCellRendererText into one tree view column. Packing renderers into a
|
||||
tree view column is similar to packing widgets into a #GtkBox.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>GtkTreeModels for Data Storage: GtkListStore and GtkTreeStore</title>
|
||||
|
||||
<para>It is important to realise what #GtkTreeModel is and what it is
|
||||
not. #GtkTreeModel is basically just an 'interface' to the data store,
|
||||
meaning that it is a standardised set of functions that allows a
|
||||
#GtkTreeView widget (and the application programmer) to query certain
|
||||
characteristics of a data store, for example how many rows there are,
|
||||
which rows have children, and how many children a particular row has.
|
||||
It also provides functions to retrieve data from the data store, and
|
||||
tell the tree view what type of data is stored in the model. Every
|
||||
data store must implement the #GtkTreeModel interface and provide these
|
||||
functions. #GtkTreeModel itself only provides a way to query a data
|
||||
store's characteristics and to retrieve existing data, it does not
|
||||
provide a way to remove or add rows to the store or put data into the
|
||||
store. This is done using the specific store's functions.</para>
|
||||
|
||||
<para>GTK comes with two built-in data stores (models): #GtkListStore
|
||||
and #GtkTreeStore. As the names imply, #GtkListStore is used for simple
|
||||
lists of data items where items have no hierarchical parent-child
|
||||
relationships, and #GtkTreeStore is used for tree-like data structures,
|
||||
where items can have parent-child relationships. A list of files in a
|
||||
directory would be an example of a simple list structure, whereas a
|
||||
directory tree is an example for a tree structure. A list is basically
|
||||
just a special case of a tree with none of the items having any
|
||||
children, so one could use a tree store to maintain a simple list of
|
||||
items as well. The only reason #GtkListStore exists is in order to
|
||||
provide an easier interface that does not need to cater for
|
||||
child-parent relationships, and because a simple list model can be
|
||||
optimised for the special case where no children exist, which makes it
|
||||
faster and more efficient.</para>
|
||||
|
||||
<para>#GtkListStore and #GtkTreeStore should cater for most types of
|
||||
data an application developer might want to display in a #GtkTreeView.
|
||||
However, it should be noted that #GtkListStore and #GtkTreeStore have
|
||||
been designed to cater to a large number of potential use cases, and
|
||||
so are not overly optimized. If you already have your specialized data
|
||||
store; if you plan to store a lot of data; or if have a large number
|
||||
of rows, you should consider implementing your own custom model that
|
||||
stores and manipulates data your own way and implements the
|
||||
#GtkTreeModel interface. This will not only be more efficient, but
|
||||
probably also lead to saner code in the long run, and give you more
|
||||
control over your data. See below for more details on how to implement
|
||||
custom models.</para>
|
||||
|
||||
<para>Tree model implementations like #GtkListStore and #GtkTreeStore
|
||||
will take care of the view side for you once you have configured the
|
||||
#GtkTreeView to display what you want. If you change data in the store,
|
||||
the model will notify the tree view and your data display will be
|
||||
updated. If you add or remove rows, the model will also notify the
|
||||
store, and your row will appear in or disappear from the view as
|
||||
well.</para>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
@@ -12,6 +12,9 @@ docpath = join_paths(gtk_datadir, 'gtk-doc', 'html')
|
||||
version_conf = configuration_data()
|
||||
version_conf.set('GTK_VERSION', meson.project_version())
|
||||
|
||||
src_dir_conf = configuration_data()
|
||||
src_dir_conf.set('SRC_DIR', meson.source_root())
|
||||
|
||||
subdir('gdk')
|
||||
subdir('gsk')
|
||||
subdir('gtk')
|
||||
|
||||
@@ -2,8 +2,8 @@ To make gnome-shell use the desktop file and icon for this example
|
||||
while running it uninstalled, do the following:
|
||||
|
||||
mkdir -p ~/.local/share/applications
|
||||
sed -e "s#@bindir@#$PWD#" exampleapp.desktop \
|
||||
> ~/.local/share/applications/lt-exampleapp.desktop
|
||||
sed -e "s#@bindir@#$PWD#" org.gtk.exampleapp.desktop \
|
||||
> ~/.local/share/applications/org.gtk.exampleapp.desktop
|
||||
|
||||
mkdir -p ~/.local/share/icons/hicolor/48x48/apps
|
||||
cp exampleapp.png ~/.local/share/icons/hicolor/48x48/apps
|
||||
|
||||
@@ -285,7 +285,6 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message)
|
||||
event->key.state = message->key.state;
|
||||
event->key.hardware_keycode = message->key.key;
|
||||
gdk_event_set_scancode (event, message->key.key);
|
||||
event->key.length = 0;
|
||||
gdk_event_set_device (event, gdk_seat_get_keyboard (seat));
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
|
||||
@@ -32,6 +32,7 @@ void gdk_display_set_cursor_theme (GdkDisplay *display,
|
||||
const char *theme,
|
||||
int size);
|
||||
gboolean gdk_running_in_sandbox (void);
|
||||
gboolean gdk_should_use_portal (void);
|
||||
|
||||
const gchar * gdk_get_startup_notification_id (void);
|
||||
|
||||
|
||||
@@ -269,14 +269,27 @@ gdk_get_startup_notification_id (void)
|
||||
gboolean
|
||||
gdk_running_in_sandbox (void)
|
||||
{
|
||||
char *path;
|
||||
gboolean ret;
|
||||
return g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
|
||||
}
|
||||
|
||||
path = g_build_filename (g_get_user_runtime_dir (), "flatpak-info", NULL);
|
||||
ret = g_file_test (path, G_FILE_TEST_EXISTS);
|
||||
g_free (path);
|
||||
gboolean
|
||||
gdk_should_use_portal (void)
|
||||
{
|
||||
static const char *use_portal = NULL;
|
||||
|
||||
return ret;
|
||||
if (G_UNLIKELY (use_portal == NULL))
|
||||
{
|
||||
if (gdk_running_in_sandbox ())
|
||||
use_portal = "1";
|
||||
else
|
||||
{
|
||||
use_portal = g_getenv ("GTK_USE_PORTAL");
|
||||
if (!use_portal)
|
||||
use_portal = "";
|
||||
}
|
||||
}
|
||||
|
||||
return use_portal[0] == '1';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ gdk_drop_read_local_async (GdkDrop *self,
|
||||
if (priv->drag == NULL)
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Drag'n'drop from other applications is not supported."));
|
||||
_("Drag’n’drop from other applications is not supported."));
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -631,11 +631,6 @@ gdk_event_copy (const GdkEvent *event)
|
||||
|
||||
switch ((guint) event->any.type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
new_event->key.string = g_strdup (event->key.string);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (event->crossing.child_surface != NULL)
|
||||
@@ -698,11 +693,6 @@ gdk_event_finalize (GObject *object)
|
||||
|
||||
switch ((guint) event->any.type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
g_free (event->key.string);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
g_clear_object (&event->crossing.child_surface);
|
||||
@@ -1293,37 +1283,6 @@ gdk_event_get_key_group (const GdkEvent *event,
|
||||
return fetched;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_string:
|
||||
* @event: a #GdkEvent
|
||||
* @string: (out) (transfer none): return location for the string
|
||||
*
|
||||
* Extracts a string from an event. The string is an
|
||||
* approximation of the keyval in a key event.
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE
|
||||
**/
|
||||
gboolean
|
||||
gdk_event_get_string (const GdkEvent *event,
|
||||
const char **string)
|
||||
{
|
||||
gboolean fetched = TRUE;
|
||||
|
||||
switch ((guint) event->any.type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
*string = event->key.string;
|
||||
break;
|
||||
default:
|
||||
*string = NULL;
|
||||
fetched = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return fetched;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_key_is_modifier:
|
||||
* @event: a #GdkEvent
|
||||
|
||||
+1
-4
@@ -54,7 +54,7 @@ G_BEGIN_DECLS
|
||||
#define GDK_PRIORITY_EVENTS (G_PRIORITY_DEFAULT)
|
||||
|
||||
/**
|
||||
* GDK_PRIORITY_REDRAW:
|
||||
* GDK_PRIORITY_REDRAW: (value 120)
|
||||
*
|
||||
* This is the priority that the idle handler processing surface updates
|
||||
* is given in the
|
||||
@@ -403,9 +403,6 @@ gboolean gdk_event_get_key_is_modifier (const GdkEvent *event,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_event_get_key_group (const GdkEvent *event,
|
||||
guint *group);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_event_get_string (const GdkEvent *event,
|
||||
const char **string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_event_get_scroll_direction (const GdkEvent *event,
|
||||
|
||||
@@ -244,18 +244,6 @@ struct _GdkEventScroll
|
||||
* @keyval: the key that was pressed or released. See the
|
||||
* `gdk/gdkkeysyms.h` header file for a
|
||||
* complete list of GDK key codes.
|
||||
* @length: the length of @string.
|
||||
* @string: a string containing an approximation of the text that
|
||||
* would result from this keypress. The only correct way to handle text
|
||||
* input of text is using input methods (see #GtkIMContext), so this
|
||||
* field is deprecated and should never be used.
|
||||
* (gdk_unicode_to_keyval() provides a non-deprecated way of getting
|
||||
* an approximate translation for a key.) The string is encoded in the
|
||||
* encoding of the current locale (Note: this for backwards compatibility:
|
||||
* strings in GTK+ and GDK are typically in UTF-8.) and NUL-terminated.
|
||||
* In some cases, the translation of the key code will be a single
|
||||
* NUL byte, in which case looking at @length is necessary to distinguish
|
||||
* it from the an empty translation.
|
||||
* @hardware_keycode: the raw code of the key that was pressed or released.
|
||||
* @group: the keyboard group.
|
||||
* @is_modifier: a flag that indicates if @hardware_keycode is mapped to a
|
||||
@@ -269,8 +257,6 @@ struct _GdkEventKey
|
||||
guint32 time;
|
||||
guint state;
|
||||
guint keyval;
|
||||
gint length;
|
||||
gchar *string;
|
||||
guint16 hardware_keycode;
|
||||
guint16 key_scancode;
|
||||
guint8 group;
|
||||
|
||||
+8
-8
@@ -175,7 +175,7 @@ parse_rgb_value (const gchar *str,
|
||||
* - A RGBA color in the form “rgba(r,g,b,a)”
|
||||
*
|
||||
* Where “r”, “g”, “b” and “a” are respectively the red, green, blue and
|
||||
* alpha color values. In the last two cases, r g and b are either integers
|
||||
* alpha color values. In the last two cases, “r”, “g”, and “b” are either integers
|
||||
* in the range 0 to 255 or percentage values in the range 0% to 100%, and
|
||||
* a is a floating point value in the range 0 to 1.
|
||||
*
|
||||
@@ -353,18 +353,18 @@ gdk_rgba_equal (gconstpointer p1,
|
||||
* @rgba: a #GdkRGBA
|
||||
*
|
||||
* Returns a textual specification of @rgba in the form
|
||||
* `rgb (r, g, b)` or
|
||||
* `rgba (r, g, b, a)`,
|
||||
* `rgb(r,g,b)` or
|
||||
* `rgba(r g,b,a)`,
|
||||
* where “r”, “g”, “b” and “a” represent the red, green,
|
||||
* blue and alpha values respectively. r, g, and b are
|
||||
* represented as integers in the range 0 to 255, and a
|
||||
* is represented as floating point value in the range 0 to 1.
|
||||
* blue and alpha values respectively. “r”, “g”, and “b” are
|
||||
* represented as integers in the range 0 to 255, and “a”
|
||||
* is represented as a floating point value in the range 0 to 1.
|
||||
*
|
||||
* These string forms are string forms those supported by
|
||||
* These string forms are string forms that are supported by
|
||||
* the CSS3 colors module, and can be parsed by gdk_rgba_parse().
|
||||
*
|
||||
* Note that this string representation may lose some
|
||||
* precision, since r, g and b are represented as 8-bit
|
||||
* precision, since “r”, “g” and “b” are represented as 8-bit
|
||||
* integers. If this is a concern, you should use a
|
||||
* different representation.
|
||||
*
|
||||
|
||||
+3
-2
@@ -434,14 +434,15 @@ gdk_seat_tool_removed (GdkSeat *seat,
|
||||
|
||||
GdkDeviceTool *
|
||||
gdk_seat_get_tool (GdkSeat *seat,
|
||||
guint64 serial)
|
||||
guint64 serial,
|
||||
guint64 hw_id)
|
||||
{
|
||||
GdkSeatClass *seat_class;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_SEAT (seat), NULL);
|
||||
|
||||
seat_class = GDK_SEAT_GET_CLASS (seat);
|
||||
return seat_class->get_tool (seat, serial);
|
||||
return seat_class->get_tool (seat, serial, hw_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -282,7 +282,8 @@ gdk_seat_default_get_slaves (GdkSeat *seat,
|
||||
|
||||
static GdkDeviceTool *
|
||||
gdk_seat_default_get_tool (GdkSeat *seat,
|
||||
guint64 serial)
|
||||
guint64 serial,
|
||||
guint64 hw_id)
|
||||
{
|
||||
GdkSeatDefaultPrivate *priv;
|
||||
GdkDeviceTool *tool;
|
||||
@@ -297,7 +298,7 @@ gdk_seat_default_get_tool (GdkSeat *seat,
|
||||
{
|
||||
tool = g_ptr_array_index (priv->tools, i);
|
||||
|
||||
if (tool->serial == serial)
|
||||
if (tool->serial == serial && tool->hw_id == hw_id)
|
||||
return tool;
|
||||
}
|
||||
|
||||
@@ -457,8 +458,7 @@ gdk_seat_default_remove_tool (GdkSeatDefault *seat,
|
||||
|
||||
priv = gdk_seat_default_get_instance_private (seat);
|
||||
|
||||
if (tool != gdk_seat_get_tool (GDK_SEAT (seat),
|
||||
gdk_device_tool_get_serial (tool)))
|
||||
if (tool != gdk_seat_get_tool (GDK_SEAT (seat), tool->serial, tool->hw_id))
|
||||
return;
|
||||
|
||||
g_signal_emit_by_name (seat, "tool-removed", tool);
|
||||
|
||||
@@ -57,7 +57,8 @@ struct _GdkSeatClass
|
||||
GdkSeatCapabilities capabilities);
|
||||
|
||||
GdkDeviceTool * (* get_tool) (GdkSeat *seat,
|
||||
guint64 serial);
|
||||
guint64 serial,
|
||||
guint64 tool_id);
|
||||
GList * (* get_master_pointers) (GdkSeat *seat,
|
||||
GdkSeatCapabilities capabilities);
|
||||
};
|
||||
@@ -74,6 +75,7 @@ void gdk_seat_tool_removed (GdkSeat *seat,
|
||||
|
||||
GdkDeviceTool *
|
||||
gdk_seat_get_tool (GdkSeat *seat,
|
||||
guint64 serial);
|
||||
guint64 serial,
|
||||
guint64 hw_id);
|
||||
|
||||
#endif /* __GDK_SEAT_PRIVATE_H__ */
|
||||
|
||||
+3
-31
@@ -461,12 +461,6 @@ gdk_surface_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_surface_is_subsurface (GdkSurface *surface)
|
||||
{
|
||||
return surface->surface_type == GDK_SURFACE_SUBSURFACE;
|
||||
}
|
||||
|
||||
static GdkSurface *
|
||||
gdk_surface_get_impl_surface (GdkSurface *surface)
|
||||
{
|
||||
@@ -555,10 +549,7 @@ recompute_visible_regions_internal (GdkSurface *private,
|
||||
old_abs_y = private->abs_y;
|
||||
|
||||
/* Update absolute position */
|
||||
if ((gdk_surface_has_impl (private) &&
|
||||
private->surface_type != GDK_SURFACE_SUBSURFACE) ||
|
||||
(gdk_surface_is_toplevel (private) &&
|
||||
private->surface_type == GDK_SURFACE_SUBSURFACE))
|
||||
if (gdk_surface_has_impl (private))
|
||||
{
|
||||
/* Native surfaces and toplevel subsurfaces start here */
|
||||
private->abs_x = 0;
|
||||
@@ -677,15 +668,6 @@ gdk_surface_new (GdkDisplay *display,
|
||||
if (parent != NULL)
|
||||
g_warning (G_STRLOC "Toplevel surfaces must be created without a parent");
|
||||
break;
|
||||
case GDK_SURFACE_SUBSURFACE:
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (!GDK_IS_WAYLAND_DISPLAY (display))
|
||||
{
|
||||
g_warning (G_STRLOC "Subsurface surfaces can only be used on Wayland");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case GDK_SURFACE_CHILD:
|
||||
break;
|
||||
default:
|
||||
@@ -715,11 +697,6 @@ gdk_surface_new (GdkDisplay *display,
|
||||
native = TRUE; /* Always use native surfaces for toplevels */
|
||||
}
|
||||
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (surface->surface_type == GDK_SURFACE_SUBSURFACE)
|
||||
native = TRUE; /* Always use native windows for subsurfaces as well */
|
||||
#endif
|
||||
|
||||
if (native)
|
||||
{
|
||||
/* Create the impl */
|
||||
@@ -922,7 +899,6 @@ _gdk_surface_destroy_hierarchy (GdkSurface *surface,
|
||||
case GDK_SURFACE_TOPLEVEL:
|
||||
case GDK_SURFACE_CHILD:
|
||||
case GDK_SURFACE_TEMP:
|
||||
case GDK_SURFACE_SUBSURFACE:
|
||||
if (surface->parent)
|
||||
{
|
||||
if (surface->parent->children)
|
||||
@@ -1173,10 +1149,7 @@ gdk_surface_get_parent (GdkSurface *surface)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
|
||||
|
||||
if (gdk_surface_is_subsurface (surface))
|
||||
return surface->transient_for;
|
||||
else
|
||||
return surface->parent;
|
||||
return surface->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1196,8 +1169,7 @@ gdk_surface_get_toplevel (GdkSurface *surface)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
|
||||
|
||||
while (surface->surface_type == GDK_SURFACE_CHILD ||
|
||||
surface->surface_type == GDK_SURFACE_SUBSURFACE)
|
||||
while (surface->surface_type == GDK_SURFACE_CHILD)
|
||||
{
|
||||
if (gdk_surface_is_toplevel (surface))
|
||||
break;
|
||||
|
||||
+2
-7
@@ -43,11 +43,7 @@ typedef struct _GdkGeometry GdkGeometry;
|
||||
* GdkSurfaceType:
|
||||
* @GDK_SURFACE_TOPLEVEL: toplevel window (used to implement #GtkWindow)
|
||||
* @GDK_SURFACE_CHILD: child surface (used to implement e.g. #GtkEntry)
|
||||
* @GDK_SURFACE_TEMP: override redirect temporary surface (used to implement
|
||||
* #GtkMenu)
|
||||
* @GDK_SURFACE_SUBSURFACE: subsurface; This surface is visually
|
||||
* tied to a toplevel, and is moved/stacked with it. Currently this window
|
||||
* type is only implemented in Wayland
|
||||
* @GDK_SURFACE_TEMP: override redirect temporary surface (used to implement #GtkMenu)
|
||||
*
|
||||
* Describes the kind of surface.
|
||||
*/
|
||||
@@ -55,8 +51,7 @@ typedef enum
|
||||
{
|
||||
GDK_SURFACE_TOPLEVEL,
|
||||
GDK_SURFACE_CHILD,
|
||||
GDK_SURFACE_TEMP,
|
||||
GDK_SURFACE_SUBSURFACE
|
||||
GDK_SURFACE_TEMP
|
||||
} GdkSurfaceType;
|
||||
|
||||
/* Size restriction enumeration.
|
||||
|
||||
@@ -190,6 +190,11 @@ gdk_vulkan_strerror (VkResult result)
|
||||
case VK_ERROR_FRAGMENTATION_EXT:
|
||||
return "A descriptor pool creation has failed due to fragmentation";
|
||||
#endif
|
||||
#if VK_HEADER_VERSION >= 89
|
||||
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
|
||||
return "Invalid DRM format modifier plane layout";
|
||||
#endif
|
||||
|
||||
case VK_RESULT_RANGE_SIZE:
|
||||
case VK_RESULT_MAX_ENUM:
|
||||
default:
|
||||
@@ -706,7 +711,7 @@ gdk_vulkan_context_get_image (GdkVulkanContext *context,
|
||||
*
|
||||
* Gets the index of the image that is currently being drawn.
|
||||
*
|
||||
* This function can only be used between gdk_cairo_context_begin_frame() and
|
||||
* This function can only be used between gdk_draw_context_begin_frame() and
|
||||
* gdk_draw_context_end_frame() calls.
|
||||
*
|
||||
* Returns: the index of the images that is being drawn
|
||||
@@ -729,7 +734,7 @@ gdk_vulkan_context_get_draw_index (GdkVulkanContext *context)
|
||||
* Gets the Vulkan semaphore that protects access to the image that is
|
||||
* currently being drawn.
|
||||
*
|
||||
* This function can only be used between gdk_cairo_context_begin_frame() and
|
||||
* This function can only be used between gdk_draw_context_begin_frame() and
|
||||
* gdk_draw_context_end_frame() calls.
|
||||
*
|
||||
* Returns: (transfer none): the VkSemaphore
|
||||
|
||||
@@ -1113,8 +1113,6 @@ fill_key_event (GdkSurface *window,
|
||||
{
|
||||
GdkEventPrivate *priv;
|
||||
GdkQuartzDeviceManagerCore *device_manager;
|
||||
gchar buf[7];
|
||||
gunichar c = 0;
|
||||
|
||||
priv = (GdkEventPrivate *) event;
|
||||
priv->windowing_data = [nsevent retain];
|
||||
@@ -1189,44 +1187,6 @@ fill_key_event (GdkSurface *window,
|
||||
gdk_keymap_add_virtual_modifiers (gdk_display_get_keymap (_gdk_display),
|
||||
&event->key.state);
|
||||
|
||||
event->key.string = NULL;
|
||||
|
||||
/* Fill in ->string since apps depend on it, taken from the x11 backend. */
|
||||
if (event->key.keyval != GDK_KEY_VoidSymbol)
|
||||
c = gdk_keyval_to_unicode (event->key.keyval);
|
||||
|
||||
if (c)
|
||||
{
|
||||
gsize bytes_written;
|
||||
gint len;
|
||||
|
||||
len = g_unichar_to_utf8 (c, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
event->key.string = g_locale_from_utf8 (buf, len,
|
||||
NULL, &bytes_written,
|
||||
NULL);
|
||||
if (event->key.string)
|
||||
event->key.length = bytes_written;
|
||||
}
|
||||
else if (event->key.keyval == GDK_KEY_Escape)
|
||||
{
|
||||
event->key.length = 1;
|
||||
event->key.string = g_strdup ("\033");
|
||||
}
|
||||
else if (event->key.keyval == GDK_KEY_Return ||
|
||||
event->key.keyval == GDK_KEY_KP_Enter)
|
||||
{
|
||||
event->key.length = 1;
|
||||
event->key.string = g_strdup ("\r");
|
||||
}
|
||||
|
||||
if (!event->key.string)
|
||||
{
|
||||
event->key.length = 0;
|
||||
event->key.string = g_strdup ("");
|
||||
}
|
||||
|
||||
GDK_NOTE(EVENTS,
|
||||
g_message ("key %s:\t\twindow: %p key: %12s %d",
|
||||
type == GDK_KEY_PRESS ? "press" : "release",
|
||||
|
||||
@@ -35,12 +35,19 @@ gdk_quartz_monitor_get_workarea (GdkMonitor *monitor,
|
||||
|
||||
GDK_QUARTZ_ALLOC_POOL;
|
||||
|
||||
NSRect rect = [quartz_monitor->nsscreen visibleFrame];
|
||||
NSArray *array = [NSScreen screens];
|
||||
if (quartz_monitor->monitor_num < [array count])
|
||||
{
|
||||
NSScreen *screen = [array objectAtIndex:quartz_monitor->monitor_num];
|
||||
NSRect rect = [screen visibleFrame];
|
||||
|
||||
dest->x = rect.origin.x - quartz_screen->min_x;
|
||||
dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
|
||||
dest->width = rect.size.width;
|
||||
dest->height = rect.size.height;
|
||||
dest->x = rect.origin.x - quartz_screen->min_x;
|
||||
dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
|
||||
dest->width = rect.size.width;
|
||||
dest->height = rect.size.height;
|
||||
}
|
||||
else
|
||||
*dest = monitor->geometry;
|
||||
|
||||
GDK_QUARTZ_RELEASE_POOL;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ struct _GdkQuartzMonitor
|
||||
{
|
||||
GdkMonitor parent;
|
||||
|
||||
NSScreen *nsscreen;
|
||||
gint monitor_num;
|
||||
};
|
||||
|
||||
struct _GdkQuartzMonitorClass {
|
||||
|
||||
@@ -52,7 +52,9 @@ typedef enum
|
||||
GDK_OSX_YOSEMITE = 10,
|
||||
GDK_OSX_EL_CAPITAN = 11,
|
||||
GDK_OSX_SIERRA = 12,
|
||||
GDK_OSX_CURRENT = 12,
|
||||
GDK_OSX_HIGH_SIERRA = 13,
|
||||
GDK_OSX_MOJAVE = 14,
|
||||
GDK_OSX_CURRENT = 14,
|
||||
GDK_OSX_NEW = 99
|
||||
} GdkOSXVersion;
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ gdk_quartz_screen_calculate_layout (GdkQuartzScreen *screen)
|
||||
"display", display,
|
||||
NULL);
|
||||
g_ptr_array_add (display_quartz->monitors, monitor);
|
||||
monitor->nsscreen = [array objectAtIndex:i];
|
||||
monitor->monitor_num = i;
|
||||
|
||||
NSRect rect = [[array objectAtIndex:i] frame];
|
||||
|
||||
|
||||
@@ -134,8 +134,12 @@ gdk_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *surface_impl,
|
||||
if (![surface_impl->view lockFocusIfCanDraw])
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
|
||||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
else
|
||||
cg_context = [[NSGraphicsContext currentContext] CGContext];
|
||||
if (!cg_context)
|
||||
return NULL;
|
||||
CGContextSaveGState (cg_context);
|
||||
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
||||
|
||||
@@ -276,15 +280,15 @@ gdk_quartz_create_cairo_surface (GdkSurfaceImplQuartz *impl,
|
||||
|
||||
cg_context = gdk_quartz_surface_get_context (impl, TRUE);
|
||||
|
||||
if (!cg_context)
|
||||
return NULL;
|
||||
|
||||
surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
|
||||
surface_data->surface_impl = impl;
|
||||
surface_data->cg_context = cg_context;
|
||||
|
||||
surface = cairo_quartz_surface_create_for_cg_context (cg_context,
|
||||
width, height);
|
||||
if (cg_context)
|
||||
surface = cairo_quartz_surface_create_for_cg_context (cg_context,
|
||||
width, height);
|
||||
else
|
||||
surface = cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
|
||||
cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
|
||||
surface_data,
|
||||
|
||||
@@ -2009,73 +2009,6 @@ keyboard_handle_leave (void *data,
|
||||
|
||||
static gboolean keyboard_repeat (gpointer data);
|
||||
|
||||
static void
|
||||
translate_keyboard_string (GdkEventKey *event)
|
||||
{
|
||||
gunichar c = 0;
|
||||
gchar buf[7];
|
||||
|
||||
/* Fill in event->string crudely, since various programs
|
||||
* depend on it.
|
||||
*/
|
||||
event->string = NULL;
|
||||
|
||||
if (event->keyval != GDK_KEY_VoidSymbol)
|
||||
c = gdk_keyval_to_unicode (event->keyval);
|
||||
|
||||
if (c)
|
||||
{
|
||||
gsize bytes_written;
|
||||
gint len;
|
||||
|
||||
/* Apply the control key - Taken from Xlib */
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
if ((c >= '@' && c < '\177') || c == ' ')
|
||||
c &= 0x1F;
|
||||
else if (c == '2')
|
||||
{
|
||||
event->string = g_memdup ("\0\0", 2);
|
||||
event->length = 1;
|
||||
buf[0] = '\0';
|
||||
return;
|
||||
}
|
||||
else if (c >= '3' && c <= '7')
|
||||
c -= ('3' - '\033');
|
||||
else if (c == '8')
|
||||
c = '\177';
|
||||
else if (c == '/')
|
||||
c = '_' & 0x1F;
|
||||
}
|
||||
|
||||
len = g_unichar_to_utf8 (c, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
event->string = g_locale_from_utf8 (buf, len,
|
||||
NULL, &bytes_written,
|
||||
NULL);
|
||||
if (event->string)
|
||||
event->length = bytes_written;
|
||||
}
|
||||
else if (event->keyval == GDK_KEY_Escape)
|
||||
{
|
||||
event->length = 1;
|
||||
event->string = g_strdup ("\033");
|
||||
}
|
||||
else if (event->keyval == GDK_KEY_Return ||
|
||||
event->keyval == GDK_KEY_KP_Enter)
|
||||
{
|
||||
event->length = 1;
|
||||
event->string = g_strdup ("\r");
|
||||
}
|
||||
|
||||
if (!event->string)
|
||||
{
|
||||
event->length = 0;
|
||||
event->string = g_strdup ("");
|
||||
}
|
||||
}
|
||||
|
||||
static GSettings *
|
||||
get_keyboard_settings (GdkWaylandSeat *seat)
|
||||
{
|
||||
@@ -2191,17 +2124,15 @@ deliver_key_event (GdkWaylandSeat *seat,
|
||||
event->key.keyval = sym;
|
||||
event->key.is_modifier = _gdk_wayland_keymap_key_is_modifier (keymap, key);
|
||||
|
||||
translate_keyboard_string (&event->key);
|
||||
|
||||
_gdk_wayland_display_deliver_event (seat->display, event);
|
||||
|
||||
GDK_DISPLAY_NOTE (seat->display, EVENTS,
|
||||
g_message ("keyboard %s event%s, code %d, sym %d, "
|
||||
"string %s, mods 0x%x",
|
||||
"mods 0x%x",
|
||||
(state ? "press" : "release"),
|
||||
(from_key_repeat ? " (repeat)" : ""),
|
||||
event->key.hardware_keycode, event->key.keyval,
|
||||
event->key.string, event->key.state));
|
||||
event->key.state));
|
||||
|
||||
if (!xkb_keymap_key_repeats (xkb_keymap, key))
|
||||
return;
|
||||
|
||||
@@ -730,7 +730,10 @@ gdk_wayland_display_finalize (GObject *object)
|
||||
|
||||
g_ptr_array_free (display_wayland->monitors, TRUE);
|
||||
|
||||
g_hash_table_destroy (display_wayland->settings);
|
||||
if (display_wayland->settings)
|
||||
g_hash_table_destroy (display_wayland->settings);
|
||||
|
||||
g_clear_object (&display_wayland->settings_portal);
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_display_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -1207,13 +1210,21 @@ open_shared_memory (void)
|
||||
#if defined (__NR_memfd_create)
|
||||
if (!force_shm_open)
|
||||
{
|
||||
ret = syscall (__NR_memfd_create, "gdk-wayland", MFD_CLOEXEC);
|
||||
int options = MFD_CLOEXEC;
|
||||
#if defined (MFD_ALLOW_SEALING)
|
||||
options |= MFD_ALLOW_SEALING;
|
||||
#endif
|
||||
ret = syscall (__NR_memfd_create, "gdk-wayland", options);
|
||||
|
||||
/* fall back to shm_open until debian stops shipping 3.16 kernel
|
||||
* See bug 766341
|
||||
*/
|
||||
if (ret < 0 && errno == ENOSYS)
|
||||
force_shm_open = TRUE;
|
||||
#if defined (F_ADD_SEALS) && defined (F_SEAL_SHRINK)
|
||||
if (ret >= 0)
|
||||
fcntl (ret, F_ADD_SEALS, F_SEAL_SHRINK);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1368,6 +1379,19 @@ typedef enum
|
||||
GSD_FONT_ANTIALIASING_MODE_RGBA
|
||||
} GsdFontAntialiasingMode;
|
||||
|
||||
static int
|
||||
get_antialiasing (const char *s)
|
||||
{
|
||||
const char *names[] = { "none", "grayscale", "rgba" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSD_FONT_HINTING_NONE,
|
||||
@@ -1376,6 +1400,19 @@ typedef enum
|
||||
GSD_FONT_HINTING_FULL
|
||||
} GsdFontHinting;
|
||||
|
||||
static int
|
||||
get_hinting (const char *s)
|
||||
{
|
||||
const char *names[] = { "none", "slight", "medium", "full" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSD_FONT_RGBA_ORDER_RGBA,
|
||||
@@ -1385,6 +1422,19 @@ typedef enum
|
||||
GSD_FONT_RGBA_ORDER_VBGR
|
||||
} GsdFontRgbaOrder;
|
||||
|
||||
static int
|
||||
get_order (const char *s)
|
||||
{
|
||||
const char *names[] = { "rgba", "rgb", "bgr", "vrgb", "vbgr" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_dpi_from_gsettings (GdkWaylandDisplay *display_wayland)
|
||||
{
|
||||
@@ -1401,6 +1451,26 @@ get_dpi_from_gsettings (GdkWaylandDisplay *display_wayland)
|
||||
return 96.0 * factor;
|
||||
}
|
||||
|
||||
/* When using the Settings portal, we cache the value in
|
||||
* the fallback member, and we ignore the valid field
|
||||
*/
|
||||
typedef struct _TranslationEntry TranslationEntry;
|
||||
struct _TranslationEntry {
|
||||
gboolean valid;
|
||||
const gchar *schema;
|
||||
const gchar *key;
|
||||
const gchar *setting;
|
||||
GType type;
|
||||
union {
|
||||
const char *s;
|
||||
gint i;
|
||||
gboolean b;
|
||||
} fallback;
|
||||
};
|
||||
|
||||
static TranslationEntry * find_translation_entry_by_schema (const char *schema,
|
||||
const char *key);
|
||||
|
||||
static void
|
||||
update_xft_settings (GdkDisplay *display)
|
||||
{
|
||||
@@ -1411,25 +1481,47 @@ update_xft_settings (GdkDisplay *display)
|
||||
GsdFontRgbaOrder order;
|
||||
gboolean use_rgba = FALSE;
|
||||
GsdXftSettings xft_settings;
|
||||
double dpi;
|
||||
|
||||
settings = g_hash_table_lookup (display_wayland->settings,
|
||||
"org.gnome.settings-daemon.plugins.xsettings");
|
||||
|
||||
if (settings)
|
||||
if (display_wayland->settings_portal)
|
||||
{
|
||||
antialiasing = g_settings_get_enum (settings, "antialiasing");
|
||||
hinting = g_settings_get_enum (settings, "hinting");
|
||||
order = g_settings_get_enum (settings, "rgba-order");
|
||||
TranslationEntry *entry;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "antialiasing");
|
||||
antialiasing = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "hinting");
|
||||
hinting = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "rgba-order");
|
||||
order = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "text-scaling-factor");
|
||||
dpi = 96.0 * entry->fallback.i / 65536.0 * 1024; /* Xft wants 1/1024th of an inch */
|
||||
}
|
||||
else
|
||||
{
|
||||
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
|
||||
hinting = GSD_FONT_HINTING_MEDIUM;
|
||||
order = GSD_FONT_RGBA_ORDER_RGB;
|
||||
settings = g_hash_table_lookup (display_wayland->settings,
|
||||
"org.gnome.settings-daemon.plugins.xsettings");
|
||||
|
||||
if (settings)
|
||||
{
|
||||
antialiasing = g_settings_get_enum (settings, "antialiasing");
|
||||
hinting = g_settings_get_enum (settings, "hinting");
|
||||
order = g_settings_get_enum (settings, "rgba-order");
|
||||
}
|
||||
else
|
||||
{
|
||||
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
|
||||
hinting = GSD_FONT_HINTING_MEDIUM;
|
||||
order = GSD_FONT_RGBA_ORDER_RGB;
|
||||
}
|
||||
|
||||
dpi = get_dpi_from_gsettings (display_wayland) * 1024;
|
||||
}
|
||||
|
||||
xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE);
|
||||
xft_settings.dpi = get_dpi_from_gsettings (display_wayland) * 1024; /* Xft wants 1/1024ths of an inch */
|
||||
xft_settings.dpi = dpi;
|
||||
|
||||
switch (hinting)
|
||||
{
|
||||
@@ -1516,23 +1608,6 @@ update_xft_settings (GdkDisplay *display)
|
||||
}
|
||||
}
|
||||
|
||||
#define WM_SETTINGS_SCHEMA "org.gnome.desktop.wm.preferences"
|
||||
#define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides"
|
||||
|
||||
typedef struct _TranslationEntry TranslationEntry;
|
||||
struct _TranslationEntry {
|
||||
gboolean valid;
|
||||
const gchar *schema;
|
||||
const gchar *key;
|
||||
const gchar *setting;
|
||||
GType type;
|
||||
union {
|
||||
const gchar *s;
|
||||
gint i;
|
||||
gboolean b;
|
||||
} fallback;
|
||||
};
|
||||
|
||||
static TranslationEntry translations[] = {
|
||||
{ FALSE, "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } },
|
||||
{ FALSE, "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } },
|
||||
@@ -1552,41 +1627,48 @@ static TranslationEntry translations[] = {
|
||||
{ FALSE, "org.gnome.desktop.sound", "input-feedback-sounds", "gtk-enable-input-feedback-sounds", G_TYPE_BOOLEAN, { . b = FALSE } },
|
||||
{ FALSE, "org.gnome.desktop.privacy", "recent-files-max-age", "gtk-recent-files-max-age", G_TYPE_INT, { .i = 30 } },
|
||||
{ FALSE, "org.gnome.desktop.privacy", "remember-recent-files", "gtk-recent-files-enabled", G_TYPE_BOOLEAN, { .b = TRUE } },
|
||||
{ FALSE, WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
|
||||
{ FALSE, CLASSIC_WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
|
||||
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 0 } },
|
||||
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 0 } },
|
||||
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 0 } },
|
||||
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } },
|
||||
{ FALSE, "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } },
|
||||
{ FALSE, "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } }, /* We store the factor as 16.16 */
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
|
||||
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } }
|
||||
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
|
||||
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_NONE, { .i = 0 } }
|
||||
};
|
||||
|
||||
|
||||
static TranslationEntry *
|
||||
find_translation_entry_by_key (GSettings *settings,
|
||||
const char *key)
|
||||
find_translation_entry_by_schema (const char *schema,
|
||||
const char *key)
|
||||
{
|
||||
guint i;
|
||||
char *schema;
|
||||
|
||||
g_object_get (settings, "schema", &schema, NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (translations); i++)
|
||||
{
|
||||
if (g_str_equal (schema, translations[i].schema) &&
|
||||
g_str_equal (key, translations[i].key))
|
||||
{
|
||||
g_free (schema);
|
||||
return &translations[i];
|
||||
}
|
||||
return &translations[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TranslationEntry *
|
||||
find_translation_entry_by_key (GSettings *settings,
|
||||
const char *key)
|
||||
{
|
||||
char *schema;
|
||||
TranslationEntry *entry;
|
||||
|
||||
g_object_get (settings, "schema", &schema, NULL);
|
||||
entry = find_translation_entry_by_schema (schema, key);
|
||||
g_free (schema);
|
||||
|
||||
return NULL;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static TranslationEntry *
|
||||
@@ -1621,6 +1703,79 @@ settings_changed (GSettings *settings,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
apply_portal_setting (TranslationEntry *entry,
|
||||
GVariant *value,
|
||||
GdkDisplay *display)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
entry->fallback.s = g_intern_string (g_variant_get_string (value, NULL));
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
entry->fallback.i = g_variant_get_int32 (value);
|
||||
break;
|
||||
case G_TYPE_BOOLEAN:
|
||||
entry->fallback.b = g_variant_get_boolean (value);
|
||||
break;
|
||||
case G_TYPE_NONE:
|
||||
if (strcmp (entry->key, "serial") == 0)
|
||||
{
|
||||
entry->fallback.i = g_variant_get_int32 (value);
|
||||
break;
|
||||
}
|
||||
if (strcmp (entry->key, "antialiasing") == 0)
|
||||
entry->fallback.i = get_antialiasing (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "hinting") == 0)
|
||||
entry->fallback.i = get_hinting (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "rgba-order") == 0)
|
||||
entry->fallback.i = get_order (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "text-scaling-factor") == 0)
|
||||
entry->fallback.i = (int) (g_variant_get_double (value) * 65536.0);
|
||||
update_xft_settings (display);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
settings_portal_changed (GDBusProxy *proxy,
|
||||
const char *sender_name,
|
||||
const char *signal_name,
|
||||
GVariant *parameters,
|
||||
GdkDisplay *display)
|
||||
{
|
||||
if (strcmp (signal_name, "SettingChanged") == 0)
|
||||
{
|
||||
const char *namespace;
|
||||
const char *name;
|
||||
GVariant *value;
|
||||
TranslationEntry *entry;
|
||||
|
||||
g_variant_get (parameters, "(&s&sv)", &namespace, &name, &value);
|
||||
|
||||
entry = find_translation_entry_by_schema (namespace, name);
|
||||
if (entry != NULL)
|
||||
{
|
||||
char *a = g_variant_print (value, FALSE);
|
||||
g_debug ("Using changed portal setting %s %s: %s", namespace, name, a);
|
||||
g_free (a);
|
||||
apply_portal_setting (entry, value, display);
|
||||
gdk_display_setting_changed (display, entry->setting);
|
||||
}
|
||||
else
|
||||
g_debug ("Ignoring portal setting %s %s", namespace, name);
|
||||
|
||||
g_variant_unref (value);
|
||||
}
|
||||
}
|
||||
|
||||
#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
|
||||
#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
|
||||
#define PORTAL_SETTINGS_INTERFACE "org.freedesktop.portal.Settings"
|
||||
|
||||
static void
|
||||
init_settings (GdkDisplay *display)
|
||||
{
|
||||
@@ -1630,6 +1785,86 @@ init_settings (GdkDisplay *display)
|
||||
GSettings *settings;
|
||||
gint i;
|
||||
|
||||
if (gdk_should_use_portal ())
|
||||
{
|
||||
GVariant *ret;
|
||||
GError *error = NULL;
|
||||
const char *schema;
|
||||
GVariant *val;
|
||||
GVariantIter *iter;
|
||||
const char *patterns[] = { "org.gnome.*", NULL };
|
||||
|
||||
display_wayland->settings_portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
PORTAL_BUS_NAME,
|
||||
PORTAL_OBJECT_PATH,
|
||||
PORTAL_SETTINGS_INTERFACE,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Settings portal not found: %s", error->message);
|
||||
g_error_free (error);
|
||||
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
ret = g_dbus_proxy_call_sync (display_wayland->settings_portal,
|
||||
"ReadAll",
|
||||
g_variant_new ("(^as)", patterns),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
G_MAXINT,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Failed to read portal settings: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_clear_object (&display_wayland->settings_portal);
|
||||
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
g_variant_get (ret, "(a{sa{sv}})", &iter);
|
||||
|
||||
while (g_variant_iter_loop (iter, "{s@a{sv}}", &schema, &val))
|
||||
{
|
||||
GVariantIter *iter2 = g_variant_iter_new (val);
|
||||
const char *key;
|
||||
GVariant *v;
|
||||
|
||||
while (g_variant_iter_loop (iter2, "{sv}", &key, &v))
|
||||
{
|
||||
TranslationEntry *entry = find_translation_entry_by_schema (schema, key);
|
||||
if (entry)
|
||||
{
|
||||
char *a = g_variant_print (v, FALSE);
|
||||
g_debug ("Using portal setting for %s %s: %s\n", schema, key, a);
|
||||
g_free (a);
|
||||
apply_portal_setting (entry, v, display);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Ignoring portal setting for %s %s", schema, key);
|
||||
}
|
||||
}
|
||||
g_variant_iter_free (iter2);
|
||||
}
|
||||
g_variant_iter_free (iter);
|
||||
|
||||
g_variant_unref (ret);
|
||||
|
||||
g_signal_connect (display_wayland->settings_portal, "g-signal",
|
||||
G_CALLBACK (settings_portal_changed), display_wayland);
|
||||
|
||||
return;
|
||||
|
||||
fallback:
|
||||
g_debug ("Failed to use Settings portal; falling back to gsettings");
|
||||
}
|
||||
|
||||
g_intern_static_string ("antialiasing");
|
||||
g_intern_static_string ("hinting");
|
||||
g_intern_static_string ("rgba-order");
|
||||
@@ -1701,6 +1936,43 @@ set_value_from_entry (GdkDisplay *display,
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
GSettings *settings;
|
||||
|
||||
if (display_wayland->settings_portal)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
g_value_set_string (value, entry->fallback.s);
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
g_value_set_int (value, entry->fallback.i);
|
||||
break;
|
||||
case G_TYPE_BOOLEAN:
|
||||
g_value_set_boolean (value, entry->fallback.b);
|
||||
break;
|
||||
case G_TYPE_NONE:
|
||||
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
||||
g_value_set_uint (value, (guint)entry->fallback.i);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-antialias"))
|
||||
g_value_set_int (value, display_wayland->xft_settings.antialias);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
|
||||
g_value_set_int (value, display_wayland->xft_settings.hinting);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-hintstyle"))
|
||||
g_value_set_static_string (value, display_wayland->xft_settings.hintstyle);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-rgba"))
|
||||
g_value_set_static_string (value, display_wayland->xft_settings.rgba);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-dpi"))
|
||||
g_value_set_int (value, display_wayland->xft_settings.dpi);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, entry->schema);
|
||||
switch (entry->type)
|
||||
{
|
||||
@@ -1728,7 +2000,9 @@ set_value_from_entry (GdkDisplay *display,
|
||||
: entry->fallback.b);
|
||||
break;
|
||||
case G_TYPE_NONE:
|
||||
if (g_str_equal (entry->setting, "gtk-xft-antialias"))
|
||||
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
||||
g_value_set_uint (value, (guint)entry->fallback.i);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-antialias"))
|
||||
g_value_set_int (value, display_wayland->xft_settings.antialias);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
|
||||
g_value_set_int (value, display_wayland->xft_settings.hinting);
|
||||
@@ -1753,18 +2027,14 @@ set_decoration_layout_from_entry (GdkDisplay *display,
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
GSettings *settings = NULL;
|
||||
const char *session;
|
||||
|
||||
/* Hack: until we get session-dependent defaults in GSettings,
|
||||
* swap out the usual schema for the "classic" one when
|
||||
* running in classic mode
|
||||
*/
|
||||
session = g_getenv ("XDG_CURRENT_DESKTOP");
|
||||
if (session && strstr (session, "GNOME-Classic"))
|
||||
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, CLASSIC_WM_SETTINGS_SCHEMA);
|
||||
if (display_wayland->settings_portal)
|
||||
{
|
||||
g_value_set_string (value, entry->fallback.s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings == NULL)
|
||||
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, WM_SETTINGS_SCHEMA);
|
||||
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings, entry->schema);
|
||||
|
||||
if (settings)
|
||||
{
|
||||
@@ -1800,7 +2070,8 @@ gdk_wayland_display_get_setting (GdkDisplay *display,
|
||||
{
|
||||
TranslationEntry *entry;
|
||||
|
||||
if (g_hash_table_size (GDK_WAYLAND_DISPLAY (display)->settings) == 0)
|
||||
if (GDK_WAYLAND_DISPLAY (display)->settings != NULL &&
|
||||
g_hash_table_size (GDK_WAYLAND_DISPLAY (display)->settings) == 0)
|
||||
return FALSE;
|
||||
|
||||
entry = find_translation_entry_by_setting (name);
|
||||
|
||||
@@ -77,6 +77,7 @@ struct _GdkWaylandDisplay
|
||||
|
||||
GHashTable *settings;
|
||||
GsdXftSettings xft_settings;
|
||||
GDBusProxy *settings_portal;
|
||||
|
||||
guint32 shell_capabilities;
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ gdk_wayland_gl_context_get_damage (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContext *shared;
|
||||
GdkWaylandGLContext *shared_wayland;
|
||||
|
||||
|
||||
shared = gdk_gl_context_get_shared_context (context);
|
||||
if (shared == NULL)
|
||||
shared = context;
|
||||
@@ -182,20 +182,29 @@ gdk_wayland_gl_context_get_damage (GdkGLContext *context)
|
||||
eglQuerySurface (display_wayland->egl_display, egl_surface,
|
||||
EGL_BUFFER_AGE_EXT, &buffer_age);
|
||||
|
||||
if (buffer_age == 2)
|
||||
switch (buffer_age)
|
||||
{
|
||||
if (context->old_updated_area[0])
|
||||
return cairo_region_copy (context->old_updated_area[0]);
|
||||
}
|
||||
else if (buffer_age == 3)
|
||||
{
|
||||
if (context->old_updated_area[0] &&
|
||||
context->old_updated_area[1])
|
||||
{
|
||||
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
|
||||
cairo_region_union (damage, context->old_updated_area[1]);
|
||||
return damage;
|
||||
}
|
||||
case 1:
|
||||
return cairo_region_create ();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (context->old_updated_area[0])
|
||||
return cairo_region_copy (context->old_updated_area[0]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (context->old_updated_area[0] &&
|
||||
context->old_updated_area[1])
|
||||
{
|
||||
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
|
||||
cairo_region_union (damage, context->old_updated_area[1]);
|
||||
return damage;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,6 @@ struct _GdkSurfaceImplWayland
|
||||
struct zxdg_popup_v6 *zxdg_popup_v6;
|
||||
|
||||
struct gtk_surface1 *gtk_surface;
|
||||
struct wl_subsurface *wl_subsurface;
|
||||
struct wl_egl_window *egl_window;
|
||||
struct wl_egl_window *dummy_egl_window;
|
||||
struct zxdg_exported_v1 *xdg_exported;
|
||||
@@ -218,8 +217,6 @@ static void gdk_wayland_surface_maybe_configure (GdkSurface *surface,
|
||||
static void maybe_set_gtk_surface_dbus_properties (GdkSurface *surface);
|
||||
static void maybe_set_gtk_surface_modal (GdkSurface *surface);
|
||||
|
||||
static void gdk_surface_request_transient_parent_commit (GdkSurface *surface);
|
||||
|
||||
static void gdk_wayland_surface_sync_margin (GdkSurface *surface);
|
||||
static void gdk_wayland_surface_sync_input_region (GdkSurface *surface);
|
||||
static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface);
|
||||
@@ -1030,31 +1027,6 @@ gdk_wayland_surface_sync_input_region (GdkSurface *surface)
|
||||
impl->input_region_dirty = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_set_input_region_if_empty (GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
GdkWaylandDisplay *display;
|
||||
struct wl_region *empty;
|
||||
|
||||
if (!impl->input_region_dirty)
|
||||
return;
|
||||
|
||||
if (impl->input_region == NULL)
|
||||
return;
|
||||
|
||||
if (!cairo_region_is_empty (impl->input_region))
|
||||
return;
|
||||
|
||||
display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
empty = wl_compositor_create_region (display->compositor);
|
||||
|
||||
wl_surface_set_input_region (impl->display_server.wl_surface, empty);
|
||||
wl_region_destroy (empty);
|
||||
|
||||
impl->input_region_dirty = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_enter (void *data,
|
||||
struct wl_surface *wl_surface,
|
||||
@@ -1093,61 +1065,6 @@ static const struct wl_surface_listener surface_listener = {
|
||||
surface_leave
|
||||
};
|
||||
|
||||
static void
|
||||
on_parent_surface_committed (GdkSurfaceImplWayland *parent_impl,
|
||||
GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
|
||||
g_signal_handler_disconnect (parent_impl,
|
||||
impl->parent_surface_committed_handler);
|
||||
impl->parent_surface_committed_handler = 0;
|
||||
|
||||
wl_subsurface_set_desync (impl->display_server.wl_subsurface);
|
||||
|
||||
/* Special case if the input region is empty, it won't change on resize */
|
||||
gdk_wayland_set_input_region_if_empty (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_create_subsurface (GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl, *parent_impl = NULL;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
|
||||
impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
|
||||
if (!impl->display_server.wl_surface)
|
||||
return; /* Bail out, surface and subsurface will be created later when shown */
|
||||
|
||||
if (impl->display_server.wl_subsurface)
|
||||
return;
|
||||
|
||||
if (impl->transient_for)
|
||||
parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
|
||||
|
||||
if (parent_impl && parent_impl->display_server.wl_surface)
|
||||
{
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
impl->display_server.wl_subsurface =
|
||||
wl_subcompositor_get_subsurface (display_wayland->subcompositor,
|
||||
impl->display_server.wl_surface, parent_impl->display_server.wl_surface);
|
||||
wl_subsurface_set_position (impl->display_server.wl_subsurface,
|
||||
surface->x + surface->abs_x,
|
||||
surface->y + surface->abs_y);
|
||||
|
||||
/* In order to synchronize the initial position with the initial frame
|
||||
* content, wait with making the subsurface desynchronized until after
|
||||
* the parent was committed.
|
||||
*/
|
||||
impl->parent_surface_committed_handler =
|
||||
g_signal_connect_object (parent_impl, "committed",
|
||||
G_CALLBACK (on_parent_surface_committed),
|
||||
surface, 0);
|
||||
gdk_surface_request_transient_parent_commit (surface);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_create_surface (GdkSurface *surface)
|
||||
{
|
||||
@@ -1515,7 +1432,9 @@ gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface)
|
||||
|
||||
impl->initial_fullscreen_output = NULL;
|
||||
|
||||
app_id = g_get_prgname ();
|
||||
app_id = impl->application.application_id;
|
||||
if (app_id == NULL)
|
||||
app_id = g_get_prgname ();
|
||||
|
||||
if (app_id == NULL)
|
||||
app_id = "GTK+ Application";
|
||||
@@ -1567,6 +1486,8 @@ gdk_wayland_surface_handle_configure_popup (GdkSurface *surface,
|
||||
&flipped_x,
|
||||
&flipped_y);
|
||||
|
||||
impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
|
||||
|
||||
g_signal_emit_by_name (surface,
|
||||
"moved-to-rect",
|
||||
&flipped_rect,
|
||||
@@ -1789,23 +1710,15 @@ get_real_parent_and_translate (GdkSurface *surface,
|
||||
|
||||
while (parent)
|
||||
{
|
||||
GdkSurfaceImplWayland *parent_impl =
|
||||
GDK_SURFACE_IMPL_WAYLAND (parent->impl);
|
||||
GdkSurface *effective_parent = gdk_surface_get_parent (parent);
|
||||
|
||||
if ((gdk_surface_has_native (parent) &&
|
||||
!parent_impl->display_server.wl_subsurface) ||
|
||||
!effective_parent)
|
||||
if (gdk_surface_has_native (parent) && !effective_parent)
|
||||
break;
|
||||
|
||||
*x += parent->x;
|
||||
*y += parent->y;
|
||||
|
||||
if (gdk_surface_has_native (parent) &&
|
||||
parent_impl->display_server.wl_subsurface)
|
||||
parent = parent->transient_for;
|
||||
else
|
||||
parent = effective_parent;
|
||||
parent = effective_parent;
|
||||
}
|
||||
|
||||
return parent;
|
||||
@@ -2465,38 +2378,9 @@ should_map_as_popup (GdkSurface *surface)
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_map_as_subsurface (GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
|
||||
if (GDK_SURFACE_TYPE (surface) == GDK_SURFACE_SUBSURFACE)
|
||||
if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
|
||||
return TRUE;
|
||||
|
||||
if (GDK_SURFACE_TYPE (surface) != GDK_SURFACE_TEMP)
|
||||
return FALSE;
|
||||
|
||||
/* if we want a popup, we do not want a subsurface */
|
||||
if (should_map_as_popup (surface))
|
||||
return FALSE;
|
||||
|
||||
if (impl->transient_for)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl_parent;
|
||||
|
||||
impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
|
||||
/* subsurface require that the parent is mapped */
|
||||
if (impl_parent->mapped)
|
||||
return TRUE;
|
||||
else
|
||||
g_warning ("Couldn't map surface %p as subsurface because its parent is not mapped.",
|
||||
surface);
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -2532,15 +2416,7 @@ gdk_wayland_surface_map (GdkSurface *surface)
|
||||
if (impl->mapped || impl->use_custom_surface)
|
||||
return;
|
||||
|
||||
if (should_map_as_subsurface (surface))
|
||||
{
|
||||
if (impl->transient_for)
|
||||
gdk_wayland_surface_create_subsurface (surface);
|
||||
else
|
||||
g_warning ("Couldn't map surface %p as susburface yet because it doesn't have a parent",
|
||||
surface);
|
||||
}
|
||||
else if (should_map_as_popup (surface))
|
||||
if (should_map_as_popup (surface))
|
||||
{
|
||||
gboolean create_fallback = FALSE;
|
||||
struct wl_seat *grab_input_seat;
|
||||
@@ -2641,26 +2517,6 @@ gdk_wayland_surface_show (GdkSurface *surface,
|
||||
gdk_wayland_surface_map (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_subsurface (GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
GdkSurfaceImplWayland *parent_impl;
|
||||
|
||||
g_return_if_fail (impl->display_server.wl_subsurface);
|
||||
g_return_if_fail (impl->transient_for);
|
||||
|
||||
parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
|
||||
wl_subsurface_destroy (impl->display_server.wl_subsurface);
|
||||
if (impl->parent_surface_committed_handler)
|
||||
{
|
||||
g_signal_handler_disconnect (parent_impl,
|
||||
impl->parent_surface_committed_handler);
|
||||
impl->parent_surface_committed_handler = 0;
|
||||
}
|
||||
impl->display_server.wl_subsurface = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_popups_for_surface (GdkSurface *surface)
|
||||
{
|
||||
@@ -2761,9 +2617,6 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
|
||||
impl->initial_configure_received = FALSE;
|
||||
}
|
||||
|
||||
if (impl->display_server.wl_subsurface)
|
||||
unmap_subsurface (surface);
|
||||
|
||||
if (impl->awaiting_frame)
|
||||
{
|
||||
GdkFrameClock *frame_clock;
|
||||
@@ -2837,32 +2690,6 @@ gdk_surface_wayland_restack_toplevel (GdkSurface *surface,
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_surface_request_transient_parent_commit (GdkSurface *surface)
|
||||
{
|
||||
GdkSurfaceImplWayland *surface_impl, *impl;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
surface_impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
|
||||
if (!surface_impl->transient_for)
|
||||
return;
|
||||
|
||||
impl = GDK_SURFACE_IMPL_WAYLAND (surface_impl->transient_for->impl);
|
||||
|
||||
if (!impl->display_server.wl_surface || impl->pending_commit)
|
||||
return;
|
||||
|
||||
frame_clock = gdk_surface_get_frame_clock (surface_impl->transient_for);
|
||||
|
||||
if (!frame_clock)
|
||||
return;
|
||||
|
||||
impl->pending_commit = TRUE;
|
||||
gdk_frame_clock_request_phase (frame_clock,
|
||||
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_surface_wayland_move_resize (GdkSurface *surface,
|
||||
gboolean with_move,
|
||||
@@ -2881,14 +2708,6 @@ gdk_surface_wayland_move_resize (GdkSurface *surface,
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
impl->position_method = POSITION_METHOD_MOVE_RESIZE;
|
||||
|
||||
if (impl->display_server.wl_subsurface)
|
||||
{
|
||||
wl_subsurface_set_position (impl->display_server.wl_subsurface,
|
||||
surface->x + surface->abs_x,
|
||||
surface->y + surface->abs_y);
|
||||
gdk_surface_request_transient_parent_commit (surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3414,9 +3233,6 @@ gdk_wayland_surface_set_transient_for (GdkSurface *surface,
|
||||
|
||||
unset_transient_for_exported (surface);
|
||||
|
||||
if (impl->display_server.wl_subsurface)
|
||||
unmap_subsurface (surface);
|
||||
|
||||
previous_parent = impl->transient_for;
|
||||
impl->transient_for = parent;
|
||||
|
||||
@@ -3429,9 +3245,6 @@ gdk_wayland_surface_set_transient_for (GdkSurface *surface,
|
||||
g_list_remove (display_wayland->orphan_dialogs, surface);
|
||||
}
|
||||
gdk_wayland_surface_sync_parent (surface, NULL);
|
||||
if (should_map_as_subsurface (surface) &&
|
||||
parent && gdk_surface_is_visible (surface))
|
||||
gdk_wayland_surface_create_subsurface (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4098,34 +3911,6 @@ _gdk_wayland_surface_set_grab_seat (GdkSurface *surface,
|
||||
impl->grab_input_seat = seat;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_wayland_surface_new_subsurface: (constructor)
|
||||
* @display: the display to create the surface on
|
||||
* @position: position relative to the transient surface
|
||||
*
|
||||
* Creates a new subsurface surface.
|
||||
*
|
||||
* Returns: (transfer full): the new #GdkSurface
|
||||
**/
|
||||
GdkSurface *
|
||||
gdk_wayland_surface_new_subsurface (GdkDisplay *display,
|
||||
const GdkRectangle *position)
|
||||
{
|
||||
GdkSurfaceAttr attr;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
||||
g_return_val_if_fail (position != NULL, NULL);
|
||||
|
||||
attr.wclass = GDK_INPUT_OUTPUT;
|
||||
attr.x = position->x;
|
||||
attr.y = position->y;
|
||||
attr.width = position->width;
|
||||
attr.height = position->height;
|
||||
attr.surface_type = GDK_SURFACE_SUBSURFACE;
|
||||
|
||||
return gdk_surface_new (display, NULL, &attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_wayland_surface_get_wl_surface:
|
||||
* @surface: (type GdkWaylandSurface): a #GdkSurface
|
||||
@@ -4533,8 +4318,7 @@ gdk_wayland_surface_set_transient_for_exported (GdkSurface *surface,
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), FALSE);
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
|
||||
g_return_val_if_fail (!should_map_as_subsurface (surface) &&
|
||||
!should_map_as_popup (surface), FALSE);
|
||||
g_return_val_if_fail (!should_map_as_popup (surface), FALSE);
|
||||
|
||||
impl = GDK_SURFACE_IMPL_WAYLAND (surface->impl);
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
@@ -1655,7 +1655,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
|
||||
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_PNG);
|
||||
@@ -1665,14 +1665,10 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.w32format = CF_DIB;
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG);
|
||||
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_JPEG);
|
||||
@@ -1682,17 +1678,10 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.w32format = CF_DIB;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF);
|
||||
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_IMAGE_GIF);
|
||||
@@ -1702,13 +1691,6 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.w32format = CF_DIB;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_w32formats, (gpointer) fmt.contentformat, comp);
|
||||
|
||||
|
||||
@@ -1771,7 +1753,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (CF_UNICODETEXT), comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG);
|
||||
fmt.transmute = FALSE;
|
||||
|
||||
@@ -1781,14 +1763,10 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_PNG)), comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF);
|
||||
fmt.transmute = FALSE;
|
||||
|
||||
@@ -1798,17 +1776,10 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_JPEG);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_JFIF)), comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 4);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF);
|
||||
fmt.transmute = FALSE;
|
||||
|
||||
@@ -1818,17 +1789,10 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_GIF);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_PNG);
|
||||
fmt.transmute = TRUE;
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
fmt.contentformat = _gdk_atom_array_index (atoms, GDK_WIN32_ATOM_INDEX_IMAGE_BMP);
|
||||
g_array_append_val (comp, fmt);
|
||||
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (_gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_GIF)), comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.w32format = CF_DIB;
|
||||
fmt.transmute = FALSE;
|
||||
|
||||
@@ -1842,7 +1806,7 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop)
|
||||
g_hash_table_replace (win32_clipdrop->compatibility_contentformats, GINT_TO_POINTER (CF_DIB), comp);
|
||||
|
||||
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 3);
|
||||
comp = g_array_sized_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair), 2);
|
||||
fmt.w32format = _gdk_cf_array_index (cfs, GDK_WIN32_CF_INDEX_CFSTR_SHELLIDLIST);
|
||||
fmt.transmute = FALSE;
|
||||
|
||||
|
||||
+32
-90
@@ -738,8 +738,6 @@ build_wm_ime_composition_event (GdkEvent *event,
|
||||
build_key_event_state (event, key_state);
|
||||
|
||||
event->key.hardware_keycode = 0; /* FIXME: What should it be? */
|
||||
event->key.string = NULL;
|
||||
event->key.length = 0;
|
||||
event->key.keyval = gdk_unicode_to_keyval (wc);
|
||||
}
|
||||
|
||||
@@ -768,7 +766,7 @@ print_event_state (guint state)
|
||||
void
|
||||
_gdk_win32_print_event (const GdkEvent *event)
|
||||
{
|
||||
gchar *escaped, *kvname;
|
||||
gchar *kvname;
|
||||
|
||||
g_print ("%s%*s===> ", (debug_indent > 0 ? "\n" : ""), debug_indent, "");
|
||||
switch (event->any.type)
|
||||
@@ -819,17 +817,10 @@ _gdk_win32_print_event (const GdkEvent *event)
|
||||
break;
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
if (event->key.length == 0)
|
||||
escaped = g_strdup ("");
|
||||
else
|
||||
escaped = g_strescape (event->key.string, NULL);
|
||||
kvname = gdk_keyval_name (event->key.keyval);
|
||||
g_print ("%#.02x group:%d %s %d:\"%s\" ",
|
||||
g_print ("%#.02x group:%d %s",
|
||||
event->key.hardware_keycode, event->key.group,
|
||||
(kvname ? kvname : "??"),
|
||||
event->key.length,
|
||||
escaped);
|
||||
g_free (escaped);
|
||||
(kvname ? kvname : "??"));
|
||||
print_event_state (event->key.state);
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
@@ -940,73 +931,6 @@ _gdk_win32_append_event (GdkEvent *event)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
fill_key_event_string (GdkEvent *event)
|
||||
{
|
||||
gunichar c;
|
||||
gchar buf[256];
|
||||
|
||||
/* Fill in event->string crudely, since various programs
|
||||
* depend on it.
|
||||
*/
|
||||
|
||||
c = 0;
|
||||
if (event->key.keyval != GDK_KEY_VoidSymbol)
|
||||
c = gdk_keyval_to_unicode (event->key.keyval);
|
||||
|
||||
if (c)
|
||||
{
|
||||
gsize bytes_written;
|
||||
gint len;
|
||||
|
||||
/* Apply the control key - Taken from Xlib
|
||||
*/
|
||||
if (event->key.state & GDK_CONTROL_MASK)
|
||||
{
|
||||
if ((c >= '@' && c < '\177') || c == ' ')
|
||||
c &= 0x1F;
|
||||
else if (c == '2')
|
||||
{
|
||||
event->key.string = g_memdup ("\0\0", 2);
|
||||
event->key.length = 1;
|
||||
return;
|
||||
}
|
||||
else if (c >= '3' && c <= '7')
|
||||
c -= ('3' - '\033');
|
||||
else if (c == '8')
|
||||
c = '\177';
|
||||
else if (c == '/')
|
||||
c = '_' & 0x1F;
|
||||
}
|
||||
|
||||
len = g_unichar_to_utf8 (c, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
event->key.string = g_locale_from_utf8 (buf, len,
|
||||
NULL, &bytes_written,
|
||||
NULL);
|
||||
if (event->key.string)
|
||||
event->key.length = bytes_written;
|
||||
}
|
||||
else if (event->key.keyval == GDK_KEY_Escape)
|
||||
{
|
||||
event->key.length = 1;
|
||||
event->key.string = g_strdup ("\033");
|
||||
}
|
||||
else if (event->key.keyval == GDK_KEY_Return ||
|
||||
event->key.keyval == GDK_KEY_KP_Enter)
|
||||
{
|
||||
event->key.length = 1;
|
||||
event->key.string = g_strdup ("\r");
|
||||
}
|
||||
|
||||
if (!event->key.string)
|
||||
{
|
||||
event->key.length = 0;
|
||||
event->key.string = g_strdup ("");
|
||||
}
|
||||
}
|
||||
|
||||
static GdkWin32MessageFilterReturn
|
||||
apply_message_filters (GdkDisplay *display,
|
||||
MSG *msg,
|
||||
@@ -1777,7 +1701,7 @@ ensure_stacking_on_unminimize (MSG *msg)
|
||||
g_print (" restacking %p above %p",
|
||||
msg->hwnd, lowest_transient));
|
||||
SetWindowPos (msg->hwnd, lowest_transient, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1858,7 +1782,7 @@ ensure_stacking_on_activate_app (MSG *msg,
|
||||
impl->transient_owner != NULL)
|
||||
{
|
||||
SetWindowPos (msg->hwnd, HWND_TOP, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1900,7 +1824,7 @@ ensure_stacking_on_activate_app (MSG *msg,
|
||||
g_print (" restacking %p above %p",
|
||||
msg->hwnd, rover));
|
||||
SetWindowPos (msg->hwnd, rover, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2200,6 +2124,7 @@ gdk_event_translate (MSG *msg,
|
||||
(gulong) msg->wParam,
|
||||
(gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
|
||||
_gdk_input_codepage));
|
||||
gdk_display_setting_changed (display, "gtk-im-module");
|
||||
break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
@@ -2288,8 +2213,6 @@ gdk_event_translate (MSG *msg,
|
||||
event->any.surface = window;
|
||||
event->key.time = _gdk_win32_get_next_tick (msg->time);
|
||||
event->key.keyval = GDK_KEY_VoidSymbol;
|
||||
event->key.string = NULL;
|
||||
event->key.length = 0;
|
||||
event->key.hardware_keycode = msg->wParam;
|
||||
/* save original scancode */
|
||||
gdk_event_set_scancode (event, msg->lParam >> 16);
|
||||
@@ -2360,8 +2283,6 @@ gdk_event_translate (MSG *msg,
|
||||
else
|
||||
impl->leading_surrogate_keyup = 0;
|
||||
|
||||
fill_key_event_string (event);
|
||||
|
||||
/* Only one release key event is fired when both shift keys are pressed together
|
||||
and then released. In order to send the missing event, press events for shift
|
||||
keys are recorded and sent together when the release event occurs.
|
||||
@@ -2792,13 +2713,20 @@ gdk_event_translate (MSG *msg,
|
||||
|
||||
event = gdk_event_new (GDK_SCROLL);
|
||||
event->any.surface = window;
|
||||
event->scroll.direction = GDK_SCROLL_SMOOTH;
|
||||
|
||||
if (msg->message == WM_MOUSEWHEEL)
|
||||
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
|
||||
GDK_SCROLL_UP : GDK_SCROLL_DOWN;
|
||||
{
|
||||
event->scroll.delta_y = (gdouble) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (gdouble) WHEEL_DELTA;
|
||||
}
|
||||
else if (msg->message == WM_MOUSEHWHEEL)
|
||||
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
|
||||
GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
|
||||
{
|
||||
event->scroll.delta_x = (gdouble) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (gdouble) WHEEL_DELTA;
|
||||
}
|
||||
/* Positive delta scrolls up, not down,
|
||||
see API documentation for WM_MOUSEWHEEL message.
|
||||
*/
|
||||
event->scroll.delta_y *= -1.0;
|
||||
event->scroll.time = _gdk_win32_get_next_tick (msg->time);
|
||||
event->scroll.x = (gint16) point.x / impl->surface_scale;
|
||||
event->scroll.y = (gint16) point.y / impl->surface_scale;
|
||||
@@ -2807,6 +2735,20 @@ gdk_event_translate (MSG *msg,
|
||||
event->scroll.state = build_pointer_event_state (msg);
|
||||
gdk_event_set_device (event, device_manager_win32->core_pointer);
|
||||
gdk_event_set_source_device (event, device_manager_win32->system_pointer);
|
||||
gdk_event_set_pointer_emulated (event, FALSE);
|
||||
|
||||
_gdk_win32_append_event (gdk_event_copy (event));
|
||||
|
||||
/* Append the discrete version too */
|
||||
if (msg->message == WM_MOUSEWHEEL)
|
||||
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
|
||||
GDK_SCROLL_UP : GDK_SCROLL_DOWN;
|
||||
else if (msg->message == WM_MOUSEHWHEEL)
|
||||
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
|
||||
GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
|
||||
event->scroll.delta_x = 0;
|
||||
event->scroll.delta_y = 0;
|
||||
gdk_event_set_pointer_emulated (event, TRUE);
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ gdk_win32_hdata_output_stream_close (GOutputStream *output_stream,
|
||||
if (priv->handle_is_buffer)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
_("Can't transmute a single handle"));
|
||||
_("Can’t transmute a single handle"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,39 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <pango/pangowin32.h>
|
||||
|
||||
#include "gdkproperty.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkprivate-win32.h"
|
||||
#include "gdkwin32.h"
|
||||
|
||||
static gchar*
|
||||
_get_system_font_name (HDC hdc)
|
||||
{
|
||||
NONCLIENTMETRICSW ncm;
|
||||
PangoFontDescription *font_desc;
|
||||
gchar *result, *font_desc_string;
|
||||
int logpixelsy;
|
||||
gint font_size;
|
||||
|
||||
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
|
||||
if (!SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
|
||||
return NULL;
|
||||
|
||||
logpixelsy = GetDeviceCaps (hdc, LOGPIXELSY);
|
||||
font_desc = pango_win32_font_description_from_logfontw (&ncm.lfMessageFont);
|
||||
font_desc_string = pango_font_description_to_string (font_desc);
|
||||
pango_font_description_free (font_desc);
|
||||
|
||||
/* https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-taglogfonta */
|
||||
font_size = -MulDiv (ncm.lfMessageFont.lfHeight, 72, logpixelsy);
|
||||
result = g_strdup_printf ("%s %d", font_desc_string, font_size);
|
||||
g_free (font_desc_string);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
For reference, from gdk/x11/gdksettings.c:
|
||||
|
||||
@@ -124,61 +151,75 @@ _gdk_win32_get_setting (const gchar *name,
|
||||
g_value_set_boolean (value, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp ("gtk-xft-hinting", name) == 0)
|
||||
{
|
||||
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : 1\n", name));
|
||||
g_value_set_int (value, 1);
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp ("gtk-xft-antialias", name) == 0)
|
||||
{
|
||||
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : 1\n", name));
|
||||
g_value_set_int (value, 1);
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp ("gtk-xft-hintstyle", name) == 0)
|
||||
{
|
||||
g_value_set_static_string (value, "hintfull");
|
||||
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : %s\n", name, g_value_get_string (value)));
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp ("gtk-xft-rgba", name) == 0)
|
||||
{
|
||||
unsigned int orientation = 0;
|
||||
if (SystemParametersInfoW (SPI_GETFONTSMOOTHINGORIENTATION, 0, &orientation, 0))
|
||||
{
|
||||
if (orientation == FE_FONTSMOOTHINGORIENTATIONRGB)
|
||||
g_value_set_static_string (value, "rgb");
|
||||
else if (orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
|
||||
g_value_set_static_string (value, "bgr");
|
||||
else
|
||||
g_value_set_static_string (value, "none");
|
||||
}
|
||||
else
|
||||
g_value_set_static_string (value, "none");
|
||||
|
||||
GDK_NOTE(MISC, g_print ("gdk_screen_get_setting(\"%s\") : %s\n", name, g_value_get_string (value)));
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp ("gtk-font-name", name) == 0)
|
||||
{
|
||||
NONCLIENTMETRICS ncm;
|
||||
CPINFOEX cpinfoex_default, cpinfoex_curr_thread;
|
||||
OSVERSIONINFO info;
|
||||
BOOL result_default, result_curr_thread;
|
||||
gchar *font_name = _get_system_font_name (_gdk_display_hdc);
|
||||
|
||||
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
||||
|
||||
/* TODO: Fallback to using Pango on Windows 8 and later,
|
||||
* as this method of handling gtk-font-name does not work
|
||||
* well there, where garbled text will be displayed for texts
|
||||
* that are not supported by the default menu font. Look for
|
||||
* whether there is a better solution for this on Windows 8 and
|
||||
* later
|
||||
*/
|
||||
if (!GetVersionEx (&info) ||
|
||||
info.dwMajorVersion > 6 ||
|
||||
(info.dwMajorVersion == 6 && info.dwMinorVersion >= 2))
|
||||
return FALSE;
|
||||
|
||||
/* check whether the system default ANSI codepage matches the
|
||||
* ANSI code page of the running thread. If so, continue, otherwise
|
||||
* fall back to using Pango to handle gtk-font-name
|
||||
*/
|
||||
result_default = GetCPInfoEx (CP_ACP, 0, &cpinfoex_default);
|
||||
result_curr_thread = GetCPInfoEx (CP_THREAD_ACP, 0, &cpinfoex_curr_thread);
|
||||
|
||||
if (!result_default ||
|
||||
!result_curr_thread ||
|
||||
cpinfoex_default.CodePage != cpinfoex_curr_thread.CodePage)
|
||||
return FALSE;
|
||||
|
||||
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
||||
if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
|
||||
if (font_name)
|
||||
{
|
||||
/* Pango finally uses GetDeviceCaps to scale, we use simple
|
||||
* approximation here.
|
||||
*/
|
||||
int nHeight = (0 > ncm.lfMenuFont.lfHeight ? - 3 * ncm.lfMenuFont.lfHeight / 4 : 10);
|
||||
if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
|
||||
GDK_NOTE(MISC, g_print("gdk_display_get_setting(%s) : ignoring bitmap font '%s'\n",
|
||||
name, ncm.lfMenuFont.lfFaceName));
|
||||
else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
|
||||
/* Avoid issues like those described in bug #135098 */
|
||||
g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
|
||||
/* The pango font fallback list got fixed during 1.43, before that
|
||||
* using anything but "Segoe UI" would lead to a poor glyph coverage */
|
||||
if (pango_version_check (1, 43, 0) != NULL &&
|
||||
g_ascii_strncasecmp (font_name, "Segoe UI", strlen ("Segoe UI")) != 0)
|
||||
{
|
||||
char *s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);
|
||||
GDK_NOTE(MISC, g_print("gdk_display_get_setting(%s) : %s\n", name, s));
|
||||
g_value_set_string (value, s);
|
||||
|
||||
g_free(s);
|
||||
return TRUE;
|
||||
g_free (font_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %s\n", name, font_name));
|
||||
g_value_take_string (value, font_name);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("gdk_screen_get_setting: Detecting the system font failed");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (strcmp ("gtk-im-module", name) == 0)
|
||||
{
|
||||
if (_gdk_input_locale_is_ime)
|
||||
g_value_set_string (value, "ime");
|
||||
else
|
||||
g_value_set_string (value, "");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
@@ -760,17 +760,11 @@ gdk_win32_surface_destroy (GdkSurface *window,
|
||||
_gdk_remove_modal_window (window);
|
||||
|
||||
/* Remove all our transient children */
|
||||
tmp = surface_impl->transient_children;
|
||||
while (tmp != NULL)
|
||||
while (surface_impl->transient_children != NULL)
|
||||
{
|
||||
GdkSurface *child = tmp->data;
|
||||
GdkSurfaceImplWin32 *child_impl = GDK_SURFACE_IMPL_WIN32 (GDK_SURFACE (child)->impl);
|
||||
|
||||
child_impl->transient_owner = NULL;
|
||||
tmp = tmp->next;
|
||||
GdkSurface *child = surface_impl->transient_children->data;
|
||||
gdk_surface_set_transient_for (child, NULL);
|
||||
}
|
||||
g_slist_free (surface_impl->transient_children);
|
||||
surface_impl->transient_children = NULL;
|
||||
|
||||
/* Remove ourself from our transient owner */
|
||||
if (surface_impl->transient_owner != NULL)
|
||||
@@ -1124,7 +1118,7 @@ show_window_internal (GdkSurface *window,
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
(window->state & GDK_SURFACE_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,7 +1376,7 @@ gdk_win32_surface_raise (GdkSurface *window)
|
||||
if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
|
||||
else if (window->accept_focus)
|
||||
/* Do not wrap this in an API_CALL macro as SetForegroundWindow might
|
||||
* fail when for example dragging a window belonging to a different
|
||||
@@ -1392,7 +1386,7 @@ gdk_win32_surface_raise (GdkSurface *window)
|
||||
else
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1409,7 +1403,7 @@ gdk_win32_surface_lower (GdkSurface *window)
|
||||
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_BOTTOM,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1672,27 +1666,29 @@ gdk_win32_surface_set_transient_for (GdkSurface *window,
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent == NULL)
|
||||
if (surface_impl->transient_owner == parent)
|
||||
return;
|
||||
|
||||
if (GDK_IS_SURFACE (surface_impl->transient_owner))
|
||||
{
|
||||
GdkSurfaceImplWin32 *trans_impl = GDK_SURFACE_IMPL_WIN32 (surface_impl->transient_owner->impl);
|
||||
if (trans_impl->transient_children != NULL)
|
||||
{
|
||||
item = g_slist_find (trans_impl->transient_children, window);
|
||||
item->data = NULL;
|
||||
trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
|
||||
trans_impl->num_transients--;
|
||||
item = g_slist_find (trans_impl->transient_children, window);
|
||||
item->data = NULL;
|
||||
trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
|
||||
trans_impl->num_transients--;
|
||||
|
||||
if (!trans_impl->num_transients)
|
||||
{
|
||||
trans_impl->transient_children = NULL;
|
||||
}
|
||||
if (!trans_impl->num_transients)
|
||||
{
|
||||
trans_impl->transient_children = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (G_OBJECT (surface_impl->transient_owner));
|
||||
g_object_unref (G_OBJECT (window));
|
||||
|
||||
surface_impl->transient_owner = NULL;
|
||||
}
|
||||
else
|
||||
|
||||
if (parent)
|
||||
{
|
||||
parent_impl = GDK_SURFACE_IMPL_WIN32 (parent->impl);
|
||||
|
||||
@@ -2317,7 +2313,7 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
|
||||
rect.right += after.right - before.right;
|
||||
rect.bottom += after.bottom - before.bottom;
|
||||
|
||||
flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION;
|
||||
flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOOWNERZORDER;
|
||||
|
||||
if (will_be_topmost && !was_topmost)
|
||||
{
|
||||
@@ -4771,7 +4767,7 @@ gdk_win32_surface_fullscreen (GdkSurface *window)
|
||||
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
|
||||
x, y, width, height,
|
||||
SWP_NOCOPYBITS | SWP_SHOWWINDOW));
|
||||
SWP_NOCOPYBITS | SWP_SHOWWINDOW | SWP_NOOWNERZORDER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4794,7 +4790,7 @@ gdk_win32_surface_unfullscreen (GdkSurface *window)
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST,
|
||||
fi->r.left, fi->r.top,
|
||||
fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
|
||||
SWP_NOCOPYBITS | SWP_SHOWWINDOW));
|
||||
SWP_NOCOPYBITS | SWP_SHOWWINDOW | SWP_NOOWNERZORDER));
|
||||
|
||||
g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
|
||||
g_free (fi);
|
||||
@@ -4820,7 +4816,7 @@ gdk_win32_surface_set_keep_above (GdkSurface *window,
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
setting ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
|
||||
}
|
||||
|
||||
gdk_synthesize_surface_state (window,
|
||||
@@ -4846,7 +4842,7 @@ gdk_win32_surface_set_keep_below (GdkSurface *window,
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
setting ? HWND_BOTTOM : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER));
|
||||
}
|
||||
|
||||
gdk_synthesize_surface_state (window,
|
||||
|
||||
@@ -45,6 +45,7 @@ install_headers(gdk_win32_public_headers, subdir: 'gtk-4.0/gdk/win32/')
|
||||
install_headers('gdkwin32.h', subdir: 'gtk-4.0/gdk/')
|
||||
|
||||
gdk_win32_deps = [ # FIXME
|
||||
pangowin32_dep
|
||||
]
|
||||
|
||||
libgdk_win32 = static_library('gdk-win32',
|
||||
|
||||
@@ -261,7 +261,7 @@ gdk_x11_cursor_create_for_name (GdkDisplay *display,
|
||||
/**
|
||||
* gdk_x11_display_set_cursor_theme:
|
||||
* @display: (type GdkX11Display): a #GdkDisplay
|
||||
* @theme: the name of the cursor theme to use, or %NULL to unset
|
||||
* @theme: (nullable): the name of the cursor theme to use, or %NULL to unset
|
||||
* a previously set value
|
||||
* @size: the cursor size to use, or 0 to keep the previous size
|
||||
*
|
||||
|
||||
@@ -221,8 +221,6 @@ translate_key_event (GdkDisplay *display,
|
||||
|
||||
event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
|
||||
|
||||
_gdk_x11_event_translate_keyboard_string (&event->key);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (display, EVENTS))
|
||||
{
|
||||
@@ -231,10 +229,6 @@ translate_key_event (GdkDisplay *display,
|
||||
xevent->xkey.window,
|
||||
event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
|
||||
event->key.keyval);
|
||||
|
||||
if (event->key.length > 0)
|
||||
g_message ("\t\tlength: %4d string: \"%s\"",
|
||||
event->key.length, event->key.string);
|
||||
}
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
return;
|
||||
@@ -724,70 +718,6 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
|
||||
return return_val;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_x11_event_translate_keyboard_string (GdkEventKey *event)
|
||||
{
|
||||
gunichar c = 0;
|
||||
gchar buf[7];
|
||||
|
||||
/* Fill in event->string crudely, since various programs
|
||||
* depend on it.
|
||||
*/
|
||||
event->string = NULL;
|
||||
|
||||
if (event->keyval != GDK_KEY_VoidSymbol)
|
||||
c = gdk_keyval_to_unicode (event->keyval);
|
||||
|
||||
if (c)
|
||||
{
|
||||
gsize bytes_written;
|
||||
gint len;
|
||||
|
||||
/* Apply the control key - Taken from Xlib
|
||||
*/
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
|
||||
else if (c == '2')
|
||||
{
|
||||
event->string = g_memdup ("\0\0", 2);
|
||||
event->length = 1;
|
||||
buf[0] = '\0';
|
||||
return;
|
||||
}
|
||||
else if (c >= '3' && c <= '7') c -= ('3' - '\033');
|
||||
else if (c == '8') c = '\177';
|
||||
else if (c == '/') c = '_' & 0x1F;
|
||||
}
|
||||
|
||||
len = g_unichar_to_utf8 (c, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
event->string = g_locale_from_utf8 (buf, len,
|
||||
NULL, &bytes_written,
|
||||
NULL);
|
||||
if (event->string)
|
||||
event->length = bytes_written;
|
||||
}
|
||||
else if (event->keyval == GDK_KEY_Escape)
|
||||
{
|
||||
event->length = 1;
|
||||
event->string = g_strdup ("\033");
|
||||
}
|
||||
else if (event->keyval == GDK_KEY_Return ||
|
||||
event->keyval == GDK_KEY_KP_Enter)
|
||||
{
|
||||
event->length = 1;
|
||||
event->string = g_strdup ("\r");
|
||||
}
|
||||
|
||||
if (!event->string)
|
||||
{
|
||||
event->length = 0;
|
||||
event->string = g_strdup ("");
|
||||
}
|
||||
}
|
||||
|
||||
/* We only care about focus events that indicate that _this_
|
||||
* surface (not a ancestor or child) got or lost the focus
|
||||
*/
|
||||
|
||||
@@ -40,6 +40,23 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const char *wacom_type_atoms[] = {
|
||||
"STYLUS",
|
||||
"CURSOR",
|
||||
"ERASER",
|
||||
"PAD",
|
||||
"TOUCH"
|
||||
};
|
||||
#define N_WACOM_TYPE_ATOMS G_N_ELEMENTS (wacom_type_atoms)
|
||||
|
||||
enum {
|
||||
WACOM_TYPE_STYLUS,
|
||||
WACOM_TYPE_CURSOR,
|
||||
WACOM_TYPE_ERASER,
|
||||
WACOM_TYPE_PAD,
|
||||
WACOM_TYPE_TOUCH,
|
||||
};
|
||||
|
||||
struct _GdkX11DeviceManagerXI2
|
||||
{
|
||||
GdkX11DeviceManagerCore parent_object;
|
||||
@@ -999,6 +1016,66 @@ device_get_tool_serial_and_id (GdkDevice *device,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkDeviceToolType
|
||||
device_get_tool_type (GdkDevice *device)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
gulong nitems, bytes_after;
|
||||
guint32 *data;
|
||||
int rc, format;
|
||||
Atom type;
|
||||
Atom device_type;
|
||||
Atom types[N_WACOM_TYPE_ATOMS];
|
||||
GdkDeviceToolType tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
|
||||
display = gdk_device_get_display (device);
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
|
||||
gdk_x11_device_get_id (device),
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "Wacom Tool Type"),
|
||||
0, 1, False, XA_ATOM, &type, &format, &nitems, &bytes_after,
|
||||
(guchar **) &data);
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
if (rc != Success)
|
||||
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
|
||||
if (type != XA_ATOM || format != 32 || nitems != 1)
|
||||
{
|
||||
XFree (data);
|
||||
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
device_type = *data;
|
||||
XFree (data);
|
||||
|
||||
if (device_type == 0)
|
||||
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
rc = XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
|
||||
(char **) wacom_type_atoms,
|
||||
N_WACOM_TYPE_ATOMS,
|
||||
False,
|
||||
types);
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
if (rc == 0)
|
||||
return GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
|
||||
if (device_type == types[WACOM_TYPE_STYLUS])
|
||||
tool_type = GDK_DEVICE_TOOL_TYPE_PEN;
|
||||
else if (device_type == types[WACOM_TYPE_CURSOR])
|
||||
tool_type = GDK_DEVICE_TOOL_TYPE_MOUSE;
|
||||
else if (device_type == types[WACOM_TYPE_ERASER])
|
||||
tool_type = GDK_DEVICE_TOOL_TYPE_ERASER;
|
||||
else if (device_type == types[WACOM_TYPE_TOUCH])
|
||||
tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
|
||||
|
||||
return tool_type;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_property_change (GdkX11DeviceManagerXI2 *device_manager,
|
||||
XIPropertyEvent *ev)
|
||||
@@ -1019,13 +1096,18 @@ handle_property_change (GdkX11DeviceManagerXI2 *device_manager,
|
||||
device_get_tool_serial_and_id (device, &serial_id, &tool_id))
|
||||
{
|
||||
seat = gdk_device_get_seat (device);
|
||||
tool = gdk_seat_get_tool (seat, serial_id);
|
||||
tool = gdk_seat_get_tool (seat, serial_id, tool_id);
|
||||
|
||||
if (!tool && serial_id > 0)
|
||||
{
|
||||
tool = gdk_device_tool_new (serial_id, tool_id,
|
||||
GDK_DEVICE_TOOL_TYPE_UNKNOWN, 0);
|
||||
gdk_seat_default_add_tool (GDK_SEAT_DEFAULT (seat), tool);
|
||||
GdkDeviceToolType tool_type;
|
||||
|
||||
tool_type = device_get_tool_type (device);
|
||||
if (tool_type != GDK_DEVICE_TOOL_TYPE_UNKNOWN)
|
||||
{
|
||||
tool = gdk_device_tool_new (serial_id, tool_id, tool_type, 0);
|
||||
gdk_seat_default_add_tool (GDK_SEAT_DEFAULT (seat), tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1471,8 +1553,6 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
_gdk_x11_keymap_add_virt_mods (keymap, &state);
|
||||
event->key.state |= state;
|
||||
|
||||
_gdk_x11_event_translate_keyboard_string (&event->key);
|
||||
|
||||
if (ev->evtype == XI_KeyPress)
|
||||
set_user_time (event);
|
||||
|
||||
|
||||
@@ -1600,7 +1600,7 @@ gdk_x11_display_open (const gchar *display_name)
|
||||
if (!gdk_running_in_sandbox ())
|
||||
{
|
||||
/* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
|
||||
pid_t pid = getpid ();
|
||||
long pid = getpid ();
|
||||
XChangeProperty (display_x11->xdisplay,
|
||||
display_x11->leader_window,
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
|
||||
@@ -2822,8 +2822,8 @@ gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
|
||||
|
||||
/**
|
||||
* gdk_x11_set_sm_client_id:
|
||||
* @sm_client_id: the client id assigned by the session manager when the
|
||||
* connection was opened, or %NULL to remove the property.
|
||||
* @sm_client_id: (nullable): the client id assigned by the session manager
|
||||
* when the connection was opened, or %NULL to remove the property.
|
||||
*
|
||||
* Sets the `SM_CLIENT_ID` property on the application’s leader window so that
|
||||
* the window manager can save the application’s state using the X11R6 ICCCM
|
||||
|
||||
+26
-16
@@ -201,31 +201,41 @@ gdk_x11_gl_context_get_damage (GdkGLContext *context)
|
||||
{
|
||||
GdkGLContext *shared;
|
||||
GdkX11GLContext *shared_x11;
|
||||
|
||||
|
||||
shared = gdk_gl_context_get_shared_context (context);
|
||||
if (shared == NULL)
|
||||
shared = context;
|
||||
shared_x11 = GDK_X11_GL_CONTEXT (shared);
|
||||
|
||||
gdk_gl_context_make_current (shared);
|
||||
glXQueryDrawable(dpy, shared_x11->attached_drawable,
|
||||
GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
|
||||
glXQueryDrawable (dpy, shared_x11->attached_drawable,
|
||||
GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
|
||||
|
||||
if (buffer_age == 2)
|
||||
switch (buffer_age)
|
||||
{
|
||||
if (context->old_updated_area[0])
|
||||
return cairo_region_copy (context->old_updated_area[0]);
|
||||
}
|
||||
else if (buffer_age == 3)
|
||||
{
|
||||
if (context->old_updated_area[0] &&
|
||||
context->old_updated_area[1])
|
||||
{
|
||||
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
|
||||
cairo_region_union (damage, context->old_updated_area[1]);
|
||||
return damage;
|
||||
}
|
||||
case 1:
|
||||
return cairo_region_create ();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (context->old_updated_area[0])
|
||||
return cairo_region_copy (context->old_updated_area[0]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (context->old_updated_area[0] &&
|
||||
context->old_updated_area[1])
|
||||
{
|
||||
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
|
||||
cairo_region_union (damage, context->old_updated_area[1]);
|
||||
return damage;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->get_damage (context);
|
||||
|
||||
@@ -166,8 +166,6 @@ void gdk_x11_device_xi2_store_axes (GdkX11DeviceXI2 *device,
|
||||
gint n_axes);
|
||||
#endif
|
||||
|
||||
void _gdk_x11_event_translate_keyboard_string (GdkEventKey *event);
|
||||
|
||||
GdkAtom _gdk_x11_display_manager_atom_intern (GdkDisplayManager *manager,
|
||||
const gchar *atom_name,
|
||||
gboolean copy_name);
|
||||
|
||||
@@ -140,7 +140,7 @@ gdk_x11_selection_input_stream_flush (GdkX11SelectionInputStream *stream)
|
||||
written, priv->pending_size));
|
||||
g_task_return_int (priv->pending_task, written);
|
||||
|
||||
priv->pending_task = NULL;
|
||||
g_clear_object (&priv->pending_task);
|
||||
priv->pending_data = NULL;
|
||||
priv->pending_size = 0;
|
||||
}
|
||||
|
||||
@@ -746,7 +746,7 @@ setup_toplevel_window (GdkSurface *surface,
|
||||
if (!gdk_running_in_sandbox ())
|
||||
{
|
||||
/* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
|
||||
pid_t pid = getpid ();
|
||||
long pid = getpid ();
|
||||
XChangeProperty (xdisplay, xid,
|
||||
gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
|
||||
XA_CARDINAL, 32,
|
||||
|
||||
+49
-35
@@ -46,6 +46,7 @@ struct _GskGLDriver
|
||||
Fbo default_fbo;
|
||||
|
||||
GHashTable *textures;
|
||||
GHashTable *pointer_textures;
|
||||
|
||||
const Texture *bound_source_texture;
|
||||
const Fbo *bound_fbo;
|
||||
@@ -119,6 +120,7 @@ gsk_gl_driver_finalize (GObject *gobject)
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
g_clear_pointer (&self->textures, g_hash_table_unref);
|
||||
g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
|
||||
g_clear_object (&self->profiler);
|
||||
|
||||
if (self->gl_context == gdk_gl_context_get_current ())
|
||||
@@ -263,7 +265,28 @@ gsk_gl_driver_collect_textures (GskGLDriver *self)
|
||||
}
|
||||
}
|
||||
else
|
||||
g_hash_table_iter_remove (&iter);
|
||||
{
|
||||
/* Remove from self->pointer_textures. */
|
||||
/* TODO: Is there a better way for this? */
|
||||
if (self->pointer_textures)
|
||||
{
|
||||
GHashTableIter pointer_iter;
|
||||
gpointer value;
|
||||
gpointer p;
|
||||
|
||||
g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
|
||||
while (g_hash_table_iter_next (&pointer_iter, &p, &value))
|
||||
{
|
||||
if (GPOINTER_TO_INT (value) == t->texture_id)
|
||||
{
|
||||
g_hash_table_iter_remove (&pointer_iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
return old_size - g_hash_table_size (self->textures);
|
||||
@@ -307,26 +330,6 @@ gsk_gl_driver_get_fbo (GskGLDriver *self,
|
||||
return &t->fbo;
|
||||
}
|
||||
|
||||
static Texture *
|
||||
find_texture_by_size (GHashTable *textures,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
|
||||
g_hash_table_iter_init (&iter, textures);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Texture *t = value_p;
|
||||
|
||||
if (t->width == width && t->height == height)
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Texture *
|
||||
create_texture (GskGLDriver *self,
|
||||
float fwidth,
|
||||
@@ -351,21 +354,7 @@ create_texture (GskGLDriver *self,
|
||||
height = MIN (height, self->max_texture_size);
|
||||
}
|
||||
|
||||
t = find_texture_by_size (self->textures, width, height);
|
||||
if (t != NULL && !t->in_use && t->user == NULL)
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_message ("Reusing Texture(%d) for size %dx%d",
|
||||
t->texture_id, t->width, t->height));
|
||||
t->in_use = TRUE;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (self->profiler, self->counters.reused_textures);
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
|
||||
t = texture_new ();
|
||||
t->texture_id = texture_id;
|
||||
t->width = width;
|
||||
@@ -547,6 +536,31 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
|
||||
gpointer pointer)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
if (G_UNLIKELY (self->pointer_textures == NULL))
|
||||
self->pointer_textures = g_hash_table_new (NULL, NULL);
|
||||
|
||||
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, pointer));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_set_texture_for_pointer (GskGLDriver *self,
|
||||
gpointer pointer,
|
||||
int texture_id)
|
||||
{
|
||||
if (G_UNLIKELY (self->pointer_textures == NULL))
|
||||
self->pointer_textures = g_hash_table_new (NULL, NULL);
|
||||
|
||||
g_hash_table_insert (self->pointer_textures, pointer, GINT_TO_POINTER (texture_id));
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_create_permanent_texture (GskGLDriver *self,
|
||||
float width,
|
||||
|
||||
@@ -33,6 +33,11 @@ int gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
int gsk_gl_driver_get_texture_for_pointer (GskGLDriver *driver,
|
||||
gpointer pointer);
|
||||
void gsk_gl_driver_set_texture_for_pointer (GskGLDriver *driver,
|
||||
gpointer pointer,
|
||||
int texture_id);
|
||||
int gsk_gl_driver_create_permanent_texture (GskGLDriver *driver,
|
||||
float width,
|
||||
float height);
|
||||
|
||||
+27
-76
@@ -24,23 +24,6 @@
|
||||
|
||||
#define ATLAS_SIZE 512
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
guint xshift;
|
||||
guint yshift;
|
||||
guint scale; /* times 1024 */
|
||||
} GlyphCacheKey;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GlyphCacheKey *key;
|
||||
GskGLCachedGlyph *value;
|
||||
cairo_surface_t *surface;
|
||||
} DirtyGlyph;
|
||||
|
||||
|
||||
static guint glyph_cache_hash (gconstpointer v);
|
||||
static gboolean glyph_cache_equal (gconstpointer v1,
|
||||
gconstpointer v2);
|
||||
@@ -60,8 +43,6 @@ create_atlas (GskGLGlyphCache *cache)
|
||||
atlas->y = 1;
|
||||
atlas->x = 1;
|
||||
atlas->image = NULL;
|
||||
atlas->num_glyphs = 0;
|
||||
atlas->dirty_glyphs = NULL;
|
||||
|
||||
return atlas;
|
||||
}
|
||||
@@ -76,7 +57,7 @@ free_atlas (gpointer v)
|
||||
g_assert (atlas->image->texture_id == 0);
|
||||
g_free (atlas->image);
|
||||
}
|
||||
g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
|
||||
|
||||
g_free (atlas);
|
||||
}
|
||||
|
||||
@@ -122,8 +103,6 @@ glyph_cache_equal (gconstpointer v1, gconstpointer v2)
|
||||
|
||||
return key1->font == key2->font &&
|
||||
key1->glyph == key2->glyph &&
|
||||
key1->xshift == key2->xshift &&
|
||||
key1->yshift == key2->yshift &&
|
||||
key1->scale == key2->scale;
|
||||
}
|
||||
|
||||
@@ -132,7 +111,7 @@ glyph_cache_hash (gconstpointer v)
|
||||
{
|
||||
const GlyphCacheKey *key = v;
|
||||
|
||||
return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ (key->xshift << 24) ^ (key->yshift << 26) ^ key->scale;
|
||||
return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -157,7 +136,6 @@ dirty_glyph_free (gpointer v)
|
||||
|
||||
if (glyph->surface)
|
||||
cairo_surface_destroy (glyph->surface);
|
||||
g_free (glyph);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -167,7 +145,6 @@ add_to_cache (GskGLGlyphCache *cache,
|
||||
{
|
||||
GskGLGlyphAtlas *atlas;
|
||||
int i;
|
||||
DirtyGlyph *dirty;
|
||||
int width = value->draw_width * key->scale / 1024;
|
||||
int height = value->draw_height * key->scale / 1024;
|
||||
|
||||
@@ -209,16 +186,12 @@ add_to_cache (GskGLGlyphCache *cache,
|
||||
|
||||
value->atlas = atlas;
|
||||
|
||||
dirty = g_new0 (DirtyGlyph, 1);
|
||||
dirty->key = key;
|
||||
dirty->value = value;
|
||||
atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
|
||||
atlas->pending_glyph.key = key;
|
||||
atlas->pending_glyph.value = value;
|
||||
|
||||
atlas->x = atlas->x + width + 1;
|
||||
atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
|
||||
|
||||
atlas->num_glyphs++;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_RENDERER_DEBUG_CHECK (cache->renderer, GLYPH_CACHE))
|
||||
{
|
||||
@@ -226,9 +199,8 @@ add_to_cache (GskGLGlyphCache *cache,
|
||||
for (i = 0; i < cache->atlases->len; i++)
|
||||
{
|
||||
atlas = g_ptr_array_index (cache->atlases, i);
|
||||
g_print ("\tGskGLGlyphAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
|
||||
g_print ("\tGskGLGlyphAtlas %d (%dx%d): %.2g%% old pixels, filled to %d, %d / %d\n",
|
||||
i, atlas->width, atlas->height,
|
||||
atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
|
||||
100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
|
||||
atlas->x, atlas->y0, atlas->y);
|
||||
}
|
||||
@@ -266,10 +238,10 @@ render_glyph (const GskGLGlyphAtlas *atlas,
|
||||
glyph_info.glyph = key->glyph;
|
||||
glyph_info.geometry.width = value->draw_width * 1024;
|
||||
if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
|
||||
glyph_info.geometry.x_offset = key->xshift * 256;
|
||||
glyph_info.geometry.x_offset = 0;
|
||||
else
|
||||
glyph_info.geometry.x_offset = key->xshift * 256 - value->draw_x * 1024;
|
||||
glyph_info.geometry.y_offset = key->yshift * 256 - value->draw_y * 1024;
|
||||
glyph_info.geometry.x_offset = - value->draw_x * 1024;
|
||||
glyph_info.geometry.y_offset = - value->draw_y * 1024;
|
||||
|
||||
glyph_string.num_glyphs = 1;
|
||||
glyph_string.glyphs = &glyph_info;
|
||||
@@ -288,54 +260,35 @@ render_glyph (const GskGLGlyphAtlas *atlas,
|
||||
}
|
||||
|
||||
static void
|
||||
upload_dirty_glyphs (GskGLGlyphCache *self,
|
||||
GskGLGlyphAtlas *atlas)
|
||||
upload_dirty_glyph (GskGLGlyphCache *self,
|
||||
GskGLGlyphAtlas *atlas)
|
||||
{
|
||||
GList *l;
|
||||
guint num_regions;
|
||||
GskImageRegion *regions;
|
||||
int i;
|
||||
GskImageRegion region;
|
||||
|
||||
num_regions = g_list_length (atlas->dirty_glyphs);
|
||||
regions = alloca (sizeof (GskImageRegion) * num_regions);
|
||||
g_assert (atlas->pending_glyph.key != NULL);
|
||||
|
||||
for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
|
||||
render_glyph (atlas, (DirtyGlyph *)l->data, ®ions[i]);
|
||||
render_glyph (atlas, &atlas->pending_glyph, ®ion);
|
||||
|
||||
GSK_RENDERER_NOTE (self->renderer, GLYPH_CACHE,
|
||||
g_message ("uploading %d glyphs to cache", num_regions));
|
||||
gsk_gl_image_upload_regions (atlas->image, self->gl_driver, 1, ®ion);
|
||||
|
||||
|
||||
gsk_gl_image_upload_regions (atlas->image, self->gl_driver, num_regions, regions);
|
||||
|
||||
g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
|
||||
atlas->dirty_glyphs = NULL;
|
||||
dirty_glyph_free (&atlas->pending_glyph);
|
||||
atlas->pending_glyph.key = NULL;
|
||||
atlas->pending_glyph.value = NULL;
|
||||
}
|
||||
|
||||
#define PHASE(x) ((x % PANGO_SCALE) * 4 / PANGO_SCALE)
|
||||
|
||||
const GskGLCachedGlyph *
|
||||
gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
|
||||
gboolean create,
|
||||
PangoFont *font,
|
||||
const PangoGlyph glyph,
|
||||
int x,
|
||||
int y,
|
||||
float scale)
|
||||
gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
|
||||
gboolean create,
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
float scale)
|
||||
{
|
||||
GskGLCachedGlyph *value;
|
||||
guint xshift;
|
||||
guint yshift;
|
||||
|
||||
xshift = PHASE (x);
|
||||
yshift = PHASE (y);
|
||||
|
||||
value = g_hash_table_lookup (cache->hash_table,
|
||||
&(GlyphCacheKey) {
|
||||
.font = font,
|
||||
.glyph = glyph,
|
||||
.xshift = xshift,
|
||||
.yshift = yshift,
|
||||
.scale = (guint)(scale * 1024)
|
||||
});
|
||||
|
||||
@@ -369,14 +322,13 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
|
||||
value->draw_height = ink_rect.height;
|
||||
value->timestamp = cache->timestamp;
|
||||
value->atlas = NULL; /* For now */
|
||||
value->scale = (guint)(scale * 1024);
|
||||
|
||||
key->font = g_object_ref (font);
|
||||
key->glyph = glyph;
|
||||
key->xshift = xshift;
|
||||
key->yshift = yshift;
|
||||
key->scale = (guint)(scale * 1024);
|
||||
|
||||
if (ink_rect.width > 0 && ink_rect.height > 0)
|
||||
if (ink_rect.width > 0 && ink_rect.height > 0 && key->scale > 0)
|
||||
add_to_cache (cache, key, value);
|
||||
|
||||
g_hash_table_insert (cache->hash_table, key, value);
|
||||
@@ -386,22 +338,21 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
|
||||
}
|
||||
|
||||
GskGLImage *
|
||||
gsk_gl_glyph_cache_get_glyph_image (GskGLGlyphCache *self,
|
||||
gsk_gl_glyph_cache_get_glyph_image (GskGLGlyphCache *self,
|
||||
const GskGLCachedGlyph *glyph)
|
||||
{
|
||||
GskGLGlyphAtlas *atlas = glyph->atlas;
|
||||
|
||||
g_assert (atlas != NULL);
|
||||
|
||||
|
||||
if (atlas->image == NULL)
|
||||
{
|
||||
atlas->image = g_new0 (GskGLImage, 1);
|
||||
gsk_gl_image_create (atlas->image, self->gl_driver, atlas->width, atlas->height);
|
||||
}
|
||||
|
||||
if (atlas->dirty_glyphs)
|
||||
upload_dirty_glyphs (self, atlas);
|
||||
if (atlas->pending_glyph.key != NULL)
|
||||
upload_dirty_glyph (self, atlas);
|
||||
|
||||
return atlas->image;
|
||||
}
|
||||
|
||||
@@ -18,18 +18,34 @@ typedef struct
|
||||
guint64 timestamp;
|
||||
} GskGLGlyphCache;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
guint scale; /* times 1024 */
|
||||
} GlyphCacheKey;
|
||||
|
||||
typedef struct _DirtyGlyph DirtyGlyph;
|
||||
typedef struct _GskGLCachedGlyph GskGLCachedGlyph;
|
||||
|
||||
struct _DirtyGlyph
|
||||
{
|
||||
GlyphCacheKey *key;
|
||||
GskGLCachedGlyph *value;
|
||||
cairo_surface_t *surface;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskGLImage *image;
|
||||
int width, height;
|
||||
int x, y, y0;
|
||||
int num_glyphs;
|
||||
GList *dirty_glyphs;
|
||||
guint old_pixels;
|
||||
|
||||
DirtyGlyph pending_glyph;
|
||||
} GskGLGlyphAtlas;
|
||||
|
||||
typedef struct
|
||||
struct _GskGLCachedGlyph
|
||||
{
|
||||
GskGLGlyphAtlas *atlas;
|
||||
|
||||
@@ -43,8 +59,11 @@ typedef struct
|
||||
int draw_width;
|
||||
int draw_height;
|
||||
|
||||
float scale;
|
||||
|
||||
guint64 timestamp;
|
||||
} GskGLCachedGlyph;
|
||||
};
|
||||
|
||||
|
||||
void gsk_gl_glyph_cache_init (GskGLGlyphCache *self,
|
||||
GskRenderer *renderer,
|
||||
@@ -56,9 +75,7 @@ GskGLImage * gsk_gl_glyph_cache_get_glyph_image (GskGLGlyphCache
|
||||
const GskGLCachedGlyph * gsk_gl_glyph_cache_lookup (GskGLGlyphCache *self,
|
||||
gboolean create,
|
||||
PangoFont *font,
|
||||
const PangoGlyph glyph,
|
||||
int x,
|
||||
int y,
|
||||
PangoGlyph glyph,
|
||||
float scale);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
#include "gskglnodesampleprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
void
|
||||
node_sample_init (NodeSample *self)
|
||||
{
|
||||
memset (self->nodes, 0, sizeof (self->nodes));
|
||||
self->count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_reset (NodeSample *self)
|
||||
{
|
||||
node_sample_init (self);
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_add (NodeSample *self,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
const guint node_type = gsk_render_node_get_node_type (node);
|
||||
|
||||
g_assert (node_type <= N_NODE_TYPES);
|
||||
|
||||
if (self->nodes[node_type].class_name == NULL)
|
||||
self->nodes[node_type].class_name = node->node_class->type_name;
|
||||
|
||||
self->nodes[node_type].count ++;
|
||||
self->count ++;
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_print (const NodeSample *self,
|
||||
const char *prefix)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_printf ("%s:\n", prefix);
|
||||
|
||||
for (i = 0; i < N_NODE_TYPES; i ++)
|
||||
{
|
||||
if (self->nodes[i].count > 0)
|
||||
{
|
||||
double p = (double)self->nodes[i].count / (double)self->count;
|
||||
|
||||
g_printf ("%s: %u (%.2f%%)\n", self->nodes[i].class_name, self->nodes[i].count, p * 100.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#ifndef __GSK_GL_NODE_SAMPLE_PRIVATE_H__
|
||||
#define __GSK_GL_NODE_SAMPLE_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "gskenums.h"
|
||||
#include "gskrendernode.h"
|
||||
|
||||
/* TODO: We have no other way for this...? */
|
||||
#define N_NODE_TYPES (GSK_DEBUG_NODE + 1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct {
|
||||
const char *class_name;
|
||||
guint count;
|
||||
} nodes[N_NODE_TYPES];
|
||||
guint count;
|
||||
} NodeSample;
|
||||
|
||||
void node_sample_init (NodeSample *self);
|
||||
void node_sample_reset (NodeSample *self);
|
||||
void node_sample_add (NodeSample *self,
|
||||
GskRenderNode *node);
|
||||
void node_sample_print (const NodeSample *self,
|
||||
const char *prefix);
|
||||
|
||||
#endif
|
||||
+381
-167
@@ -14,6 +14,7 @@
|
||||
#include "gskglrenderopsprivate.h"
|
||||
#include "gskcairoblurprivate.h"
|
||||
#include "gskglshadowcacheprivate.h"
|
||||
#include "gskglnodesampleprivate.h"
|
||||
|
||||
#include "gskprivate.h"
|
||||
|
||||
@@ -104,8 +105,19 @@ print_render_node_tree (GskRenderNode *root, int level)
|
||||
g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root));
|
||||
break;
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
g_print ("%*s Debug: %s\n", level * INDENT, " ", gsk_debug_node_get_message (root));
|
||||
print_render_node_tree (gsk_debug_node_get_child (root), level + 1);
|
||||
break;
|
||||
|
||||
case GSK_CLIP_NODE:
|
||||
g_print ("%*s Clip (%f, %f, %f, %f):\n", level * INDENT, " ",
|
||||
root->bounds.origin.x, root->bounds.origin.y, root->bounds.size.width, root->bounds.size.height);
|
||||
print_render_node_tree (gsk_clip_node_get_child (root), level + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_print ("UNKNOWN: %u\n", type);
|
||||
g_print ("%*s %s\n", level * INDENT, " ", root->node_class->type_name);
|
||||
}
|
||||
|
||||
#undef INDENT
|
||||
@@ -219,18 +231,40 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
|
||||
MAX (self->corner[2].height, self->corner[3].height)) * 2);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
node_supports_transform (GskRenderNode *node)
|
||||
{
|
||||
/* Some nodes can't handle non-trivial transforms without being
|
||||
* rendered to a texture (e.g. rotated clips, etc.). Some however
|
||||
* work just fine, mostly because they already draw their child
|
||||
* to a texture and just render the texture manipulated in some
|
||||
* way, think opacity or color matrix. */
|
||||
const guint node_type = gsk_render_node_get_node_type (node);
|
||||
|
||||
switch (node_type)
|
||||
{
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_OPACITY_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
|
||||
static void add_offscreen_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
float min_x,
|
||||
float max_x,
|
||||
float min_y,
|
||||
float max_y,
|
||||
GskRenderNode *child_node,
|
||||
int *texture_id,
|
||||
gboolean *is_offscreen,
|
||||
gboolean force_offscreen,
|
||||
gboolean reset_clip);
|
||||
RenderOpBuilder *builder,
|
||||
const graphene_rect_t *bounds,
|
||||
GskRenderNode *child_node,
|
||||
int *texture_id,
|
||||
gboolean *is_offscreen,
|
||||
gboolean force_offscreen,
|
||||
gboolean reset_clip);
|
||||
static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder);
|
||||
@@ -248,7 +282,6 @@ struct _GskGLRenderer
|
||||
union {
|
||||
Program programs[GL_N_PROGRAMS];
|
||||
struct {
|
||||
Program blend_program;
|
||||
Program blit_program;
|
||||
Program color_program;
|
||||
Program coloring_program;
|
||||
@@ -289,6 +322,49 @@ struct _GskGLRendererClass
|
||||
|
||||
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
|
||||
|
||||
static void G_GNUC_UNUSED
|
||||
add_rect_ops (RenderOpBuilder *builder,
|
||||
const graphene_rect_t *r)
|
||||
{
|
||||
const float min_x = r->origin.x;
|
||||
const float min_y = r->origin.y;
|
||||
const float max_x = min_x + r->size.width;
|
||||
const float max_y = min_y + r->size.height;
|
||||
|
||||
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
|
||||
{ { min_x, min_y }, { 0, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
});
|
||||
}
|
||||
|
||||
static void G_GNUC_UNUSED
|
||||
add_rect_outline_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
ops_set_program (builder, &self->color_program);
|
||||
ops_set_color (builder, &(GdkRGBA) { 1, 0, 0, 1 });
|
||||
|
||||
add_rect_ops (builder,
|
||||
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y,
|
||||
1, rect->size.height));
|
||||
add_rect_ops (builder,
|
||||
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y,
|
||||
rect->size.width, 1));
|
||||
add_rect_ops (builder,
|
||||
&GRAPHENE_RECT_INIT (rect->origin.x + rect->size.width - 1, rect->origin.y,
|
||||
1, rect->size.height));
|
||||
|
||||
add_rect_ops (builder,
|
||||
&GRAPHENE_RECT_INIT (rect->origin.x, rect->origin.y + rect->size.height - 1,
|
||||
rect->size.width, 1));
|
||||
}
|
||||
|
||||
static inline void
|
||||
rounded_rect_to_floats (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
@@ -301,7 +377,7 @@ rounded_rect_to_floats (GskGLRenderer *self,
|
||||
int i;
|
||||
graphene_rect_t transformed_bounds;
|
||||
|
||||
graphene_matrix_transform_bounds (&builder->current_modelview, &rect->bounds, &transformed_bounds);
|
||||
ops_transform_bounds_modelview (builder, &rect->bounds, &transformed_bounds);
|
||||
|
||||
outline[0] = transformed_bounds.origin.x;
|
||||
outline[1] = transformed_bounds.origin.y;
|
||||
@@ -417,16 +493,14 @@ render_text_node (GskGLRenderer *self,
|
||||
TRUE,
|
||||
(PangoFont *)font,
|
||||
gi->glyph,
|
||||
x_position + gi->geometry.x_offset,
|
||||
gi->geometry.y_offset,
|
||||
text_scale);
|
||||
|
||||
/* e.g. whitespace */
|
||||
if (glyph->draw_width <= 0 || glyph->draw_height <= 0)
|
||||
if (glyph->draw_width <= 0 || glyph->draw_height <= 0 || glyph->scale <= 0)
|
||||
goto next;
|
||||
|
||||
cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
cy = gi->geometry.y_offset / PANGO_SCALE;
|
||||
cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
|
||||
|
||||
ops_set_texture (builder, gsk_gl_glyph_cache_get_glyph_image (&self->glyph_cache,
|
||||
glyph)->texture_id);
|
||||
@@ -462,8 +536,8 @@ render_border_node (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
const float scale = ops_get_scale (builder);
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
const GdkRGBA *colors = gsk_border_node_peek_colors (node);
|
||||
@@ -580,8 +654,8 @@ render_border_node (GskGLRenderer *self,
|
||||
|
||||
/* Prepare outline */
|
||||
outline = *rounded_outline;
|
||||
graphene_matrix_transform_bounds (&builder->current_modelview,
|
||||
&outline.bounds, &outline.bounds);
|
||||
ops_transform_bounds_modelview (builder, &outline.bounds, &outline.bounds);
|
||||
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
outline.corner[i].width *= scale;
|
||||
@@ -589,7 +663,8 @@ render_border_node (GskGLRenderer *self,
|
||||
}
|
||||
|
||||
ops_set_program (builder, &self->border_program);
|
||||
ops_set_border (builder, widths, &outline);
|
||||
ops_set_border_width (builder, widths);
|
||||
ops_set_border (builder, &outline);
|
||||
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
@@ -691,41 +766,12 @@ render_offset_node (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskRenderNode *child = gsk_offset_node_get_child (node);
|
||||
const guint child_type = gsk_render_node_get_node_type (child);
|
||||
const float dx = gsk_offset_node_get_x_offset (node);
|
||||
const float dy = gsk_offset_node_get_y_offset (node);
|
||||
|
||||
/* TODO: We do this only for selected node type we know handle
|
||||
* builder->dx/dy correctly. That should be "all nodes" eventually.
|
||||
*/
|
||||
switch (child_type)
|
||||
{
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
{
|
||||
ops_offset (builder, dx, dy);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_offset (builder, - dx, - dy);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
graphene_matrix_t prev_mv;
|
||||
graphene_matrix_t transform, transformed_mv;
|
||||
|
||||
graphene_matrix_init_translate (&transform,
|
||||
&GRAPHENE_POINT3D_INIT(dx, dy, 1.0));
|
||||
graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
|
||||
prev_mv = ops_set_modelview (builder, &transformed_mv);
|
||||
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
|
||||
ops_set_modelview (builder, &prev_mv);
|
||||
}
|
||||
}
|
||||
ops_offset (builder, dx, dy);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_offset (builder, - dx, - dy);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -733,17 +779,64 @@ render_transform_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
const float scale = ops_get_scale (builder);
|
||||
GskRenderNode *child = gsk_transform_node_get_child (node);
|
||||
graphene_matrix_t prev_mv;
|
||||
graphene_matrix_t transform, transformed_mv;
|
||||
|
||||
graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
|
||||
graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
|
||||
prev_mv = ops_set_modelview (builder, &transformed_mv);
|
||||
graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
|
||||
graphene_matrix_translate (&transformed_mv,
|
||||
&(graphene_point3d_t) { builder->dx * scale, builder->dy * scale, 0});
|
||||
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
/* We just added the offset to the new modelview matrix, so the following
|
||||
* cases dont' have to care about builder->dx/dy! */
|
||||
|
||||
ops_set_modelview (builder, &prev_mv);
|
||||
ops_push_modelview (builder, &transformed_mv);
|
||||
if (ops_modelview_is_simple (builder) ||
|
||||
node_supports_transform (child))
|
||||
{
|
||||
const float dx = builder->dx;
|
||||
const float dy = builder->dy;
|
||||
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
builder->dx = dx;
|
||||
builder->dy = dy;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
|
||||
{ { min_x, min_y }, { 0, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
};
|
||||
int texture_id;
|
||||
gboolean is_offscreen;
|
||||
/* For non-trivial transforms, we draw everything on a texture and then
|
||||
* draw the texture transformed. */
|
||||
/* TODO: We should compute a modelview containing only the "non-trivial"
|
||||
* part (e.g. the rotation) and use that. We want to keep the scale
|
||||
* for the texture.
|
||||
*/
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
child,
|
||||
&texture_id, &is_offscreen,
|
||||
FALSE, TRUE);
|
||||
ops_set_texture (builder, texture_id);
|
||||
ops_set_program (builder, &self->blit_program);
|
||||
ops_draw (builder, vertex_data);
|
||||
}
|
||||
ops_pop_modelview (builder);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -789,7 +882,11 @@ render_linear_gradient_node (GskGLRenderer *self,
|
||||
op.op = OP_CHANGE_LINEAR_GRADIENT;
|
||||
op.linear_gradient.n_color_stops = n_color_stops;
|
||||
op.linear_gradient.start_point = *start;
|
||||
op.linear_gradient.start_point.x += builder->dx;
|
||||
op.linear_gradient.start_point.y += builder->dy;
|
||||
op.linear_gradient.end_point = *end;
|
||||
op.linear_gradient.end_point.x += builder->dx;
|
||||
op.linear_gradient.end_point.y += builder->dy;
|
||||
ops_add (builder, &op);
|
||||
|
||||
ops_draw (builder, vertex_data);
|
||||
@@ -800,64 +897,98 @@ render_clip_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskRoundedRect prev_clip;
|
||||
GskRenderNode *child = gsk_clip_node_get_child (node);
|
||||
graphene_rect_t transformed_clip;
|
||||
graphene_rect_t intersection;
|
||||
GskRoundedRect child_clip;
|
||||
|
||||
transformed_clip = *gsk_clip_node_peek_clip (node);
|
||||
graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
|
||||
ops_transform_bounds_modelview (builder, &transformed_clip, &transformed_clip);
|
||||
|
||||
graphene_rect_intersection (&transformed_clip,
|
||||
&builder->current_clip.bounds,
|
||||
&builder->current_clip->bounds,
|
||||
&intersection);
|
||||
|
||||
gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
|
||||
|
||||
prev_clip = ops_set_clip (builder, &child_clip);
|
||||
ops_push_clip (builder, &child_clip);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_set_clip (builder, &prev_clip);
|
||||
ops_pop_clip (builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_rect_intersection (const GskRoundedRect *self,
|
||||
const GskRoundedRect *other,
|
||||
GskRoundedRect *out_intersection)
|
||||
{
|
||||
const graphene_rect_t *self_bounds = &self->bounds;
|
||||
const graphene_rect_t *other_bounds = &other->bounds;
|
||||
|
||||
if (graphene_rect_contains_rect (self_bounds, other_bounds))
|
||||
{
|
||||
*out_intersection = *other;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TODO: There are a few cases here that we can express using a single
|
||||
* rounded rectangle, which are even interesting in every day usage.
|
||||
* For example, a partially scrolled-away rounded rectangle
|
||||
* might just work.
|
||||
*/
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline void
|
||||
render_rounded_clip_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
const float scale = ops_get_scale (builder);
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
GskRoundedRect child_clip = *gsk_rounded_clip_node_peek_clip (node);
|
||||
GskRoundedRect transformed_clip;
|
||||
GskRoundedRect prev_clip;
|
||||
GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
|
||||
GskRoundedRect intersection;
|
||||
gboolean need_offscreen;
|
||||
int i;
|
||||
|
||||
transformed_clip = child_clip;
|
||||
graphene_matrix_transform_bounds (&builder->current_modelview, &child_clip.bounds, &transformed_clip.bounds);
|
||||
ops_transform_bounds_modelview (builder, &child_clip.bounds, &transformed_clip.bounds);
|
||||
|
||||
if (graphene_rect_contains_rect (&builder->current_clip.bounds,
|
||||
&transformed_clip.bounds))
|
||||
if (!ops_has_clip (builder))
|
||||
{
|
||||
intersection = transformed_clip;
|
||||
need_offscreen = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
need_offscreen = !gsk_rounded_rect_intersection (builder->current_clip,
|
||||
&transformed_clip,
|
||||
&intersection);
|
||||
}
|
||||
|
||||
if (!need_offscreen)
|
||||
{
|
||||
/* If they don't intersect at all, we can simply set
|
||||
* the new clip and add the render ops */
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
transformed_clip.corner[i].width *= scale;
|
||||
transformed_clip.corner[i].height *= scale;
|
||||
intersection.corner[i].width *= scale;
|
||||
intersection.corner[i].height *= scale;
|
||||
}
|
||||
|
||||
prev_clip = ops_set_clip (builder, &transformed_clip);
|
||||
ops_push_clip (builder, &intersection);
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
|
||||
ops_set_clip (builder, &prev_clip);
|
||||
ops_pop_clip (builder);
|
||||
}
|
||||
else if (graphene_rect_intersection (&builder->current_clip.bounds,
|
||||
&transformed_clip.bounds, NULL))
|
||||
else
|
||||
{
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
graphene_matrix_t scale_matrix;
|
||||
gboolean is_offscreen;
|
||||
int texture_id;
|
||||
@@ -878,12 +1009,12 @@ render_rounded_clip_node (GskGLRenderer *self,
|
||||
child_clip.corner[i].height *= scale;
|
||||
}
|
||||
|
||||
prev_clip = ops_set_clip (builder, &child_clip);
|
||||
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
|
||||
ops_push_clip (builder, &child_clip);
|
||||
add_offscreen_ops (self, builder, &node->bounds,
|
||||
child,
|
||||
&texture_id, &is_offscreen, TRUE, FALSE);
|
||||
ops_pop_clip (builder);
|
||||
|
||||
ops_set_clip (builder, &prev_clip);
|
||||
ops_set_program (builder, &self->blit_program);
|
||||
ops_set_texture (builder, texture_id);
|
||||
|
||||
@@ -913,7 +1044,9 @@ render_color_matrix_node (GskGLRenderer *self,
|
||||
int texture_id;
|
||||
gboolean is_offscreen;
|
||||
|
||||
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
|
||||
/* Pass min_x/max_x/min_y/max_y without builder->dx/dy! */
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
gsk_color_matrix_node_get_child (node),
|
||||
&texture_id, &is_offscreen, FALSE, TRUE);
|
||||
|
||||
@@ -950,16 +1083,23 @@ render_blur_node (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
const GskQuadVertex *vertex_data)
|
||||
{
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
int texture_id;
|
||||
gboolean is_offscreen;
|
||||
RenderOp op;
|
||||
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
|
||||
|
||||
/* TODO(perf): We're forcing the child offscreen even if it's a texture
|
||||
* so the resulting offscreen texture is bigger by the gaussian blur factor
|
||||
* (see gsk_blur_node_new), but we didn't have to do that if the blur
|
||||
* shader could handle that situation. */
|
||||
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
gsk_blur_node_get_child (node),
|
||||
&texture_id, &is_offscreen, FALSE, TRUE);
|
||||
&texture_id, &is_offscreen, TRUE, TRUE);
|
||||
|
||||
ops_set_program (builder, &self->blur_program);
|
||||
op.op = OP_CHANGE_BLUR;
|
||||
@@ -1065,15 +1205,14 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
const float spread = gsk_outset_shadow_node_get_spread (node);
|
||||
const float dx = gsk_outset_shadow_node_get_dx (node);
|
||||
const float dy = gsk_outset_shadow_node_get_dy (node);
|
||||
const float min_x = outline->bounds.origin.x - spread - blur_extra / 2.0;
|
||||
const float min_y = outline->bounds.origin.y - spread - blur_extra / 2.0;
|
||||
const float min_x = builder->dx + outline->bounds.origin.x - spread - blur_extra / 2.0;
|
||||
const float min_y = builder->dy + outline->bounds.origin.y - spread - blur_extra / 2.0;
|
||||
const float max_x = min_x + outline->bounds.size.width + (spread + blur_extra/2.0) * 2;
|
||||
const float max_y = min_y + outline->bounds.size.height + (spread + blur_extra/2.0) * 2;
|
||||
float texture_width, texture_height;
|
||||
RenderOp op;
|
||||
graphene_matrix_t identity;
|
||||
graphene_matrix_t prev_projection;
|
||||
graphene_matrix_t prev_modelview;
|
||||
graphene_rect_t prev_viewport;
|
||||
graphene_matrix_t item_proj;
|
||||
int blurred_texture_id;
|
||||
@@ -1108,7 +1247,7 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
int texture_id, render_target;
|
||||
int blurred_render_target;
|
||||
int prev_render_target;
|
||||
GskRoundedRect prev_clip, blit_clip;
|
||||
GskRoundedRect blit_clip;
|
||||
|
||||
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
|
||||
@@ -1126,12 +1265,12 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
op.op = OP_CLEAR;
|
||||
ops_add (builder, &op);
|
||||
prev_projection = ops_set_projection (builder, &item_proj);
|
||||
prev_modelview = ops_set_modelview (builder, &identity);
|
||||
ops_push_modelview (builder, &identity);
|
||||
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
|
||||
|
||||
/* Draw outline */
|
||||
ops_set_program (builder, &self->color_program);
|
||||
prev_clip = ops_set_clip (builder, &offset_outline);
|
||||
ops_push_clip (builder, &offset_outline);
|
||||
ops_set_color (builder, gsk_outset_shadow_node_peek_color (node));
|
||||
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
|
||||
{ { 0, }, { 0, 1 }, },
|
||||
@@ -1149,6 +1288,7 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
|
||||
|
||||
ops_set_render_target (builder, blurred_render_target);
|
||||
ops_pop_clip (builder);
|
||||
op.op = OP_CLEAR;
|
||||
ops_add (builder, &op);
|
||||
|
||||
@@ -1162,7 +1302,7 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
op.blur.radius = blur_radius;
|
||||
ops_add (builder, &op);
|
||||
|
||||
ops_set_clip (builder, &blit_clip);
|
||||
ops_push_clip (builder, &blit_clip);
|
||||
ops_set_texture (builder, texture_id);
|
||||
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
|
||||
{ { 0, 0 }, { 0, 1 }, },
|
||||
@@ -1175,9 +1315,9 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
});
|
||||
|
||||
|
||||
ops_set_clip (builder, &prev_clip);
|
||||
ops_pop_clip (builder);
|
||||
ops_set_viewport (builder, &prev_viewport);
|
||||
ops_set_modelview (builder, &prev_modelview);
|
||||
ops_pop_modelview (builder);
|
||||
ops_set_projection (builder, &prev_projection);
|
||||
ops_set_render_target (builder, prev_render_target);
|
||||
|
||||
@@ -1461,11 +1601,6 @@ render_shadow_node (GskGLRenderer *self,
|
||||
|
||||
g_assert (shadow->radius <= 0);
|
||||
|
||||
min_x = shadow_child->bounds.origin.x;
|
||||
min_y = shadow_child->bounds.origin.y;
|
||||
max_x = min_x + shadow_child->bounds.size.width;
|
||||
max_y = min_y + shadow_child->bounds.size.height;
|
||||
|
||||
if (gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
|
||||
{
|
||||
ops_offset (builder, dx, dy);
|
||||
@@ -1474,9 +1609,14 @@ render_shadow_node (GskGLRenderer *self,
|
||||
continue;
|
||||
}
|
||||
|
||||
min_x = builder->dx + shadow_child->bounds.origin.x;
|
||||
min_y = builder->dy + shadow_child->bounds.origin.y;
|
||||
max_x = min_x + shadow_child->bounds.size.width;
|
||||
max_y = min_y + shadow_child->bounds.size.height;
|
||||
|
||||
/* Draw the child offscreen, without the offset. */
|
||||
add_offscreen_ops (self, builder,
|
||||
min_x, max_x, min_y, max_y,
|
||||
&shadow_child->bounds,
|
||||
shadow_child, &texture_id, &is_offscreen, FALSE, TRUE);
|
||||
|
||||
ops_offset (builder, dx, dy);
|
||||
@@ -1524,8 +1664,8 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float min_x = builder->dx + node->bounds.origin.x;
|
||||
const float min_y = builder->dy + node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
|
||||
@@ -1548,10 +1688,14 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
|
||||
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, start_node,
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
start_node,
|
||||
&start_texture_id, &is_offscreen1, TRUE, TRUE);
|
||||
|
||||
add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, end_node,
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
end_node,
|
||||
&end_texture_id, &is_offscreen2, TRUE, TRUE);
|
||||
|
||||
ops_set_program (builder, &self->cross_fade_program);
|
||||
@@ -1779,8 +1923,7 @@ apply_border_op (const Program *program,
|
||||
float widths[4];
|
||||
float heights[4];
|
||||
int i;
|
||||
OP_PRINT (" -> Border (%f, %f, %f, %f)",
|
||||
op->border.widths[0], op->border.widths[1], op->border.widths[2], op->border.widths[3]);
|
||||
OP_PRINT (" -> Border Outline");
|
||||
|
||||
outline[0] = o->bounds.origin.x;
|
||||
outline[1] = o->bounds.origin.y;
|
||||
@@ -1793,12 +1936,21 @@ apply_border_op (const Program *program,
|
||||
heights[i] = o->corner[i].height;
|
||||
}
|
||||
|
||||
glUniform4fv (program->border.widths_location, 1, op->border.widths);
|
||||
glUniform4fv (program->border.outline_location, 1, outline);
|
||||
glUniform4fv (program->border.corner_widths_location, 1, widths);
|
||||
glUniform4fv (program->border.corner_heights_location, 1, heights);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_border_width_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
{
|
||||
OP_PRINT (" -> Border width (%f, %f, %f, %f)",
|
||||
op->border.widths[0], op->border.widths[1], op->border.widths[2], op->border.widths[3]);
|
||||
|
||||
glUniform4fv (program->border.widths_location, 1, op->border.widths);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_border_color_op (const Program *program,
|
||||
const RenderOp *op)
|
||||
@@ -1849,21 +2001,19 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
int i;
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *vs;
|
||||
const char *fs;
|
||||
} program_definitions[] = {
|
||||
{ "blend", "blend.vs.glsl", "blend.fs.glsl" },
|
||||
{ "blit", "blit.vs.glsl", "blit.fs.glsl" },
|
||||
{ "color", "blit.vs.glsl", "color.fs.glsl" },
|
||||
{ "coloring", "blit.vs.glsl", "coloring.fs.glsl" },
|
||||
{ "color matrix", "blit.vs.glsl", "color_matrix.fs.glsl" },
|
||||
{ "linear gradient", "blit.vs.glsl", "linear_gradient.fs.glsl" },
|
||||
{ "blur", "blit.vs.glsl", "blur.fs.glsl" },
|
||||
{ "inset shadow", "blit.vs.glsl", "inset_shadow.fs.glsl" },
|
||||
{ "outset shadow", "blit.vs.glsl", "outset_shadow.fs.glsl" },
|
||||
{ "unblurred outset shadow", "blit.vs.glsl", "unblurred_outset_shadow.fs.glsl" },
|
||||
{ "border", "blit.vs.glsl", "border.fs.glsl" },
|
||||
{ "cross fade", "blit.vs.glsl", "cross_fade.fs.glsl" },
|
||||
{ "blit", "blit.fs.glsl" },
|
||||
{ "color", "color.fs.glsl" },
|
||||
{ "coloring", "coloring.fs.glsl" },
|
||||
{ "color matrix", "color_matrix.fs.glsl" },
|
||||
{ "linear gradient", "linear_gradient.fs.glsl" },
|
||||
{ "blur", "blur.fs.glsl" },
|
||||
{ "inset shadow", "inset_shadow.fs.glsl" },
|
||||
{ "outset shadow", "outset_shadow.fs.glsl" },
|
||||
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
|
||||
{ "border", "border.fs.glsl" },
|
||||
{ "cross fade", "cross_fade.fs.glsl" },
|
||||
};
|
||||
|
||||
builder = gsk_shader_builder_new ();
|
||||
@@ -1904,13 +2054,17 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
|
||||
#endif
|
||||
|
||||
gsk_shader_builder_set_common_vertex_shader (builder, "blit.vs.glsl",
|
||||
&shader_error);
|
||||
|
||||
g_assert_no_error (shader_error);
|
||||
|
||||
for (i = 0; i < GL_N_PROGRAMS; i ++)
|
||||
{
|
||||
Program *prog = &self->programs[i];
|
||||
|
||||
prog->index = i;
|
||||
prog->id = gsk_shader_builder_create_program (builder,
|
||||
program_definitions[i].vs,
|
||||
program_definitions[i].fs,
|
||||
&shader_error);
|
||||
|
||||
@@ -1919,7 +2073,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
g_propagate_prefixed_error (error, shader_error,
|
||||
"Unable to create '%s' program (from %s and %s):\n",
|
||||
program_definitions[i].name,
|
||||
program_definitions[i].vs,
|
||||
"blit.vs.glsl",
|
||||
program_definitions[i].fs);
|
||||
|
||||
g_object_unref (builder);
|
||||
@@ -2142,12 +2296,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
{
|
||||
graphene_rect_t transformed_node_bounds;
|
||||
|
||||
graphene_matrix_transform_bounds (&builder->current_modelview,
|
||||
&node->bounds,
|
||||
&transformed_node_bounds);
|
||||
graphene_rect_offset (&transformed_node_bounds, builder->dx, builder->dy);
|
||||
ops_transform_bounds_modelview (builder,
|
||||
&node->bounds,
|
||||
&transformed_node_bounds);
|
||||
|
||||
if (!graphene_rect_intersection (&builder->current_clip.bounds,
|
||||
if (!graphene_rect_intersection (&builder->current_clip->bounds,
|
||||
&transformed_node_bounds, NULL))
|
||||
return;
|
||||
}
|
||||
@@ -2256,30 +2409,29 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
}
|
||||
|
||||
static void
|
||||
add_offscreen_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
float min_x,
|
||||
float max_x,
|
||||
float min_y,
|
||||
float max_y,
|
||||
GskRenderNode *child_node,
|
||||
int *texture_id,
|
||||
gboolean *is_offscreen,
|
||||
gboolean force_offscreen,
|
||||
gboolean reset_clip)
|
||||
add_offscreen_ops (GskGLRenderer *self,
|
||||
RenderOpBuilder *builder,
|
||||
const graphene_rect_t *bounds,
|
||||
GskRenderNode *child_node,
|
||||
int *texture_id_out,
|
||||
gboolean *is_offscreen,
|
||||
gboolean force_offscreen,
|
||||
gboolean reset_clip)
|
||||
{
|
||||
const float scale = ops_get_scale (builder);
|
||||
const float width = (max_x - min_x) * scale;
|
||||
const float height = (max_y - min_y) * scale;
|
||||
const float width = bounds->size.width * scale;
|
||||
const float height = bounds->size.height * scale;
|
||||
const float dx = builder->dx;
|
||||
const float dy = builder->dy;
|
||||
int render_target;
|
||||
int prev_render_target;
|
||||
RenderOp op;
|
||||
graphene_matrix_t identity;
|
||||
graphene_matrix_t prev_projection;
|
||||
graphene_matrix_t prev_modelview;
|
||||
graphene_rect_t prev_viewport;
|
||||
graphene_matrix_t item_proj;
|
||||
GskRoundedRect prev_clip;
|
||||
float prev_opacity;
|
||||
int texture_id = 0;
|
||||
|
||||
/* We need the child node as a texture. If it already is one, we don't need to draw
|
||||
* it on a framebuffer of course. */
|
||||
@@ -2290,22 +2442,37 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
|
||||
get_gl_scaling_filters (child_node, &gl_min_filter, &gl_mag_filter);
|
||||
|
||||
*texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
|
||||
texture,
|
||||
gl_min_filter,
|
||||
gl_mag_filter);
|
||||
*texture_id_out = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
|
||||
texture,
|
||||
gl_min_filter,
|
||||
gl_mag_filter);
|
||||
*is_offscreen = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
*texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, *texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, *texture_id);
|
||||
render_target = gsk_gl_driver_create_render_target (self->gl_driver, *texture_id, TRUE, TRUE);
|
||||
/* Check if we've already cached the drawn texture. */
|
||||
{
|
||||
const int cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, child_node);
|
||||
|
||||
if (cached_id != 0)
|
||||
{
|
||||
*texture_id_out = cached_id;
|
||||
/* We didn't render it offscreen, but hand out an offscreen texture id */
|
||||
*is_offscreen = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
|
||||
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, TRUE, TRUE);
|
||||
|
||||
graphene_matrix_init_ortho (&item_proj,
|
||||
min_x * scale, max_x * scale,
|
||||
min_y * scale, max_y * scale,
|
||||
bounds->origin.x * scale,
|
||||
(bounds->origin.x + bounds->size.width) * scale,
|
||||
bounds->origin.y * scale,
|
||||
(bounds->origin.y + bounds->size.height) * scale,
|
||||
ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
|
||||
graphene_matrix_scale (&item_proj, 1, -1, 1);
|
||||
graphene_matrix_init_identity (&identity);
|
||||
@@ -2316,27 +2483,39 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
op.op = OP_CLEAR;
|
||||
ops_add (builder, &op);
|
||||
prev_projection = ops_set_projection (builder, &item_proj);
|
||||
prev_modelview = ops_set_modelview (builder, &identity);
|
||||
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (min_x * scale,
|
||||
min_y * scale,
|
||||
width, height));
|
||||
ops_push_modelview (builder, &identity);
|
||||
prev_viewport = ops_set_viewport (builder,
|
||||
&GRAPHENE_RECT_INIT (bounds->origin.x * scale,
|
||||
bounds->origin.y * scale,
|
||||
width, height));
|
||||
if (reset_clip)
|
||||
prev_clip = ops_set_clip (builder,
|
||||
&GSK_ROUNDED_RECT_INIT (min_x * scale,
|
||||
min_y * scale,
|
||||
width, height));
|
||||
ops_push_clip (builder,
|
||||
&GSK_ROUNDED_RECT_INIT (bounds->origin.x * scale,
|
||||
bounds->origin.y * scale,
|
||||
width, height));
|
||||
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
prev_opacity = ops_set_opacity (builder, 1.0);
|
||||
|
||||
gsk_gl_renderer_add_render_ops (self, child_node, builder);
|
||||
|
||||
ops_set_opacity (builder, prev_opacity);
|
||||
builder->dx = dx;
|
||||
builder->dy = dy;
|
||||
|
||||
if (reset_clip)
|
||||
ops_set_clip (builder, &prev_clip);
|
||||
ops_pop_clip (builder);
|
||||
|
||||
ops_set_viewport (builder, &prev_viewport);
|
||||
ops_set_modelview (builder, &prev_modelview);
|
||||
ops_pop_modelview (builder);
|
||||
ops_set_projection (builder, &prev_projection);
|
||||
ops_set_render_target (builder, prev_render_target);
|
||||
|
||||
*is_offscreen = TRUE;
|
||||
*texture_id_out = texture_id;
|
||||
|
||||
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2483,6 +2662,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
|
||||
apply_border_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_BORDER_WIDTH:
|
||||
apply_border_width_op (program, op);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_UNBLURRED_OUTSET_SHADOW:
|
||||
apply_unblurred_outset_shadow_op (program, op);
|
||||
break;
|
||||
@@ -2493,6 +2676,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
|
||||
glDrawArrays (GL_TRIANGLES, op->draw.vao_offset, op->draw.vao_size);
|
||||
break;
|
||||
|
||||
case OP_DUMP_FRAMEBUFFER:
|
||||
dump_framebuffer (op->dump.filename, op->dump.width, op->dump.height);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
@@ -2550,11 +2737,35 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
||||
memset (&render_op_builder, 0, sizeof (render_op_builder));
|
||||
render_op_builder.renderer = self;
|
||||
render_op_builder.current_projection = projection;
|
||||
render_op_builder.current_modelview = modelview;
|
||||
render_op_builder.current_viewport = *viewport;
|
||||
render_op_builder.current_opacity = 1.0f;
|
||||
render_op_builder.render_ops = self->render_ops;
|
||||
gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, viewport, 0.0f);
|
||||
ops_push_modelview (&render_op_builder, &modelview);
|
||||
|
||||
/* Initial clip is self->render_region! */
|
||||
if (self->render_region != NULL)
|
||||
{
|
||||
GskRoundedRect transformed_render_region = { 0, };
|
||||
cairo_rectangle_int_t render_extents;
|
||||
|
||||
cairo_region_get_extents (self->render_region, &render_extents);
|
||||
|
||||
ops_transform_bounds_modelview (&render_op_builder,
|
||||
&GRAPHENE_RECT_INIT (render_extents.x,
|
||||
render_extents.y,
|
||||
render_extents.width,
|
||||
render_extents.height),
|
||||
&transformed_render_region.bounds);
|
||||
ops_push_clip (&render_op_builder, &transformed_render_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
ops_push_clip (&render_op_builder,
|
||||
&GSK_ROUNDED_RECT_INIT (viewport->origin.x,
|
||||
viewport->origin.y,
|
||||
viewport->size.width,
|
||||
viewport->size.height));
|
||||
}
|
||||
|
||||
if (fbo_id != 0)
|
||||
ops_set_render_target (&render_op_builder, fbo_id);
|
||||
@@ -2563,6 +2774,9 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
|
||||
|
||||
/* We correctly reset the state everywhere */
|
||||
g_assert_cmpint (render_op_builder.current_render_target, ==, fbo_id);
|
||||
ops_pop_modelview (&render_op_builder);
|
||||
ops_pop_clip (&render_op_builder);
|
||||
ops_finish (&render_op_builder);
|
||||
|
||||
/*g_message ("Ops: %u", self->render_ops->len);*/
|
||||
|
||||
|
||||
+312
-60
@@ -1,5 +1,22 @@
|
||||
#include "gskglrenderopsprivate.h"
|
||||
|
||||
static inline gboolean
|
||||
rect_equal (const graphene_rect_t *a,
|
||||
const graphene_rect_t *b)
|
||||
{
|
||||
return memcmp (a, b, sizeof (graphene_rect_t)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
ops_finish (RenderOpBuilder *builder)
|
||||
{
|
||||
if (builder->mv_stack)
|
||||
g_array_free (builder->mv_stack, TRUE);
|
||||
|
||||
if (builder->clip_stack)
|
||||
g_array_free (builder->clip_stack, TRUE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rgba_to_float (const GdkRGBA *c,
|
||||
float *f)
|
||||
@@ -10,13 +27,134 @@ rgba_to_float (const GdkRGBA *c,
|
||||
f[3] = c->alpha;
|
||||
}
|
||||
|
||||
/* Debugging only! */
|
||||
void
|
||||
ops_dump_framebuffer (RenderOpBuilder *builder,
|
||||
const char *filename,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
RenderOp op;
|
||||
|
||||
op.op = OP_DUMP_FRAMEBUFFER;
|
||||
op.dump.filename = g_strdup (filename);
|
||||
op.dump.width = width;
|
||||
op.dump.height = height;
|
||||
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
|
||||
float
|
||||
ops_get_scale (const RenderOpBuilder *builder)
|
||||
{
|
||||
const graphene_matrix_t *mv = &builder->current_modelview;
|
||||
const MatrixStackEntry *head;
|
||||
|
||||
return MAX (graphene_matrix_get_x_scale (mv),
|
||||
graphene_matrix_get_y_scale (mv));
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
/* TODO: Use two separate values */
|
||||
return MAX (head->metadata.scale_x,
|
||||
head->metadata.scale_y);
|
||||
}
|
||||
|
||||
static void
|
||||
extract_matrix_metadata (const graphene_matrix_t *m,
|
||||
OpsMatrixMetadata *md)
|
||||
{
|
||||
graphene_vec3_t col1;
|
||||
graphene_vec3_t col2;
|
||||
|
||||
/* Translate */
|
||||
md->translate_x = graphene_matrix_get_value (m, 3, 0);
|
||||
md->translate_y = graphene_matrix_get_value (m, 3, 1);
|
||||
|
||||
/* Scale */
|
||||
graphene_vec3_init (&col1,
|
||||
graphene_matrix_get_value (m, 0, 0),
|
||||
graphene_matrix_get_value (m, 1, 0),
|
||||
graphene_matrix_get_value (m, 2, 0));
|
||||
|
||||
graphene_vec3_init (&col2,
|
||||
graphene_matrix_get_value (m, 0, 1),
|
||||
graphene_matrix_get_value (m, 1, 1),
|
||||
graphene_matrix_get_value (m, 2, 1));
|
||||
|
||||
md->scale_x = graphene_vec3_length (&col1);
|
||||
md->scale_y = graphene_vec3_length (&col2);
|
||||
|
||||
/* A simple matrix (in our case) is one that doesn't do anything but scale
|
||||
* and/or translate.
|
||||
*
|
||||
* For orher matrices, we fall back to offscreen drawing.
|
||||
*/
|
||||
md->simple = TRUE;
|
||||
{
|
||||
static const guchar check_zero[4][4] = {
|
||||
{ 0, 1, 0, 1 }, /* If any of the values marked as '1' here is non-zero, */
|
||||
{ 1, 0, 0, 1 }, /* We have to resort to offscreen drawing later on. */
|
||||
{ 1, 1, 0, 1 },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < 4; x ++)
|
||||
for (y = 0; y < 4; y ++)
|
||||
if (check_zero[y][x] &&
|
||||
graphene_matrix_get_value (m, y, x) != 0.0f)
|
||||
{
|
||||
md->simple = FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
md->only_translation = (md->simple && md->scale_x == 1 && md->scale_y == 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
|
||||
const graphene_rect_t *src,
|
||||
graphene_rect_t *dst)
|
||||
{
|
||||
const float scale = ops_get_scale (builder);
|
||||
const MatrixStackEntry *head;
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
if (head->metadata.only_translation)
|
||||
{
|
||||
*dst = *src;
|
||||
graphene_rect_offset (dst,
|
||||
head->metadata.translate_x,
|
||||
head->metadata.translate_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
graphene_matrix_transform_bounds (builder->current_modelview,
|
||||
src,
|
||||
dst);
|
||||
}
|
||||
|
||||
graphene_rect_offset (dst, builder->dx * scale, builder->dy * scale);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ops_modelview_is_simple (const RenderOpBuilder *builder)
|
||||
{
|
||||
const MatrixStackEntry *head;
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
return head->metadata.simple;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -29,6 +167,7 @@ ops_set_program (RenderOpBuilder *builder,
|
||||
static const graphene_matrix_t empty_matrix;
|
||||
static const graphene_rect_t empty_rect;
|
||||
RenderOp op;
|
||||
ProgramState *program_state;
|
||||
|
||||
if (builder->current_program == program)
|
||||
return;
|
||||
@@ -38,58 +177,61 @@ ops_set_program (RenderOpBuilder *builder,
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->current_program = program;
|
||||
|
||||
program_state = &builder->program_state[program->index];
|
||||
|
||||
/* If the projection is not yet set for this program, we use the current one. */
|
||||
if (memcmp (&empty_matrix, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) == 0 ||
|
||||
memcmp (&builder->current_projection, &builder->program_state[program->index].projection, sizeof (graphene_matrix_t)) != 0)
|
||||
if (memcmp (&empty_matrix, &program_state->projection, sizeof (graphene_matrix_t)) == 0 ||
|
||||
memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
|
||||
{
|
||||
op.op = OP_CHANGE_PROJECTION;
|
||||
op.projection = builder->current_projection;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->program_state[program->index].projection = builder->current_projection;
|
||||
program_state->projection = builder->current_projection;
|
||||
}
|
||||
|
||||
if (memcmp (&empty_matrix, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) == 0 ||
|
||||
memcmp (&builder->current_modelview, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) != 0)
|
||||
if (memcmp (&empty_matrix, &program_state->modelview, sizeof (graphene_matrix_t)) == 0 ||
|
||||
memcmp (builder->current_modelview, &program_state->modelview, sizeof (graphene_matrix_t)) != 0)
|
||||
{
|
||||
op.op = OP_CHANGE_MODELVIEW;
|
||||
op.modelview = builder->current_modelview;
|
||||
op.modelview = *builder->current_modelview;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->program_state[program->index].modelview = builder->current_modelview;
|
||||
program_state->modelview = *builder->current_modelview;
|
||||
}
|
||||
|
||||
if (memcmp (&empty_rect, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) == 0 ||
|
||||
memcmp (&builder->current_viewport, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) != 0)
|
||||
if (rect_equal (&empty_rect, &program_state->viewport) ||
|
||||
!rect_equal (&builder->current_viewport, &program_state->viewport))
|
||||
{
|
||||
op.op = OP_CHANGE_VIEWPORT;
|
||||
op.viewport = builder->current_viewport;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->program_state[program->index].viewport = builder->current_viewport;
|
||||
program_state->viewport = builder->current_viewport;
|
||||
}
|
||||
|
||||
if (memcmp (&empty_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) == 0 ||
|
||||
memcmp (&builder->current_clip, &builder->program_state[program->index].clip, sizeof (GskRoundedRect)) != 0)
|
||||
if (memcmp (&empty_clip, &program_state->clip, sizeof (GskRoundedRect)) == 0 ||
|
||||
memcmp (&builder->current_clip, &program_state->clip, sizeof (GskRoundedRect)) != 0)
|
||||
{
|
||||
op.op = OP_CHANGE_CLIP;
|
||||
op.clip = builder->current_clip;
|
||||
op.clip = *builder->current_clip;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->program_state[program->index].clip = builder->current_clip;
|
||||
program_state->clip = *builder->current_clip;
|
||||
}
|
||||
|
||||
if (builder->program_state[program->index].opacity != builder->current_opacity)
|
||||
if (program_state->opacity != builder->current_opacity)
|
||||
{
|
||||
op.op = OP_CHANGE_OPACITY;
|
||||
op.opacity = builder->current_opacity;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
builder->program_state[program->index].opacity = builder->current_opacity;
|
||||
program_state->opacity = builder->current_opacity;
|
||||
}
|
||||
|
||||
builder->current_program_state = &builder->program_state[program->index];
|
||||
}
|
||||
|
||||
GskRoundedRect
|
||||
static void
|
||||
ops_set_clip (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *clip)
|
||||
{
|
||||
RenderOp *last_op;
|
||||
GskRoundedRect prev_clip;
|
||||
|
||||
if (builder->render_ops->len > 0)
|
||||
{
|
||||
@@ -110,25 +252,62 @@ ops_set_clip (RenderOpBuilder *builder,
|
||||
}
|
||||
|
||||
if (builder->current_program != NULL)
|
||||
builder->program_state[builder->current_program->index].clip = *clip;
|
||||
|
||||
prev_clip = builder->current_clip;
|
||||
builder->current_clip = *clip;
|
||||
|
||||
return prev_clip;
|
||||
builder->current_program_state->clip = *clip;
|
||||
}
|
||||
|
||||
graphene_matrix_t
|
||||
void
|
||||
ops_push_clip (RenderOpBuilder *self,
|
||||
const GskRoundedRect *clip)
|
||||
{
|
||||
if (G_UNLIKELY (self->clip_stack == NULL))
|
||||
self->clip_stack = g_array_new (FALSE, TRUE, sizeof (GskRoundedRect));
|
||||
|
||||
g_assert (self->clip_stack != NULL);
|
||||
|
||||
g_array_append_val (self->clip_stack, *clip);
|
||||
self->current_clip = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
|
||||
ops_set_clip (self, clip);
|
||||
}
|
||||
|
||||
void
|
||||
ops_pop_clip (RenderOpBuilder *self)
|
||||
{
|
||||
const GskRoundedRect *head;
|
||||
|
||||
g_assert (self->clip_stack);
|
||||
g_assert (self->clip_stack->len >= 1);
|
||||
|
||||
self->clip_stack->len --;
|
||||
head = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
|
||||
|
||||
if (self->clip_stack->len >= 1)
|
||||
{
|
||||
self->current_clip = head;
|
||||
ops_set_clip (self, head);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->current_clip = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
ops_has_clip (RenderOpBuilder *self)
|
||||
{
|
||||
return self->clip_stack != NULL &&
|
||||
self->clip_stack->len > 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ops_set_modelview (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *modelview)
|
||||
{
|
||||
RenderOp op;
|
||||
graphene_matrix_t prev_mv;
|
||||
|
||||
if (builder->current_program &&
|
||||
memcmp (&builder->program_state[builder->current_program->index].modelview, modelview,
|
||||
memcmp (&builder->current_program_state->modelview, modelview,
|
||||
sizeof (graphene_matrix_t)) == 0)
|
||||
return *modelview;
|
||||
return;
|
||||
|
||||
if (builder->render_ops->len > 0)
|
||||
{
|
||||
@@ -152,12 +331,52 @@ ops_set_modelview (RenderOpBuilder *builder,
|
||||
}
|
||||
|
||||
if (builder->current_program != NULL)
|
||||
builder->program_state[builder->current_program->index].modelview = *modelview;
|
||||
builder->current_program_state->modelview = *modelview;
|
||||
}
|
||||
|
||||
prev_mv = builder->current_modelview;
|
||||
builder->current_modelview = *modelview;
|
||||
void
|
||||
ops_push_modelview (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *mv)
|
||||
{
|
||||
MatrixStackEntry *entry;
|
||||
|
||||
return prev_mv;
|
||||
if (G_UNLIKELY (builder->mv_stack == NULL))
|
||||
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
|
||||
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
|
||||
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
entry->matrix = *mv;
|
||||
extract_matrix_metadata (mv, &entry->metadata);
|
||||
|
||||
builder->current_modelview = &entry->matrix;
|
||||
ops_set_modelview (builder, mv);
|
||||
}
|
||||
|
||||
void
|
||||
ops_pop_modelview (RenderOpBuilder *builder)
|
||||
{
|
||||
const graphene_matrix_t *m;
|
||||
const MatrixStackEntry *head;
|
||||
|
||||
g_assert (builder->mv_stack);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
builder->mv_stack->len --;
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
m = &head->matrix;
|
||||
|
||||
if (builder->mv_stack->len >= 1)
|
||||
{
|
||||
builder->current_modelview = m;
|
||||
ops_set_modelview (builder, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder->current_modelview = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
graphene_matrix_t
|
||||
@@ -189,7 +408,7 @@ ops_set_projection (RenderOpBuilder *builder,
|
||||
}
|
||||
|
||||
if (builder->current_program != NULL)
|
||||
builder->program_state[builder->current_program->index].projection = *projection;
|
||||
builder->current_program_state->projection = *projection;
|
||||
|
||||
prev_mv = builder->current_projection;
|
||||
builder->current_projection = *projection;
|
||||
@@ -204,12 +423,16 @@ ops_set_viewport (RenderOpBuilder *builder,
|
||||
RenderOp op;
|
||||
graphene_rect_t prev_viewport;
|
||||
|
||||
if (builder->current_program_state != NULL &&
|
||||
rect_equal (&builder->current_program_state->viewport, viewport))
|
||||
return builder->current_program_state->viewport;
|
||||
|
||||
op.op = OP_CHANGE_VIEWPORT;
|
||||
op.viewport = *viewport;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
|
||||
if (builder->current_program != NULL)
|
||||
builder->program_state[builder->current_program->index].viewport = *viewport;
|
||||
builder->current_program_state->viewport = *viewport;
|
||||
|
||||
prev_viewport = builder->current_viewport;
|
||||
builder->current_viewport = *viewport;
|
||||
@@ -243,9 +466,28 @@ ops_set_render_target (RenderOpBuilder *builder,
|
||||
return render_target_id;
|
||||
|
||||
prev_render_target = builder->current_render_target;
|
||||
op.op = OP_CHANGE_RENDER_TARGET;
|
||||
op.render_target_id = render_target_id;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
|
||||
if (builder->render_ops->len > 0)
|
||||
{
|
||||
RenderOp *last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1);
|
||||
if (last_op->op == OP_CHANGE_RENDER_TARGET)
|
||||
{
|
||||
last_op->render_target_id = render_target_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
op.op = OP_CHANGE_RENDER_TARGET;
|
||||
op.render_target_id = render_target_id;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
op.op = OP_CHANGE_RENDER_TARGET;
|
||||
op.render_target_id = render_target_id;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
|
||||
builder->current_render_target = render_target_id;
|
||||
|
||||
return prev_render_target;
|
||||
@@ -288,7 +530,7 @@ ops_set_opacity (RenderOpBuilder *builder,
|
||||
builder->current_opacity = opacity;
|
||||
|
||||
if (builder->current_program != NULL)
|
||||
builder->program_state[builder->current_program->index].opacity = opacity;
|
||||
builder->current_program_state->opacity = opacity;
|
||||
|
||||
return prev_opacity;
|
||||
}
|
||||
@@ -299,10 +541,10 @@ ops_set_color (RenderOpBuilder *builder,
|
||||
{
|
||||
RenderOp op;
|
||||
|
||||
if (gdk_rgba_equal (color, &builder->program_state[builder->current_program->index].color))
|
||||
if (gdk_rgba_equal (color, &builder->current_program_state->color))
|
||||
return;
|
||||
|
||||
builder->program_state[builder->current_program->index].color = *color;
|
||||
builder->current_program_state->color = *color;
|
||||
|
||||
op.op = OP_CHANGE_COLOR;
|
||||
op.color = *color;
|
||||
@@ -317,15 +559,15 @@ ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
RenderOp op;
|
||||
|
||||
if (memcmp (matrix,
|
||||
&builder->program_state[builder->current_program->index].color_matrix.matrix,
|
||||
&builder->current_program_state->color_matrix.matrix,
|
||||
sizeof (graphene_matrix_t)) == 0 &&
|
||||
memcmp (offset,
|
||||
&builder->program_state[builder->current_program->index].color_matrix.offset,
|
||||
&builder->current_program_state->color_matrix.offset,
|
||||
sizeof (graphene_vec4_t)) == 0)
|
||||
return;
|
||||
|
||||
builder->program_state[builder->current_program->index].color_matrix.matrix = *matrix;
|
||||
builder->program_state[builder->current_program->index].color_matrix.offset = *offset;
|
||||
builder->current_program_state->color_matrix.matrix = *matrix;
|
||||
builder->current_program_state->color_matrix.offset = *offset;
|
||||
|
||||
op.op = OP_CHANGE_COLOR_MATRIX;
|
||||
op.color_matrix.matrix = *matrix;
|
||||
@@ -335,30 +577,40 @@ ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
|
||||
void
|
||||
ops_set_border (RenderOpBuilder *builder,
|
||||
const float *widths,
|
||||
const GskRoundedRect *outline)
|
||||
{
|
||||
RenderOp op;
|
||||
|
||||
/* TODO: Assert that current_program == border program? */
|
||||
|
||||
if (memcmp (&builder->program_state[builder->current_program->index].border.widths,
|
||||
widths, sizeof (float) * 4) == 0 &&
|
||||
memcmp (&builder->program_state[builder->current_program->index].border.outline,
|
||||
if (memcmp (&builder->current_program_state->border.outline,
|
||||
outline, sizeof (GskRoundedRect)) == 0)
|
||||
return;
|
||||
|
||||
memcpy (&builder->program_state[builder->current_program->index].border.widths,
|
||||
widths, sizeof (float) * 4);
|
||||
|
||||
builder->program_state[builder->current_program->index].border.outline = *outline;
|
||||
builder->current_program_state->border.outline = *outline;
|
||||
|
||||
op.op = OP_CHANGE_BORDER;
|
||||
op.border.outline = *outline;
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_border_width (RenderOpBuilder *builder,
|
||||
const float *widths)
|
||||
{
|
||||
RenderOp op;
|
||||
|
||||
if (memcmp (builder->current_program_state->border.widths,
|
||||
widths, sizeof (float) * 4) == 0)
|
||||
return;
|
||||
|
||||
memcpy (&builder->current_program_state->border.widths,
|
||||
widths, sizeof (float) * 4);
|
||||
|
||||
op.op = OP_CHANGE_BORDER_WIDTH;
|
||||
op.border.widths[0] = widths[0];
|
||||
op.border.widths[1] = widths[1];
|
||||
op.border.widths[2] = widths[2];
|
||||
op.border.widths[3] = widths[3];
|
||||
op.border.outline = *outline;
|
||||
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
|
||||
@@ -370,11 +622,11 @@ ops_set_border_color (RenderOpBuilder *builder,
|
||||
op.op = OP_CHANGE_BORDER_COLOR;
|
||||
rgba_to_float (color, op.border.color);
|
||||
|
||||
if (memcmp (&op.border.color, &builder->program_state[builder->current_program->index].border.color,
|
||||
if (memcmp (&op.border.color, &builder->current_program_state->border.color,
|
||||
sizeof (float) * 4) == 0)
|
||||
return;
|
||||
|
||||
rgba_to_float (color, builder->program_state[builder->current_program->index].border.color);
|
||||
rgba_to_float (color, builder->current_program_state->border.color);
|
||||
|
||||
g_array_append_val (builder->render_ops, op);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,26 @@
|
||||
#include "gskglrendererprivate.h"
|
||||
|
||||
#define GL_N_VERTICES 6
|
||||
#define GL_N_PROGRAMS 12
|
||||
#define GL_N_PROGRAMS 11
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float translate_x;
|
||||
float translate_y;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
|
||||
guint simple : 1;
|
||||
guint only_translation : 1;
|
||||
} OpsMatrixMetadata;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
graphene_matrix_t matrix;
|
||||
OpsMatrixMetadata metadata;
|
||||
} MatrixStackEntry;
|
||||
|
||||
enum {
|
||||
OP_NONE,
|
||||
@@ -31,10 +50,12 @@ enum {
|
||||
OP_CHANGE_OUTSET_SHADOW = 15,
|
||||
OP_CHANGE_BORDER = 16,
|
||||
OP_CHANGE_BORDER_COLOR = 17,
|
||||
OP_CHANGE_CROSS_FADE = 18,
|
||||
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 19,
|
||||
OP_CLEAR = 20,
|
||||
OP_DRAW = 21,
|
||||
OP_CHANGE_BORDER_WIDTH = 18,
|
||||
OP_CHANGE_CROSS_FADE = 19,
|
||||
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 20,
|
||||
OP_CLEAR = 21,
|
||||
OP_DRAW = 22,
|
||||
OP_DUMP_FRAMEBUFFER = 23,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -188,40 +209,46 @@ typedef struct
|
||||
float progress;
|
||||
int source2;
|
||||
} cross_fade;
|
||||
struct {
|
||||
char *filename;
|
||||
int width;
|
||||
int height;
|
||||
} dump;
|
||||
};
|
||||
} RenderOp;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Per-Program State */
|
||||
struct {
|
||||
GskRoundedRect clip;
|
||||
graphene_matrix_t modelview;
|
||||
graphene_matrix_t projection;
|
||||
int source_texture;
|
||||
graphene_rect_t viewport;
|
||||
float opacity;
|
||||
/* Per-program state */
|
||||
union {
|
||||
GdkRGBA color;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
float widths[4];
|
||||
float color[4];
|
||||
GskRoundedRect outline;
|
||||
} border;
|
||||
};
|
||||
} program_state[GL_N_PROGRAMS];
|
||||
GskRoundedRect clip;
|
||||
graphene_matrix_t modelview;
|
||||
graphene_matrix_t projection;
|
||||
int source_texture;
|
||||
graphene_rect_t viewport;
|
||||
float opacity;
|
||||
/* Per-program state */
|
||||
union {
|
||||
GdkRGBA color;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
float widths[4];
|
||||
float color[4];
|
||||
GskRoundedRect outline;
|
||||
} border;
|
||||
};
|
||||
} ProgramState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ProgramState program_state[GL_N_PROGRAMS];
|
||||
/* Current global state */
|
||||
ProgramState *current_program_state;
|
||||
const Program *current_program;
|
||||
int current_render_target;
|
||||
int current_texture;
|
||||
GskRoundedRect current_clip;
|
||||
graphene_matrix_t current_modelview;
|
||||
|
||||
graphene_matrix_t current_projection;
|
||||
graphene_rect_t current_viewport;
|
||||
float current_opacity;
|
||||
@@ -231,20 +258,41 @@ typedef struct
|
||||
|
||||
GArray *render_ops;
|
||||
GskGLRenderer *renderer;
|
||||
|
||||
/* Stack of modelview matrices */
|
||||
GArray *mv_stack;
|
||||
/* Pointer into mv_stack */
|
||||
const graphene_matrix_t *current_modelview;
|
||||
|
||||
/* Same thing */
|
||||
GArray *clip_stack;
|
||||
const GskRoundedRect *current_clip;
|
||||
} RenderOpBuilder;
|
||||
|
||||
|
||||
void ops_dump_framebuffer (RenderOpBuilder *builder,
|
||||
const char *filename,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void ops_finish (RenderOpBuilder *builder);
|
||||
void ops_push_modelview (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *mv);
|
||||
void ops_pop_modelview (RenderOpBuilder *builder);
|
||||
gboolean ops_modelview_is_simple (const RenderOpBuilder *builder);
|
||||
float ops_get_scale (const RenderOpBuilder *builder);
|
||||
|
||||
void ops_set_program (RenderOpBuilder *builder,
|
||||
const Program *program);
|
||||
|
||||
GskRoundedRect ops_set_clip (RenderOpBuilder *builder,
|
||||
void ops_push_clip (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *clip);
|
||||
void ops_pop_clip (RenderOpBuilder *builder);
|
||||
gboolean ops_has_clip (RenderOpBuilder *builder);
|
||||
|
||||
graphene_matrix_t ops_set_modelview (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *modelview);
|
||||
void ops_transform_bounds_modelview (const RenderOpBuilder *builder,
|
||||
const graphene_rect_t *src,
|
||||
graphene_rect_t *dst);
|
||||
|
||||
graphene_matrix_t ops_set_projection (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *projection);
|
||||
@@ -268,8 +316,9 @@ void ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
const graphene_vec4_t *offset);
|
||||
|
||||
void ops_set_border (RenderOpBuilder *builder,
|
||||
const float *widths,
|
||||
const GskRoundedRect *outline);
|
||||
void ops_set_border_width (RenderOpBuilder *builder,
|
||||
const float *widths);
|
||||
|
||||
void ops_set_border_color (RenderOpBuilder *builder,
|
||||
const GdkRGBA *color);
|
||||
|
||||
+29
-11
@@ -15,6 +15,9 @@ struct _GskShaderBuilder
|
||||
char *vertex_preamble;
|
||||
char *fragment_preamble;
|
||||
|
||||
|
||||
int common_vertex_shader_id;
|
||||
|
||||
int version;
|
||||
|
||||
GPtrArray *defines;
|
||||
@@ -37,6 +40,9 @@ gsk_shader_builder_finalize (GObject *gobject)
|
||||
|
||||
g_clear_pointer (&self->defines, g_ptr_array_unref);
|
||||
|
||||
if (self->common_vertex_shader_id > 0)
|
||||
glDeleteShader (self->common_vertex_shader_id);
|
||||
|
||||
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
@@ -230,27 +236,39 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder *self,
|
||||
const char *vertex_shader,
|
||||
GError **error)
|
||||
{
|
||||
int shader_id;
|
||||
|
||||
|
||||
shader_id = gsk_shader_builder_compile_shader (self,
|
||||
GL_VERTEX_SHADER,
|
||||
self->vertex_preamble,
|
||||
vertex_shader,
|
||||
error);
|
||||
|
||||
g_assert (shader_id > 0);
|
||||
self->common_vertex_shader_id = shader_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error)
|
||||
{
|
||||
int vertex_id, fragment_id;
|
||||
int vertex_id;
|
||||
int fragment_id;
|
||||
int program_id;
|
||||
int status;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
|
||||
g_return_val_if_fail (vertex_shader != NULL, -1);
|
||||
g_return_val_if_fail (fragment_shader != NULL, -1);
|
||||
g_return_val_if_fail (builder->common_vertex_shader_id != 0, -1);
|
||||
|
||||
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
|
||||
builder->vertex_preamble,
|
||||
vertex_shader,
|
||||
error);
|
||||
if (vertex_id < 0)
|
||||
return -1;
|
||||
|
||||
vertex_id = builder->common_vertex_shader_id;
|
||||
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
|
||||
builder->fragment_preamble,
|
||||
fragment_shader,
|
||||
@@ -290,8 +308,8 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
out:
|
||||
if (vertex_id > 0)
|
||||
{
|
||||
/* We delete the common vertex shader when destroying the shader builder */
|
||||
glDetachShader (program_id, vertex_id);
|
||||
glDeleteShader (vertex_id);
|
||||
}
|
||||
|
||||
if (fragment_id > 0)
|
||||
|
||||
@@ -25,8 +25,11 @@ void gsk_shader_builder_add_define (GskShad
|
||||
const char *define_name,
|
||||
const char *define_value);
|
||||
|
||||
void gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder *self,
|
||||
const char *vertex_shader,
|
||||
GError **error);
|
||||
|
||||
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error);
|
||||
|
||||
|
||||
+1
-2
@@ -1,6 +1,4 @@
|
||||
gsk_private_gl_shaders = [
|
||||
'resources/glsl/blend.fs.glsl',
|
||||
'resources/glsl/blend.vs.glsl',
|
||||
'resources/glsl/blit.fs.glsl',
|
||||
'resources/glsl/blit.vs.glsl',
|
||||
'resources/glsl/color.fs.glsl',
|
||||
@@ -43,6 +41,7 @@ gsk_private_sources = files([
|
||||
'gl/gskgldriver.c',
|
||||
'gl/gskglrenderops.c',
|
||||
'gl/gskglshadowcache.c',
|
||||
'gl/gskglnodesample.c',
|
||||
])
|
||||
|
||||
gsk_public_headers = files([
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
vec3 BlendMultiply(vec3 Cb, vec3 Cs) {
|
||||
return Cb * Cs;
|
||||
}
|
||||
|
||||
vec3 BlendScreen(vec3 Cb, vec3 Cs) {
|
||||
return Cb + Cs - (Cb * Cs);
|
||||
}
|
||||
|
||||
vec3 BlendHardLight(vec3 Cb, vec3 Cs) {
|
||||
vec3 m = BlendMultiply(Cb, 2.0 * Cs);
|
||||
vec3 s = BlendScreen(Cb, 2.0 * Cs - 1.0);
|
||||
vec3 edge = vec3(0.5, 0.5, 0.5);
|
||||
|
||||
/* Use mix() and step() to avoid a branch */
|
||||
return mix(m, s, step(edge, Cs));
|
||||
}
|
||||
|
||||
vec3 BlendOverlay(vec3 Cb, vec3 Cs) {
|
||||
return BlendHardLight(Cs, Cb);
|
||||
}
|
||||
|
||||
vec3 BlendDarken(vec3 Cb, vec3 Cs) {
|
||||
return min(Cb, Cs);
|
||||
}
|
||||
|
||||
vec3 BlendLighten(vec3 Cb, vec3 Cs) {
|
||||
return max(Cb, Cs);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 Cs = Texture(u_source, vUv);
|
||||
vec4 Cb = Texture(u_mask, vUv);
|
||||
vec3 res;
|
||||
|
||||
if (uBlendMode == 0) {
|
||||
res = Cs.xyz;
|
||||
}
|
||||
else if (uBlendMode == 1) {
|
||||
res = BlendMultiply(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 2) {
|
||||
res = BlendScreen(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 3) {
|
||||
res = BlendOverlay(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 4) {
|
||||
res = BlendDarken(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 5) {
|
||||
res = BlendLighten(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 8) {
|
||||
res = BlendHardLight(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else {
|
||||
// Use red for debugging missing blend modes
|
||||
res = vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
setOutputColor(vec4(res, Cs.a) * u_alpha);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
void main() {
|
||||
gl_Position = u_modelview * u_projection * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
@@ -120,16 +120,12 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
|
||||
|
||||
if (gi->glyph != PANGO_GLYPH_EMPTY)
|
||||
{
|
||||
double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
double cy = gi->geometry.y_offset / PANGO_SCALE;
|
||||
double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
|
||||
GskVulkanColorTextInstance *instance = &instances[count];
|
||||
GskVulkanCachedGlyph *glyph;
|
||||
|
||||
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font,
|
||||
gi->glyph,
|
||||
x_position + gi->geometry.x_offset,
|
||||
gi->geometry.y_offset,
|
||||
scale);
|
||||
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
|
||||
|
||||
instance->tex_rect[0] = glyph->tx;
|
||||
instance->tex_rect[1] = glyph->ty;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user