Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fac12b5426 | |||
| b58278acf1 | |||
| 4e166f39fe | |||
| 5f79958716 | |||
| aee0af34af | |||
| 7e32eb2e98 | |||
| 7ea7d5c390 | |||
| e3e9dda429 | |||
| a3ab25bf1d | |||
| 095dec9238 | |||
| 0e34365139 | |||
| 88a62564f1 | |||
| 6ac94dc5c3 | |||
| 5a9a0874bd | |||
| 91992111c3 | |||
| 120d874805 | |||
| 9454bad891 | |||
| 9cb410fd9b | |||
| 0f3fbed13c | |||
| 43ee9746bd | |||
| 7283c5c22f | |||
| 8b71fe4af6 | |||
| b627fb5970 | |||
| be3ad1ef99 | |||
| 54264a9f78 | |||
| 65380c66bd | |||
| 8c96991ce0 | |||
| 07a44993ac | |||
| 60d2d25463 | |||
| 907f99b176 | |||
| ce6aa73c64 | |||
| 257bef85d0 | |||
| a48df87a85 | |||
| fe4cd7cf0f | |||
| 229b34d478 | |||
| 1985f2c9ad | |||
| 01d57a7566 | |||
| 7a4b2c10c7 | |||
| 208b2d37b6 | |||
| ef98912779 | |||
| b1e3b18ede | |||
| 0194cadbc0 | |||
| b4dfc4adfc | |||
| fd556ec377 | |||
| 1dbc1d67f5 | |||
| 8790c83a76 | |||
| 6b202fb838 | |||
| f69476435f | |||
| 8df6e2cdaf | |||
| 2861ab38ac | |||
| 23c2122c13 | |||
| 5b83ffa4a0 | |||
| cf8e3157a7 | |||
| 7323172755 | |||
| cfee8f4b11 | |||
| 7ae099c94c | |||
| 42298d8ab1 | |||
| 68912698f1 | |||
| c8c56f8d42 | |||
| 7f48b5a05c | |||
| 1e5e977b37 | |||
| 62d44b6bc7 | |||
| 862afeffe0 | |||
| 92f9195015 | |||
| fc6e08082b | |||
| af7516b797 | |||
| 3f1821e372 | |||
| b569470b87 | |||
| f1a3235039 | |||
| 34e90005af | |||
| 4f1cc8ec6d | |||
| 5242205a65 | |||
| 59633a6781 | |||
| d82316edda | |||
| 0815640b22 | |||
| 26de2eae20 | |||
| 8fa358c4d4 | |||
| fc72449228 | |||
| 84a304e66e | |||
| ecf1b7c18a | |||
| a7c5b53f46 | |||
| 09736dde93 | |||
| 66c00dc9f3 | |||
| 3eacf8bd39 | |||
| 34e9ef9e78 | |||
| a5955106ea | |||
| ea0cfed735 | |||
| f312d1ee6a | |||
| 69b6f4cf4f | |||
| d7e1c377fe | |||
| cc17577763 | |||
| ef4ae61c66 | |||
| e04ea3f311 | |||
| 77a2cd4d8d | |||
| 0986981d1a | |||
| 913f850f83 | |||
| ed31da3730 | |||
| 428ff6c4ab | |||
| 53786841cc | |||
| 8f8ece44a8 | |||
| 41a892b958 | |||
| b494ed5876 | |||
| 7b589f991d | |||
| d83faf82d7 | |||
| cd46016238 | |||
| f2a3218455 | |||
| 85b1959714 | |||
| b23600ae4b | |||
| bdc43b8fca | |||
| da2ef6911f | |||
| 0626246367 | |||
| 0edfafdfdf | |||
| 1863b79fb3 | |||
| 9aa90f8df0 | |||
| 8080d9e7c1 | |||
| f432ee775f | |||
| 77f9cb11a9 | |||
| d92e3cb864 | |||
| 733fa156b9 | |||
| d181d53762 | |||
| 644e6f8ebe | |||
| 0b4c695d65 | |||
| 448287bd58 | |||
| 5e6aff69c6 | |||
| d88e616711 | |||
| 0e5c94a094 | |||
| bb0aeec99c | |||
| 880e3ef289 | |||
| 94a09263d7 | |||
| ab9106ac89 | |||
| ff6451a77e | |||
| 4f2d63b8ac | |||
| 81c97f0910 | |||
| d1b52cc292 | |||
| ddedb39329 | |||
| d45987e637 | |||
| b95eceea60 | |||
| 2774e80fc4 | |||
| 7c207c4868 | |||
| c6c8abcf21 | |||
| a59c967675 | |||
| c3329f5fcc | |||
| 4f06e46759 | |||
| 7e522a8c55 | |||
| d9447fd2e7 | |||
| 95214f3697 | |||
| fe64c998f8 | |||
| 84582ad762 | |||
| fcc7a58058 | |||
| 8a48becb7e | |||
| 465446430e | |||
| 4060c43ae7 | |||
| 4ec9a2a330 | |||
| 90c017a762 | |||
| e011434223 | |||
| b1ccb4103d | |||
| 8033809f8b | |||
| 66ba1f76ba | |||
| 0ca822c716 | |||
| 4ac288c1b4 | |||
| 64316ab185 | |||
| 4d90a693ae | |||
| 0c5f943783 | |||
| 42fc165b94 | |||
| 20a4e3f351 | |||
| f3f90e1d71 | |||
| b018da2acd | |||
| ab5f3f59ce | |||
| 0127217e10 | |||
| 16a476fe22 | |||
| c8ca6930c5 | |||
| c4f33f36de | |||
| 0543c48862 | |||
| fcb17a86e6 | |||
| 5633b5b637 | |||
| f7eaf69d67 | |||
| 32411943ea | |||
| 58fa5d7617 | |||
| f9ee1967f4 | |||
| 6a376f0a30 | |||
| 66826c26db | |||
| 8d1e37789e | |||
| 6c39a5946e | |||
| 2a98928286 | |||
| c7806eb908 | |||
| 9015734e65 | |||
| f5159e1ecb | |||
| aec2f50d82 | |||
| 74860f7602 | |||
| a9175e0c03 | |||
| e1c56555af | |||
| 24120c8fd0 | |||
| f284331f79 | |||
| a82de96e1a | |||
| eba9b116ed | |||
| 1f89b3c7df | |||
| c739b9fe7f | |||
| 556b729b97 | |||
| 9fd5558acd | |||
| b7422c0f62 | |||
| ace684c7ab | |||
| 752e704e99 | |||
| 8c7e13746b | |||
| c2311c7154 | |||
| 44fa748826 | |||
| dfed398371 | |||
| 962ba49a8e | |||
| 5811e443f8 | |||
| f55e1392d4 | |||
| 0fbe5ba40c | |||
| 980ea63d78 | |||
| dcc3533363 | |||
| 28964aa0a4 | |||
| 7fd8a0ac99 | |||
| d919ed4e4b | |||
| 61ec6fb5eb | |||
| 237eb8bb90 | |||
| ff57cd9331 | |||
| c97d02f487 | |||
| 36ced69ebf | |||
| 427a52a9ad | |||
| 9b5aee0d1b | |||
| ee5afdf919 | |||
| 49a6b5d50a | |||
| dd7a0cbeb7 | |||
| 38d808f3e2 | |||
| 16a608b9e5 | |||
| f1ff37e970 | |||
| 71c68f5f36 | |||
| 0d3265edc7 | |||
| 854e40c60c | |||
| 882387a62a | |||
| 73f7370ead | |||
| 8e9241f3ba | |||
| 3c67931f5f | |||
| 06f3b5dfd4 | |||
| 05acb70d1c | |||
| 7b380b2ffc | |||
| f6e4b964b7 | |||
| 0b2d08f076 | |||
| 1ad1a9fe4a | |||
| fe15db92bd | |||
| 682b7773fc | |||
| 9055b6c6e5 | |||
| 9fd56dc5ad | |||
| 1ec7f2bbcd | |||
| 4eb7208e35 | |||
| 1ad88f7662 | |||
| 96b30073cf | |||
| 456956a2bd | |||
| 4c794505da | |||
| f627c9443e | |||
| 06fa9befe0 | |||
| a95dc5d609 | |||
| 2abe588e91 | |||
| ecdee288a7 | |||
| e363fcca3c | |||
| f46fb7c6fc | |||
| 985d964a34 | |||
| 2a0286c19c | |||
| 9a05af61e8 | |||
| 68d2e9c068 | |||
| 89ba937fd3 | |||
| 840cd6f10f | |||
| cccfc1a38d | |||
| ff26aa2fa7 | |||
| 7192e67a6f | |||
| 5354b91e64 | |||
| c9c6b7bb2a | |||
| c93fa922dc | |||
| 8d7bfa2628 | |||
| e6a4cc8ba2 | |||
| 7926ee68b8 | |||
| 239d47791d | |||
| 33f210bc85 | |||
| 021aae84dd | |||
| e8508762f5 | |||
| a0bbdfbeee | |||
| f6561fc401 | |||
| dfe56c8b70 | |||
| 7f29b466be | |||
| 8f5a185ae5 | |||
| 309b28fa2c | |||
| e9f311e6b6 | |||
| 045262282b | |||
| a44701faa2 | |||
| eeee3151b6 | |||
| 0cd077e80f | |||
| 0e9b098f4e | |||
| 40b5002338 | |||
| 28fd3fbf50 | |||
| 10c782b106 | |||
| 5dd1803288 | |||
| 7e9f2e2311 | |||
| 610a5d6c0d | |||
| 5453628491 | |||
| 6e0596e122 | |||
| 0ca8d74842 | |||
| 04f8170841 | |||
| 1124793702 | |||
| 8d4b0f05da | |||
| ca8ba8ce87 | |||
| 849e3403cd | |||
| 02a7a30978 | |||
| 79568d2944 | |||
| ae45be7875 | |||
| 73e8b39bc6 | |||
| 72b2938e43 | |||
| 785aaa8c03 | |||
| 1d7983da05 | |||
| cb652c7f0f | |||
| a2b84fc98a | |||
| 0d9bbc9d64 | |||
| 6fd5e5f61c | |||
| b7285bd688 | |||
| 938e50c876 | |||
| e76bfcf2f6 | |||
| ee06ac3ad2 | |||
| 19a8870f76 | |||
| d828f2477e | |||
| 99a3a7e94e | |||
| 4d2bad4c11 | |||
| ed14df9738 | |||
| a516441513 | |||
| d75abc9104 | |||
| bc83969f6b | |||
| dff8e34bc9 | |||
| 6d9662cf8d | |||
| 2e6b32083e | |||
| b4b42a462a | |||
| a48a2a3dc9 | |||
| 9628599620 | |||
| 3a4d5ff5c3 | |||
| e7fa2571ca | |||
| fa3bbed200 | |||
| 1237fd9ab5 | |||
| 1e5a9eb7b9 | |||
| 41fc0955f6 | |||
| 2f5278a139 |
+32
-29
@@ -210,52 +210,54 @@ msys2-mingw64:
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
|
||||
|
||||
macos-x86_64:
|
||||
macos:
|
||||
rules:
|
||||
# Do not run in forks as the runner is not available there.
|
||||
# (except for dehesselle who maintains the runner)
|
||||
- if: $CI_PROJECT_NAMESPACE == "GNOME"
|
||||
- if: $CI_PROJECT_NAMESPACE == "dehesselle"
|
||||
- if: $CI_PROJECT_NAMESPACE != "GNOME" && $CI_PROJECT_NAMESPACE != "dehesselle"
|
||||
when: never
|
||||
- if: $RUNNER == "macosintel"
|
||||
variables:
|
||||
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
|
||||
NINJA_PKG: $CI_API_V4_URL/projects/30745/packages/generic/ninja_macos/v1.11.1.1+9/ninja-1.11.1.1-cp38-cp38-macosx_11_0_x86_64.whl
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: $RUNNER == "macosarm"
|
||||
variables:
|
||||
SDKROOT: /opt/sdks/MacOSX11.3.sdk
|
||||
NINJA_PKG: ninja==1.11.1.1
|
||||
stage: build
|
||||
parallel:
|
||||
matrix:
|
||||
- RUNNER: [ "macosintel", "macosarm" ]
|
||||
tags:
|
||||
- macosintel
|
||||
- ${RUNNER}
|
||||
needs: []
|
||||
variables:
|
||||
MESON_FORCE_BACKTRACKE: 1
|
||||
EXTRA_MESON_FLAGS: ""
|
||||
BACKEND_FLAGS: "-Dx11-backend=false -Dbroadway-backend=true"
|
||||
FEATURE_FLAGS: "-Dmedia-gstreamer=disabled -Dintrospection=enabled -Dgobject-introspection:werror=false"
|
||||
TMPDIR: /Users/Shared/work/tmp
|
||||
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
|
||||
PIP_CACHE_DIR: /Users/Shared/build/cache
|
||||
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
|
||||
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
|
||||
EXTRA_MESON_FLAGS: "-Dgobject-introspection:werror=false"
|
||||
before_script:
|
||||
# Not using ccache on purpose as it accelerates the build so much that it
|
||||
# can trigger race conditions in the gobject-introspection subproject.
|
||||
- bash .gitlab-ci/show-info-osx.sh
|
||||
- /opt/macports/bin/python3.10 -m venv .venv
|
||||
- ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin
|
||||
- ln -s /opt/pkg-config/bin/pkg-config .venv/bin
|
||||
- ln -s /opt/bison/bin/bison .venv/bin
|
||||
- .gitlab-ci/show-info-macos.sh
|
||||
- python3 -m venv .venv
|
||||
# Building the introspection feature requires pkg-config and bison.
|
||||
- curl -L $CI_API_V4_URL/projects/30437/packages/generic/pkgconfig/v0.29.2+10/pkg-config-0.29.2+10_$(uname -m).tar.xz | tar -C .venv -xJ
|
||||
- curl -L $CI_API_V4_URL/projects/30438/packages/generic/bison/v3.8.2+3/bison-3.8.2+3_$(uname -m).tar.xz | tar -C .venv -xJ
|
||||
- source .venv/bin/activate
|
||||
- pip3 install meson==1.2.0
|
||||
- pip3 install ninja==1.11.1
|
||||
- pip3 install /Users/Shared/build/pkgs/PyGObject-3.44.0-cp310-cp310-macosx_10_13_x86_64.whl
|
||||
/Users/Shared/build/pkgs/pycairo-1.23.0-cp310-cp310-macosx_10_13_x86_64.whl
|
||||
- pip3 install meson==1.3.2 $NINJA_PKG
|
||||
# We're not setting up ccache here on purpose as it accelerates the build
|
||||
# so much that it triggers race conditions in the gobject-introspection
|
||||
# subproject.
|
||||
script:
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
-Dx11-backend=false
|
||||
-Dbroadway-backend=true
|
||||
-Dmacos-backend=true
|
||||
-Dmedia-gstreamer=disabled
|
||||
-Dintrospection=enabled
|
||||
-Dcpp_std=c++11
|
||||
-Dpixman:tests=disabled
|
||||
-Dlibjpeg-turbo:simd=disabled
|
||||
-Dbuild-demos=false
|
||||
-Dbuild-examples=false
|
||||
-Dbuild-testsuite=false
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
_build
|
||||
- meson compile -C _build
|
||||
artifacts:
|
||||
@@ -479,3 +481,4 @@ publish-docs:
|
||||
- "curl -X POST -F token=${PAGES_TRIGGER_TOKEN} -F ref=docs-gtk-org https://gitlab.gnome.org/api/v4/projects/665/trigger/pipeline"
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == "main"
|
||||
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
set -eux -o pipefail
|
||||
|
||||
xcodebuild -version || :
|
||||
xcodebuild -showsdks || :
|
||||
|
||||
if [ -z "$SDKROOT" ]; then
|
||||
xcodebuild -showsdks || :
|
||||
else
|
||||
echo "SDKROOT = $SDKROOT"
|
||||
fi
|
||||
|
||||
system_profiler SPSoftwareDataType || :
|
||||
@@ -1,11 +1,155 @@
|
||||
Overview of Changes in 4.13.8, xx-xx-xxxx
|
||||
Overview of Changes in 4.14.1, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
|
||||
Overview of Changes in 4.14.0, 12-03-2024
|
||||
=========================================
|
||||
|
||||
Note: The new renderers and dmabuf support are using graphics drivers
|
||||
in different ways than the old gl renderer, and trigger new driver bugs,
|
||||
(see for example https://gitlab.gnome.org/GNOME/gtk/-/issues/6418 and
|
||||
https://gitlab.gnome.org/GNOME/gtk/-/issues/6388). Therefore, it is
|
||||
recommended to use the latest mesa release (24.0) with the new renderers.
|
||||
recommended to use the latest mesa release (24.x) with the new renderers.
|
||||
|
||||
* GtkTextView:
|
||||
- Don't snapshot children twice
|
||||
- Don't blink the cursor when hidden
|
||||
|
||||
* GtkEmojiChooser:
|
||||
- Fix presentation selector handling
|
||||
|
||||
* GtkSnapshot:
|
||||
- Fix wrong nodes with transformed shadows
|
||||
|
||||
* GtkIMContext:
|
||||
- Make gtk_im_context_activate_osk public
|
||||
|
||||
* Accessibility:
|
||||
- Implement get_contents_at for all our text widgets
|
||||
- Add GtkAccessibleText.get_default_attributes
|
||||
|
||||
* GSK:
|
||||
- Don't fall back to cairo for software rendering. gl+llvmpipe is better
|
||||
- Round vertical glyph position to a device pixel position if the font is hinted
|
||||
- Fix problems with clip handling
|
||||
- Make vulkan and ngl match their font handling
|
||||
- Fix some corner-cases with offloading and clips
|
||||
- Fix problem with rendering of missing glyphs in hinted fonts
|
||||
|
||||
* MacOs:
|
||||
- Implement cursor-from-texture
|
||||
|
||||
* Translation updates:
|
||||
Basque
|
||||
British English
|
||||
French
|
||||
Indonesian
|
||||
Kazakh
|
||||
Latvian
|
||||
Lithuanian
|
||||
Norwegian Bokmål
|
||||
Slovenian
|
||||
Spanish
|
||||
Turkish
|
||||
|
||||
|
||||
Overview of Changes in 4.13.9, 02-03-2024
|
||||
=========================================
|
||||
|
||||
* GtkEditable:
|
||||
- Fix preconditions to be not too strict
|
||||
|
||||
* GtkEmojiChooser:
|
||||
- Support search in the locale as well as in English
|
||||
|
||||
* GtkIconTheme:
|
||||
- Make gtk_icon_paintable_new_for_file support symbolics
|
||||
|
||||
* GtkVideo:
|
||||
- Fix a problem with cursor handling that could lead to crashes
|
||||
|
||||
* Accessibility:
|
||||
- Fix GetCharacterAtOffset implementation
|
||||
- Add a Terminal role
|
||||
- Make TextCaretMoved match gtk3
|
||||
- Support multiple levels of GtkEditable delegates
|
||||
|
||||
* GSK:
|
||||
- Make the node parser more flexible for text nodes
|
||||
- Change the way font scaling is handled to avoid clipping
|
||||
- Fix handling of missing glyphs in the new renderers
|
||||
|
||||
* X11:
|
||||
- Don't claim to support shadows without a compositor
|
||||
|
||||
* Wayland:
|
||||
- Fix handling of output scales
|
||||
|
||||
* Tools:
|
||||
- Add a compare command to gtk4-rendernode-tool
|
||||
|
||||
* Build:
|
||||
- Fix some ubsan complaints
|
||||
|
||||
* Translation updates:
|
||||
Basque
|
||||
British English
|
||||
Catalan
|
||||
Finnish
|
||||
Galician
|
||||
Georgian
|
||||
Hebrew
|
||||
Indonesian
|
||||
Kazakh
|
||||
Latvian
|
||||
Lithuanian
|
||||
Persian
|
||||
Polish
|
||||
Russian
|
||||
Slovenian
|
||||
Spanish
|
||||
Turkish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.13.8, 20-02-2024
|
||||
=========================================
|
||||
|
||||
* Accessibility:
|
||||
- Add a GtkAccessibleText interface for allowing 3rd party
|
||||
text widgets (notably vte) to be accessible
|
||||
- Avoid duplicate accessible descriptions
|
||||
- Fix GetAccessibleAtPoint
|
||||
|
||||
* GSK:
|
||||
- Avoid offscreens for disjoint containers
|
||||
- Don't use the gpu renderers with llvmpipe
|
||||
- Fix various rendering issues found by tests
|
||||
- Allow unnormalized node bounds again
|
||||
- Fix a broken case of rounded-rect intersection
|
||||
- Fix handling of external textures in gpu renderers
|
||||
- Make gpu renderers work with WGL on Windows
|
||||
|
||||
* build:
|
||||
- Allow building without dmabuf support on (old) Linux
|
||||
|
||||
* X11:
|
||||
- Fix monitor enter/leave signals
|
||||
|
||||
* Translation updates:
|
||||
Basque
|
||||
Brazilian Portuguese
|
||||
Catalan
|
||||
Czech
|
||||
Galician
|
||||
Georgian
|
||||
Hebrew
|
||||
Lithuanian
|
||||
Persian
|
||||
Russian
|
||||
Turkish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.13.7, 11-02-2024
|
||||
=========================================
|
||||
|
||||
@@ -600,8 +600,8 @@ update_display (void)
|
||||
if (s->len > 0)
|
||||
{
|
||||
pango_font_description_set_variations (desc, s->str);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
font_desc = pango_font_description_to_string (desc);
|
||||
|
||||
|
||||
@@ -116,7 +116,9 @@ static gboolean gtk_shadertoy_tick (GtkWidget *widget,
|
||||
GtkWidget *
|
||||
gtk_shadertoy_new (void)
|
||||
{
|
||||
return g_object_new (gtk_shadertoy_get_type (), NULL);
|
||||
return g_object_new (gtk_shadertoy_get_type (),
|
||||
"allowed-apis", GDK_GL_API_GL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -354,6 +354,7 @@ do_images (GtkWidget *do_widget)
|
||||
gicon = g_themed_icon_new_with_default_fallbacks ("battery-caution-charging-symbolic");
|
||||
image = gtk_image_new_from_gicon (gicon);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
g_object_unref (gicon);
|
||||
|
||||
gtk_frame_set_child (GTK_FRAME (frame), image);
|
||||
|
||||
|
||||
@@ -322,12 +322,14 @@ stroke bounds of the path.
|
||||
|
||||
### text
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ------------------- | ------------------- | ----------- |
|
||||
| color | `<color>` | black | non-default |
|
||||
| font | `<string>` `<url>`? | "Cantarell 11" | always |
|
||||
| glyphs | `<glyphs>` | "Hello" | always |
|
||||
| offset | `<point>` | 0 0 | non-default |
|
||||
| property | syntax | default | printed |
|
||||
| ------------ | ------------------- | ------------------- | ----------- |
|
||||
| color | `<color>` | black | non-default |
|
||||
| font | `<string>` `<url>`? | "Cantarell 15px" | always |
|
||||
| glyphs | `<glyphs>` | "Hello" | always |
|
||||
| offset | `<point>` | 0 0 | non-default |
|
||||
| hint-style | `<hint style>` | slight | non-default |
|
||||
| antialias | `<antialias>` | gray | non-default |
|
||||
|
||||
Creates a node like `gsk_text_node_new()` with the given properties.
|
||||
|
||||
@@ -336,12 +338,15 @@ font that is specified in the string. It can be either a data url containing
|
||||
a base64-encoded font file, or a regular url that points to a font file.
|
||||
|
||||
Glyphs can be specified as an ASCII string, or as a comma-separated list of
|
||||
their glyph ID and advance width. Optionally, x and y offsets and flags can
|
||||
their glyph IDs. Optionally, the advance width, x and y offsets and flags can
|
||||
be specified as well, like this: 40 10 0 0 color.
|
||||
|
||||
If the given font does not exist or the given glyphs are invalid for the given
|
||||
font, an error node will be returned.
|
||||
|
||||
Possible values for hint-style are none, slight or full.
|
||||
Possible value for antialias are none or gray.
|
||||
|
||||
### texture
|
||||
|
||||
| property | syntax | default | printed |
|
||||
|
||||
+3
-3
@@ -69,9 +69,9 @@ Image:
|
||||
4 CARD32 IMAGE_DATA_OFFSET
|
||||
|
||||
ICON_FLAGS
|
||||
HAS_SUFFIX_PNG 1
|
||||
HAS_SUFFIX_XPM 2
|
||||
HAS_SUFFIX_SVG 4
|
||||
HAS_SUFFIX_XPM 1
|
||||
HAS_SUFFIX_SVG 2
|
||||
HAS_SUFFIX_PNG 4
|
||||
HAS_ICON_FILE 8
|
||||
|
||||
ImageData:
|
||||
|
||||
@@ -13,6 +13,7 @@ SYNOPSIS
|
||||
| **gtk4-rendernode-tool** <COMMAND> [OPTIONS...] <FILE>
|
||||
|
|
||||
| **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE>
|
||||
| **gtk4-rendernode-tool** compare [OPTIONS...] <FILE1> <FILE2>
|
||||
| **gtk4-rendernode-tool** info [OPTIONS...] <FILE>
|
||||
| **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>]
|
||||
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
|
||||
@@ -75,7 +76,21 @@ and prints the runtimes.
|
||||
the execution of the commands on the GPU. It can be useful to use this flag to test
|
||||
command submission performance.
|
||||
|
||||
Compare
|
||||
^^^^^^^
|
||||
|
||||
The ``compare`` command compares the rendering of a node with a reference image,
|
||||
or the renderings of two nodes, or two images. If any differences are found, the
|
||||
exit code is 1. If the images are identical, it is 0.
|
||||
|
||||
``--renderer=RENDERER``
|
||||
|
||||
Use the given renderer.
|
||||
|
||||
``--output=FILE``
|
||||
|
||||
Save the differences as a png image in ``FILE``.
|
||||
|
||||
``--quiet``
|
||||
|
||||
Don't write results to stdout.`
|
||||
|
||||
+4
-1
@@ -2037,9 +2037,12 @@ gdk_display_get_dmabuf_formats (GdkDisplay *display)
|
||||
GdkDebugFlags
|
||||
gdk_display_get_debug_flags (GdkDisplay *display)
|
||||
{
|
||||
if (display == NULL)
|
||||
return _gdk_debug_flags;
|
||||
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
|
||||
|
||||
return display ? priv->debug_flags : _gdk_debug_flags;
|
||||
return priv->debug_flags;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+177
-42
@@ -309,67 +309,202 @@ typedef enum
|
||||
* The color values are premultiplied with the alpha value.
|
||||
* @GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: 4 bytes; for red, green, blue, alpha
|
||||
* The color values are premultiplied with the alpha value.
|
||||
* @GDK_MEMORY_A8B8G8R8_PREMULTIPLIED: 4 bytes; for alpha, blue, green, red,
|
||||
* The color values are premultiplied with the alpha value. Since 4.14
|
||||
* @GDK_MEMORY_B8G8R8A8: 4 bytes; for blue, green, red, alpha.
|
||||
* @GDK_MEMORY_A8R8G8B8: 4 bytes; for alpha, red, green, blue.
|
||||
* @GDK_MEMORY_R8G8B8A8: 4 bytes; for red, green, blue, alpha.
|
||||
* @GDK_MEMORY_A8B8G8R8: 4 bytes; for alpha, blue, green, red.
|
||||
* @GDK_MEMORY_B8G8R8X8: 4 bytes; for blue, green, red, unused. Since 4.14
|
||||
* @GDK_MEMORY_X8R8G8B8: 4 bytes; for unused, red, green, blue. Since 4.14
|
||||
* @GDK_MEMORY_R8G8B8X8: 4 bytes; for red, green, blue, unused. Since 4.14
|
||||
* @GDK_MEMORY_X8B8G8R8: 4 bytes; for unused, blue, green, red. Since 4.14
|
||||
* @GDK_MEMORY_R8G8B8: 3 bytes; for red, green, blue. The data is opaque.
|
||||
* @GDK_MEMORY_B8G8R8: 3 bytes; for blue, green, red. The data is opaque.
|
||||
* @GDK_MEMORY_R16G16B16: 3 guint16 values; for red, green, blue. Since: 4.6
|
||||
* @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green,
|
||||
* blue, alpha. The color values are premultiplied with the alpha value.
|
||||
* Since: 4.6
|
||||
* @GDK_MEMORY_R16G16B16A16: 4 guint16 values; for red, green, blue, alpha.
|
||||
* Since: 4.6
|
||||
* @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue.
|
||||
* The data is opaque. Since: 4.6
|
||||
* @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for
|
||||
* red, green, blue and alpha. The color values are premultiplied with
|
||||
* the alpha value. Since: 4.6
|
||||
* @GDK_MEMORY_R16G16B16A16_FLOAT: 4 half-float values; for red, green,
|
||||
* blue and alpha. Since: 4.6
|
||||
* @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red.
|
||||
* The data is opaque. Since: 4.6
|
||||
* @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for
|
||||
* red, green, blue and alpha. The color values are premultiplied with
|
||||
* the alpha value. Since: 4.6
|
||||
* @GDK_MEMORY_R32G32B32A32_FLOAT: 4 float values; for red, green, blue and
|
||||
* alpha. Since: 4.6
|
||||
* @GDK_MEMORY_G8A8_PREMULTIPLIED: 2 bytes; for grayscale, alpha. The color
|
||||
* values are premultiplied with the alpha value. Since: 4.12
|
||||
* @GDK_MEMORY_G8A8: 2 bytes; for grayscale, alpha. Since: 4.12
|
||||
* @GDK_MEMORY_G8: One byte; for grayscale. The data is opaque.
|
||||
* Since: 4.12
|
||||
* @GDK_MEMORY_G16A16_PREMULTIPLIED: 2 guint16 values; for grayscale, alpha.
|
||||
* The color values are premultiplied with the alpha value. Since: 4.12
|
||||
* @GDK_MEMORY_G16A16: 2 guint16 values; for grayscale, alpha. Since: 4.12
|
||||
* @GDK_MEMORY_G16: One guint16 value; for grayscale. The data is opaque.
|
||||
* Since: 4.12
|
||||
* @GDK_MEMORY_A8: One byte; for alpha.
|
||||
* Since: 4.12
|
||||
* @GDK_MEMORY_A16: One guint16 value; for alpha.
|
||||
* Since: 4.12
|
||||
* @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as
|
||||
* more formats get added, so do not rely on its concrete integer.
|
||||
* @GDK_MEMORY_R32G32B32_FLOAT: 3 float values; for red, green, blue.
|
||||
*
|
||||
* `GdkMemoryFormat` describes formats that image data can have in memory.
|
||||
*
|
||||
* It describes formats by listing the contents of the memory passed to it.
|
||||
* So GDK_MEMORY_A8R8G8B8 will be 1 byte (8 bits) of alpha, followed by a
|
||||
* So `GDK_MEMORY_A8R8G8B8` will be 1 byte (8 bits) of alpha, followed by a
|
||||
* byte each of red, green and blue. It is not endian-dependent, so
|
||||
* CAIRO_FORMAT_ARGB32 is represented by different `GdkMemoryFormats`
|
||||
* `CAIRO_FORMAT_ARGB32` is represented by different `GdkMemoryFormats`
|
||||
* on architectures with different endiannesses.
|
||||
*
|
||||
* Its naming is modelled after
|
||||
* [VkFormat](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VkFormat)
|
||||
* for details).
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
|
||||
*
|
||||
* 4 bytes; for alpha, blue, green, red, The color values are premultiplied with
|
||||
* the alpha value.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_B8G8R8X8:
|
||||
*
|
||||
* 4 bytes; for blue, green, red, unused.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_X8R8G8B8:
|
||||
*
|
||||
* 4 bytes; for unused, red, green, blue.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R8G8B8X8:
|
||||
*
|
||||
* 4 bytes; for red, green, blue, unused.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_X8B8G8R8:
|
||||
*
|
||||
* 4 bytes; for unused, blue, green, red.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16:
|
||||
*
|
||||
* 3 guint16 values; for red, green, blue.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
*
|
||||
* 4 guint16 values; for red, green, blue, alpha. The color values are
|
||||
* premultiplied with the alpha value.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16A16:
|
||||
*
|
||||
* 4 guint16 values; for red, green, blue, alpha.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16_FLOAT:
|
||||
*
|
||||
* 3 half-float values; for red, green, blue. The data is opaque.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
*
|
||||
* 4 half-float values; for red, green, blue and alpha. The color values are
|
||||
* premultiplied with the alpha value.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
*
|
||||
* 4 half-float values; for red, green, blue and alpha.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_B32G32R32_FLOAT:
|
||||
*
|
||||
* 3 float values; for blue, green, red. The data is opaque.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
*
|
||||
* 4 float values; for red, green, blue and alpha. The color values are
|
||||
* premultiplied with the alpha value.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
*
|
||||
* 4 float values; for red, green, blue and alpha.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G8A8_PREMULTIPLIED:
|
||||
*
|
||||
* 2 bytes; for grayscale, alpha. The color values are premultiplied with the
|
||||
* alpha value.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G8A8:
|
||||
*
|
||||
* 2 bytes; for grayscale, alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G8:
|
||||
*
|
||||
* One byte; for grayscale. The data is opaque.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G16A16_PREMULTIPLIED:
|
||||
*
|
||||
* 2 guint16 values; for grayscale, alpha. The color values are premultiplied
|
||||
* with the alpha value.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G16A16:
|
||||
*
|
||||
* 2 guint16 values; for grayscale, alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_G16:
|
||||
*
|
||||
* One guint16 value; for grayscale. The data is opaque.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_A8:
|
||||
*
|
||||
* One byte; for alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_A16:
|
||||
*
|
||||
* One guint16 value; for alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_A16_FLOAT:
|
||||
*
|
||||
* One half-float value; for alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
/**
|
||||
* GDK_MEMORY_A32_FLOAT:
|
||||
*
|
||||
* One float value; for alpha.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
typedef enum {
|
||||
GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
|
||||
GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
|
||||
|
||||
+56
-29
@@ -79,14 +79,23 @@ static guint signals[LAST_SIGNAL];
|
||||
|
||||
static guint fps_counter;
|
||||
|
||||
#define FRAME_HISTORY_MAX_LENGTH 128
|
||||
/* 60Hz plus some extra for monotonic time inaccuracy */
|
||||
#define FRAME_HISTORY_DEFAULT_LENGTH 64
|
||||
|
||||
#define frame_timings_unref(x) gdk_frame_timings_unref((GdkFrameTimings *) (x))
|
||||
|
||||
#define GDK_ARRAY_NAME timings
|
||||
#define GDK_ARRAY_TYPE_NAME Timings
|
||||
#define GDK_ARRAY_ELEMENT_TYPE GdkFrameTimings *
|
||||
#define GDK_ARRAY_PREALLOC FRAME_HISTORY_DEFAULT_LENGTH
|
||||
#define GDK_ARRAY_FREE_FUNC frame_timings_unref
|
||||
#include "gdk/gdkarrayimpl.c"
|
||||
|
||||
struct _GdkFrameClockPrivate
|
||||
{
|
||||
gint64 frame_counter;
|
||||
int n_timings;
|
||||
int current;
|
||||
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
|
||||
Timings timings;
|
||||
int n_freeze_inhibitors;
|
||||
};
|
||||
|
||||
@@ -99,11 +108,8 @@ static void
|
||||
gdk_frame_clock_finalize (GObject *object)
|
||||
{
|
||||
GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
|
||||
if (priv->timings[i] != 0)
|
||||
gdk_frame_timings_unref (priv->timings[i]);
|
||||
timings_clear (&priv->timings);
|
||||
|
||||
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -257,7 +263,8 @@ gdk_frame_clock_init (GdkFrameClock *clock)
|
||||
clock->priv = priv = gdk_frame_clock_get_instance_private (clock);
|
||||
|
||||
priv->frame_counter = -1;
|
||||
priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
|
||||
priv->current = 0;
|
||||
timings_init (&priv->timings);
|
||||
|
||||
if (fps_counter == 0)
|
||||
fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
|
||||
@@ -416,7 +423,7 @@ gdk_frame_clock_get_frame_counter (GdkFrameClock *frame_clock)
|
||||
static inline gint64
|
||||
_gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
|
||||
{
|
||||
return frame_clock->priv->frame_counter + 1 - frame_clock->priv->n_timings;
|
||||
return frame_clock->priv->frame_counter + 1 - timings_get_size (&frame_clock->priv->timings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,31 +452,44 @@ gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock)
|
||||
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock,
|
||||
gint64 monotonic_time)
|
||||
{
|
||||
GdkFrameClockPrivate *priv;
|
||||
|
||||
g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
|
||||
|
||||
priv = frame_clock->priv;
|
||||
|
||||
priv->frame_counter++;
|
||||
priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
|
||||
|
||||
/* Try to steal the previous frame timing instead of discarding
|
||||
* and allocating a new one.
|
||||
*/
|
||||
if G_LIKELY (priv->n_timings == FRAME_HISTORY_MAX_LENGTH &&
|
||||
_gdk_frame_timings_steal (priv->timings[priv->current],
|
||||
priv->frame_counter))
|
||||
return;
|
||||
|
||||
if (priv->n_timings < FRAME_HISTORY_MAX_LENGTH)
|
||||
priv->n_timings++;
|
||||
if (G_UNLIKELY (timings_get_size (&priv->timings) == 0))
|
||||
timings_append (&priv->timings, _gdk_frame_timings_new (priv->frame_counter));
|
||||
else
|
||||
gdk_frame_timings_unref (priv->timings[priv->current]);
|
||||
{
|
||||
GdkFrameTimings *timings;
|
||||
|
||||
priv->timings[priv->current] = _gdk_frame_timings_new (priv->frame_counter);
|
||||
priv->current = (priv->current + 1) % timings_get_size (&priv->timings);
|
||||
|
||||
timings = timings_get (&priv->timings, priv->current);
|
||||
|
||||
if (timings->frame_time + G_USEC_PER_SEC > monotonic_time)
|
||||
{
|
||||
/* Keep the timings, not a second old yet */
|
||||
timings = _gdk_frame_timings_new (priv->frame_counter);
|
||||
timings_splice (&priv->timings, priv->current, 0, FALSE, &timings, 1);
|
||||
}
|
||||
else if (_gdk_frame_timings_steal (timings, priv->frame_counter))
|
||||
{
|
||||
/* Stole the previous frame timing instead of discarding
|
||||
* and allocating a new one, so nothing to do
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
timings = _gdk_frame_timings_new (priv->frame_counter);
|
||||
timings_splice (&priv->timings, priv->current, 1, FALSE, &timings, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline GdkFrameTimings *
|
||||
@@ -477,17 +497,21 @@ _gdk_frame_clock_get_timings (GdkFrameClock *frame_clock,
|
||||
gint64 frame_counter)
|
||||
{
|
||||
GdkFrameClockPrivate *priv = frame_clock->priv;
|
||||
int pos;
|
||||
gsize size, pos;
|
||||
|
||||
if (frame_counter > priv->frame_counter)
|
||||
return NULL;
|
||||
|
||||
if (frame_counter <= priv->frame_counter - priv->n_timings)
|
||||
size = timings_get_size (&priv->timings);
|
||||
if (G_UNLIKELY (size == 0))
|
||||
return NULL;
|
||||
|
||||
pos = (priv->current - (priv->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
|
||||
if (priv->frame_counter - frame_counter >= size)
|
||||
return NULL;
|
||||
|
||||
return priv->timings[pos];
|
||||
pos = (priv->current - (priv->frame_counter - frame_counter) + size) % size;
|
||||
|
||||
return timings_get (&priv->timings, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,7 +803,10 @@ gdk_frame_clock_get_fps (GdkFrameClock *frame_clock)
|
||||
|
||||
start_counter = _gdk_frame_clock_get_history_start (frame_clock);
|
||||
end_counter = _gdk_frame_clock_get_frame_counter (frame_clock);
|
||||
start = _gdk_frame_clock_get_timings (frame_clock, start_counter);
|
||||
for (start = _gdk_frame_clock_get_timings (frame_clock, start_counter);
|
||||
end_counter > start_counter && start != NULL && !gdk_frame_timings_get_complete (start);
|
||||
start = _gdk_frame_clock_get_timings (frame_clock, start_counter))
|
||||
start_counter++;
|
||||
for (end = _gdk_frame_clock_get_timings (frame_clock, end_counter);
|
||||
end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
|
||||
end = _gdk_frame_clock_get_timings (frame_clock, end_counter))
|
||||
|
||||
@@ -192,6 +192,13 @@ compute_smooth_frame_time (GdkFrameClock *clock,
|
||||
* and new_frame_time >= old_frame_time. */
|
||||
frames_passed = (new_frame_time - smoothed_frame_time_base + frame_interval / 2) / frame_interval;
|
||||
|
||||
if (frames_passed > 1)
|
||||
gdk_profiler_add_markf ((smoothed_frame_time_base - (frame_interval * (frames_passed-1))) * 1000L,
|
||||
frame_interval * (frames_passed-1) * 1000L,
|
||||
"Dropped Frames",
|
||||
"%u frames may have been dropped",
|
||||
frames_passed-1);
|
||||
|
||||
/* We use an approximately whole number of frames in the future from
|
||||
* last smoothed frame time. This way we avoid minor jitter in the
|
||||
* frame times making the animation speed uneven, but still animate
|
||||
@@ -548,7 +555,7 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
priv->smoothed_frame_time_period = frame_interval;
|
||||
priv->smoothed_frame_time_reported = priv->smoothed_frame_time_base;
|
||||
|
||||
_gdk_frame_clock_begin_frame (clock);
|
||||
_gdk_frame_clock_begin_frame (clock, priv->frame_time);
|
||||
/* Note "current" is different now so timings != prev_timings */
|
||||
timings = gdk_frame_clock_get_current_timings (clock);
|
||||
|
||||
|
||||
@@ -106,7 +106,8 @@ struct _GdkFrameTimings
|
||||
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
|
||||
void _gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock);
|
||||
|
||||
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
|
||||
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock,
|
||||
gint64 monotonic_time);
|
||||
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
|
||||
GdkFrameTimings *timings);
|
||||
void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,
|
||||
|
||||
+3
-2
@@ -658,6 +658,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
EGLSurface egl_surface;
|
||||
G_GNUC_UNUSED gint64 begin_time = GDK_PROFILER_CURRENT_TIME;
|
||||
|
||||
if (priv->egl_context == NULL)
|
||||
return;
|
||||
@@ -666,8 +667,6 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
||||
|
||||
egl_surface = gdk_surface_get_egl_surface (surface);
|
||||
|
||||
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "EGL swap buffers", NULL);
|
||||
|
||||
if (priv->eglSwapBuffersWithDamage)
|
||||
{
|
||||
EGLint stack_rects[4 * 4]; /* 4 rects */
|
||||
@@ -698,6 +697,8 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
||||
else
|
||||
eglSwapBuffers (gdk_display_get_egl_display (display), egl_surface);
|
||||
#endif
|
||||
|
||||
gdk_profiler_add_mark (begin_time, GDK_PROFILER_CURRENT_TIME - begin_time, "EGL swap buffers", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -260,6 +260,11 @@ gdk_vulkan_strerror (VkResult result)
|
||||
case VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT:
|
||||
return "The provided binary shader code is not compatible with this device. (VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT)";
|
||||
#endif
|
||||
#if VK_HEADER_VERSION >= 274
|
||||
case VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR:
|
||||
return "The specified Video Std parameters do not adhere to the syntactic or semantic requirements of the used video compression standard or implementation";
|
||||
#endif
|
||||
|
||||
case VK_RESULT_MAX_ENUM:
|
||||
default:
|
||||
return "Unknown Vulkan error.";
|
||||
|
||||
@@ -214,22 +214,6 @@ typedef NSString *CALayerContentsGravity;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setFrame:(NSRect)frame display:(BOOL)display
|
||||
{
|
||||
NSRect contentRect = [self contentRectForFrameRect:frame];
|
||||
GdkSurface *surface = GDK_SURFACE (gdk_surface);
|
||||
gboolean maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
|
||||
|
||||
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, frame))
|
||||
{
|
||||
gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
|
||||
_gdk_surface_update_size (surface);
|
||||
}
|
||||
|
||||
[super setFrame:frame display:display];
|
||||
[[self contentView] setFrame:NSMakeRect (0, 0, contentRect.size.width, contentRect.size.height)];
|
||||
}
|
||||
|
||||
-(id)initWithContentRect:(NSRect)contentRect
|
||||
styleMask:(NSWindowStyleMask)styleMask
|
||||
backing:(NSBackingStoreType)backingType
|
||||
@@ -387,12 +371,17 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)windowDidMove:(NSNotification *)notification
|
||||
{
|
||||
if ([self isZoomed])
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_TOPLEVEL_STATE_MAXIMIZED);
|
||||
else
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
|
||||
|
||||
_gdk_macos_surface_configure ([self gdkSurface]);
|
||||
}
|
||||
|
||||
-(void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
_gdk_macos_surface_configure (gdk_surface);
|
||||
[self windowDidMove: notification];
|
||||
|
||||
/* If we're using server-side decorations, this notification is coming
|
||||
* in from a display-side change. We need to request a layout in
|
||||
@@ -413,7 +402,6 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)beginManualMove
|
||||
{
|
||||
gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
NSPoint initialMoveLocation;
|
||||
GdkPoint point;
|
||||
GdkMonitor *monitor;
|
||||
@@ -432,13 +420,6 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
initialMoveLocation = [NSEvent mouseLocation];
|
||||
|
||||
if (maximized)
|
||||
[self setFrame:NSMakeRect (initialMoveLocation.x - (int)lastUnmaximizedFrame.size.width/2,
|
||||
initialMoveLocation.y,
|
||||
lastUnmaximizedFrame.size.width,
|
||||
lastUnmaximizedFrame.size.height)
|
||||
display:YES];
|
||||
|
||||
_gdk_macos_display_from_display_coords ([self gdkDisplay],
|
||||
initialMoveLocation.x,
|
||||
initialMoveLocation.y,
|
||||
@@ -781,43 +762,11 @@ typedef NSString *CALayerContentsGravity;
|
||||
return rect;
|
||||
}
|
||||
|
||||
/* Implementing this method avoids new windows move around the screen. */
|
||||
-(NSRect)windowWillUseStandardFrame:(NSWindow *)nsWindow
|
||||
defaultFrame:(NSRect)newFrame
|
||||
{
|
||||
NSRect screenFrame = [[self screen] visibleFrame];
|
||||
GdkMacosSurface *surface = gdk_surface;
|
||||
gboolean maximized = GDK_SURFACE (surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
|
||||
if (!maximized)
|
||||
return screenFrame;
|
||||
else
|
||||
return lastUnmaximizedFrame;
|
||||
}
|
||||
|
||||
-(BOOL)windowShouldZoom:(NSWindow *)nsWindow
|
||||
toFrame:(NSRect)newFrame
|
||||
{
|
||||
GdkMacosSurface *surface = gdk_surface;
|
||||
GdkToplevelState state = GDK_SURFACE (surface)->state;
|
||||
|
||||
if (state & GDK_TOPLEVEL_STATE_MAXIMIZED)
|
||||
{
|
||||
lastMaximizedFrame = newFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastUnmaximizedFrame = [nsWindow frame];
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_TOPLEVEL_STATE_MAXIMIZED);
|
||||
}
|
||||
|
||||
inMaximizeTransition = YES;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)windowDidEndLiveResize:(NSNotification *)aNotification
|
||||
{
|
||||
inMaximizeTransition = NO;
|
||||
return newFrame;
|
||||
}
|
||||
|
||||
-(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
|
||||
|
||||
@@ -49,10 +49,7 @@
|
||||
|
||||
EdgeSnapping snapping;
|
||||
|
||||
NSRect lastUnmaximizedFrame;
|
||||
NSRect lastMaximizedFrame;
|
||||
NSRect lastUnfullscreenFrame;
|
||||
BOOL inMaximizeTransition;
|
||||
BOOL inFullscreenTransition;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,57 @@ create_blank_cursor (void)
|
||||
return nscursor;
|
||||
}
|
||||
|
||||
static NSCursor *
|
||||
create_cursor_from_texture (GdkTexture *texture,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
guint32 width;
|
||||
guint32 height;
|
||||
guchar *pixels;
|
||||
gsize stride;
|
||||
GdkTextureDownloader *downloader;
|
||||
NSCursor *nscursor;
|
||||
NSBitmapImageRep *nsbitmap;
|
||||
NSImage *nsimage;
|
||||
|
||||
if (texture == NULL)
|
||||
return create_blank_cursor ();
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
nsbitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:width
|
||||
pixelsHigh:height
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:0
|
||||
bitsPerPixel:0];
|
||||
pixels = [nsbitmap bitmapData];
|
||||
stride = [nsbitmap bytesPerRow];
|
||||
|
||||
downloader = gdk_texture_downloader_new (texture);
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED);
|
||||
gdk_texture_downloader_download_into (downloader,
|
||||
pixels,
|
||||
stride);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
nsimage = [[NSImage alloc] init];
|
||||
[nsimage addRepresentation:nsbitmap];
|
||||
[nsimage setSize:NSMakeSize(width, height)];
|
||||
[nsbitmap release];
|
||||
|
||||
nscursor = [[NSCursor alloc] initWithImage:nsimage
|
||||
hotSpot:NSMakePoint(x, y)];
|
||||
[nsimage release];
|
||||
return nscursor;
|
||||
}
|
||||
|
||||
NSCursor *
|
||||
_gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor)
|
||||
{
|
||||
@@ -161,7 +212,17 @@ _gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor)
|
||||
g_return_val_if_fail (!cursor || GDK_IS_CURSOR (cursor), NULL);
|
||||
|
||||
if (cursor != NULL)
|
||||
name = gdk_cursor_get_name (cursor);
|
||||
{
|
||||
name = gdk_cursor_get_name (cursor);
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
nscursor = create_cursor_from_texture (gdk_cursor_get_texture (cursor),
|
||||
gdk_cursor_get_hotspot_x (cursor),
|
||||
gdk_cursor_get_hotspot_y (cursor));
|
||||
return nscursor;
|
||||
}
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
goto load_cursor;
|
||||
|
||||
+110
-171
@@ -96,37 +96,26 @@ _gdk_macos_toplevel_surface_unminimize (GdkMacosToplevelSurface *self)
|
||||
[window deminiaturize:window];
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
|
||||
GdkToplevelLayout *layout)
|
||||
static gboolean
|
||||
_gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
|
||||
{
|
||||
GdkSurface *surface = GDK_SURFACE (toplevel);
|
||||
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
|
||||
NSWindow *nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
GdkMonitor *monitor;
|
||||
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
|
||||
GdkMacosSurface *macos_surface = (GdkMacosSurface *)surface;
|
||||
GdkToplevelSize size;
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
int bounds_width, bounds_height;
|
||||
int width, height;
|
||||
GdkGeometry geometry;
|
||||
GdkSurfaceHints mask;
|
||||
NSWindowStyleMask style_mask;
|
||||
gboolean maximize;
|
||||
gboolean fullscreen;
|
||||
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
|
||||
g_assert (GDK_IS_MACOS_WINDOW (nswindow));
|
||||
|
||||
if (layout != self->layout)
|
||||
{
|
||||
g_clear_pointer (&self->layout, gdk_toplevel_layout_unref);
|
||||
self->layout = gdk_toplevel_layout_copy (layout);
|
||||
}
|
||||
if (!GDK_MACOS_SURFACE (surface)->geometry_dirty)
|
||||
return FALSE;
|
||||
|
||||
_gdk_macos_toplevel_surface_attach_to_parent (self);
|
||||
|
||||
style_mask = [nswindow styleMask];
|
||||
GDK_MACOS_SURFACE (surface)->geometry_dirty = FALSE;
|
||||
|
||||
display = gdk_surface_get_display (surface);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, surface);
|
||||
|
||||
if (monitor)
|
||||
@@ -144,58 +133,127 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
|
||||
}
|
||||
|
||||
gdk_toplevel_size_init (&size, bounds_width, bounds_height);
|
||||
gdk_toplevel_notify_compute_size (toplevel, &size);
|
||||
gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
|
||||
|
||||
g_warn_if_fail (size.width > 0);
|
||||
g_warn_if_fail (size.height > 0);
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
|
||||
if (gdk_toplevel_layout_get_resizable (layout))
|
||||
if (self->layout != NULL &&
|
||||
gdk_toplevel_layout_get_resizable (self->layout))
|
||||
{
|
||||
geometry.min_width = size.min_width;
|
||||
geometry.min_height = size.min_height;
|
||||
mask = GDK_HINT_MIN_SIZE;
|
||||
|
||||
/* Only set 'Resizable' mask to get native resize zones if the window is
|
||||
* titled, otherwise we do this internally for CSD and do not need
|
||||
* NSWindow to do it for us. Additionally, it can mess things up when
|
||||
* doing a window resize since it can cause mouseDown to get passed
|
||||
* through to the next window.
|
||||
*/
|
||||
if ((style_mask & NSWindowStyleMaskTitled) != 0)
|
||||
style_mask |= NSWindowStyleMaskResizable;
|
||||
else
|
||||
style_mask &= ~NSWindowStyleMaskResizable;
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry.max_width = geometry.min_width = width;
|
||||
geometry.max_height = geometry.min_height = height;
|
||||
geometry.max_width = geometry.min_width = size.width;
|
||||
geometry.max_height = geometry.min_height = size.height;
|
||||
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
|
||||
|
||||
style_mask &= ~NSWindowStyleMaskResizable;
|
||||
}
|
||||
|
||||
if (style_mask != [nswindow styleMask])
|
||||
[nswindow setStyleMask:style_mask];
|
||||
|
||||
if (size.shadow.is_valid)
|
||||
_gdk_macos_surface_set_shadow (GDK_MACOS_SURFACE (surface),
|
||||
_gdk_macos_surface_set_shadow (macos_surface,
|
||||
size.shadow.top,
|
||||
size.shadow.right,
|
||||
size.shadow.bottom,
|
||||
size.shadow.left);
|
||||
|
||||
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
|
||||
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
|
||||
_gdk_macos_surface_set_geometry_hints (macos_surface, &geometry, mask);
|
||||
|
||||
GDK_DEBUG (MISC, "Resizing \"%s\" to %dx%d",
|
||||
GDK_MACOS_SURFACE (self)->title ?
|
||||
GDK_MACOS_SURFACE (self)->title :
|
||||
"untitled",
|
||||
width, height);
|
||||
if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
|
||||
GDK_TOPLEVEL_STATE_MAXIMIZED |
|
||||
GDK_TOPLEVEL_STATE_TILED |
|
||||
GDK_TOPLEVEL_STATE_TOP_TILED |
|
||||
GDK_TOPLEVEL_STATE_RIGHT_TILED |
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_TILED |
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED |
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED) ||
|
||||
[macos_surface->window inLiveResize])
|
||||
return FALSE;
|
||||
|
||||
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
|
||||
/* If we delayed a user resize until the beginning of the frame,
|
||||
* apply it now so we can start processing updates for it.
|
||||
*/
|
||||
if (macos_surface->next_layout.width > 0 &&
|
||||
macos_surface->next_layout.height > 0)
|
||||
{
|
||||
int root_x = macos_surface->next_layout.root_x;
|
||||
int root_y = macos_surface->next_layout.root_y;
|
||||
int width = macos_surface->next_layout.width;
|
||||
int height = macos_surface->next_layout.height;
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
width, height,
|
||||
&width, &height);
|
||||
|
||||
macos_surface->next_layout.width = 0;
|
||||
macos_surface->next_layout.height = 0;
|
||||
|
||||
_gdk_macos_surface_move_resize (macos_surface,
|
||||
root_x, root_y,
|
||||
width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
size.width, size.height,
|
||||
&size.width, &size.height);
|
||||
|
||||
if ((size.width != self->last_computed_width ||
|
||||
size.height != self->last_computed_height) &&
|
||||
(size.width != surface->width ||
|
||||
size.height != surface->height))
|
||||
{
|
||||
self->last_computed_width = size.width;
|
||||
self->last_computed_height = size.height;
|
||||
|
||||
_gdk_macos_surface_resize (macos_surface, size.width, size.height);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
|
||||
GdkToplevelLayout *layout)
|
||||
{
|
||||
GdkSurface *surface = GDK_SURFACE (toplevel);
|
||||
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
|
||||
NSWindow *nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
NSWindowStyleMask style_mask;
|
||||
gboolean maximize;
|
||||
gboolean fullscreen;
|
||||
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
|
||||
g_assert (GDK_IS_MACOS_WINDOW (nswindow));
|
||||
|
||||
if (layout != self->layout)
|
||||
{
|
||||
g_clear_pointer (&self->layout, gdk_toplevel_layout_unref);
|
||||
self->layout = gdk_toplevel_layout_copy (layout);
|
||||
}
|
||||
|
||||
_gdk_macos_toplevel_surface_attach_to_parent (self);
|
||||
_gdk_macos_toplevel_surface_compute_size (surface);
|
||||
|
||||
/* Only set 'Resizable' mask to get native resize zones if the window is
|
||||
* titled, otherwise we do this internally for CSD and do not need
|
||||
* NSWindow to do it for us. Additionally, it can mess things up when
|
||||
* doing a window resize since it can cause mouseDown to get passed
|
||||
* through to the next window.
|
||||
*/
|
||||
style_mask = [nswindow styleMask];
|
||||
if (gdk_toplevel_layout_get_resizable (layout) &&
|
||||
(style_mask & NSWindowStyleMaskTitled) != 0)
|
||||
style_mask |= NSWindowStyleMaskResizable;
|
||||
else
|
||||
style_mask &= ~NSWindowStyleMaskResizable;
|
||||
|
||||
if (style_mask != [nswindow styleMask])
|
||||
[nswindow setStyleMask:style_mask];
|
||||
|
||||
/* Maximized state */
|
||||
if (gdk_toplevel_layout_get_maximized (layout, &maximize))
|
||||
@@ -378,125 +436,6 @@ _gdk_macos_toplevel_surface_hide (GdkSurface *surface)
|
||||
GDK_SURFACE_CLASS (_gdk_macos_toplevel_surface_parent_class)->hide (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
|
||||
{
|
||||
GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
|
||||
GdkMacosSurface *macos_surface = (GdkMacosSurface *)surface;
|
||||
GdkToplevelSize size;
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
int bounds_width, bounds_height;
|
||||
GdkGeometry geometry;
|
||||
GdkSurfaceHints mask;
|
||||
|
||||
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
|
||||
|
||||
if (!GDK_MACOS_SURFACE (surface)->geometry_dirty)
|
||||
return FALSE;
|
||||
|
||||
GDK_MACOS_SURFACE (surface)->geometry_dirty = FALSE;
|
||||
|
||||
display = gdk_surface_get_display (surface);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, surface);
|
||||
|
||||
if (monitor)
|
||||
{
|
||||
GdkRectangle workarea;
|
||||
|
||||
gdk_macos_monitor_get_workarea (monitor, &workarea);
|
||||
bounds_width = workarea.width;
|
||||
bounds_height = workarea.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
bounds_width = G_MAXINT;
|
||||
bounds_height = G_MAXINT;
|
||||
}
|
||||
|
||||
gdk_toplevel_size_init (&size, bounds_width, bounds_height);
|
||||
gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
|
||||
|
||||
g_warn_if_fail (size.width > 0);
|
||||
g_warn_if_fail (size.height > 0);
|
||||
|
||||
if (self->layout != NULL &&
|
||||
gdk_toplevel_layout_get_resizable (self->layout))
|
||||
{
|
||||
geometry.min_width = size.min_width;
|
||||
geometry.min_height = size.min_height;
|
||||
mask = GDK_HINT_MIN_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry.max_width = geometry.min_width = size.width;
|
||||
geometry.max_height = geometry.min_height = size.height;
|
||||
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
|
||||
}
|
||||
|
||||
if (size.shadow.is_valid)
|
||||
_gdk_macos_surface_set_shadow (macos_surface,
|
||||
size.shadow.top,
|
||||
size.shadow.right,
|
||||
size.shadow.bottom,
|
||||
size.shadow.left);
|
||||
|
||||
_gdk_macos_surface_set_geometry_hints (macos_surface, &geometry, mask);
|
||||
|
||||
if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
|
||||
GDK_TOPLEVEL_STATE_MAXIMIZED |
|
||||
GDK_TOPLEVEL_STATE_TILED |
|
||||
GDK_TOPLEVEL_STATE_TOP_TILED |
|
||||
GDK_TOPLEVEL_STATE_RIGHT_TILED |
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_TILED |
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED |
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED) ||
|
||||
[macos_surface->window inLiveResize])
|
||||
return FALSE;
|
||||
|
||||
/* If we delayed a user resize until the beginning of the frame,
|
||||
* apply it now so we can start processing updates for it.
|
||||
*/
|
||||
if (macos_surface->next_layout.width > 0 &&
|
||||
macos_surface->next_layout.height > 0)
|
||||
{
|
||||
int root_x = macos_surface->next_layout.root_x;
|
||||
int root_y = macos_surface->next_layout.root_y;
|
||||
int width = macos_surface->next_layout.width;
|
||||
int height = macos_surface->next_layout.height;
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
width, height,
|
||||
&width, &height);
|
||||
|
||||
macos_surface->next_layout.width = 0;
|
||||
macos_surface->next_layout.height = 0;
|
||||
|
||||
_gdk_macos_surface_move_resize (macos_surface,
|
||||
root_x, root_y,
|
||||
width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_surface_constrain_size (&geometry, mask,
|
||||
size.width, size.height,
|
||||
&size.width, &size.height);
|
||||
|
||||
if ((size.width != self->last_computed_width ||
|
||||
size.height != self->last_computed_height) &&
|
||||
(size.width != surface->width ||
|
||||
size.height != surface->height))
|
||||
{
|
||||
self->last_computed_width = size.width;
|
||||
self->last_computed_height = size.height;
|
||||
|
||||
_gdk_macos_surface_resize (macos_surface, size.width, size.height);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_macos_toplevel_surface_request_layout (GdkSurface *surface)
|
||||
{
|
||||
|
||||
@@ -266,10 +266,10 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
|
||||
|
||||
if ((*file->read) (file, bytes, 4) != 4)
|
||||
return XcursorFalse;
|
||||
*u = ((bytes[0] << 0) |
|
||||
(bytes[1] << 8) |
|
||||
(bytes[2] << 16) |
|
||||
(bytes[3] << 24));
|
||||
*u = ((((unsigned int)(bytes[0])) << 0) |
|
||||
(((unsigned int)(bytes[1])) << 8) |
|
||||
(((unsigned int)(bytes[2])) << 16) |
|
||||
(((unsigned int)(bytes[3])) << 24));
|
||||
return XcursorTrue;
|
||||
}
|
||||
|
||||
|
||||
@@ -2437,12 +2437,13 @@ apply_monitor_change (GdkWaylandMonitor *monitor)
|
||||
gboolean needs_scaling = FALSE;
|
||||
double scale;
|
||||
|
||||
if (monitor->xdg_output_done)
|
||||
if (monitor_has_xdg_output (monitor) &&
|
||||
monitor->xdg_output_geometry.width != 0 &&
|
||||
monitor->xdg_output_geometry.height != 0)
|
||||
{
|
||||
logical_geometry = monitor->xdg_output_geometry;
|
||||
needs_scaling =
|
||||
logical_geometry.width == monitor->output_geometry.width ||
|
||||
logical_geometry.height == monitor->output_geometry.height;
|
||||
needs_scaling = logical_geometry.width == monitor->output_geometry.width &&
|
||||
logical_geometry.height == monitor->output_geometry.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2453,6 +2454,7 @@ apply_monitor_change (GdkWaylandMonitor *monitor)
|
||||
if (needs_scaling)
|
||||
{
|
||||
int scale_factor = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
||||
|
||||
logical_geometry.y /= scale_factor;
|
||||
logical_geometry.x /= scale_factor;
|
||||
logical_geometry.width /= scale_factor;
|
||||
|
||||
@@ -201,17 +201,23 @@ get_egl_window_size (GdkSurface *surface,
|
||||
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_NO_FRACTIONAL))
|
||||
{
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window", gdk_fractional_scale_to_int (&impl->scale));
|
||||
|
||||
*width = surface->width * gdk_fractional_scale_to_int (&impl->scale);
|
||||
*height = surface->height * gdk_fractional_scale_to_int (&impl->scale);
|
||||
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window (%d %d => %d %d)",
|
||||
gdk_fractional_scale_to_int (&impl->scale),
|
||||
surface->width, surface->height,
|
||||
*width, *height);
|
||||
}
|
||||
else
|
||||
{
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window", gdk_fractional_scale_to_double (&impl->scale));
|
||||
|
||||
*width = gdk_fractional_scale_scale (&impl->scale, surface->width),
|
||||
*height = gdk_fractional_scale_scale (&impl->scale, surface->height);
|
||||
|
||||
GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window (%d %d => %d %d)",
|
||||
gdk_fractional_scale_to_double (&impl->scale),
|
||||
surface->width, surface->height,
|
||||
*width, *height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -458,6 +458,49 @@ gdk_wayland_toplevel_compute_size (GdkSurface *surface)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
has_per_edge_tiling_info (GdkToplevelState state)
|
||||
{
|
||||
return state & (GDK_TOPLEVEL_STATE_TOP_TILED |
|
||||
GDK_TOPLEVEL_STATE_RIGHT_TILED |
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_TILED |
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED);
|
||||
}
|
||||
|
||||
static GdkToplevelState
|
||||
infer_edge_constraints (GdkToplevelState state)
|
||||
{
|
||||
if (state & (GDK_TOPLEVEL_STATE_MAXIMIZED | GDK_TOPLEVEL_STATE_FULLSCREEN))
|
||||
return state;
|
||||
|
||||
if (!(state & GDK_TOPLEVEL_STATE_TILED) || !has_per_edge_tiling_info (state))
|
||||
return state |
|
||||
GDK_TOPLEVEL_STATE_TOP_RESIZABLE |
|
||||
GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE |
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE |
|
||||
GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
|
||||
|
||||
if (!(state & GDK_TOPLEVEL_STATE_TOP_TILED))
|
||||
state |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
|
||||
if (!(state & GDK_TOPLEVEL_STATE_RIGHT_TILED))
|
||||
state |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE;
|
||||
if (!(state & GDK_TOPLEVEL_STATE_BOTTOM_TILED))
|
||||
state |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
|
||||
if (!(state & GDK_TOPLEVEL_STATE_LEFT_TILED))
|
||||
state |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
supports_native_edge_constraints (GdkWaylandToplevel*toplevel)
|
||||
{
|
||||
struct gtk_surface1 *gtk_surface = toplevel->display_server.gtk_surface;
|
||||
if (!gtk_surface)
|
||||
return FALSE;
|
||||
return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_toplevel_handle_configure (GdkWaylandSurface *wayland_surface)
|
||||
{
|
||||
@@ -475,6 +518,9 @@ gdk_wayland_toplevel_handle_configure (GdkWaylandSurface *wayland_surface)
|
||||
new_state = wayland_toplevel->pending.state;
|
||||
wayland_toplevel->pending.state = 0;
|
||||
|
||||
if (!supports_native_edge_constraints (wayland_toplevel))
|
||||
new_state = infer_edge_constraints (new_state);
|
||||
|
||||
is_resizing = wayland_toplevel->pending.is_resizing;
|
||||
wayland_toplevel->pending.is_resizing = FALSE;
|
||||
|
||||
@@ -1990,13 +2036,7 @@ gdk_wayland_toplevel_titlebar_gesture (GdkToplevel *toplevel,
|
||||
static gboolean
|
||||
gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
struct gtk_surface1 *gtk_surface = wayland_toplevel->display_server.gtk_surface;
|
||||
|
||||
if (!gtk_surface)
|
||||
return FALSE;
|
||||
|
||||
return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2667,7 +2707,7 @@ gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
|
||||
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
|
||||
|
||||
if (!display_wayland->xdg_importer)
|
||||
if (!display_wayland->xdg_importer && !display_wayland->xdg_importer_v2)
|
||||
{
|
||||
g_warning ("Server is missing xdg_foreign support");
|
||||
return FALSE;
|
||||
|
||||
+21
-10
@@ -892,11 +892,11 @@ pixbuf_to_hicon (GdkPixbuf *pixbuf,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
static GdkWin32HCursor *
|
||||
gdk_win32hcursor_create_for_texture (GdkWin32Display *display,
|
||||
GdkTexture *texture,
|
||||
int x,
|
||||
int y)
|
||||
HICON
|
||||
_gdk_win32_create_hicon_for_texture (GdkTexture *texture,
|
||||
gboolean is_icon,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GdkPixbuf *pixbuf;
|
||||
@@ -906,13 +906,24 @@ gdk_win32hcursor_create_for_texture (GdkWin32Display *display,
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_height (surface);
|
||||
|
||||
|
||||
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
|
||||
|
||||
icon = pixbuf_to_hicon (pixbuf, FALSE, x, y);
|
||||
|
||||
|
||||
icon = pixbuf_to_hicon (pixbuf, is_icon, x, y);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
static GdkWin32HCursor *
|
||||
gdk_win32hcursor_create_for_texture (GdkWin32Display *display,
|
||||
GdkTexture *texture,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
HICON icon = _gdk_win32_create_hicon_for_texture (texture, FALSE, x, y);
|
||||
|
||||
return gdk_win32_hcursor_new (display, (HCURSOR) icon, TRUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context,
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, depth, update_area);
|
||||
}
|
||||
|
||||
#define PIXEL_ATTRIBUTES 17
|
||||
#define PIXEL_ATTRIBUTES 21
|
||||
|
||||
static int
|
||||
get_wgl_pfd (HDC hdc,
|
||||
@@ -176,10 +176,19 @@ get_wgl_pfd (HDC hdc,
|
||||
pixelAttribs[i++] = WGL_ALPHA_BITS_ARB;
|
||||
pixelAttribs[i++] = 8;
|
||||
|
||||
pixelAttribs[i++] = WGL_DEPTH_BITS_ARB;
|
||||
pixelAttribs[i++] = 0;
|
||||
|
||||
pixelAttribs[i++] = WGL_STENCIL_BITS_ARB;
|
||||
pixelAttribs[i++] = 0;
|
||||
|
||||
pixelAttribs[i++] = WGL_ACCUM_BITS_ARB;
|
||||
pixelAttribs[i++] = 0;
|
||||
|
||||
/* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
|
||||
|
||||
pixelAttribs[i++] = 0; /* end of pixelAttribs */
|
||||
g_assert (i <= PIXEL_ATTRIBUTES);
|
||||
g_assert (i == PIXEL_ATTRIBUTES);
|
||||
|
||||
if (!wglMakeCurrent (display_win32->dummy_context_wgl.hdc,
|
||||
display_win32->dummy_context_wgl.hglrc))
|
||||
@@ -205,7 +214,7 @@ get_wgl_pfd (HDC hdc,
|
||||
pfd->iPixelType = PFD_TYPE_RGBA;
|
||||
pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL);
|
||||
pfd->cAlphaBits = 8;
|
||||
pfd->dwLayerMask = PFD_MAIN_PLANE;
|
||||
pfd->iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
best_pf = ChoosePixelFormat (hdc, pfd);
|
||||
}
|
||||
@@ -604,7 +613,7 @@ set_wgl_pixformat_for_hdc (GdkWin32Display *display_win32,
|
||||
{
|
||||
gboolean skip_acquire = FALSE;
|
||||
gboolean set_pixel_format_result = FALSE;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
PIXELFORMATDESCRIPTOR pfd = {0};
|
||||
|
||||
/* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
|
||||
* one single time per window HDC
|
||||
|
||||
@@ -211,6 +211,11 @@ Win32Cursor * win32_cursor_theme_get_cursor (Win32CursorTheme *theme,
|
||||
void win32_cursor_theme_destroy (Win32CursorTheme *theme);
|
||||
Win32CursorTheme *_gdk_win32_display_get_cursor_theme (GdkWin32Display *win32_display);
|
||||
|
||||
HICON _gdk_win32_create_hicon_for_texture (GdkTexture *texture,
|
||||
gboolean is_icon,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
gboolean _gdk_win32_display_has_pending (GdkDisplay *display);
|
||||
void _gdk_win32_display_queue_events (GdkDisplay *display);
|
||||
|
||||
|
||||
@@ -4308,6 +4308,82 @@ gdk_win32_surface_set_shadow_width (GdkSurface *window,
|
||||
impl->shadow_y = top + bottom;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_surface_set_icon_list (GdkSurface *surface,
|
||||
GList *textures)
|
||||
{
|
||||
GdkTexture *texture, *big_texture, *small_texture;
|
||||
gint big_diff, small_diff;
|
||||
gint big_w, big_h, small_w, small_h;
|
||||
gint w, h;
|
||||
gint dw, dh, diff;
|
||||
HICON small_hicon, big_hicon;
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (surface))
|
||||
return;
|
||||
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
/* ideal sizes for small and large icons */
|
||||
big_w = GetSystemMetrics (SM_CXICON);
|
||||
big_h = GetSystemMetrics (SM_CYICON);
|
||||
small_w = GetSystemMetrics (SM_CXSMICON);
|
||||
small_h = GetSystemMetrics (SM_CYSMICON);
|
||||
|
||||
/* find closest sized icons in the list */
|
||||
big_texture = NULL;
|
||||
small_texture = NULL;
|
||||
big_diff = 0;
|
||||
small_diff = 0;
|
||||
while (textures)
|
||||
{
|
||||
texture = (GdkTexture*) textures->data;
|
||||
w = gdk_texture_get_width (texture);
|
||||
h = gdk_texture_get_height (texture);
|
||||
|
||||
dw = ABS (w - big_w);
|
||||
dh = ABS (h - big_h);
|
||||
diff = dw*dw + dh*dh;
|
||||
if (big_texture == NULL || diff < big_diff)
|
||||
{
|
||||
big_texture = texture;
|
||||
big_diff = diff;
|
||||
}
|
||||
|
||||
dw = ABS (w - small_w);
|
||||
dh = ABS (h - small_h);
|
||||
diff = dw*dw + dh*dh;
|
||||
if (small_texture == NULL || diff < small_diff)
|
||||
{
|
||||
small_texture = texture;
|
||||
small_diff = diff;
|
||||
}
|
||||
|
||||
textures = textures->next;
|
||||
}
|
||||
|
||||
if (big_texture == NULL || small_texture == NULL)
|
||||
return;
|
||||
|
||||
/* Create the icons */
|
||||
big_hicon = big_texture ? _gdk_win32_create_hicon_for_texture (big_texture, TRUE, 0, 0) : NULL;
|
||||
small_hicon = small_texture ? _gdk_win32_create_hicon_for_texture (small_texture, TRUE, 0, 0) : NULL;
|
||||
|
||||
/* Set the icons */
|
||||
SendMessage (GDK_SURFACE_HWND (surface), WM_SETICON, ICON_BIG,
|
||||
(LPARAM)big_hicon);
|
||||
SendMessage (GDK_SURFACE_HWND (surface), WM_SETICON, ICON_SMALL,
|
||||
(LPARAM)small_hicon);
|
||||
|
||||
/* Store the icons, destroying any previous icons */
|
||||
if (impl->hicon_big)
|
||||
GDI_CALL (DestroyIcon, (impl->hicon_big));
|
||||
impl->hicon_big = big_hicon;
|
||||
if (impl->hicon_small)
|
||||
GDI_CALL (DestroyIcon, (impl->hicon_small));
|
||||
impl->hicon_small = small_hicon;
|
||||
}
|
||||
|
||||
double
|
||||
_gdk_win32_surface_get_scale (GdkSurface *surface)
|
||||
@@ -4738,6 +4814,8 @@ gdk_win32_toplevel_set_property (GObject *object,
|
||||
break;
|
||||
|
||||
case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
|
||||
gdk_win32_surface_set_icon_list (surface, g_value_get_pointer (value));
|
||||
g_object_notify_by_pspec (G_OBJECT (surface), pspec);
|
||||
break;
|
||||
|
||||
case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
|
||||
|
||||
@@ -1430,6 +1430,8 @@ gdk_x11_display_open (const char *display_name)
|
||||
int maj, min;
|
||||
char *cm_name;
|
||||
gboolean frame_extents;
|
||||
gboolean rgba;
|
||||
gboolean composited;
|
||||
|
||||
XInitThreads ();
|
||||
|
||||
@@ -1646,7 +1648,10 @@ gdk_x11_display_open (const char *display_name)
|
||||
|
||||
frame_extents = gdk_x11_screen_supports_net_wm_hint (gdk_x11_display_get_screen (display),
|
||||
g_intern_static_string ("_GTK_FRAME_EXTENTS"));
|
||||
gdk_display_set_shadow_width (display, frame_extents);
|
||||
rgba = gdk_display_is_rgba (display);
|
||||
composited = gdk_display_is_composited (display);
|
||||
|
||||
gdk_display_set_shadow_width (display, frame_extents && rgba && composited);
|
||||
|
||||
gdk_display_emit_opened (display);
|
||||
|
||||
@@ -3010,6 +3015,8 @@ gdk_x11_display_init_gl_backend (GdkX11Display *self,
|
||||
|
||||
self->egl_version = epoxy_egl_version (egl_display);
|
||||
|
||||
XFree (visinfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -2655,6 +2655,7 @@ gdk_x11_surface_get_geometry (GdkSurface *surface,
|
||||
{
|
||||
GdkX11Surface *impl;
|
||||
Window root;
|
||||
Window child;
|
||||
int tx;
|
||||
int ty;
|
||||
guint twidth;
|
||||
@@ -2669,7 +2670,11 @@ gdk_x11_surface_get_geometry (GdkSurface *surface,
|
||||
XGetGeometry (GDK_SURFACE_XDISPLAY (surface),
|
||||
GDK_SURFACE_XID (surface),
|
||||
&root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
|
||||
|
||||
|
||||
XTranslateCoordinates (GDK_SURFACE_XDISPLAY (surface),
|
||||
GDK_SURFACE_XID (surface),
|
||||
root, 0, 0, &tx, &ty, &child);
|
||||
|
||||
if (x)
|
||||
*x = tx / impl->surface_scale;
|
||||
if (y)
|
||||
|
||||
@@ -1066,8 +1066,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
|
||||
gsk_profiler_timer_begin (self->profiler, self->metrics.cpu_time);
|
||||
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
|
||||
/* Pre-multiplied alpha */
|
||||
glEnable (GL_BLEND);
|
||||
|
||||
+15
-2
@@ -1,5 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
|
||||
#include "gskglbufferprivate.h"
|
||||
|
||||
struct _GskGLBuffer
|
||||
@@ -14,6 +16,9 @@ struct _GskGLBuffer
|
||||
|
||||
G_DEFINE_TYPE (GskGLBuffer, gsk_gl_buffer, GSK_TYPE_GPU_BUFFER)
|
||||
|
||||
static guint profiler_buffer_uploads_id;
|
||||
static gint64 profiler_buffer_uploads;
|
||||
|
||||
static void
|
||||
gsk_gl_buffer_finalize (GObject *object)
|
||||
{
|
||||
@@ -34,13 +39,19 @@ gsk_gl_buffer_map (GskGpuBuffer *buffer)
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_buffer_unmap (GskGpuBuffer *buffer)
|
||||
gsk_gl_buffer_unmap (GskGpuBuffer *buffer,
|
||||
gsize used)
|
||||
{
|
||||
GskGLBuffer *self = GSK_GL_BUFFER (buffer);
|
||||
|
||||
if (used == 0)
|
||||
return;
|
||||
|
||||
gsk_gl_buffer_bind (self);
|
||||
|
||||
glBufferSubData (self->target, 0, gsk_gpu_buffer_get_size (buffer), self->data);
|
||||
profiler_buffer_uploads += used;
|
||||
glBufferSubData (self->target, 0, used, self->data);
|
||||
gdk_profiler_set_int_counter (profiler_buffer_uploads_id, profiler_buffer_uploads);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -53,6 +64,8 @@ gsk_gl_buffer_class_init (GskGLBufferClass *klass)
|
||||
buffer_class->unmap = gsk_gl_buffer_unmap;
|
||||
|
||||
gobject_class->finalize = gsk_gl_buffer_finalize;
|
||||
|
||||
profiler_buffer_uploads_id = gdk_profiler_define_int_counter ("ngl-buffer-uploads", "Number of bytes uploaded to GPU");
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+8
-42
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "gdk/gdkdisplayprivate.h"
|
||||
#include "gdk/gdkglcontextprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
@@ -131,47 +132,6 @@ gsk_gl_device_make_current (GskGpuDevice *device)
|
||||
gdk_gl_context_make_current (gdk_display_get_gl_context (gsk_gpu_device_get_display (device)));
|
||||
}
|
||||
|
||||
static void
|
||||
save_texture_to_png (GdkDisplay *display,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
const char *filename)
|
||||
{
|
||||
GdkGLTextureBuilder *builder;
|
||||
GdkTexture *texture;
|
||||
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
gdk_gl_texture_builder_set_context (builder, gdk_display_get_gl_context (display));
|
||||
gdk_gl_texture_builder_set_id (builder, texture_id);
|
||||
gdk_gl_texture_builder_set_width (builder, width);
|
||||
gdk_gl_texture_builder_set_height (builder, height);
|
||||
|
||||
texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
|
||||
gdk_texture_save_to_png (texture, filename);
|
||||
|
||||
g_object_unref (texture);
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_device_end_frame (GskGpuDevice *device)
|
||||
{
|
||||
GskGpuImage *image;
|
||||
static int count = 0;
|
||||
char *filename;
|
||||
|
||||
image = gsk_gpu_device_get_atlas_image (device);
|
||||
|
||||
filename = g_strdup_printf ("atlas%d.png", count++);
|
||||
save_texture_to_png (gsk_gpu_device_get_display (device),
|
||||
gsk_gl_image_peek_texture (GSK_GL_IMAGE (image)),
|
||||
gsk_gpu_image_get_width (image),
|
||||
gsk_gpu_image_get_height (image),
|
||||
filename);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_device_finalize (GObject *object)
|
||||
{
|
||||
@@ -199,7 +159,6 @@ gsk_gl_device_class_init (GskGLDeviceClass *klass)
|
||||
gpu_device_class->create_upload_image = gsk_gl_device_create_upload_image;
|
||||
gpu_device_class->create_download_image = gsk_gl_device_create_download_image;
|
||||
gpu_device_class->make_current = gsk_gl_device_make_current;
|
||||
gpu_device_class->end_frame = gsk_gl_device_end_frame;
|
||||
|
||||
object_class->finalize = gsk_gl_device_finalize;
|
||||
}
|
||||
@@ -515,6 +474,7 @@ gsk_gl_device_load_program (GskGLDevice *self,
|
||||
guint n_external_textures,
|
||||
GError **error)
|
||||
{
|
||||
G_GNUC_UNUSED gint64 begin_time = GDK_PROFILER_CURRENT_TIME;
|
||||
GLuint vertex_shader_id, fragment_shader_id, program_id;
|
||||
GLint link_status;
|
||||
|
||||
@@ -569,6 +529,11 @@ gsk_gl_device_load_program (GskGLDevice *self,
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdk_profiler_end_markf (begin_time,
|
||||
"Compile Program",
|
||||
"name=%s id=%u frag=%u vert=%u",
|
||||
op_class->shader_name, program_id, fragment_shader_id, vertex_shader_id);
|
||||
|
||||
return program_id;
|
||||
}
|
||||
|
||||
@@ -733,3 +698,4 @@ gsk_gl_device_find_gl_format (GskGLDevice *self,
|
||||
/* fallbacks will always fallback to a supported format */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
|
||||
@@ -144,8 +144,7 @@ gsk_gl_frame_submit (GskGpuFrame *frame,
|
||||
|
||||
glEnable (GL_SCISSOR_TEST);
|
||||
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
|
||||
if (vertex_buffer)
|
||||
|
||||
@@ -316,9 +316,3 @@ gsk_gl_image_steal_texture (GskGLImage *self)
|
||||
|
||||
return self->texture_id;
|
||||
}
|
||||
|
||||
GLuint
|
||||
gsk_gl_image_peek_texture (GskGLImage *self)
|
||||
{
|
||||
return self->texture_id;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,4 @@ GLenum gsk_gl_image_get_gl_type (GskGLIm
|
||||
|
||||
GLuint gsk_gl_image_steal_texture (GskGLImage *self);
|
||||
|
||||
GLuint gsk_gl_image_peek_texture (GskGLImage *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -45,8 +45,9 @@ gsk_gpu_buffer_map (GskGpuBuffer *self)
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_buffer_unmap (GskGpuBuffer *self)
|
||||
gsk_gpu_buffer_unmap (GskGpuBuffer *self,
|
||||
gsize size)
|
||||
{
|
||||
GSK_GPU_BUFFER_GET_CLASS (self)->unmap (self);
|
||||
GSK_GPU_BUFFER_GET_CLASS (self)->unmap (self, size);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ struct _GskGpuBufferClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
guchar * (* map) (GskGpuBuffer *self);
|
||||
void (* unmap) (GskGpuBuffer *self);
|
||||
void (* unmap) (GskGpuBuffer *self,
|
||||
gsize used);
|
||||
};
|
||||
|
||||
GType gsk_gpu_buffer_get_type (void) G_GNUC_CONST;
|
||||
@@ -34,7 +35,8 @@ void gsk_gpu_buffer_setup (GskGpuB
|
||||
gsize gsk_gpu_buffer_get_size (GskGpuBuffer *self);
|
||||
|
||||
guchar * gsk_gpu_buffer_map (GskGpuBuffer *self);
|
||||
void gsk_gpu_buffer_unmap (GskGpuBuffer *self);
|
||||
void gsk_gpu_buffer_unmap (GskGpuBuffer *self,
|
||||
gsize used);
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuBuffer, g_object_unref)
|
||||
|
||||
@@ -30,6 +30,14 @@ gsk_gpu_clip_init_rect (GskGpuClip *clip,
|
||||
gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_clip_init_rounded_rect (GskGpuClip *self,
|
||||
const GskRoundedRect *rect)
|
||||
{
|
||||
self->type = GSK_GPU_CLIP_ROUNDED;
|
||||
gsk_rounded_rect_init_copy (&self->rect, rect);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_clip_init_copy (GskGpuClip *self,
|
||||
const GskGpuClip *src)
|
||||
@@ -129,6 +137,13 @@ gsk_gpu_clip_intersect_rounded_rect (GskGpuClip *dest,
|
||||
break;
|
||||
|
||||
case GSK_GPU_CLIP_NONE:
|
||||
res = gsk_rounded_rect_intersect_with_rect (rounded, &src->rect.bounds, &dest->rect);
|
||||
if (gsk_gpu_clip_init_after_intersection (dest, res))
|
||||
break;
|
||||
/* XXX: This may grow the bounds quite substantially */
|
||||
gsk_gpu_clip_init_rounded_rect (dest, rounded);
|
||||
break;
|
||||
|
||||
case GSK_GPU_CLIP_CONTAINED:
|
||||
case GSK_GPU_CLIP_RECT:
|
||||
res = gsk_rounded_rect_intersect_with_rect (rounded, &src->rect.bounds, &dest->rect);
|
||||
|
||||
@@ -16,6 +16,7 @@ typedef enum {
|
||||
GSK_GPU_CLIP_ALL_CLIPPED,
|
||||
/* No clipping is necessary, but the clip rect is set
|
||||
* to the actual bounds of the underlying framebuffer
|
||||
* or handled via the scissor.
|
||||
*/
|
||||
GSK_GPU_CLIP_NONE,
|
||||
/* The clip exists outside the rect, so clipping must
|
||||
|
||||
+18
-14
@@ -11,6 +11,7 @@
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#include "gsk/gskdebugprivate.h"
|
||||
#include "gsk/gskprivate.h"
|
||||
|
||||
#define MAX_SLICES_PER_ATLAS 64
|
||||
|
||||
@@ -905,6 +906,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
GskGpuImage *image;
|
||||
gsize atlas_x, atlas_y, padding;
|
||||
float subpixel_x, subpixel_y;
|
||||
PangoFont *scaled_font;
|
||||
|
||||
cache = g_hash_table_lookup (priv->glyph_cache, &lookup);
|
||||
if (cache)
|
||||
@@ -916,13 +918,20 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
/* Note: we want to scale the font to the required size *and* ensure that
|
||||
* metrics hinting is off. The latter is necessary since pango lets metrics
|
||||
* hinting influence the rendering of hexboxes, and we get bad outcomes if
|
||||
* that happens.
|
||||
*/
|
||||
scaled_font = gsk_reload_font (font, scale, CAIRO_HINT_METRICS_OFF, CAIRO_HINT_STYLE_DEFAULT, CAIRO_ANTIALIAS_DEFAULT);
|
||||
|
||||
subpixel_x = (flags & 3) / 4.f;
|
||||
subpixel_y = ((flags >> 2) & 3) / 4.f;
|
||||
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
|
||||
origin.x = floor (ink_rect.x * scale / PANGO_SCALE + subpixel_x);
|
||||
origin.y = floor (ink_rect.y * scale / PANGO_SCALE + subpixel_y);
|
||||
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale / PANGO_SCALE + subpixel_x) - origin.x;
|
||||
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale / PANGO_SCALE + subpixel_y) - origin.y;
|
||||
pango_font_get_glyph_extents (scaled_font, glyph, &ink_rect, NULL);
|
||||
origin.x = floor (ink_rect.x * 1.0 / PANGO_SCALE + subpixel_x);
|
||||
origin.y = floor (ink_rect.y * 1.0 / PANGO_SCALE + subpixel_y);
|
||||
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * 1.0 / PANGO_SCALE + subpixel_x) - origin.x;
|
||||
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * 1.0 / PANGO_SCALE + subpixel_y) - origin.y;
|
||||
padding = 1;
|
||||
|
||||
image = gsk_gpu_device_add_atlas_image (self,
|
||||
@@ -956,7 +965,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
|
||||
gsk_gpu_upload_glyph_op (frame,
|
||||
cache->image,
|
||||
font,
|
||||
scaled_font,
|
||||
glyph,
|
||||
&(cairo_rectangle_int_t) {
|
||||
.x = rect.origin.x - padding,
|
||||
@@ -964,7 +973,6 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
.width = rect.size.width + 2 * padding,
|
||||
.height = rect.size.height + 2 * padding,
|
||||
},
|
||||
scale,
|
||||
&GRAPHENE_POINT_INIT (cache->origin.x + padding,
|
||||
cache->origin.y + padding));
|
||||
|
||||
@@ -973,14 +981,10 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_device_end_frame (GskGpuDevice *self)
|
||||
{
|
||||
if (GSK_GPU_DEVICE_GET_CLASS (self))
|
||||
GSK_GPU_DEVICE_GET_CLASS (self)->end_frame (self);
|
||||
g_object_unref (scaled_font);
|
||||
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
@@ -42,7 +42,7 @@ struct _GskGpuDeviceClass
|
||||
gsize width,
|
||||
gsize height);
|
||||
void (* make_current) (GskGpuDevice *self);
|
||||
void (* end_frame) (GskGpuDevice *self);
|
||||
|
||||
};
|
||||
|
||||
GType gsk_gpu_device_get_type (void) G_GNUC_CONST;
|
||||
@@ -99,8 +99,6 @@ GskGpuImage * gsk_gpu_device_lookup_glyph_image (GskGpuD
|
||||
graphene_point_t *out_origin);
|
||||
|
||||
|
||||
void gsk_gpu_device_end_frame (GskGpuDevice *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuDevice, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -126,7 +126,7 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
|
||||
bytes,
|
||||
stride);
|
||||
g_bytes_unref (bytes);
|
||||
gsk_gpu_buffer_unmap (self->buffer);
|
||||
gsk_gpu_buffer_unmap (self->buffer, 0);
|
||||
}
|
||||
|
||||
static GskGpuOp *
|
||||
|
||||
@@ -426,7 +426,7 @@ gsk_gpu_frame_reserve_vertex_data (GskGpuFrame *self,
|
||||
if (priv->vertex_buffer_data)
|
||||
{
|
||||
memcpy (new_data, priv->vertex_buffer_data, old_size);
|
||||
gsk_gpu_buffer_unmap (priv->vertex_buffer);
|
||||
gsk_gpu_buffer_unmap (priv->vertex_buffer, old_size);
|
||||
}
|
||||
g_object_unref (priv->vertex_buffer);
|
||||
priv->vertex_buffer = new_buffer;
|
||||
@@ -434,7 +434,7 @@ gsk_gpu_frame_reserve_vertex_data (GskGpuFrame *self,
|
||||
}
|
||||
|
||||
priv->vertex_buffer_used = size_needed;
|
||||
|
||||
|
||||
return size_needed - size;
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ gsk_gpu_frame_write_storage_buffer (GskGpuFrame *self,
|
||||
{
|
||||
g_assert (offset > 0);
|
||||
|
||||
gsk_gpu_buffer_unmap (priv->storage_buffer);
|
||||
gsk_gpu_buffer_unmap (priv->storage_buffer, 0);
|
||||
g_clear_object (&priv->storage_buffer);
|
||||
priv->storage_buffer_data = 0;
|
||||
priv->storage_buffer_used = 0;
|
||||
@@ -591,14 +591,14 @@ gsk_gpu_frame_submit (GskGpuFrame *self)
|
||||
|
||||
if (priv->vertex_buffer)
|
||||
{
|
||||
gsk_gpu_buffer_unmap (priv->vertex_buffer);
|
||||
gsk_gpu_buffer_unmap (priv->vertex_buffer, priv->vertex_buffer_used);
|
||||
priv->vertex_buffer_data = NULL;
|
||||
priv->vertex_buffer_used = 0;
|
||||
}
|
||||
|
||||
if (priv->storage_buffer_data)
|
||||
{
|
||||
gsk_gpu_buffer_unmap (priv->storage_buffer);
|
||||
gsk_gpu_buffer_unmap (priv->storage_buffer, priv->storage_buffer_used);
|
||||
priv->storage_buffer_data = NULL;
|
||||
priv->storage_buffer_used = 0;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "gskroundedrectprivate.h"
|
||||
#include "gskstrokeprivate.h"
|
||||
#include "gsktransformprivate.h"
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include "gdk/gdkrgbaprivate.h"
|
||||
#include "gdk/gdksubsurfaceprivate.h"
|
||||
@@ -183,13 +184,13 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self,
|
||||
{
|
||||
float scale_x = viewport->size.width / width;
|
||||
float scale_y = viewport->size.height / height;
|
||||
gsk_gpu_clip_init_rect (&self->clip,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
scale_x * clip->x,
|
||||
scale_y * clip->y,
|
||||
scale_x * clip->width,
|
||||
scale_y * clip->height
|
||||
));
|
||||
gsk_gpu_clip_init_empty (&self->clip,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
scale_x * clip->x,
|
||||
scale_y * clip->y,
|
||||
scale_x * clip->width,
|
||||
scale_y * clip->height
|
||||
));
|
||||
}
|
||||
|
||||
self->modelview = NULL;
|
||||
@@ -1327,7 +1328,7 @@ gsk_gpu_node_processor_add_node_clipped (GskGpuNodeProcessor *self,
|
||||
gsk_gpu_clip_init_copy (&self->clip, &old_clip);
|
||||
return;
|
||||
}
|
||||
else if (self->clip.type == GSK_GPU_CLIP_RECT &&
|
||||
else if ((self->clip.type == GSK_GPU_CLIP_RECT || self->clip.type == GSK_GPU_CLIP_CONTAINED) &&
|
||||
gsk_rect_contains_rect (&self->clip.rect.bounds, &clip))
|
||||
{
|
||||
self->clip.type = GSK_GPU_CLIP_NONE;
|
||||
@@ -1610,7 +1611,7 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self,
|
||||
inverse = gsk_transform_invert (gsk_transform_ref (clip_transform));
|
||||
gsk_transform_transform_bounds (inverse, &old_clip.rect.bounds, &new_bounds);
|
||||
gsk_transform_unref (inverse);
|
||||
gsk_gpu_clip_init_contained (&self->clip, &new_bounds);
|
||||
gsk_gpu_clip_init_empty (&self->clip, &new_bounds);
|
||||
}
|
||||
else if (!gsk_gpu_clip_transform (&self->clip, &old_clip, clip_transform, &child->bounds))
|
||||
{
|
||||
@@ -1648,10 +1649,13 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self,
|
||||
|
||||
extract_scale_from_transform (self->modelview, &scale_x, &scale_y);
|
||||
|
||||
old_pixels = graphene_vec2_get_x (&old_scale) * graphene_vec2_get_y (&old_scale) *
|
||||
old_clip.rect.bounds.size.width * old_clip.rect.bounds.size.height;
|
||||
new_pixels = scale_x * scale_y * self->clip.rect.bounds.size.width * self->clip.rect.bounds.size.height;
|
||||
if (new_pixels > 2 * old_pixels)
|
||||
old_pixels = MAX (graphene_vec2_get_x (&old_scale) * old_clip.rect.bounds.size.width,
|
||||
graphene_vec2_get_y (&old_scale) * old_clip.rect.bounds.size.height);
|
||||
new_pixels = MAX (scale_x * self->clip.rect.bounds.size.width,
|
||||
scale_y * self->clip.rect.bounds.size.height);
|
||||
|
||||
/* Check that our offscreen doesn't get too big. 1.5 ~ sqrt(2) */
|
||||
if (new_pixels > 1.5 * old_pixels)
|
||||
{
|
||||
float forced_downscale = 2 * old_pixels / new_pixels;
|
||||
scale_x *= forced_downscale;
|
||||
@@ -2055,7 +2059,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
guint32 descriptor;
|
||||
gboolean need_mipmap, need_offscreen;
|
||||
|
||||
need_offscreen = self->modelview != NULL ||
|
||||
need_offscreen = self->modelview != NULL ||
|
||||
!graphene_vec2_equal (&self->scale, graphene_vec2_one ());
|
||||
if (need_offscreen)
|
||||
{
|
||||
@@ -2997,6 +3001,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
float scale, inv_scale;
|
||||
GdkRGBA color;
|
||||
gboolean glyph_align;
|
||||
gboolean hinting;
|
||||
|
||||
if (self->opacity < 1.0 &&
|
||||
gsk_text_node_has_color_glyphs (node))
|
||||
@@ -3005,14 +3010,14 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
return;
|
||||
}
|
||||
|
||||
glyph_align = gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_GLYPH_ALIGN) &&
|
||||
gsk_transform_get_category (self->modelview) >= GSK_TRANSFORM_CATEGORY_2D;
|
||||
device = gsk_gpu_frame_get_device (self->frame);
|
||||
|
||||
color = *gsk_text_node_get_color (node);
|
||||
color.alpha *= self->opacity;
|
||||
num_glyphs = gsk_text_node_get_num_glyphs (node);
|
||||
glyphs = gsk_text_node_get_glyphs (node, NULL);
|
||||
font = gsk_text_node_get_font (node);
|
||||
hinting = gsk_text_node_use_font_hinting (node);
|
||||
offset = *gsk_text_node_get_offset (node);
|
||||
offset.x += self->offset.x;
|
||||
offset.y += self->offset.y;
|
||||
@@ -3020,6 +3025,8 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
|
||||
inv_scale = 1.f / scale;
|
||||
|
||||
glyph_align = gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_GLYPH_ALIGN);
|
||||
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
GskGpuImage *image;
|
||||
@@ -3030,10 +3037,21 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
|
||||
glyph_origin = GRAPHENE_POINT_INIT (offset.x + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||
offset.y + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
||||
if (glyph_align)
|
||||
|
||||
if (hinting && glyph_align)
|
||||
{
|
||||
glyph_origin.x = roundf (glyph_origin.x * scale * 4);
|
||||
glyph_origin.y = roundf (glyph_origin.y * scale * 4);
|
||||
/* Force glyph_origin.y to be device pixel aligned.
|
||||
* The hinter expects that.
|
||||
*/
|
||||
glyph_origin.x = floor (glyph_origin.x * scale * 4 + .5);
|
||||
flags = ((int) glyph_origin.x & 3);
|
||||
glyph_origin.x = 0.25 * inv_scale * glyph_origin.x;
|
||||
glyph_origin.y = floor (glyph_origin.y * scale + .5) * inv_scale;
|
||||
}
|
||||
else if (glyph_align)
|
||||
{
|
||||
glyph_origin.x = floor (glyph_origin.x * scale * 4 + .5);
|
||||
glyph_origin.y = floor (glyph_origin.y * scale * 4 + .5);
|
||||
flags = ((int) glyph_origin.x & 3) |
|
||||
(((int) glyph_origin.y & 3) << 2);
|
||||
glyph_origin.x = 0.25 * inv_scale * glyph_origin.x;
|
||||
@@ -3041,6 +3059,8 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph_origin.x = floor (glyph_origin.x * scale + .5) * inv_scale;
|
||||
glyph_origin.y = floor (glyph_origin.y * scale + .5) * inv_scale;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
@@ -3053,11 +3073,19 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
|
||||
gsk_rect_scale (&GRAPHENE_RECT_INIT (-glyph_bounds.origin.x, -glyph_bounds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), inv_scale, inv_scale, &glyph_tex_rect);
|
||||
gsk_rect_scale (&GRAPHENE_RECT_INIT(0, 0, glyph_bounds.size.width, glyph_bounds.size.height), inv_scale, inv_scale, &glyph_bounds);
|
||||
glyph_tex_rect = GRAPHENE_RECT_INIT (-glyph_bounds.origin.x * inv_scale,
|
||||
-glyph_bounds.origin.y * inv_scale,
|
||||
gsk_gpu_image_get_width (image) * inv_scale,
|
||||
gsk_gpu_image_get_height (image) * inv_scale);
|
||||
glyph_bounds = GRAPHENE_RECT_INIT (0,
|
||||
0,
|
||||
glyph_bounds.size.width * inv_scale,
|
||||
glyph_bounds.size.height * inv_scale);
|
||||
glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x * inv_scale,
|
||||
glyph_origin.y - glyph_offset.y * inv_scale);
|
||||
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
|
||||
|
||||
if (glyphs[i].attr.is_color)
|
||||
gsk_gpu_texture_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_offset, &glyph_bounds),
|
||||
@@ -3093,6 +3121,8 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
guint32 tex_id;
|
||||
GskGpuImage *last_image;
|
||||
graphene_point_t offset;
|
||||
gboolean glyph_align;
|
||||
gboolean hinting;
|
||||
|
||||
if (gsk_text_node_has_color_glyphs (node))
|
||||
return FALSE;
|
||||
@@ -3112,18 +3142,51 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
gsk_gpu_pattern_writer_append_rgba (self, gsk_text_node_get_color (node));
|
||||
gsk_gpu_pattern_writer_append_uint (self, num_glyphs);
|
||||
|
||||
glyph_align = gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_GLYPH_ALIGN);
|
||||
hinting = gsk_font_get_hint_style (font) != CAIRO_HINT_STYLE_NONE;
|
||||
|
||||
last_image = NULL;
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
GskGpuImage *image;
|
||||
graphene_rect_t glyph_bounds;
|
||||
graphene_point_t glyph_offset;
|
||||
graphene_point_t glyph_offset, glyph_origin;
|
||||
GskGpuGlyphLookupFlags flags;
|
||||
|
||||
glyph_origin = GRAPHENE_POINT_INIT (offset.x + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||
offset.y + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
||||
|
||||
if (hinting && glyph_align)
|
||||
{
|
||||
/* Force glyph_origin.y to be device pixel aligned.
|
||||
* The hinter expects that.
|
||||
*/
|
||||
glyph_origin.x = roundf (glyph_origin.x * scale * 4);
|
||||
flags = ((int) glyph_origin.x & 3);
|
||||
glyph_origin.x = 0.25 * inv_scale * glyph_origin.x;
|
||||
glyph_origin.y = roundf (glyph_origin.y * scale) * inv_scale;
|
||||
}
|
||||
else if (glyph_align)
|
||||
{
|
||||
glyph_origin.x = roundf (glyph_origin.x * scale * 4);
|
||||
glyph_origin.y = roundf (glyph_origin.y * scale * 4);
|
||||
flags = ((int) glyph_origin.x & 3) |
|
||||
(((int) glyph_origin.y & 3) << 2);
|
||||
glyph_origin.x = 0.25 * inv_scale * glyph_origin.x;
|
||||
glyph_origin.y = 0.25 * inv_scale * glyph_origin.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph_origin.x = roundf (glyph_origin.x * scale) * inv_scale;
|
||||
glyph_origin.y = roundf (glyph_origin.y * scale) * inv_scale;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
image = gsk_gpu_device_lookup_glyph_image (device,
|
||||
self->frame,
|
||||
font,
|
||||
glyphs[i].glyph,
|
||||
0,
|
||||
flags,
|
||||
scale,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
@@ -3136,8 +3199,8 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
last_image = image;
|
||||
}
|
||||
|
||||
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
|
||||
glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x * inv_scale,
|
||||
glyph_origin.y - glyph_offset.y * inv_scale);
|
||||
|
||||
gsk_gpu_pattern_writer_append_uint (self, tex_id);
|
||||
gsk_gpu_pattern_writer_append_rect (self,
|
||||
@@ -3147,7 +3210,7 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
glyph_bounds.size.width * inv_scale,
|
||||
glyph_bounds.size.height * inv_scale
|
||||
),
|
||||
&glyph_offset);
|
||||
&glyph_origin);
|
||||
gsk_gpu_pattern_writer_append_rect (self,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
- glyph_bounds.origin.x * inv_scale,
|
||||
@@ -3155,7 +3218,7 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
gsk_gpu_image_get_width (image) * inv_scale,
|
||||
gsk_gpu_image_get_height (image) * inv_scale
|
||||
),
|
||||
&glyph_offset);
|
||||
&glyph_origin);
|
||||
|
||||
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
||||
}
|
||||
|
||||
@@ -428,7 +428,6 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
|
||||
gsk_gpu_device_queue_gc (priv->device);
|
||||
|
||||
gdk_draw_context_end_frame (priv->context);
|
||||
gsk_gpu_device_end_frame (priv->device);
|
||||
|
||||
g_clear_pointer (&render_region, cairo_region_destroy);
|
||||
}
|
||||
|
||||
+20
-27
@@ -110,8 +110,8 @@ gsk_gpu_upload_op_vk_command_with_area (GskGpuOp *op,
|
||||
data = gsk_gpu_buffer_map (*buffer);
|
||||
|
||||
draw_func (op, data, stride);
|
||||
|
||||
gsk_gpu_buffer_unmap (*buffer);
|
||||
|
||||
gsk_gpu_buffer_unmap (*buffer, area->height * stride);
|
||||
|
||||
vkCmdPipelineBarrier (state->vk_command_buffer,
|
||||
VK_PIPELINE_STAGE_HOST_BIT,
|
||||
@@ -485,7 +485,6 @@ struct _GskGpuUploadGlyphOp
|
||||
cairo_rectangle_int_t area;
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
float scale;
|
||||
graphene_point_t origin;
|
||||
|
||||
GskGpuBuffer *buffer;
|
||||
@@ -509,11 +508,19 @@ gsk_gpu_upload_glyph_op_print (GskGpuOp *op,
|
||||
guint indent)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
PangoFontDescription *desc;
|
||||
char *str;
|
||||
|
||||
desc = pango_font_describe_with_absolute_size (self->font);
|
||||
str = pango_font_description_to_string (desc);
|
||||
|
||||
gsk_gpu_print_op (string, indent, "upload-glyph");
|
||||
gsk_gpu_print_int_rect (string, &self->area);
|
||||
g_string_append_printf (string, "glyph %u @ %g ", self->glyph, self->scale);
|
||||
g_string_append_printf (string, "glyph %u font %s ", self->glyph, str);
|
||||
gsk_gpu_print_newline (string);
|
||||
|
||||
g_free (str);
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -524,6 +531,7 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
PangoRectangle ink_rect = { 0, };
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
@@ -531,7 +539,6 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
|
||||
self->area.height,
|
||||
stride);
|
||||
cairo_surface_set_device_offset (surface, self->origin.x, self->origin.y);
|
||||
cairo_surface_set_device_scale (surface, self->scale, self->scale);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
@@ -546,34 +553,22 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
|
||||
/* Draw glyph */
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 1);
|
||||
|
||||
/* The pango code for drawing hex boxes uses the glyph width */
|
||||
if (self->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
|
||||
pango_font_get_glyph_extents (self->font, self->glyph, &ink_rect, NULL);
|
||||
|
||||
pango_cairo_show_glyph_string (cr,
|
||||
self->font,
|
||||
&(PangoGlyphString) {
|
||||
.num_glyphs = 1,
|
||||
.glyphs = (PangoGlyphInfo[1]) { {
|
||||
.glyph = self->glyph
|
||||
.glyph = self->glyph,
|
||||
.geometry = {
|
||||
.width = ink_rect.width,
|
||||
}
|
||||
} }
|
||||
});
|
||||
|
||||
for (int y = 0; y < self->area.height; y++)
|
||||
{
|
||||
int *row = (int *) (data + y * stride);
|
||||
if (row[0] != 0 || row[self->area.width - 1] != 0)
|
||||
g_warning ("glyph %u overflow", self->glyph);
|
||||
row[0] = 0xff0000ff;
|
||||
row[self->area.width - 1] = 0xff0000ff;
|
||||
}
|
||||
|
||||
for (int x = 0; x < self->area.width; x++)
|
||||
{
|
||||
int *row0 = (int *) data;
|
||||
int * row1 = (int *) (data + (self->area.height - 1) * stride);
|
||||
if (row0[x] != 0 || row1[x] != 0)
|
||||
g_warning ("glyph %u overflow", self->glyph);
|
||||
row0[x] = 0xff0000ff;
|
||||
row1[x] = 0xff0000ff;
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_finish (surface);
|
||||
@@ -629,7 +624,6 @@ gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
PangoFont *font,
|
||||
const PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self;
|
||||
@@ -640,6 +634,5 @@ gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
self->area = *area;
|
||||
self->font = g_object_ref (font);
|
||||
self->glyph = glyph;
|
||||
self->scale = scale;
|
||||
self->origin = *origin;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ void gsk_gpu_upload_glyph_op (GskGpuF
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -45,7 +45,8 @@ gsk_vulkan_buffer_map (GskGpuBuffer *buffer)
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_vulkan_buffer_unmap (GskGpuBuffer *buffer)
|
||||
gsk_vulkan_buffer_unmap (GskGpuBuffer *buffer,
|
||||
gsize size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#include "gskresources.h"
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <pango/pangoft2.h>
|
||||
#include <math.h>
|
||||
|
||||
static gpointer
|
||||
register_resources (gpointer data)
|
||||
{
|
||||
@@ -15,3 +20,173 @@ gsk_ensure_resources (void)
|
||||
|
||||
g_once (®ister_resources_once, register_resources, NULL);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_reload_font:
|
||||
* @font: a `PangoFont`
|
||||
* @scale: the scale to apply
|
||||
* @hint_metris: hint metrics to use or `CAIRO_HINT_METRICS_DEFAILT` to keep the
|
||||
* hint metrics of the font unchanged
|
||||
* @hint_style: hint style to use or `CAIRO_HINT_STYLE_DEFAULT` to keep the
|
||||
* hint style of @font unchanged
|
||||
* @antialias: antialiasing to use, or `CAIRO_ANTIALIAS_DEFAULT` to keep the
|
||||
* antialias option of @font unchanged
|
||||
*
|
||||
* Returns a font that is just like @font, but uses the
|
||||
* given scale and hinting options for its glyphs and metrics.
|
||||
*
|
||||
* Returns: (transfer full): the modified `PangoFont`
|
||||
*/
|
||||
PangoFont *
|
||||
gsk_reload_font (PangoFont *font,
|
||||
float scale,
|
||||
cairo_hint_metrics_t hint_metrics,
|
||||
cairo_hint_style_t hint_style,
|
||||
cairo_antialias_t antialias)
|
||||
{
|
||||
cairo_font_options_t *options;
|
||||
cairo_scaled_font_t *sf;
|
||||
static PangoContext *context = NULL;
|
||||
#if !PANGO_VERSION_CHECK (1, 52, 0)
|
||||
PangoFontDescription *desc;
|
||||
FcPattern *pattern;
|
||||
double dpi;
|
||||
int size;
|
||||
#endif
|
||||
|
||||
/* These requests often come in sequentially so keep the result
|
||||
* around and re-use it if everything matches.
|
||||
*/
|
||||
static PangoFont *last_font;
|
||||
static float last_scale;
|
||||
static cairo_hint_metrics_t last_hint_metrics;
|
||||
static cairo_hint_style_t last_hint_style;
|
||||
static cairo_antialias_t last_antialias;
|
||||
static PangoFont *last_result;
|
||||
|
||||
if (last_result != NULL &&
|
||||
last_font == font &&
|
||||
last_scale == scale &&
|
||||
last_hint_metrics == hint_metrics &&
|
||||
last_hint_style == hint_style &&
|
||||
last_antialias == antialias)
|
||||
return g_object_ref (last_result);
|
||||
|
||||
last_scale = scale;
|
||||
last_hint_metrics = hint_metrics;
|
||||
last_hint_style = hint_style;
|
||||
last_antialias = antialias;
|
||||
|
||||
g_set_object (&last_font, font);
|
||||
g_clear_object (&last_result);
|
||||
|
||||
options = cairo_font_options_create ();
|
||||
sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
|
||||
cairo_scaled_font_get_font_options (sf, options);
|
||||
|
||||
if (hint_metrics == CAIRO_HINT_METRICS_DEFAULT)
|
||||
hint_metrics = cairo_font_options_get_hint_metrics (options);
|
||||
|
||||
if (hint_style == CAIRO_HINT_STYLE_DEFAULT)
|
||||
hint_style = cairo_font_options_get_hint_style (options);
|
||||
|
||||
if (antialias == CAIRO_ANTIALIAS_DEFAULT)
|
||||
antialias = cairo_font_options_get_antialias (options);
|
||||
|
||||
if (1.0 == scale &&
|
||||
cairo_font_options_get_hint_metrics (options) == hint_metrics &&
|
||||
cairo_font_options_get_hint_style (options) == hint_style &&
|
||||
cairo_font_options_get_antialias (options) == antialias &&
|
||||
cairo_font_options_get_subpixel_order (options) == CAIRO_SUBPIXEL_ORDER_DEFAULT)
|
||||
{
|
||||
last_result = g_object_ref (font);
|
||||
cairo_font_options_destroy (options);
|
||||
return g_object_ref (font);
|
||||
}
|
||||
|
||||
cairo_font_options_set_hint_metrics (options, hint_metrics);
|
||||
cairo_font_options_set_hint_style (options, hint_style);
|
||||
cairo_font_options_set_antialias (options, antialias);
|
||||
cairo_font_options_set_subpixel_order (options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
|
||||
|
||||
if (!context)
|
||||
context = pango_context_new ();
|
||||
|
||||
pango_cairo_context_set_font_options (context, options);
|
||||
cairo_font_options_destroy (options);
|
||||
|
||||
#if PANGO_VERSION_CHECK (1, 52, 0)
|
||||
last_result = pango_font_map_reload_font (pango_font_get_font_map (font), font, scale, context, NULL);
|
||||
#else
|
||||
|
||||
pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font));
|
||||
if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) == FcResultMatch)
|
||||
pango_cairo_context_set_resolution (context, dpi);
|
||||
|
||||
desc = pango_font_describe (font);
|
||||
size = pango_font_description_get_size (desc);
|
||||
|
||||
if (pango_font_description_get_size_is_absolute (desc))
|
||||
pango_font_description_set_absolute_size (desc, size * scale);
|
||||
else
|
||||
pango_font_description_set_size (desc, (int) floor (size * scale + .5));
|
||||
|
||||
last_result = pango_font_map_load_font (pango_font_get_font_map (font), context, desc);
|
||||
pango_font_description_free (desc);
|
||||
#endif
|
||||
|
||||
return g_object_ref (last_result);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_get_unhinted_glyph_string_extents:
|
||||
* @glyphs: a `PangoGlyphString`
|
||||
* @font: a `PangoFont`
|
||||
* @ink_rect: (out): rectangle used to store the extents of the glyph string as drawn
|
||||
*
|
||||
* Compute the ink extents of a glyph string.
|
||||
*
|
||||
* This is like [method@Pango.GlyphString.extents], but it
|
||||
* ignores hinting of the font.
|
||||
*/
|
||||
void
|
||||
gsk_get_unhinted_glyph_string_extents (PangoGlyphString *glyphs,
|
||||
PangoFont *font,
|
||||
PangoRectangle *ink_rect)
|
||||
{
|
||||
PangoFont *unhinted;
|
||||
|
||||
unhinted = gsk_reload_font (font,
|
||||
1.0,
|
||||
CAIRO_HINT_METRICS_OFF,
|
||||
CAIRO_HINT_STYLE_NONE,
|
||||
CAIRO_ANTIALIAS_DEFAULT);
|
||||
|
||||
pango_glyph_string_extents (glyphs, unhinted, ink_rect, NULL);
|
||||
|
||||
g_object_unref (unhinted);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_font_get_hint_style:
|
||||
* @font: a `PangoFont`
|
||||
*
|
||||
* Get the hint style from the cairo font options.
|
||||
*
|
||||
* Returns: the hint style
|
||||
*/
|
||||
cairo_hint_style_t
|
||||
gsk_font_get_hint_style (PangoFont *font)
|
||||
{
|
||||
cairo_scaled_font_t *sf;
|
||||
cairo_font_options_t *options;
|
||||
cairo_hint_style_t style;
|
||||
|
||||
sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
|
||||
options = cairo_font_options_create ();
|
||||
cairo_scaled_font_get_font_options (sf, options);
|
||||
style = cairo_font_options_get_hint_style (options);
|
||||
cairo_font_options_destroy (options);
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
+14
-1
@@ -2,10 +2,23 @@
|
||||
|
||||
#include <glib.h>
|
||||
#include <pango/pango.h>
|
||||
#include <cairo.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gsk_ensure_resources (void);
|
||||
void gsk_ensure_resources (void);
|
||||
|
||||
PangoFont *gsk_reload_font (PangoFont *font,
|
||||
float scale,
|
||||
cairo_hint_metrics_t hint_metrics,
|
||||
cairo_hint_style_t hint_style,
|
||||
cairo_antialias_t antialias);
|
||||
|
||||
void gsk_get_unhinted_glyph_string_extents (PangoGlyphString *glyphs,
|
||||
PangoFont *font,
|
||||
PangoRectangle *ink_rect);
|
||||
|
||||
cairo_hint_style_t gsk_font_get_hint_style (PangoFont *font);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -688,9 +688,6 @@ get_renderer_for_vulkan (GdkSurface *surface)
|
||||
static GType
|
||||
get_renderer_for_gles2 (GdkSurface *surface)
|
||||
{
|
||||
if (gl_software_rendering (surface))
|
||||
return G_TYPE_INVALID;
|
||||
|
||||
return GSK_TYPE_GL_RENDERER;
|
||||
}
|
||||
|
||||
|
||||
+14
-7
@@ -31,6 +31,7 @@
|
||||
#include "gskroundedrectprivate.h"
|
||||
#include "gskstrokeprivate.h"
|
||||
#include "gsktransformprivate.h"
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include "gdk/gdkmemoryformatprivate.h"
|
||||
#include "gdk/gdkprivate.h"
|
||||
@@ -3473,7 +3474,7 @@ gsk_transform_node_draw (GskRenderNode *node,
|
||||
* (like when flipping an axis at the point where scale == 0)
|
||||
* and just means that nothing should be drawn.
|
||||
* But Cairo throws lots of ugly errors instead of silently
|
||||
* going on. So We silently go on.
|
||||
* going on. So we silently go on.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
@@ -5791,6 +5792,12 @@ gsk_text_node_class_init (gpointer g_class,
|
||||
node_class->diff = gsk_text_node_diff;
|
||||
}
|
||||
|
||||
static inline float
|
||||
pango_units_to_float (int i)
|
||||
{
|
||||
return (float) i / PANGO_SCALE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_text_node_new:
|
||||
* @font: the `PangoFont` containing the glyphs
|
||||
@@ -5817,8 +5824,7 @@ gsk_text_node_new (PangoFont *font,
|
||||
PangoGlyphInfo *glyph_infos;
|
||||
int n;
|
||||
|
||||
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
|
||||
pango_extents_to_pixels (&ink_rect, NULL);
|
||||
gsk_get_unhinted_glyph_string_extents (glyphs, font, &ink_rect);
|
||||
|
||||
/* Don't create nodes with empty bounds */
|
||||
if (ink_rect.width == 0 || ink_rect.height == 0)
|
||||
@@ -5827,6 +5833,7 @@ gsk_text_node_new (PangoFont *font,
|
||||
self = gsk_render_node_alloc (GSK_TEXT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
node->font_hinting = gsk_font_get_hint_style (font) != CAIRO_HINT_STYLE_NONE;
|
||||
|
||||
self->fontmap = g_object_ref (pango_font_get_font_map (font));
|
||||
self->font = g_object_ref (font);
|
||||
@@ -5855,10 +5862,10 @@ gsk_text_node_new (PangoFont *font,
|
||||
self->num_glyphs = n;
|
||||
|
||||
gsk_rect_init (&node->bounds,
|
||||
offset->x + ink_rect.x,
|
||||
offset->y + ink_rect.y,
|
||||
ink_rect.width,
|
||||
ink_rect.height);
|
||||
offset->x + pango_units_to_float (ink_rect.x),
|
||||
offset->y + pango_units_to_float (ink_rect.y),
|
||||
pango_units_to_float (ink_rect.width),
|
||||
pango_units_to_float (ink_rect.height));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
+188
-77
@@ -30,6 +30,7 @@
|
||||
#include "gskstroke.h"
|
||||
#include "gsktransformprivate.h"
|
||||
#include "gskenumtypes.h"
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include "gdk/gdkrgbaprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
@@ -46,7 +47,9 @@
|
||||
#include <cairo-script-interpreter.h>
|
||||
#endif
|
||||
|
||||
#include <cairo-gobject.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
#include <pango/pangofc-fontmap.h>
|
||||
#endif
|
||||
@@ -86,6 +89,39 @@ context_finish (Context *context)
|
||||
g_clear_object (&context->fontmap);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_enum (GtkCssParser *parser,
|
||||
GType type,
|
||||
gpointer out_value)
|
||||
{
|
||||
GEnumClass *class;
|
||||
GEnumValue *v;
|
||||
char *enum_name;
|
||||
|
||||
enum_name = gtk_css_parser_consume_ident (parser);
|
||||
if (enum_name == NULL)
|
||||
return FALSE;
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
|
||||
v = g_enum_get_value_by_nick (class, enum_name);
|
||||
if (v == NULL)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
|
||||
enum_name, g_type_name (type));
|
||||
g_free (enum_name);
|
||||
g_type_class_unref (class);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(int*)out_value = v->value;
|
||||
|
||||
g_free (enum_name);
|
||||
g_type_class_unref (class);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_rect (GtkCssParser *parser,
|
||||
Context *context,
|
||||
@@ -1182,6 +1218,8 @@ clear_font (gpointer inout_font)
|
||||
g_clear_object ((PangoFont **) inout_font);
|
||||
}
|
||||
|
||||
#define GLYPH_NEEDS_WIDTH (1 << 15)
|
||||
|
||||
static gboolean
|
||||
parse_glyphs (GtkCssParser *parser,
|
||||
Context *context,
|
||||
@@ -1208,6 +1246,7 @@ parse_glyphs (GtkCssParser *parser,
|
||||
gtk_css_parser_error_value (parser, "Unsupported character %d in string", i);
|
||||
}
|
||||
gi.glyph = PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH + s[i];
|
||||
*(unsigned int *) &gi.attr |= GLYPH_NEEDS_WIDTH;
|
||||
pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1);
|
||||
glyph_string->glyphs[glyph_string->num_glyphs - 1] = gi;
|
||||
}
|
||||
@@ -1216,14 +1255,22 @@ parse_glyphs (GtkCssParser *parser,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gtk_css_parser_consume_integer (parser, &i) ||
|
||||
!gtk_css_parser_consume_number (parser, &d))
|
||||
if (!gtk_css_parser_consume_integer (parser, &i))
|
||||
{
|
||||
pango_glyph_string_free (glyph_string);
|
||||
return FALSE;
|
||||
}
|
||||
gi.glyph = i;
|
||||
gi.geometry.width = (int) (d * PANGO_SCALE);
|
||||
|
||||
if (gtk_css_parser_has_number (parser))
|
||||
{
|
||||
gtk_css_parser_consume_number (parser, &d);
|
||||
gi.geometry.width = (int) (d * PANGO_SCALE);
|
||||
}
|
||||
else
|
||||
{
|
||||
*(unsigned int *) &gi.attr |= GLYPH_NEEDS_WIDTH;
|
||||
}
|
||||
|
||||
if (gtk_css_parser_has_number (parser))
|
||||
{
|
||||
@@ -2193,23 +2240,36 @@ unpack_glyphs (PangoFont *font,
|
||||
|
||||
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||
{
|
||||
PangoGlyph glyph = glyphs->glyphs[i].glyph;
|
||||
PangoGlyphInfo *gi = &glyphs->glyphs[i];
|
||||
|
||||
if (glyph < PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH ||
|
||||
glyph >= PANGO_GLYPH_INVALID_INPUT)
|
||||
if (((*(unsigned int *) &gi->attr) & GLYPH_NEEDS_WIDTH) == 0)
|
||||
continue;
|
||||
|
||||
glyph = glyph - (PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH) - MIN_ASCII_GLYPH;
|
||||
*(unsigned int *) &gi->attr &= ~GLYPH_NEEDS_WIDTH;
|
||||
|
||||
if (ascii == NULL)
|
||||
if (gi->glyph >= PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH &&
|
||||
gi->glyph < PANGO_GLYPH_INVALID_INPUT)
|
||||
{
|
||||
ascii = create_ascii_glyphs (font);
|
||||
if (ascii == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
PangoGlyph idx = gi->glyph - (PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH) - MIN_ASCII_GLYPH;
|
||||
|
||||
glyphs->glyphs[i].glyph = ascii->glyphs[glyph].glyph;
|
||||
glyphs->glyphs[i].geometry.width = ascii->glyphs[glyph].geometry.width;
|
||||
if (ascii == NULL)
|
||||
{
|
||||
ascii = create_ascii_glyphs (font);
|
||||
if (ascii == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gi->glyph = ascii->glyphs[idx].glyph;
|
||||
gi->geometry.width = ascii->glyphs[idx].geometry.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
PangoRectangle ink_rect;
|
||||
|
||||
pango_font_get_glyph_extents (font, gi->glyph, &ink_rect, NULL);
|
||||
|
||||
gi->geometry.width = ink_rect.width;
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_pointer (&ascii, pango_glyph_string_free);
|
||||
@@ -2217,6 +2277,45 @@ unpack_glyphs (PangoFont *font,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_hint_style (GtkCssParser *parser,
|
||||
Context *context,
|
||||
gpointer out)
|
||||
{
|
||||
if (!parse_enum (parser, CAIRO_GOBJECT_TYPE_HINT_STYLE, out))
|
||||
return FALSE;
|
||||
|
||||
if (*(cairo_hint_style_t *) out != CAIRO_HINT_STYLE_NONE &&
|
||||
*(cairo_hint_style_t *) out != CAIRO_HINT_STYLE_SLIGHT &&
|
||||
*(cairo_hint_style_t *) out != CAIRO_HINT_STYLE_FULL)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Unsupported value for enum \"%s\"",
|
||||
g_type_name (CAIRO_GOBJECT_TYPE_HINT_STYLE));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_antialias (GtkCssParser *parser,
|
||||
Context *context,
|
||||
gpointer out)
|
||||
{
|
||||
if (!parse_enum (parser, CAIRO_GOBJECT_TYPE_ANTIALIAS, out))
|
||||
return FALSE;
|
||||
|
||||
if (*(cairo_antialias_t *) out != CAIRO_ANTIALIAS_NONE &&
|
||||
*(cairo_antialias_t *) out != CAIRO_ANTIALIAS_GRAY)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Unsupported value for enum \"%s\"",
|
||||
g_type_name (CAIRO_GOBJECT_TYPE_ANTIALIAS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_text_node (GtkCssParser *parser,
|
||||
Context *context)
|
||||
@@ -2225,11 +2324,16 @@ parse_text_node (GtkCssParser *parser,
|
||||
graphene_point_t offset = GRAPHENE_POINT_INIT (0, 0);
|
||||
GdkRGBA color = GDK_RGBA("000000");
|
||||
PangoGlyphString *glyphs = NULL;
|
||||
cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_SLIGHT;
|
||||
cairo_antialias_t antialias = CAIRO_ANTIALIAS_GRAY;
|
||||
PangoFont *hinted;
|
||||
const Declaration declarations[] = {
|
||||
{ "font", parse_font, clear_font, &font },
|
||||
{ "offset", parse_point, NULL, &offset },
|
||||
{ "color", parse_color, NULL, &color },
|
||||
{ "glyphs", parse_glyphs, clear_glyphs, &glyphs }
|
||||
{ "glyphs", parse_glyphs, clear_glyphs, &glyphs },
|
||||
{ "hint-style", parse_hint_style, NULL, &hint_style },
|
||||
{ "antialias", parse_antialias, NULL, &antialias },
|
||||
};
|
||||
GskRenderNode *result;
|
||||
|
||||
@@ -2237,10 +2341,14 @@ parse_text_node (GtkCssParser *parser,
|
||||
|
||||
if (font == NULL)
|
||||
{
|
||||
font = font_from_string (pango_cairo_font_map_get_default (), "Cantarell 11", TRUE);
|
||||
font = font_from_string (pango_cairo_font_map_get_default (), "Cantarell 15px", TRUE);
|
||||
g_assert (font);
|
||||
}
|
||||
|
||||
hinted = gsk_reload_font (font, 1.0, CAIRO_HINT_METRICS_OFF, hint_style, antialias);
|
||||
g_object_unref (font);
|
||||
font = hinted;
|
||||
|
||||
if (!glyphs)
|
||||
{
|
||||
const char *text = "Hello";
|
||||
@@ -2252,6 +2360,7 @@ parse_text_node (GtkCssParser *parser,
|
||||
for (i = 0; i < strlen (text); i++)
|
||||
{
|
||||
gi.glyph = PANGO_GLYPH_INVALID_INPUT - MAX_ASCII_GLYPH + text[i];
|
||||
*(unsigned int *) &gi.attr |= GLYPH_NEEDS_WIDTH;
|
||||
glyphs->glyphs[i] = gi;
|
||||
}
|
||||
}
|
||||
@@ -2429,39 +2538,6 @@ clear_dash (gpointer inout_array)
|
||||
g_clear_pointer ((GArray **) inout_array, g_array_unref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_enum (GtkCssParser *parser,
|
||||
GType type,
|
||||
gpointer out_value)
|
||||
{
|
||||
GEnumClass *class;
|
||||
GEnumValue *v;
|
||||
char *enum_name;
|
||||
|
||||
enum_name = gtk_css_parser_consume_ident (parser);
|
||||
if (enum_name == NULL)
|
||||
return FALSE;
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
|
||||
v = g_enum_get_value_by_nick (class, enum_name);
|
||||
if (v == NULL)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
|
||||
enum_name, g_type_name (type));
|
||||
g_free (enum_name);
|
||||
g_type_class_unref (class);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(int*)out_value = v->value;
|
||||
|
||||
g_free (enum_name);
|
||||
g_type_class_unref (class);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_fill_rule (GtkCssParser *parser,
|
||||
Context *context,
|
||||
@@ -3248,6 +3324,33 @@ append_string_param (Printer *p,
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static const char *
|
||||
enum_to_nick (GType type,
|
||||
int value)
|
||||
{
|
||||
GEnumClass *class;
|
||||
GEnumValue *v;
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
v = g_enum_get_value (class, value);
|
||||
g_type_class_unref (class);
|
||||
|
||||
return v->value_nick;
|
||||
}
|
||||
|
||||
static void
|
||||
append_enum_param (Printer *p,
|
||||
const char *param_name,
|
||||
GType type,
|
||||
int value)
|
||||
{
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "%s: ", param_name);
|
||||
g_string_append (p->str, enum_to_nick (type, value));
|
||||
g_string_append_c (p->str, ';');
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_vec4_param (Printer *p,
|
||||
const char *param_name,
|
||||
@@ -3471,7 +3574,7 @@ gsk_text_node_serialize_font (GskRenderNode *node,
|
||||
PangoFontDescription *desc;
|
||||
char *s;
|
||||
|
||||
desc = pango_font_describe (font);
|
||||
desc = pango_font_describe_with_absolute_size (font);
|
||||
s = pango_font_description_to_string (desc);
|
||||
g_string_append_printf (p->str, "\"%s\"", s);
|
||||
g_free (s);
|
||||
@@ -3515,6 +3618,37 @@ gsk_text_node_serialize_font (GskRenderNode *node,
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_text_node_serialize_font_options (GskRenderNode *node,
|
||||
Printer *p)
|
||||
{
|
||||
PangoFont *font = gsk_text_node_get_font (node);
|
||||
cairo_scaled_font_t *sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
|
||||
cairo_font_options_t *options;
|
||||
cairo_hint_style_t hint_style;
|
||||
cairo_antialias_t antialias;
|
||||
|
||||
options = cairo_font_options_create ();
|
||||
cairo_scaled_font_get_font_options (sf, options);
|
||||
hint_style = cairo_font_options_get_hint_style (options);
|
||||
antialias = cairo_font_options_get_antialias (options);
|
||||
cairo_font_options_destroy (options);
|
||||
|
||||
/* medium and full are identical in the absence of subpixel modes */
|
||||
if (hint_style == CAIRO_HINT_STYLE_MEDIUM)
|
||||
hint_style = CAIRO_HINT_STYLE_FULL;
|
||||
|
||||
if (hint_style == CAIRO_HINT_STYLE_NONE ||
|
||||
hint_style == CAIRO_HINT_STYLE_FULL)
|
||||
append_enum_param (p, "hint-style", CAIRO_GOBJECT_TYPE_HINT_STYLE, hint_style);
|
||||
|
||||
/* CAIRO_ANTIALIAS_NONE is the only value we ever emit here, since gray is the default,
|
||||
* and we don't accept any other values.
|
||||
*/
|
||||
if (antialias == CAIRO_ANTIALIAS_NONE)
|
||||
append_enum_param (p, "antialias", CAIRO_GOBJECT_TYPE_ANTIALIAS, antialias);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_text_node_serialize_glyphs (GskRenderNode *node,
|
||||
GString *p)
|
||||
@@ -3596,33 +3730,6 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
|
||||
pango_glyph_string_free (ascii);
|
||||
}
|
||||
|
||||
static const char *
|
||||
enum_to_nick (GType type,
|
||||
int value)
|
||||
{
|
||||
GEnumClass *class;
|
||||
GEnumValue *v;
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
v = g_enum_get_value (class, value);
|
||||
g_type_class_unref (class);
|
||||
|
||||
return v->value_nick;
|
||||
}
|
||||
|
||||
static void
|
||||
append_enum_param (Printer *p,
|
||||
const char *param_name,
|
||||
GType type,
|
||||
int value)
|
||||
{
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "%s: ", param_name);
|
||||
g_string_append (p->str, enum_to_nick (type, value));
|
||||
g_string_append_c (p->str, ';');
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_path_param (Printer *p,
|
||||
const char *param_name,
|
||||
@@ -4087,6 +4194,8 @@ render_node_print (Printer *p,
|
||||
if (!graphene_point_equal (offset, graphene_point_zero ()))
|
||||
append_point_param (p, "offset", offset);
|
||||
|
||||
gsk_text_node_serialize_font_options (node, p);
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
@@ -4357,6 +4466,8 @@ render_node_print (Printer *p,
|
||||
start_node (p, "subsurface", node_name);
|
||||
|
||||
append_node_param (p, "child", gsk_subsurface_node_get_child (node));
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ struct _GskRenderNode
|
||||
|
||||
guint preferred_depth : 2;
|
||||
guint offscreen_for_opacity : 1;
|
||||
guint font_hinting : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -100,6 +101,12 @@ gboolean gsk_container_node_is_disjoint (const GskRenderNode
|
||||
|
||||
gboolean gsk_render_node_use_offscreen_for_opacity (const GskRenderNode *node) G_GNUC_PURE;
|
||||
|
||||
static inline gboolean
|
||||
gsk_text_node_use_font_hinting (const GskRenderNode *node)
|
||||
{
|
||||
return node->font_hinting;
|
||||
}
|
||||
|
||||
#define gsk_render_node_ref(node) _gsk_render_node_ref(node)
|
||||
#define gsk_render_node_unref(node) _gsk_render_node_unref(node)
|
||||
|
||||
|
||||
+118
-3
@@ -23,6 +23,7 @@
|
||||
#include "gtkatspicontextprivate.h"
|
||||
|
||||
#include "gtkaccessibleprivate.h"
|
||||
#include "gtkaccessibletextprivate.h"
|
||||
|
||||
#include "gtkatspiactionprivate.h"
|
||||
#include "gtkatspieditabletextprivate.h"
|
||||
@@ -770,7 +771,7 @@ emit_text_selection_changed (GtkAtSpiContext *self,
|
||||
"org.a11y.atspi.Event.Object",
|
||||
"TextCaretMoved",
|
||||
g_variant_new ("(siiva{sv})",
|
||||
"", cursor_position, 0, g_variant_new_string (""), NULL),
|
||||
"", cursor_position, 0, g_variant_new_int32 (0), NULL),
|
||||
NULL);
|
||||
else
|
||||
g_dbus_connection_emit_signal (self->connection,
|
||||
@@ -1154,8 +1155,8 @@ gtk_at_spi_context_state_change (GtkATContext *ctx,
|
||||
|
||||
if (changed_properties & GTK_ACCESSIBLE_PROPERTY_CHANGE_DESCRIPTION)
|
||||
{
|
||||
char *label = gtk_at_context_get_description (GTK_AT_CONTEXT (self));
|
||||
GVariant *v = g_variant_new_take_string (label);
|
||||
char *label = gtk_at_context_get_description (GTK_AT_CONTEXT (self));
|
||||
GVariant *v = g_variant_new_take_string (label);
|
||||
emit_property_changed (self, "accessible-description", v);
|
||||
}
|
||||
|
||||
@@ -1567,6 +1568,117 @@ gtk_at_spi_context_announce (GtkATContext *context,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_spi_context_update_caret_position (GtkATContext *context)
|
||||
{
|
||||
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
|
||||
GtkAccessible *accessible = gtk_at_context_get_accessible (context);
|
||||
GtkAccessibleText *accessible_text = GTK_ACCESSIBLE_TEXT (accessible);
|
||||
guint offset;
|
||||
|
||||
if (self->connection == NULL)
|
||||
return;
|
||||
|
||||
offset = gtk_accessible_text_get_caret_position (accessible_text);
|
||||
|
||||
g_dbus_connection_emit_signal (self->connection,
|
||||
NULL,
|
||||
self->context_path,
|
||||
"org.a11y.atspi.Event.Object",
|
||||
"TextCaretMoved",
|
||||
g_variant_new ("(siiva{sv})",
|
||||
"",
|
||||
(int) offset,
|
||||
0,
|
||||
g_variant_new_int32 (0),
|
||||
NULL),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_spi_context_update_selection_bound (GtkATContext *context)
|
||||
{
|
||||
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
|
||||
|
||||
if (self->connection == NULL)
|
||||
return;
|
||||
|
||||
g_dbus_connection_emit_signal (self->connection,
|
||||
NULL,
|
||||
self->context_path,
|
||||
"org.a11y.atspi.Event.Object",
|
||||
"TextSelectionChanged",
|
||||
g_variant_new ("(siiva{sv})",
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
g_variant_new_string (""),
|
||||
NULL),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_spi_context_update_text_contents (GtkATContext *context,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
|
||||
|
||||
if (self->connection == NULL)
|
||||
return;
|
||||
|
||||
GtkAccessible *accessible = gtk_at_context_get_accessible (context);
|
||||
if (!GTK_IS_ACCESSIBLE_TEXT (accessible))
|
||||
return;
|
||||
|
||||
const char *kind = "";
|
||||
|
||||
switch (change)
|
||||
{
|
||||
case GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT:
|
||||
kind = "insert";
|
||||
break;
|
||||
|
||||
case GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE:
|
||||
kind = "delete";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* Retrieve the text using the given range */
|
||||
GBytes *contents = gtk_accessible_text_get_contents (GTK_ACCESSIBLE_TEXT (accessible),
|
||||
start, end);
|
||||
if (contents == NULL)
|
||||
goto out;
|
||||
|
||||
const char *text = g_bytes_get_data (contents, NULL);
|
||||
if (text == NULL)
|
||||
goto out;
|
||||
|
||||
/* Using G_MAXUINT in GTK maps to the text length */
|
||||
if (end == G_MAXUINT)
|
||||
end = g_utf8_strlen (text, -1);
|
||||
|
||||
g_dbus_connection_emit_signal (self->connection,
|
||||
NULL,
|
||||
self->context_path,
|
||||
"org.a11y.atspi.Event.Object",
|
||||
"TextChanged",
|
||||
g_variant_new ("(siiva{sv})",
|
||||
kind,
|
||||
start,
|
||||
end - start,
|
||||
g_variant_new_string (text),
|
||||
NULL),
|
||||
NULL);
|
||||
|
||||
out:
|
||||
g_clear_pointer (&contents, g_bytes_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
|
||||
{
|
||||
@@ -1582,6 +1694,9 @@ gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
|
||||
context_class->bounds_change = gtk_at_spi_context_bounds_change;
|
||||
context_class->child_change = gtk_at_spi_context_child_change;
|
||||
context_class->announce = gtk_at_spi_context_announce;
|
||||
context_class->update_caret_position = gtk_at_spi_context_update_caret_position;
|
||||
context_class->update_selection_bound = gtk_at_spi_context_update_selection_bound;
|
||||
context_class->update_text_contents = gtk_at_spi_context_update_text_contents;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -20,266 +20,6 @@
|
||||
#include "gtkatspipangoprivate.h"
|
||||
#include "gtkpangoprivate.h"
|
||||
|
||||
void
|
||||
gtk_pango_get_font_attributes (PangoFontDescription *font,
|
||||
GVariantBuilder *builder)
|
||||
{
|
||||
char buf[60];
|
||||
|
||||
g_variant_builder_add (builder, "{ss}", "style",
|
||||
pango_style_to_string (pango_font_description_get_style (font)));
|
||||
g_variant_builder_add (builder, "{ss}", "variant",
|
||||
pango_variant_to_string (pango_font_description_get_variant (font)));
|
||||
g_variant_builder_add (builder, "{ss}", "stretch",
|
||||
pango_stretch_to_string (pango_font_description_get_stretch (font)));
|
||||
g_variant_builder_add (builder, "{ss}", "family-name",
|
||||
pango_font_description_get_family (font));
|
||||
|
||||
g_snprintf (buf, 60, "%d", pango_font_description_get_weight (font));
|
||||
g_variant_builder_add (builder, "{ss}", "weight", buf);
|
||||
g_snprintf (buf, 60, "%i", pango_font_description_get_size (font) / PANGO_SCALE);
|
||||
g_variant_builder_add (builder, "{ss}", "size", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_pango_get_default_attributes:
|
||||
* @layout: the `PangoLayout` from which to get attributes
|
||||
* @builder: a `GVariantBuilder` to add to
|
||||
*
|
||||
* Adds the default text attributes from @layout to @builder,
|
||||
* after translating them from Pango attributes to atspi
|
||||
* attributes.
|
||||
*
|
||||
* This is a convenience function that can be used to implement
|
||||
* support for the `AtkText` interface in widgets using Pango
|
||||
* layouts.
|
||||
*
|
||||
* Returns: the modified @attributes
|
||||
*/
|
||||
void
|
||||
gtk_pango_get_default_attributes (PangoLayout *layout,
|
||||
GVariantBuilder *builder)
|
||||
{
|
||||
PangoContext *context;
|
||||
|
||||
context = pango_layout_get_context (layout);
|
||||
if (context)
|
||||
{
|
||||
PangoLanguage *language;
|
||||
PangoFontDescription *font;
|
||||
|
||||
language = pango_context_get_language (context);
|
||||
if (language)
|
||||
g_variant_builder_add (builder, "{ss}", "language",
|
||||
pango_language_to_string (language));
|
||||
|
||||
font = pango_context_get_font_description (context);
|
||||
if (font)
|
||||
gtk_pango_get_font_attributes (font, builder);
|
||||
}
|
||||
|
||||
g_variant_builder_add (builder, "{ss}", "justification",
|
||||
pango_align_to_string (pango_layout_get_alignment (layout)));
|
||||
|
||||
g_variant_builder_add (builder, "{ss}", "wrap-mode",
|
||||
pango_wrap_mode_to_string (pango_layout_get_wrap (layout)));
|
||||
g_variant_builder_add (builder, "{ss}", "strikethrough", "false");
|
||||
g_variant_builder_add (builder, "{ss}", "underline", "false");
|
||||
g_variant_builder_add (builder, "{ss}", "rise", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "scale", "1");
|
||||
g_variant_builder_add (builder, "{ss}", "bg-full-height", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-inside-wrap", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-below-lines", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-above-lines", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "editable", "false");
|
||||
g_variant_builder_add (builder, "{ss}", "invisible", "false");
|
||||
g_variant_builder_add (builder, "{ss}", "indent", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "right-margin", "0");
|
||||
g_variant_builder_add (builder, "{ss}", "left-margin", "0");
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_pango_get_run_attributes:
|
||||
* @layout: the `PangoLayout` to get the attributes from
|
||||
* @builder: `GVariantBuilder` to add to
|
||||
* @offset: the offset at which the attributes are wanted
|
||||
* @start_offset: return location for the starting offset
|
||||
* of the current run
|
||||
* @end_offset: return location for the ending offset of the
|
||||
* current run
|
||||
*
|
||||
* Finds the “run” around index (i.e. the maximal range of characters
|
||||
* where the set of applicable attributes remains constant) and
|
||||
* returns the starting and ending offsets for it.
|
||||
*
|
||||
* The attributes for the run are added to @attributes, after
|
||||
* translating them from Pango attributes to atspi attributes.
|
||||
*
|
||||
* This is a convenience function that can be used to implement
|
||||
* support for the #AtkText interface in widgets using Pango
|
||||
* layouts.
|
||||
*/
|
||||
void
|
||||
gtk_pango_get_run_attributes (PangoLayout *layout,
|
||||
GVariantBuilder *builder,
|
||||
int offset,
|
||||
int *start_offset,
|
||||
int *end_offset)
|
||||
{
|
||||
PangoAttrIterator *iter;
|
||||
PangoAttrList *attr;
|
||||
PangoAttrString *pango_string;
|
||||
PangoAttrInt *pango_int;
|
||||
PangoAttrColor *pango_color;
|
||||
PangoAttrLanguage *pango_lang;
|
||||
PangoAttrFloat *pango_float;
|
||||
int index, start_index, end_index;
|
||||
gboolean is_next;
|
||||
glong len;
|
||||
const char *text;
|
||||
char *value;
|
||||
const char *val;
|
||||
|
||||
text = pango_layout_get_text (layout);
|
||||
len = g_utf8_strlen (text, -1);
|
||||
|
||||
/* Grab the attributes of the PangoLayout, if any */
|
||||
attr = pango_layout_get_attributes (layout);
|
||||
|
||||
if (attr == NULL)
|
||||
{
|
||||
*start_offset = 0;
|
||||
*end_offset = len;
|
||||
return;
|
||||
}
|
||||
|
||||
iter = pango_attr_list_get_iterator (attr);
|
||||
/* Get invariant range offsets */
|
||||
/* If offset out of range, set offset in range */
|
||||
if (offset > len)
|
||||
offset = len;
|
||||
else if (offset < 0)
|
||||
offset = 0;
|
||||
|
||||
index = g_utf8_offset_to_pointer (text, offset) - text;
|
||||
pango_attr_iterator_range (iter, &start_index, &end_index);
|
||||
is_next = TRUE;
|
||||
while (is_next)
|
||||
{
|
||||
if (index >= start_index && index < end_index)
|
||||
{
|
||||
*start_offset = g_utf8_pointer_to_offset (text, text + start_index);
|
||||
if (end_index == G_MAXINT) /* Last iterator */
|
||||
end_index = len;
|
||||
|
||||
*end_offset = g_utf8_pointer_to_offset (text, text + end_index);
|
||||
break;
|
||||
}
|
||||
is_next = pango_attr_iterator_next (iter);
|
||||
pango_attr_iterator_range (iter, &start_index, &end_index);
|
||||
}
|
||||
|
||||
/* Get attributes */
|
||||
pango_string = (PangoAttrString *) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
|
||||
if (pango_string != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%s", pango_string->value);
|
||||
g_variant_builder_add (builder, "{ss}", "family-name", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_STYLE);
|
||||
if (pango_int != NULL)
|
||||
g_variant_builder_add (builder, "{ss}", "style", pango_style_to_string (pango_int->value));
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT);
|
||||
if (pango_int != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%i", pango_int->value);
|
||||
g_variant_builder_add (builder, "{ss}", "weight", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT);
|
||||
if (pango_int != NULL)
|
||||
g_variant_builder_add (builder, "{ss}", "variant",
|
||||
pango_variant_to_string (pango_int->value));
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH);
|
||||
if (pango_int != NULL)
|
||||
g_variant_builder_add (builder, "{ss}", "stretch",
|
||||
pango_stretch_to_string (pango_int->value));
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
|
||||
if (pango_int != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%i", pango_int->value / PANGO_SCALE);
|
||||
g_variant_builder_add (builder, "{ss}", "size", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
|
||||
if (pango_int != NULL)
|
||||
g_variant_builder_add (builder, "{ss}", "underline",
|
||||
pango_underline_to_string (pango_int->value));
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH);
|
||||
if (pango_int != NULL)
|
||||
{
|
||||
if (pango_int->value)
|
||||
val = "true";
|
||||
else
|
||||
val = "false";
|
||||
g_variant_builder_add (builder, "{ss}", "strikethrough", val);
|
||||
}
|
||||
|
||||
pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_RISE);
|
||||
if (pango_int != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%i", pango_int->value);
|
||||
g_variant_builder_add (builder, "{ss}", "rise", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_lang = (PangoAttrLanguage *) pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE);
|
||||
if (pango_lang != NULL)
|
||||
{
|
||||
g_variant_builder_add (builder, "{ss}", "language",
|
||||
pango_language_to_string (pango_lang->value));
|
||||
}
|
||||
|
||||
pango_float = (PangoAttrFloat *) pango_attr_iterator_get (iter, PANGO_ATTR_SCALE);
|
||||
if (pango_float != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%g", pango_float->value);
|
||||
g_variant_builder_add (builder, "{ss}", "scale", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_color = (PangoAttrColor *) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
|
||||
if (pango_color != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%u,%u,%u",
|
||||
pango_color->color.red,
|
||||
pango_color->color.green,
|
||||
pango_color->color.blue);
|
||||
g_variant_builder_add (builder, "{ss}", "fg-color", value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
pango_color = (PangoAttrColor *) pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND);
|
||||
if (pango_color != NULL)
|
||||
{
|
||||
value = g_strdup_printf ("%u,%u,%u",
|
||||
pango_color->color.red,
|
||||
pango_color->color.green,
|
||||
pango_color->color.blue);
|
||||
g_variant_builder_add (builder, "{ss}", "bg-color", value);
|
||||
g_free (value);
|
||||
}
|
||||
pango_attr_iterator_destroy (iter);
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_pango_move_chars:
|
||||
* @layout: a `PangoLayout`
|
||||
@@ -1080,75 +820,3 @@ gtk_pango_get_text_at (PangoLayout *layout,
|
||||
|
||||
return g_utf8_substring (text, start, end);
|
||||
}
|
||||
|
||||
char *gtk_pango_get_string_at (PangoLayout *layout,
|
||||
int offset,
|
||||
AtspiTextGranularity granularity,
|
||||
int *start_offset,
|
||||
int *end_offset)
|
||||
{
|
||||
const char *text;
|
||||
int start, end;
|
||||
const PangoLogAttr *attrs;
|
||||
int n_attrs;
|
||||
|
||||
text = pango_layout_get_text (layout);
|
||||
|
||||
if (text[0] == 0)
|
||||
{
|
||||
*start_offset = 0;
|
||||
*end_offset = 0;
|
||||
return g_strdup ("");
|
||||
}
|
||||
|
||||
attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
|
||||
|
||||
start = offset;
|
||||
end = start;
|
||||
|
||||
switch (granularity)
|
||||
{
|
||||
case ATSPI_TEXT_GRANULARITY_CHAR:
|
||||
end = gtk_pango_move_chars (layout, end, 1);
|
||||
break;
|
||||
|
||||
case ATSPI_TEXT_GRANULARITY_WORD:
|
||||
if (!attrs[start].is_word_start)
|
||||
start = gtk_pango_move_words (layout, start, -1);
|
||||
if (gtk_pango_is_inside_word (layout, end))
|
||||
end = gtk_pango_move_words (layout, end, 1);
|
||||
while (!attrs[end].is_word_start && end < n_attrs - 1)
|
||||
end = gtk_pango_move_chars (layout, end, 1);
|
||||
break;
|
||||
|
||||
case ATSPI_TEXT_GRANULARITY_SENTENCE:
|
||||
if (!attrs[start].is_sentence_start)
|
||||
start = gtk_pango_move_sentences (layout, start, -1);
|
||||
if (gtk_pango_is_inside_sentence (layout, end))
|
||||
end = gtk_pango_move_sentences (layout, end, 1);
|
||||
while (!attrs[end].is_sentence_start && end < n_attrs - 1)
|
||||
end = gtk_pango_move_chars (layout, end, 1);
|
||||
break;
|
||||
|
||||
case ATSPI_TEXT_GRANULARITY_LINE:
|
||||
pango_layout_get_line_at (layout, offset, ATSPI_TEXT_BOUNDARY_LINE_START, &start, &end);
|
||||
break;
|
||||
|
||||
case ATSPI_TEXT_GRANULARITY_PARAGRAPH:
|
||||
/* FIXME: In theory, a layout can hold more than one paragraph */
|
||||
start = 0;
|
||||
end = g_utf8_strlen (text, -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
*start_offset = start;
|
||||
*end_offset = end;
|
||||
|
||||
g_assert (start <= end);
|
||||
|
||||
return g_utf8_substring (text, start, end);
|
||||
}
|
||||
|
||||
@@ -19,19 +19,10 @@
|
||||
|
||||
#include <pango/pangocairo.h>
|
||||
#include "gtkatspiprivate.h"
|
||||
#include "gtkpangoprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gtk_pango_get_font_attributes (PangoFontDescription *font,
|
||||
GVariantBuilder *builder);
|
||||
void gtk_pango_get_default_attributes (PangoLayout *layout,
|
||||
GVariantBuilder *builder);
|
||||
void gtk_pango_get_run_attributes (PangoLayout *layout,
|
||||
GVariantBuilder *builder,
|
||||
int offset,
|
||||
int *start_offset,
|
||||
int *end_offset);
|
||||
|
||||
char *gtk_pango_get_text_before (PangoLayout *layout,
|
||||
int offset,
|
||||
AtspiTextBoundaryType boundary_type,
|
||||
@@ -47,10 +38,5 @@ char *gtk_pango_get_text_after (PangoLayout *layout,
|
||||
AtspiTextBoundaryType boundary_type,
|
||||
int *start_offset,
|
||||
int *end_offset);
|
||||
char *gtk_pango_get_string_at (PangoLayout *layout,
|
||||
int offset,
|
||||
AtspiTextGranularity granularity,
|
||||
int *start_offset,
|
||||
int *end_offset);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -418,8 +418,8 @@ gtk_at_spi_socket_embed (GtkAtSpiSocket *self,
|
||||
* usually done through a side channel with the remote side, for
|
||||
* example using sockets, or reading the output of a subprocess.
|
||||
*
|
||||
* The remote accessible object at @object_path must be a must
|
||||
* have an `org.a11y.atspi.Socket` interface with the `Embedded()`
|
||||
* The remote accessible object at @object_path must support
|
||||
* the `org.a11y.atspi.Socket` interface with the `Embedded()`
|
||||
* method.
|
||||
*
|
||||
* This constructor can fail, most notably if the accessibility
|
||||
@@ -463,7 +463,7 @@ gtk_at_spi_socket_get_bus_name (GtkAtSpiSocket *self)
|
||||
* gtk_at_spi_socket_get_object_path:
|
||||
* @self: a #GtkAtSpiSocket
|
||||
*
|
||||
* Retrieves the object path of the remove accessible object that
|
||||
* Retrieves the object path of the remote accessible object that
|
||||
* the socket is connected to.
|
||||
*
|
||||
* Returns: (transfer none): the object path of the socket remote
|
||||
|
||||
+563
-75
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "a11y/atspi/atspi-text.h"
|
||||
|
||||
#include "gtkaccessibletextprivate.h"
|
||||
#include "gtkatcontextprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkeditable.h"
|
||||
@@ -44,6 +45,356 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
static GtkAccessibleTextGranularity
|
||||
atspi_granularity_to_gtk (AtspiTextGranularity granularity)
|
||||
{
|
||||
switch (granularity)
|
||||
{
|
||||
case ATSPI_TEXT_GRANULARITY_CHAR:
|
||||
return GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER;
|
||||
case ATSPI_TEXT_GRANULARITY_WORD:
|
||||
return GTK_ACCESSIBLE_TEXT_GRANULARITY_WORD;
|
||||
case ATSPI_TEXT_GRANULARITY_SENTENCE:
|
||||
return GTK_ACCESSIBLE_TEXT_GRANULARITY_SENTENCE;
|
||||
case ATSPI_TEXT_GRANULARITY_LINE:
|
||||
return GTK_ACCESSIBLE_TEXT_GRANULARITY_LINE;
|
||||
case ATSPI_TEXT_GRANULARITY_PARAGRAPH:
|
||||
return GTK_ACCESSIBLE_TEXT_GRANULARITY_PARAGRAPH;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ GtkAccessibleText */
|
||||
|
||||
static void
|
||||
accessible_text_handle_method (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkATContext *self = user_data;
|
||||
GtkAccessible *accessible = gtk_at_context_get_accessible (self);
|
||||
GtkAccessibleText *accessible_text = GTK_ACCESSIBLE_TEXT (accessible);
|
||||
|
||||
if (g_strcmp0 (method_name, "GetCaretOffset") == 0)
|
||||
{
|
||||
guint offset;
|
||||
|
||||
offset = gtk_accessible_text_get_caret_position (accessible_text);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", (int)offset));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "SetCaretOffset") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetText") == 0)
|
||||
{
|
||||
int start, end;
|
||||
GBytes *contents;
|
||||
|
||||
g_variant_get (parameters, "(ii)", &start, &end);
|
||||
|
||||
contents = gtk_accessible_text_get_contents (accessible_text, start, end < 0 ? G_MAXUINT : end);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", g_bytes_get_data (contents, NULL)));
|
||||
|
||||
g_bytes_unref (contents);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetTextBeforeOffset") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetTextAtOffset") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetTextAfterOffset") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetCharacterAtOffset") == 0)
|
||||
{
|
||||
int offset;
|
||||
gunichar ch = 0;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
GBytes *text = gtk_accessible_text_get_contents (accessible_text, offset, offset + 1);
|
||||
|
||||
if (text != NULL)
|
||||
{
|
||||
const char *str = g_bytes_get_data (text, NULL);
|
||||
if (g_utf8_strlen (str, -1) > 0)
|
||||
ch = g_utf8_get_char (str);
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", ch));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetStringAtOffset") == 0)
|
||||
{
|
||||
unsigned int start, end;
|
||||
int offset;
|
||||
AtspiTextGranularity granularity;
|
||||
GBytes *bytes;
|
||||
|
||||
g_variant_get (parameters, "(iu)", &offset, &granularity);
|
||||
|
||||
bytes = gtk_accessible_text_get_contents_at (accessible_text, offset,
|
||||
atspi_granularity_to_gtk (granularity),
|
||||
&start, &end);
|
||||
|
||||
if (bytes == NULL)
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", "", -1, -1));
|
||||
else
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", g_bytes_get_data (bytes, NULL), start, end));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributes") == 0)
|
||||
{
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
gsize n_attrs = 0;
|
||||
GtkAccessibleTextRange *ranges = NULL;
|
||||
int start, end;
|
||||
char **attr_names = NULL;
|
||||
char **attr_values = NULL;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
gtk_accessible_text_get_attributes (accessible_text,
|
||||
offset,
|
||||
&n_attrs,
|
||||
&ranges,
|
||||
&attr_names,
|
||||
&attr_values);
|
||||
|
||||
start = 0;
|
||||
end = G_MAXINT;
|
||||
|
||||
for (int i = 0; i < n_attrs; i++)
|
||||
{
|
||||
g_variant_builder_add (&builder, "{ss}", attr_names[i], attr_values[i]);
|
||||
start = MAX (start, ranges[i].start);
|
||||
end = MIN (end, start + ranges[i].length);
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
|
||||
g_clear_pointer (&ranges, g_free);
|
||||
g_strfreev (attr_names);
|
||||
g_strfreev (attr_values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
|
||||
{
|
||||
int offset;
|
||||
const char *name;
|
||||
const char *val = "";
|
||||
char **names, **values;
|
||||
GtkAccessibleTextRange *ranges;
|
||||
gsize n_ranges;
|
||||
|
||||
g_variant_get (parameters, "(i&s)", &offset, &name);
|
||||
|
||||
gtk_accessible_text_get_attributes (accessible_text, offset,
|
||||
&n_ranges, &ranges,
|
||||
&names, &values);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (g_strcmp0 (names[i], name) == 0)
|
||||
{
|
||||
val = values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
|
||||
{
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
gboolean include_defaults = FALSE;
|
||||
int offset;
|
||||
gsize n_ranges = 0;
|
||||
GtkAccessibleTextRange *ranges = NULL;
|
||||
int start, end;
|
||||
char **attr_names = NULL;
|
||||
char **attr_values = NULL;
|
||||
gboolean res;
|
||||
|
||||
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
|
||||
|
||||
res = gtk_accessible_text_get_attributes_run (accessible_text,
|
||||
offset,
|
||||
include_defaults,
|
||||
&n_ranges,
|
||||
&ranges,
|
||||
&attr_names,
|
||||
&attr_values);
|
||||
if (!res)
|
||||
{
|
||||
/* No attributes */
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, 0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; attr_names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", attr_names[i], attr_values[i]);
|
||||
|
||||
start = 0;
|
||||
end = G_MAXINT;
|
||||
for (unsigned i = 0; i < n_ranges; i++)
|
||||
{
|
||||
start = MAX (start, ranges[i].start);
|
||||
end = MIN (end, start + ranges[i].length);
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
|
||||
g_clear_pointer (&ranges, g_free);
|
||||
g_strfreev (attr_names);
|
||||
g_strfreev (attr_values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 ||
|
||||
g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0)
|
||||
{
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
char **names, **values;
|
||||
|
||||
gtk_accessible_text_get_default_attributes (accessible_text, &names, &values);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetNSelections") == 0)
|
||||
{
|
||||
gsize n_ranges;
|
||||
GtkAccessibleTextRange *ranges = NULL;
|
||||
|
||||
if (!gtk_accessible_text_get_selection (accessible_text, &n_ranges, &ranges))
|
||||
n_ranges = 0;
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", (int)n_ranges));
|
||||
|
||||
g_clear_pointer (&ranges, g_free);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetSelection") == 0)
|
||||
{
|
||||
int num;
|
||||
gsize n_ranges;
|
||||
GtkAccessibleTextRange *ranges = NULL;
|
||||
|
||||
g_variant_get (parameters, "(i)", &num);
|
||||
|
||||
if (!gtk_accessible_text_get_selection (accessible_text, &n_ranges, &ranges))
|
||||
n_ranges = 0;
|
||||
|
||||
if (num < 0 || num >= n_ranges)
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Not a valid selection: %d", num);
|
||||
else
|
||||
{
|
||||
int start = ranges[num].start;
|
||||
int end = start + ranges[num].length;
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ii)", start, end));
|
||||
}
|
||||
|
||||
g_clear_pointer (&ranges, g_free);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "AddSelection") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "RemoveSelection") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "SetSelection") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetCharacterExtents") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetRangeExtents") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetBoundedRanges") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "ScrollSubstringTo") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "ScrollSubstringToPoint") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
|
||||
}
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
accessible_text_get_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkATContext *self = user_data;
|
||||
GtkAccessible *accessible = gtk_at_context_get_accessible (self);
|
||||
GtkAccessibleText *accessible_text = GTK_ACCESSIBLE_TEXT (accessible);
|
||||
|
||||
if (g_strcmp0 (property_name, "CharacterCount") == 0)
|
||||
{
|
||||
GBytes *contents;
|
||||
const char *str;
|
||||
gsize len;
|
||||
|
||||
contents = gtk_accessible_text_get_contents (accessible_text, 0, G_MAXUINT);
|
||||
str = g_bytes_get_data (contents, NULL);
|
||||
len = g_utf8_strlen (str, -1);
|
||||
g_bytes_unref (contents);
|
||||
|
||||
return g_variant_new_int32 ((int) len);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "CaretOffset") == 0)
|
||||
{
|
||||
guint offset;
|
||||
|
||||
offset = gtk_accessible_text_get_caret_position (accessible_text);
|
||||
|
||||
return g_variant_new_int32 ((int) offset);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusInterfaceVTable accessible_text_vtable = {
|
||||
accessible_text_handle_method,
|
||||
accessible_text_get_property,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
/* {{{ GtkLabel */
|
||||
|
||||
static void
|
||||
@@ -175,11 +526,13 @@ label_handle_method (GDBusConnection *connection,
|
||||
int offset;
|
||||
AtspiTextGranularity granularity;
|
||||
char *string;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
|
||||
g_variant_get (parameters, "(iu)", &offset, &granularity);
|
||||
|
||||
string = gtk_pango_get_string_at (layout, offset, granularity, &start, &end);
|
||||
string = gtk_pango_get_string_at (layout, offset,
|
||||
atspi_granularity_to_gtk (granularity),
|
||||
&start, &end);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
|
||||
g_free (string);
|
||||
@@ -189,34 +542,47 @@ label_handle_method (GDBusConnection *connection,
|
||||
PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
|
||||
{
|
||||
PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
const char *name;
|
||||
int start, end;
|
||||
GVariant *attrs;
|
||||
const char *val;
|
||||
unsigned int start, end;
|
||||
const char *val = "";
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i&s)", &offset, &name);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
attrs = g_variant_builder_end (&builder);
|
||||
if (!g_variant_lookup (attrs, name, "&s", &val))
|
||||
val = "";
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (g_strcmp0 (names[i], name) == 0)
|
||||
{
|
||||
val = values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
|
||||
g_variant_unref (attrs);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
|
||||
{
|
||||
@@ -224,14 +590,29 @@ label_handle_method (GDBusConnection *connection,
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
gboolean include_defaults;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
|
||||
|
||||
if (include_defaults)
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
{
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
@@ -240,8 +621,15 @@ label_handle_method (GDBusConnection *connection,
|
||||
{
|
||||
PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
char **names, **values;
|
||||
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
|
||||
}
|
||||
@@ -528,11 +916,13 @@ inscription_handle_method (GDBusConnection *connection,
|
||||
int offset;
|
||||
AtspiTextGranularity granularity;
|
||||
char *string;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
|
||||
g_variant_get (parameters, "(iu)", &offset, &granularity);
|
||||
|
||||
string = gtk_pango_get_string_at (layout, offset, granularity, &start, &end);
|
||||
string = gtk_pango_get_string_at (layout, offset,
|
||||
atspi_granularity_to_gtk (granularity),
|
||||
&start, &end);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
|
||||
g_free (string);
|
||||
@@ -542,34 +932,47 @@ inscription_handle_method (GDBusConnection *connection,
|
||||
PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
|
||||
{
|
||||
PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
const char *name;
|
||||
int start, end;
|
||||
GVariant *attrs;
|
||||
const char *val;
|
||||
unsigned int start, end;
|
||||
const char *val = "";
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i&s)", &offset, &name);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
attrs = g_variant_builder_end (&builder);
|
||||
if (!g_variant_lookup (attrs, name, "&s", &val))
|
||||
val = "";
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (g_strcmp0 (names[i], name) == 0)
|
||||
{
|
||||
val = values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
|
||||
g_variant_unref (attrs);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
|
||||
{
|
||||
@@ -577,14 +980,29 @@ inscription_handle_method (GDBusConnection *connection,
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
gboolean include_defaults;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
|
||||
|
||||
if (include_defaults)
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
{
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
@@ -593,8 +1011,15 @@ inscription_handle_method (GDBusConnection *connection,
|
||||
{
|
||||
PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
char **names, **values;
|
||||
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
|
||||
}
|
||||
@@ -685,15 +1110,20 @@ gtk_editable_get_text_widget (GtkWidget *widget)
|
||||
{
|
||||
if (GTK_IS_EDITABLE (widget))
|
||||
{
|
||||
GtkEditable *delegate;
|
||||
GtkEditable *editable;
|
||||
guint redirects = 0;
|
||||
|
||||
delegate = gtk_editable_get_delegate (GTK_EDITABLE (widget));
|
||||
editable = GTK_EDITABLE (widget);
|
||||
|
||||
if (GTK_IS_TEXT (delegate))
|
||||
return GTK_TEXT (delegate);
|
||||
do {
|
||||
if (GTK_IS_TEXT (editable))
|
||||
return GTK_TEXT (editable);
|
||||
|
||||
if (GTK_IS_TEXT (widget))
|
||||
return GTK_TEXT (widget);
|
||||
if (++redirects >= 6)
|
||||
g_assert_not_reached ();
|
||||
|
||||
editable = gtk_editable_get_delegate (editable);
|
||||
} while (editable != NULL);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -827,11 +1257,13 @@ editable_handle_method (GDBusConnection *connection,
|
||||
int offset;
|
||||
AtspiTextGranularity granularity;
|
||||
char *string;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
|
||||
g_variant_get (parameters, "(iu)", &offset, &granularity);
|
||||
|
||||
string = gtk_pango_get_string_at (layout, offset, granularity, &start, &end);
|
||||
string = gtk_pango_get_string_at (layout, offset,
|
||||
atspi_granularity_to_gtk (granularity),
|
||||
&start, &end);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
|
||||
g_free (string);
|
||||
@@ -841,33 +1273,47 @@ editable_handle_method (GDBusConnection *connection,
|
||||
PangoLayout *layout = gtk_text_get_layout (text_widget);
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
|
||||
{
|
||||
PangoLayout *layout = gtk_text_get_layout (text_widget);
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
const char *name;
|
||||
int start, end;
|
||||
GVariant *attrs;
|
||||
const char *val;
|
||||
unsigned int start, end;
|
||||
const char *val = "";
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(i&s)", &offset, &name);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
attrs = g_variant_builder_end (&builder);
|
||||
if (!g_variant_lookup (attrs, name, "&s", &val))
|
||||
val = "";
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (g_strcmp0 (names[i], name) == 0)
|
||||
{
|
||||
val = values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
|
||||
g_variant_unref (attrs);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
|
||||
{
|
||||
@@ -875,14 +1321,29 @@ editable_handle_method (GDBusConnection *connection,
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
gboolean include_defaults;
|
||||
int start, end;
|
||||
unsigned int start, end;
|
||||
char **names, **values;
|
||||
|
||||
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
|
||||
|
||||
if (include_defaults)
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
{
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
}
|
||||
|
||||
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
}
|
||||
@@ -891,8 +1352,15 @@ editable_handle_method (GDBusConnection *connection,
|
||||
{
|
||||
PangoLayout *layout = gtk_text_get_layout (text_widget);
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
char **names, **values;
|
||||
|
||||
gtk_pango_get_default_attributes (layout, &builder);
|
||||
gtk_pango_get_default_attributes (layout, &names, &values);
|
||||
|
||||
for (unsigned i = 0; names[i] != NULL; i++)
|
||||
g_variant_builder_add (&builder, "{ss}", names[i], values[i]);
|
||||
|
||||
g_strfreev (names);
|
||||
g_strfreev (values);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
|
||||
}
|
||||
@@ -1191,70 +1659,88 @@ text_view_handle_method (GDBusConnection *connection,
|
||||
|
||||
g_variant_get (parameters, "(iu)", &offset, &granularity);
|
||||
|
||||
string = gtk_text_view_get_string_at (GTK_TEXT_VIEW (widget), offset, granularity, &start, &end);
|
||||
string = gtk_text_view_get_string_at (GTK_TEXT_VIEW (widget), offset,
|
||||
granularity,
|
||||
&start, &end);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
|
||||
g_free (string);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributes") == 0)
|
||||
{
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
GHashTable *attrs;
|
||||
GHashTableIter iter;
|
||||
int offset;
|
||||
int start, end;
|
||||
gpointer key, value;
|
||||
|
||||
g_variant_get (parameters, "(i)", &offset);
|
||||
|
||||
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
|
||||
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, FALSE, &start, &end);
|
||||
g_hash_table_iter_init (&iter, attrs);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
|
||||
g_hash_table_unref (attrs);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
|
||||
{
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
const char *name;
|
||||
int start, end;
|
||||
GVariant *attrs;
|
||||
const char *val;
|
||||
GHashTable *attrs;
|
||||
|
||||
g_variant_get (parameters, "(i&s)", &offset, &name);
|
||||
|
||||
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
|
||||
|
||||
attrs = g_variant_builder_end (&builder);
|
||||
if (!g_variant_lookup (attrs, name, "&s", &val))
|
||||
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, FALSE, &start, &end);
|
||||
val = g_hash_table_lookup (attrs, name);
|
||||
if (val == NULL)
|
||||
val = "";
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
|
||||
g_variant_unref (attrs);
|
||||
g_hash_table_unref (attrs);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
|
||||
{
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
int offset;
|
||||
gboolean include_defaults;
|
||||
int start, end;
|
||||
GHashTable *attrs;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
|
||||
|
||||
if (include_defaults)
|
||||
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), &builder);
|
||||
|
||||
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
|
||||
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, include_defaults, &start, &end);
|
||||
g_hash_table_iter_init (&iter, attrs);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
|
||||
|
||||
g_hash_table_unref (attrs);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 ||
|
||||
g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0)
|
||||
{
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
|
||||
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), &builder);
|
||||
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), attrs);
|
||||
g_hash_table_iter_init (&iter, attrs);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
|
||||
|
||||
g_hash_table_unref (attrs);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GetNSelections") == 0)
|
||||
{
|
||||
@@ -1573,7 +2059,9 @@ static const GDBusInterfaceVTable text_view_vtable = {
|
||||
const GDBusInterfaceVTable *
|
||||
gtk_atspi_get_text_vtable (GtkAccessible *accessible)
|
||||
{
|
||||
if (GTK_IS_LABEL (accessible))
|
||||
if (GTK_IS_ACCESSIBLE_TEXT (accessible))
|
||||
return &accessible_text_vtable;
|
||||
else if (GTK_IS_LABEL (accessible))
|
||||
return &label_vtable;
|
||||
else if (GTK_IS_INSCRIPTION (accessible))
|
||||
return &inscription_vtable;
|
||||
|
||||
@@ -23,91 +23,6 @@
|
||||
#include "gtktextviewprivate.h"
|
||||
#include "gtkpangoprivate.h"
|
||||
|
||||
void
|
||||
gtk_text_view_add_default_attributes (GtkTextView *view,
|
||||
GVariantBuilder *builder)
|
||||
{
|
||||
GtkTextAttributes *text_attrs;
|
||||
PangoFontDescription *font;
|
||||
char *value;
|
||||
|
||||
text_attrs = gtk_text_view_get_default_attributes (view);
|
||||
|
||||
font = text_attrs->font;
|
||||
|
||||
if (font)
|
||||
gtk_pango_get_font_attributes (font, builder);
|
||||
|
||||
g_variant_builder_add (builder, "{ss}", "justification",
|
||||
gtk_justification_to_string (text_attrs->justification));
|
||||
g_variant_builder_add (builder, "{ss}", "direction",
|
||||
gtk_text_direction_to_string (text_attrs->direction));
|
||||
g_variant_builder_add (builder, "{ss}", "wrap-mode",
|
||||
gtk_wrap_mode_to_string (text_attrs->wrap_mode));
|
||||
g_variant_builder_add (builder, "{ss}", "editable",
|
||||
text_attrs->editable ? "true" : "false");
|
||||
g_variant_builder_add (builder, "{ss}", "invisible",
|
||||
text_attrs->invisible ? "true" : "false");
|
||||
g_variant_builder_add (builder, "{ss}", "bg-full-height",
|
||||
text_attrs->bg_full_height ? "true" : "false");
|
||||
g_variant_builder_add (builder, "{ss}", "strikethrough",
|
||||
text_attrs->appearance.strikethrough ? "true" : "false");
|
||||
g_variant_builder_add (builder, "{ss}", "underline",
|
||||
pango_underline_to_string (text_attrs->appearance.underline));
|
||||
|
||||
value = g_strdup_printf ("%u,%u,%u",
|
||||
(guint)(text_attrs->appearance.bg_rgba->red * 65535),
|
||||
(guint)(text_attrs->appearance.bg_rgba->green * 65535),
|
||||
(guint)(text_attrs->appearance.bg_rgba->blue * 65535));
|
||||
g_variant_builder_add (builder, "{ss}", "bg-color", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%u,%u,%u",
|
||||
(guint)(text_attrs->appearance.fg_rgba->red * 65535),
|
||||
(guint)(text_attrs->appearance.fg_rgba->green * 65535),
|
||||
(guint)(text_attrs->appearance.fg_rgba->blue * 65535));
|
||||
g_variant_builder_add (builder, "{ss}", "bg-color", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%g", text_attrs->font_scale);
|
||||
g_variant_builder_add (builder, "{ss}", "scale", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup ((gchar *)(text_attrs->language));
|
||||
g_variant_builder_add (builder, "{ss}", "language", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->appearance.rise);
|
||||
g_variant_builder_add (builder, "{ss}", "rise", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-inside-wrap", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-below-lines", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
|
||||
g_variant_builder_add (builder, "{ss}", "pixels-above-lines", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->indent);
|
||||
g_variant_builder_add (builder, "{ss}", "indent", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->left_margin);
|
||||
g_variant_builder_add (builder, "{ss}", "left-margin", value);
|
||||
g_free (value);
|
||||
|
||||
value = g_strdup_printf ("%i", text_attrs->right_margin);
|
||||
g_variant_builder_add (builder, "{ss}", "right-margin", value);
|
||||
g_free (value);
|
||||
|
||||
gtk_text_attributes_unref (text_attrs);
|
||||
}
|
||||
|
||||
char *
|
||||
gtk_text_view_get_text_before (GtkTextView *view,
|
||||
int offset,
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gtk_text_view_add_default_attributes (GtkTextView *view,
|
||||
GVariantBuilder *builder);
|
||||
|
||||
char *gtk_text_view_get_text_before (GtkTextView *view,
|
||||
int offset,
|
||||
AtspiTextBoundaryType boundary_type,
|
||||
|
||||
@@ -291,6 +291,9 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
|
||||
case GTK_ACCESSIBLE_ROLE_TOGGLE_BUTTON:
|
||||
return ATSPI_ROLE_TOGGLE_BUTTON;
|
||||
|
||||
case GTK_ACCESSIBLE_ROLE_TERMINAL:
|
||||
return ATSPI_ROLE_TERMINAL;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -370,6 +370,7 @@ gtk_cell_renderer_pixbuf_set_property (GObject *object,
|
||||
else
|
||||
texture = NULL;
|
||||
take_image_definition (cellpixbuf, gtk_image_definition_new_paintable (GDK_PAINTABLE (texture)));
|
||||
g_clear_object (&texture);
|
||||
break;
|
||||
case PROP_PIXBUF_EXPANDER_OPEN:
|
||||
g_clear_object (&priv->pixbuf_expander_open);
|
||||
|
||||
@@ -852,7 +852,8 @@ gtk_tree_path_prepend_index (GtkTreePath *path,
|
||||
int *indices;
|
||||
path->alloc = MAX (path->alloc * 2, 1);
|
||||
indices = g_new (int, path->alloc);
|
||||
memcpy (indices + 1, path->indices, path->depth * sizeof (int));
|
||||
if (path->depth > 0)
|
||||
memcpy (indices + 1, path->indices, path->depth * sizeof (int));
|
||||
g_free (path->indices);
|
||||
path->indices = indices;
|
||||
}
|
||||
@@ -972,7 +973,8 @@ gtk_tree_path_copy (const GtkTreePath *path)
|
||||
retval->depth = path->depth;
|
||||
retval->alloc = retval->depth;
|
||||
retval->indices = g_new (int, path->alloc);
|
||||
memcpy (retval->indices, path->indices, path->depth * sizeof (int));
|
||||
if (path->depth > 0)
|
||||
memcpy (retval->indices, path->indices, path->depth * sizeof (int));
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
+115
-54
@@ -22,13 +22,20 @@
|
||||
* language-specific data.raw.json as input
|
||||
*/
|
||||
|
||||
/* The format of the generated data is: a(ausasu).
|
||||
/* The format of the generated data is: a(aussasasu).
|
||||
* Each member of the array has the following fields:
|
||||
* au - sequence of unicode codepoints. If the
|
||||
* sequence contains a 0, it marks the point
|
||||
* where skin tone modifiers should be inserted
|
||||
* s - name, e.g. "man worker"
|
||||
* as - keywords, e.g. "man", "worker"
|
||||
* au - sequence of unicode codepoints, including the emoji presentation
|
||||
* selector (FE0F) where necessary. skin tone variations are represented
|
||||
* with either the first tone code point (1F3FB) or 0. the choice indicates
|
||||
* the handling of the generic sequence (i.e., no tone), which may have a
|
||||
* default text presentation and thus require the emoji presentation
|
||||
* selector (unlike sequences with a tone, which are always presented as
|
||||
* emojis). 0 indicates the text case, that is, replace this code point
|
||||
* with FE0F, while 1F3FB indicates this code point should be omitted.
|
||||
* s - name in english, e.g. "man worker"
|
||||
* s - name in locale
|
||||
* as - keywords in english, e.g. "man", "worker"
|
||||
* as - keywords in locale
|
||||
* u - the group that this item belongs to:
|
||||
* 0: smileys-emotion
|
||||
* 1: people-body
|
||||
@@ -46,7 +53,8 @@
|
||||
|
||||
gboolean
|
||||
parse_code (GVariantBuilder *b,
|
||||
const char *code)
|
||||
const char *code,
|
||||
gboolean needs_presentation_selector)
|
||||
{
|
||||
g_auto(GStrv) strv = NULL;
|
||||
int j;
|
||||
@@ -64,11 +72,31 @@ parse_code (GVariantBuilder *b,
|
||||
return FALSE;
|
||||
}
|
||||
if (0x1f3fb <= u && u <= 0x1f3ff)
|
||||
g_variant_builder_add (b, "u", 0);
|
||||
{
|
||||
if (needs_presentation_selector)
|
||||
{
|
||||
if (strv[j+1])
|
||||
{
|
||||
g_error ("unexpected inner skin tone in default-text generic sequence: %s\n", code);
|
||||
return FALSE;
|
||||
}
|
||||
g_variant_builder_add (b, "u", 0);
|
||||
needs_presentation_selector = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_variant_builder_add (b, "u", 0x1f3fb);
|
||||
}
|
||||
}
|
||||
else
|
||||
g_variant_builder_add (b, "u", u);
|
||||
{
|
||||
g_variant_builder_add (b, "u", u);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_presentation_selector)
|
||||
g_variant_builder_add (b, "u", 0xfe0f);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -77,90 +105,123 @@ main (int argc, char *argv[])
|
||||
{
|
||||
JsonParser *parser;
|
||||
JsonNode *root;
|
||||
JsonParser *parser_en;
|
||||
JsonNode *root_en;
|
||||
JsonObject *ro;
|
||||
JsonArray *array;
|
||||
JsonArray *array_en;
|
||||
JsonNode *node;
|
||||
const char *unicode;
|
||||
JsonObjectIter iter;
|
||||
GError *error = NULL;
|
||||
guint length, i;
|
||||
guint length, length_en, i;
|
||||
GVariantBuilder builder;
|
||||
GVariant *v;
|
||||
GString *s;
|
||||
GHashTable *names;
|
||||
GString *name_key;
|
||||
|
||||
if (argc != 3)
|
||||
if (argc != 4) //0 -> compiled file, 1 -> en/data.raw.json, 2 -> de/data.raw.json, 3 -> de.data
|
||||
{
|
||||
g_print ("Usage: emoji-convert INPUT OUTPUT\n");
|
||||
g_print ("Usage: emoji-convert INPUT1 INPUT2 OUTPUT\nINPUT1 should be raw json data for English\nINPUT2 should be raw json data for the locale\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
parser = json_parser_new ();
|
||||
parser_en = json_parser_new ();
|
||||
|
||||
if (!json_parser_load_from_file (parser, argv[1], &error))
|
||||
if (!json_parser_load_from_file (parser_en, argv[1], &error))
|
||||
{
|
||||
g_error ("%s", error->message);
|
||||
return 1;
|
||||
}
|
||||
if (!json_parser_load_from_file (parser, argv[2], &error))
|
||||
{
|
||||
g_error ("%s", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
root = json_parser_get_root (parser);
|
||||
array = json_node_get_array (root);
|
||||
length = json_array_get_length (array);
|
||||
root_en = json_parser_get_root (parser_en);
|
||||
array_en = json_node_get_array (root_en);
|
||||
length_en = json_array_get_length (array_en);
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ausasu)"));
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(aussasasu)"));
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
JsonObject *obj = json_array_get_object_element (array, i);
|
||||
GVariantBuilder b1;
|
||||
GVariantBuilder b2;
|
||||
guint group;
|
||||
const char *name;
|
||||
char *code;
|
||||
{
|
||||
JsonObject *obj = json_array_get_object_element (array, i);
|
||||
JsonObject *obj_en = json_array_get_object_element (array_en, i);
|
||||
GVariantBuilder b1;
|
||||
GVariantBuilder b2;
|
||||
GVariantBuilder b3;
|
||||
guint group;
|
||||
const char *name;
|
||||
const char *name_en;
|
||||
char *code;
|
||||
const char *text;
|
||||
gboolean needs_presentation_selector;
|
||||
|
||||
if (!json_object_has_member (obj, "group"))
|
||||
continue;
|
||||
if (!json_object_has_member (obj, "group"))
|
||||
continue;
|
||||
if (!json_object_has_member (obj_en, "group"))
|
||||
continue;
|
||||
|
||||
group = json_object_get_int_member (obj, "group");
|
||||
name = json_object_get_string_member (obj, "label");
|
||||
group = json_object_get_int_member (obj, "group");
|
||||
name = json_object_get_string_member (obj, "label");
|
||||
name_en = json_object_get_string_member (obj_en, "label");
|
||||
|
||||
if (json_object_has_member (obj, "skins"))
|
||||
if (g_str_has_suffix (name_en, "skin tone"))
|
||||
continue;
|
||||
|
||||
if (json_object_has_member (obj, "skins") && json_object_has_member (obj_en, "skins"))
|
||||
{
|
||||
JsonArray *a2 = json_object_get_array_member (obj, "skins");
|
||||
JsonNode *n2 = json_array_get_element (a2, 0);
|
||||
JsonObject *o2 = json_node_get_object (n2);
|
||||
code = g_strdup (json_object_get_string_member (o2, "hexcode"));
|
||||
}
|
||||
else
|
||||
{
|
||||
code = g_strdup (json_object_get_string_member (obj, "hexcode"));
|
||||
}
|
||||
|
||||
text = json_object_get_string_member (obj, "text");
|
||||
needs_presentation_selector = *text != '\0' && json_object_get_int_member (obj, "type") == 0;
|
||||
|
||||
g_variant_builder_init (&b1, G_VARIANT_TYPE ("au"));
|
||||
if (!parse_code (&b1, code, needs_presentation_selector))
|
||||
return 1;
|
||||
|
||||
g_variant_builder_init (&b2, G_VARIANT_TYPE ("as"));
|
||||
if (json_object_has_member (obj_en, "tags"))
|
||||
{
|
||||
JsonArray *tags_en = json_object_get_array_member (obj_en, "tags");
|
||||
for (int j = 0; j < json_array_get_length (tags_en); j++)
|
||||
{
|
||||
JsonArray *a2 = json_object_get_array_member (obj, "skins");
|
||||
JsonNode *n2 = json_array_get_element (a2, 0);
|
||||
JsonObject *o2 = json_node_get_object (n2);
|
||||
code = g_strdup (json_object_get_string_member (o2, "hexcode"));
|
||||
g_variant_builder_add (&b2, "s", json_array_get_string_element (tags_en, j));
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
g_variant_builder_init (&b3, G_VARIANT_TYPE ("as"));
|
||||
if (json_object_has_member (obj, "tags"))
|
||||
{
|
||||
JsonArray *tags = json_object_get_array_member (obj, "tags");
|
||||
for (int j = 0; j < json_array_get_length (tags); j++)
|
||||
{
|
||||
code = g_strdup (json_object_get_string_member (obj, "hexcode"));
|
||||
g_variant_builder_add (&b3, "s", json_array_get_string_element (tags, j));
|
||||
}
|
||||
|
||||
g_variant_builder_init (&b1, G_VARIANT_TYPE ("au"));
|
||||
|
||||
if (!parse_code (&b1, code))
|
||||
return 1;
|
||||
|
||||
g_variant_builder_init (&b2, G_VARIANT_TYPE ("as"));
|
||||
if (json_object_has_member (obj, "tags"))
|
||||
{
|
||||
JsonArray *tags = json_object_get_array_member (obj, "tags");
|
||||
for (int j = 0; j < json_array_get_length (tags); j++)
|
||||
g_variant_builder_add (&b2, "s", json_array_get_string_element (tags, j));
|
||||
}
|
||||
|
||||
g_variant_builder_add (&builder, "(ausasu)", &b1, name, &b2, group);
|
||||
}
|
||||
|
||||
}
|
||||
g_variant_builder_add (&builder, "(aussasasu)", &b1, name_en, name, &b2, &b3, group);
|
||||
}
|
||||
v = g_variant_builder_end (&builder);
|
||||
if (g_str_has_suffix (argv[2], ".json"))
|
||||
if (g_str_has_suffix (argv[3], ".json"))
|
||||
{
|
||||
JsonNode *node;
|
||||
char *out;
|
||||
|
||||
node = json_gvariant_serialize (v);
|
||||
out = json_to_string (node, TRUE);
|
||||
if (!g_file_set_contents (argv[2], out, -1, &error))
|
||||
if (!g_file_set_contents (argv[3], out, -1, &error))
|
||||
{
|
||||
g_error ("%s", error->message);
|
||||
return 1;
|
||||
@@ -171,7 +232,7 @@ main (int argc, char *argv[])
|
||||
GBytes *bytes;
|
||||
|
||||
bytes = g_variant_get_data_as_bytes (v);
|
||||
if (!g_file_set_contents (argv[2], g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &error))
|
||||
if (!g_file_set_contents (argv[3], g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &error))
|
||||
{
|
||||
g_error ("%s", error->message);
|
||||
return 1;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -34,6 +34,7 @@
|
||||
#include <gtk/gtkaccelgroup.h>
|
||||
#include <gtk/gtkaccessible.h>
|
||||
#include <gtk/gtkaccessiblerange.h>
|
||||
#include <gtk/gtkaccessibletext.h>
|
||||
#include <gtk/gtkactionable.h>
|
||||
#include <gtk/gtkactionbar.h>
|
||||
#include <gtk/gtkadjustment.h>
|
||||
|
||||
@@ -871,6 +871,7 @@ static const char *role_names[] = {
|
||||
[GTK_ACCESSIBLE_ROLE_BLOCK_QUOTE] = NC_("accessibility", "block quote"),
|
||||
[GTK_ACCESSIBLE_ROLE_ARTICLE] = NC_("accessibility", "article"),
|
||||
[GTK_ACCESSIBLE_ROLE_COMMENT] = NC_("accessibility", "comment"),
|
||||
[GTK_ACCESSIBLE_ROLE_TERMINAL] = NC_("accessibility", "terminal"),
|
||||
};
|
||||
|
||||
/*< private >
|
||||
@@ -989,6 +990,7 @@ static struct {
|
||||
{ GTK_ACCESSIBLE_ROLE_DIALOG, GTK_ACCESSIBLE_ROLE_ALERT_DIALOG },
|
||||
{ GTK_ACCESSIBLE_ROLE_DOCUMENT, GTK_ACCESSIBLE_ROLE_ARTICLE },
|
||||
{ GTK_ACCESSIBLE_ROLE_ARTICLE, GTK_ACCESSIBLE_ROLE_COMMENT },
|
||||
{ GTK_ACCESSIBLE_ROLE_TERMINAL, GTK_ACCESSIBLE_ROLE_WIDGET },
|
||||
};
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
/* gtkaccessibletext.c: Interface for accessible text objects
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2023 Emmanuele Bassi
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkaccessibletextprivate.h"
|
||||
|
||||
#include "gtkatcontextprivate.h"
|
||||
|
||||
G_DEFINE_INTERFACE (GtkAccessibleText, gtk_accessible_text, GTK_TYPE_ACCESSIBLE)
|
||||
|
||||
static GBytes *
|
||||
gtk_accessible_text_default_get_contents (GtkAccessibleText *self,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
gtk_accessible_text_default_get_contents_at (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
GtkAccessibleTextGranularity granularity,
|
||||
unsigned int *start,
|
||||
unsigned int *end)
|
||||
{
|
||||
if (start != NULL)
|
||||
*start = 0;
|
||||
if (end != NULL)
|
||||
*end = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
gtk_accessible_text_default_get_caret_position (GtkAccessibleText *self)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_accessible_text_default_get_selection (GtkAccessibleText *self,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_accessible_text_default_get_attributes (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values)
|
||||
{
|
||||
*attribute_names = NULL;
|
||||
*attribute_values = NULL;
|
||||
*n_ranges = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_accessible_text_default_get_default_attributes (GtkAccessibleText *self,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values)
|
||||
{
|
||||
*attribute_names = NULL;
|
||||
*attribute_values = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_accessible_text_default_init (GtkAccessibleTextInterface *iface)
|
||||
{
|
||||
iface->get_contents = gtk_accessible_text_default_get_contents;
|
||||
iface->get_contents_at = gtk_accessible_text_default_get_contents_at;
|
||||
iface->get_caret_position = gtk_accessible_text_default_get_caret_position;
|
||||
iface->get_selection = gtk_accessible_text_default_get_selection;
|
||||
iface->get_attributes = gtk_accessible_text_default_get_attributes;
|
||||
iface->get_default_attributes = gtk_accessible_text_default_get_default_attributes;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
nul_terminate_contents (GBytes *bytes)
|
||||
{
|
||||
const char *data;
|
||||
gsize size;
|
||||
|
||||
data = g_bytes_get_data (bytes, &size);
|
||||
if (size == 0 || (size > 0 && data[size - 1] != '\0'))
|
||||
{
|
||||
guchar *copy;
|
||||
|
||||
copy = g_new (guchar, size + 1);
|
||||
if (size > 0)
|
||||
memcpy (copy, data, size);
|
||||
copy[size] = '\0';
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
bytes = g_bytes_new_take (copy, size + 1);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_contents:
|
||||
* @self: the accessible object
|
||||
* @start: the beginning of the range, in characters
|
||||
* @end: the end of the range, in characters
|
||||
*
|
||||
* Retrieve the current contents of the accessible object within
|
||||
* the given range.
|
||||
*
|
||||
* If @end is `G_MAXUINT`, the end of the range is the full content of the
|
||||
* accessible object.
|
||||
*
|
||||
* Returns: (transfer full): the requested slice of the contents of the
|
||||
* accessible object, as NUL-terminated UTF-8
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GBytes *
|
||||
gtk_accessible_text_get_contents (GtkAccessibleText *self,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
GBytes *bytes;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), NULL);
|
||||
g_return_val_if_fail (end >= start, NULL);
|
||||
|
||||
bytes = GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_contents (self, start, end);
|
||||
|
||||
return nul_terminate_contents (bytes);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_contents_at:
|
||||
* @self: the accessible object
|
||||
* @offset: the offset of the text to retrieve
|
||||
* @granularity: specify the boundaries of the text
|
||||
* @start: (out): the starting offset of the contents, in characters
|
||||
* @end: (out): the ending offset of the contents, in characters
|
||||
*
|
||||
* Retrieve the current contents of the accessible object at the given
|
||||
* offset.
|
||||
*
|
||||
* Using the @granularity enumeration allows to adjust the offset so that
|
||||
* this function can return the beginning of the word, line, or sentence;
|
||||
* the initial and final boundaries are stored in @start and @end.
|
||||
*
|
||||
* Returns: (transfer full): the requested slice of the contents of the
|
||||
* accessible object, as NUL-terminated UTF-8 buffer
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GBytes *
|
||||
gtk_accessible_text_get_contents_at (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
GtkAccessibleTextGranularity granularity,
|
||||
unsigned int *start,
|
||||
unsigned int *end)
|
||||
{
|
||||
static const char empty[] = {0};
|
||||
GBytes *bytes;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), NULL);
|
||||
|
||||
bytes = GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_contents_at (self, offset, granularity, start, end);
|
||||
|
||||
if (bytes == NULL)
|
||||
return g_bytes_new_static (empty, sizeof empty);
|
||||
|
||||
return nul_terminate_contents (bytes);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_caret_position:
|
||||
* @self: the accessible object
|
||||
*
|
||||
* Retrieves the position of the caret inside the accessible object.
|
||||
*
|
||||
* If the accessible has no caret, 0 is returned.
|
||||
*
|
||||
* Returns: the position of the caret, in characters
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gtk_accessible_text_get_caret_position (GtkAccessibleText *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), 0);
|
||||
|
||||
return GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_caret_position (self);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_selection:
|
||||
* @self: the accessible object
|
||||
* @n_ranges: (out): the number of selection ranges
|
||||
* @ranges: (optional) (out) (array length=n_ranges): the selection ranges
|
||||
*
|
||||
* Retrieves the selection ranges in the accessible object.
|
||||
*
|
||||
* If this function returns true, `n_ranges` will be set to a value
|
||||
* greater than or equal to one, and @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange].
|
||||
*
|
||||
* Returns: true if there's at least one selected range inside the
|
||||
* accessible object, and false otherwise
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gtk_accessible_text_get_selection (GtkAccessibleText *self,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
|
||||
|
||||
return GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_selection (self, n_ranges, ranges);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_attributes:
|
||||
* @self: the accessible object
|
||||
* @offset: the offset, in characters
|
||||
* @n_ranges: (out): the number of attributes
|
||||
* @ranges: (out) (array length=n_attributes) (optional): the ranges of the attributes
|
||||
* inside the accessible object
|
||||
* @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the names of the attributes inside the accessible object
|
||||
* @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the values of the attributes inside the accessible object
|
||||
*
|
||||
* Retrieves the text attributes inside the accessible object.
|
||||
*
|
||||
* Each attribute is composed by:
|
||||
*
|
||||
* - a range
|
||||
* - a name, typically in the form of a reverse DNS identifier
|
||||
* - a value
|
||||
*
|
||||
* If this function returns true, `n_attributes` will be set to a value
|
||||
* greater than or equal to one, @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange] which should
|
||||
* be freed with g_free(), @attribute_names and @attribute_values
|
||||
* will be set to string arrays that should be freed with g_strfreev().
|
||||
*
|
||||
* Returns: true if the accessible object has at least an attribute,
|
||||
* and false otherwise
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gtk_accessible_text_get_attributes (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
|
||||
|
||||
return GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_attributes (self,
|
||||
offset,
|
||||
n_ranges,
|
||||
ranges,
|
||||
attribute_names,
|
||||
attribute_values);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_default_attributes:
|
||||
* @self: the accessible object
|
||||
* @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the names of the attributes inside the accessible object
|
||||
* @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the values of the attributes inside the accessible object
|
||||
*
|
||||
* Retrieves the default text attributes inside the accessible object.
|
||||
*
|
||||
* Each attribute is composed by:
|
||||
*
|
||||
* - a name, typically in the form of a reverse DNS identifier
|
||||
* - a value
|
||||
*
|
||||
* If this function returns true, `n_attributes` will be set to a value
|
||||
* greater than or equal to one, @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange] which should
|
||||
* be freed with g_free(), @attribute_names and @attribute_values
|
||||
* will be set to string arrays that should be freed with g_strfreev().
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gtk_accessible_text_get_default_attributes (GtkAccessibleText *self,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ACCESSIBLE_TEXT (self));
|
||||
|
||||
GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_default_attributes (self,
|
||||
attribute_names,
|
||||
attribute_values);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_accessible_text_get_attributes_run:
|
||||
* @self: the accessible object
|
||||
* @offset: the offset, in characters
|
||||
* @include_defaults: whether to include the default attributes in the
|
||||
* returned array
|
||||
* @n_ranges: (out): the number of attributes
|
||||
* @ranges: (out) (array length=n_attributes) (optional): the ranges of the attributes
|
||||
* inside the accessible object
|
||||
* @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the names of the attributes inside the accessible object
|
||||
* @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
|
||||
* the values of the attributes inside the accessible object
|
||||
*
|
||||
* Retrieves the text attributes inside the accessible object.
|
||||
*
|
||||
* Each attribute is composed by:
|
||||
*
|
||||
* - a range
|
||||
* - a name, typically in the form of a reverse DNS identifier
|
||||
* - a value
|
||||
*
|
||||
* If this function returns true, `n_ranges` will be set to a value
|
||||
* greater than or equal to one, @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange] which should
|
||||
* be freed with g_free(), @attribute_names and @attribute_values
|
||||
* will be set to string arrays that should be freed with g_strfreev().
|
||||
*
|
||||
* Returns: true if the accessible object has at least an attribute,
|
||||
* and false otherwise
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gboolean include_defaults,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values)
|
||||
{
|
||||
GHashTable *attrs;
|
||||
GHashTableIter attr_iter;
|
||||
gpointer key, value;
|
||||
char **attr_names, **attr_values;
|
||||
gboolean res;
|
||||
GStrvBuilder *names_builder;
|
||||
GStrvBuilder *values_builder;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
|
||||
|
||||
attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
if (include_defaults)
|
||||
{
|
||||
gtk_accessible_text_get_default_attributes (self,
|
||||
&attr_names,
|
||||
&attr_values);
|
||||
|
||||
for (unsigned i = 0; attr_names[i] != NULL; i++)
|
||||
{
|
||||
g_hash_table_insert (attrs,
|
||||
g_steal_pointer (&attr_names[i]),
|
||||
g_steal_pointer (&attr_values[i]));
|
||||
}
|
||||
|
||||
g_free (attr_names);
|
||||
g_free (attr_values);
|
||||
}
|
||||
|
||||
res = gtk_accessible_text_get_attributes (self,
|
||||
offset,
|
||||
n_ranges,
|
||||
ranges,
|
||||
&attr_names,
|
||||
&attr_values);
|
||||
|
||||
/* If there are no attributes, we can bail out early */
|
||||
if (!res && !include_defaults)
|
||||
{
|
||||
g_hash_table_unref (attrs);
|
||||
*attribute_names = NULL;
|
||||
*attribute_values = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The text attributes override the default ones */
|
||||
for (unsigned i = 0; i < *n_ranges; i++)
|
||||
{
|
||||
g_hash_table_insert (attrs,
|
||||
g_steal_pointer (&attr_names[i]),
|
||||
g_steal_pointer (&attr_values[i]));
|
||||
}
|
||||
|
||||
g_free (attr_names);
|
||||
g_free (attr_values);
|
||||
|
||||
names_builder = g_strv_builder_new ();
|
||||
values_builder = g_strv_builder_new ();
|
||||
g_hash_table_iter_init (&attr_iter, attrs);
|
||||
while (g_hash_table_iter_next (&attr_iter, &key, &value))
|
||||
{
|
||||
g_strv_builder_add (names_builder, key);
|
||||
g_strv_builder_add (values_builder, value);
|
||||
}
|
||||
|
||||
*attribute_names = g_strv_builder_end (names_builder);
|
||||
*attribute_values = g_strv_builder_end (values_builder);
|
||||
|
||||
g_strv_builder_unref (names_builder);
|
||||
g_strv_builder_unref (values_builder);
|
||||
g_hash_table_unref (attrs);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_accessible_text_update_caret_position:
|
||||
* @self: the accessible object
|
||||
*
|
||||
* Updates the position of the caret.
|
||||
*
|
||||
* Implementations of the `GtkAccessibleText` interface should call this
|
||||
* function every time the caret has moved, in order to notify assistive
|
||||
* technologies.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gtk_accessible_text_update_caret_position (GtkAccessibleText *self)
|
||||
{
|
||||
GtkATContext *context;
|
||||
|
||||
g_return_if_fail (GTK_IS_ACCESSIBLE_TEXT (self));
|
||||
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self));
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
gtk_at_context_update_caret_position (context);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_accessible_text_update_selection_bound:
|
||||
* @self: the accessible object
|
||||
*
|
||||
* Updates the boundary of the selection.
|
||||
*
|
||||
* Implementations of the `GtkAccessibleText` interface should call this
|
||||
* function every time the selection has moved, in order to notify assistive
|
||||
* technologies.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gtk_accessible_text_update_selection_bound (GtkAccessibleText *self)
|
||||
{
|
||||
GtkATContext *context;
|
||||
|
||||
g_return_if_fail (GTK_IS_ACCESSIBLE_TEXT (self));
|
||||
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self));
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
gtk_at_context_update_selection_bound (context);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_accessible_text_update_contents:
|
||||
* @self: the accessible object
|
||||
* @change: the type of change in the contents
|
||||
* @start: the starting offset of the change, in characters
|
||||
* @end: the end offset of the change, in characters
|
||||
*
|
||||
* Notifies assistive technologies of a change in contents.
|
||||
*
|
||||
* Implementations of the `GtkAccessibleText` interface should call this
|
||||
* function every time their contents change as the result of an operation,
|
||||
* like an insertion or a removal.
|
||||
*
|
||||
* Note: If the change is a deletion, this function must be called *before*
|
||||
* removing the contents, if it is an insertion, it must be called *after*
|
||||
* inserting the new contents.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gtk_accessible_text_update_contents (GtkAccessibleText *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
GtkATContext *context;
|
||||
|
||||
g_return_if_fail (GTK_IS_ACCESSIBLE_TEXT (self));
|
||||
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self));
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
gtk_at_context_update_text_contents (context, change, start, end);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
/* gtkaccessibletext.h: Interface for accessible objects containing text
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2023 Emmanuele Bassi
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkaccessible.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_ACCESSIBLE_TEXT (gtk_accessible_text_get_type ())
|
||||
|
||||
/**
|
||||
* GtkAccessibleText:
|
||||
*
|
||||
* An interface for accessible objects containing formatted text.
|
||||
*
|
||||
* The `GtkAccessibleText` interfaces is meant to be implemented by accessible
|
||||
* objects that have text formatted with attributes, or non-trivial text contents.
|
||||
*
|
||||
* You should use the [enum@Gtk.AccessibleProperty.LABEL] or the
|
||||
* [enum@Gtk.AccessibleProperty.DESCRIPTION] properties for accessible
|
||||
* objects containing simple, unformatted text.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
G_DECLARE_INTERFACE (GtkAccessibleText, gtk_accessible_text, GTK, ACCESSIBLE_TEXT, GtkAccessible)
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextRange:
|
||||
* @start: the start of the range, in characters
|
||||
* @length: the length of the range, in characters
|
||||
*
|
||||
* A range inside the text of an accessible object.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
typedef struct {
|
||||
gsize start;
|
||||
gsize length;
|
||||
} GtkAccessibleTextRange;
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextGranularity:
|
||||
* @GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER: Use the boundary between
|
||||
* characters (including non-printing characters)
|
||||
* @GTK_ACCESSIBLE_TEXT_GRANULARITY_WORD: Use the boundary between words,
|
||||
* starting from the beginning of the current word and ending at the
|
||||
* beginning of the next word
|
||||
* @GTK_ACCESSIBLE_TEXT_GRANULARITY_SENTENCE: Use the boundary between
|
||||
* sentences, starting from the beginning of the current sentence and
|
||||
* ending at the beginning of the next sentence
|
||||
* @GTK_ACCESSIBLE_TEXT_GRANULARITY_LINE: Use the boundary between lines,
|
||||
* starting from the beginning of the current line and ending at the
|
||||
* beginning of the next line
|
||||
* @GTK_ACCESSIBLE_TEXT_GRANULARITY_PARAGRAPH: Use the boundary between
|
||||
* paragraphs, starting from the beginning of the current paragraph and
|
||||
* ending at the beginning of the next paragraph
|
||||
*
|
||||
* The granularity for queries about the text contents of a [iface@Gtk.AccessibleText]
|
||||
* implementation.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER,
|
||||
GTK_ACCESSIBLE_TEXT_GRANULARITY_WORD,
|
||||
GTK_ACCESSIBLE_TEXT_GRANULARITY_SENTENCE,
|
||||
GTK_ACCESSIBLE_TEXT_GRANULARITY_LINE,
|
||||
GTK_ACCESSIBLE_TEXT_GRANULARITY_PARAGRAPH
|
||||
} GtkAccessibleTextGranularity;
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextContentChange:
|
||||
* @GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT: contents change as the result of
|
||||
* an insert operation
|
||||
* @GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE: contents change as the result of
|
||||
* a remove operation
|
||||
*
|
||||
* The type of contents change operation.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
|
||||
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE
|
||||
} GtkAccessibleTextContentChange;
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface:
|
||||
*
|
||||
* The interface vtable for accessible objects containing text.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
struct _GtkAccessibleTextInterface
|
||||
{
|
||||
/*< private >*/
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/*< public >*/
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_contents:
|
||||
* @self: the accessible object
|
||||
* @start: the beginning of the range, in characters
|
||||
* @end: the end of the range, in characters
|
||||
*
|
||||
* Retrieve the current contents of the accessible object within
|
||||
* the given range.
|
||||
*
|
||||
* If @end is `G_MAXUINT`, the end of the range is the full content
|
||||
* of the accessible object.
|
||||
*
|
||||
* Returns: (transfer full): the requested slice of the contents of the
|
||||
* accessible object, as UTF-8. Note that the slice does not have to
|
||||
* be NUL-terminated
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GBytes * (* get_contents) (GtkAccessibleText *self,
|
||||
unsigned int start,
|
||||
unsigned int end);
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_contents_at:
|
||||
* @self: the accessible object
|
||||
* @offset: the offset, in characters
|
||||
* @granularity: the granularity of the query
|
||||
* @start: (out): the start of the range, in characters
|
||||
* @end: (out): the end of the range, in characters
|
||||
*
|
||||
* Retrieve the current contents of the accessible object starting
|
||||
* from the given offset, and using the given granularity.
|
||||
*
|
||||
* The @start and @end values contain the boundaries of the text.
|
||||
*
|
||||
* Returns: (transfer full): the requested slice of the contents of the
|
||||
* accessible object, as UTF-8. Note that the slice does not have to
|
||||
* be NUL-terminated
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GBytes * (* get_contents_at) (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
GtkAccessibleTextGranularity granularity,
|
||||
unsigned int *start,
|
||||
unsigned int *end);
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_caret_position:
|
||||
* @self: the accessible object
|
||||
*
|
||||
* Retrieves the position of the caret inside the accessible object.
|
||||
*
|
||||
* Returns: the position of the caret, in characters
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int (* get_caret_position) (GtkAccessibleText *self);
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_selection:
|
||||
* @self: the accessible object
|
||||
* @n_ranges: (out): the number of selection ranges
|
||||
* @ranges: (optional) (out) (array length=n_ranges) (transfer container): the selection ranges
|
||||
*
|
||||
* Retrieves the selection ranges in the accessible object.
|
||||
*
|
||||
* If this function returns true, `n_ranges` will be set to a value
|
||||
* greater than or equal to one, and @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange].
|
||||
*
|
||||
* Returns: true if there is at least a selection inside the
|
||||
* accessible object, and false otherwise
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean (* get_selection) (GtkAccessibleText *self,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges);
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_attributes:
|
||||
* @self: the accessible object
|
||||
* @offset: the offset, in characters
|
||||
* @n_ranges: (out): the number of attributes
|
||||
* @ranges: (out) (array length=n_ranges) (optional) (transfer container): the ranges of the attributes
|
||||
* inside the accessible object
|
||||
* @attribute_names: (out) (array zero-terminated=1) (optional) (transfer full): the
|
||||
* names of the attributes inside the accessible object
|
||||
* @attribute_values: (out) (array zero-terminated=1) (optional) (transfer full): the
|
||||
* values of the attributes inside the accessible object
|
||||
*
|
||||
* Retrieves the text attributes inside the accessible object.
|
||||
*
|
||||
* Each attribute is composed by:
|
||||
*
|
||||
* - a range
|
||||
* - a name
|
||||
* - a value
|
||||
*
|
||||
* It is left to the implementation to determine the serialization format
|
||||
* of the value to a string.
|
||||
*
|
||||
* GTK provides support for various text attribute names and values, but
|
||||
* implementations of this interface are free to add their own attributes.
|
||||
*
|
||||
* If this function returns true, `n_ranges` will be set to a value
|
||||
* greater than or equal to one, @ranges will be set to a newly
|
||||
* allocated array of [struct#Gtk.AccessibleTextRange].
|
||||
*
|
||||
* Returns: true if the accessible object has at least an attribute,
|
||||
* and false otherwise
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean (* get_attributes) (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values);
|
||||
|
||||
/**
|
||||
* GtkAccessibleTextInterface::get_default_attributes:
|
||||
* @self: the accessible object
|
||||
* @attribute_names: (out) (array zero-terminated=1) (optional) (transfer full): the
|
||||
* names of the default attributes inside the accessible object
|
||||
* @attribute_values: (out) (array zero-terminated=1) (optional) (transfer full): the
|
||||
* values of the default attributes inside the accessible object
|
||||
*
|
||||
* Retrieves the default text attributes inside the accessible object.
|
||||
*
|
||||
* Each attribute is composed by:
|
||||
*
|
||||
* - a name
|
||||
* - a value
|
||||
*
|
||||
* It is left to the implementation to determine the serialization format
|
||||
* of the value to a string.
|
||||
*
|
||||
* GTK provides support for various text attribute names and values, but
|
||||
* implementations of this interface are free to add their own attributes.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void (* get_default_attributes) (GtkAccessibleText *self,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gtk_accessible_text_update_caret_position (GtkAccessibleText *self);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gtk_accessible_text_update_selection_bound (GtkAccessibleText *self);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gtk_accessible_text_update_contents (GtkAccessibleText *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end);
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_FAMILY:
|
||||
*
|
||||
* An attribute for the font family name.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_FAMILY "family-name"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STYLE:
|
||||
*
|
||||
* An attribute for the font style.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE_NORMAL]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE_OBLIQUE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE_ITALIC]
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STYLE "style"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_WEIGHT:
|
||||
*
|
||||
* An attribute for the font weight.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_WEIGHT "weight"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT:
|
||||
*
|
||||
* An attribute for the font variant.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_SMALL_CAPS]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_SMALL_CAPS]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_PETITE_CAPS]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_PETITE_CAPS]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_UNICASE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT_TITLE_CAPS]
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT "variant"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH:
|
||||
*
|
||||
* An attribute for the font stretch type.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH_ULTRA_CONDENSED]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH_EXTRA_CONDENSED]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH_CONDENSED]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH_SEMI_CONDENSED]
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH "stretch"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_SIZE:
|
||||
*
|
||||
* An attribute for the font size, expressed in points.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_SIZE "size"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_FOREGROUND:
|
||||
*
|
||||
* An attribute for the foreground color, expressed as an RGB value
|
||||
* encoded in a string using the format: `{r8},{g8},{b8}`.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_FOREGROUND "fg-color"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_BACKGROUND:
|
||||
*
|
||||
* An attribute for the background color, expressed as an RGB value
|
||||
* encoded in a string using the format: `{r8},{g8},{b8}`.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_BACKGROUND "bg-color"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE:
|
||||
*
|
||||
* An attribute for the underline style.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE_NONE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE_SINGLE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE_DOUBLE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE_ERROR]
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE "underline"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE:
|
||||
*
|
||||
* An attribute for the overline style.
|
||||
*
|
||||
* Possible values are:
|
||||
*
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_OVERLINE_NONE]
|
||||
* - [const@Gtk.ACCESSIBLE_ATTRIBUTE_OVERLINE_SINGLE]
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE "overline"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRIKETHROUGH:
|
||||
*
|
||||
* An attribute for strikethrough text.
|
||||
*
|
||||
* Possible values are `true` or `false`.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRIKETHROUGH "strikethrough"
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STYLE_NORMAL:
|
||||
*
|
||||
* The "normal" style value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STYLE_NORMAL "normal"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STYLE_OBLIQUE:
|
||||
*
|
||||
* The "oblique" style value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STYLE_OBLIQUE "oblique"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STYLE_ITALIC:
|
||||
*
|
||||
* The "italic" style value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STYLE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STYLE_ITALIC "italic"
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_SMALL_CAPS:
|
||||
*
|
||||
* The "small caps" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_SMALL_CAPS "small-caps"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_SMALL_CAPS:
|
||||
*
|
||||
* The "all small caps" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_SMALL_CAPS "all-small-caps"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_PETITE_CAPS:
|
||||
*
|
||||
* The "petite caps" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_PETITE_CAPS "petite-caps"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_PETITE_CAPS:
|
||||
*
|
||||
* The "all petite caps" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_ALL_PETITE_CAPS "all-petite-caps"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_UNICASE:
|
||||
*
|
||||
* The "unicase" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_UNICASE "unicase"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_TITLE_CAPS:
|
||||
*
|
||||
* The "title caps" variant value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_VARIANT].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_VARIANT_TITLE_CAPS "title-caps"
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_ULTRA_CONDENSED:
|
||||
*
|
||||
* The "ultra condensed" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_ULTRA_CONDENSED "ultra_condensed"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXTRA_CONDENSED:
|
||||
*
|
||||
* The "extra condensed" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXTRA_CONDENSED "extra_condensed"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_CONDENSED:
|
||||
*
|
||||
* The "condensed" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_CONDENSED "condensed"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_SEMI_CONDENSED:
|
||||
*
|
||||
* The "semi condensed" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_SEMI_CONDENSED "semi_condensed"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_NORMAL:
|
||||
*
|
||||
* The "normal" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_NORMAL "normal"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_SEMI_EXPANDED:
|
||||
*
|
||||
* The "semi expanded" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_SEMI_EXPANDED "semi_expanded"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXPANDED:
|
||||
*
|
||||
* The "expanded" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXPANDED "expanded"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXTRA_EXPANDED:
|
||||
*
|
||||
* The "extra expanded" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_EXTRA_EXPANDED "extra_expanded"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_ULTRA_EXPANDED:
|
||||
*
|
||||
* The "ultra expanded" stretch value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_STRETCH].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_STRETCH_ULTRA_EXPANDED "ultra_expanded"
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_NONE:
|
||||
*
|
||||
* The "none" underline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_NONE "none"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_SINGLE:
|
||||
*
|
||||
* The "single" underline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_SINGLE "single"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_DOUBLE:
|
||||
*
|
||||
* The "double" underline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_DOUBLE "double"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_ERROR:
|
||||
*
|
||||
* The "error" underline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_UNDERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_UNDERLINE_ERROR "error"
|
||||
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE_NONE:
|
||||
*
|
||||
* The "none" overline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_OVERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE_NONE "none"
|
||||
/**
|
||||
* GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE_SINGLE:
|
||||
*
|
||||
* The "single" overline value for [const@Gtk.ACCESSIBLE_ATTRIBUTE_OVERLINE].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
#define GTK_ACCESSIBLE_ATTRIBUTE_OVERLINE_SINGLE "single"
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,55 @@
|
||||
/* gtkaccessibletextprivate.h: Private definitions for GtkAccessibleText
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2023 Emmanuele Bassi
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gtkaccessibletext.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GBytes *
|
||||
gtk_accessible_text_get_contents (GtkAccessibleText *self,
|
||||
unsigned int start,
|
||||
unsigned int end);
|
||||
|
||||
GBytes *
|
||||
gtk_accessible_text_get_contents_at (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
GtkAccessibleTextGranularity granularity,
|
||||
unsigned int *start,
|
||||
unsigned int *end);
|
||||
|
||||
unsigned int
|
||||
gtk_accessible_text_get_caret_position (GtkAccessibleText *self);
|
||||
|
||||
gboolean
|
||||
gtk_accessible_text_get_selection (GtkAccessibleText *self,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges);
|
||||
|
||||
gboolean
|
||||
gtk_accessible_text_get_attributes (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values);
|
||||
|
||||
void
|
||||
gtk_accessible_text_get_default_attributes (GtkAccessibleText *self,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values);
|
||||
|
||||
gboolean
|
||||
gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
|
||||
unsigned int offset,
|
||||
gboolean include_defaults,
|
||||
gsize *n_ranges,
|
||||
GtkAccessibleTextRange **ranges,
|
||||
char ***attribute_names,
|
||||
char ***attribute_values);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -146,7 +146,8 @@ gtk_application_impl_wayland_inhibit (GtkApplicationImpl *impl,
|
||||
}
|
||||
}
|
||||
|
||||
inhibitor->dbus_cookie = ((GtkApplicationImplWaylandClass *) G_OBJECT_GET_CLASS (wayland))->dbus_inhibit (impl, window, flags, reason);
|
||||
if (flags)
|
||||
inhibitor->dbus_cookie = ((GtkApplicationImplWaylandClass *) G_OBJECT_GET_CLASS (wayland))->dbus_inhibit (impl, window, flags, reason);
|
||||
|
||||
return inhibitor->cookie;
|
||||
}
|
||||
|
||||
+71
-4
@@ -207,6 +207,24 @@ gtk_at_context_real_unrealize (GtkATContext *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_context_real_update_caret_position (GtkATContext *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_context_real_update_selection_bound (GtkATContext *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_context_real_update_text_contents (GtkATContext *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_at_context_class_init (GtkATContextClass *klass)
|
||||
{
|
||||
@@ -223,6 +241,9 @@ gtk_at_context_class_init (GtkATContextClass *klass)
|
||||
klass->platform_change = gtk_at_context_real_platform_change;
|
||||
klass->bounds_change = gtk_at_context_real_bounds_change;
|
||||
klass->child_change = gtk_at_context_real_child_change;
|
||||
klass->update_caret_position = gtk_at_context_real_update_caret_position;
|
||||
klass->update_selection_bound = gtk_at_context_real_update_selection_bound;
|
||||
klass->update_text_contents = gtk_at_context_real_update_text_contents;
|
||||
|
||||
/**
|
||||
* GtkATContext:accessible-role: (attributes org.gtk.Property.get=gtk_at_context_get_accessible_role)
|
||||
@@ -909,7 +930,7 @@ gtk_at_context_set_accessible_property (GtkATContext *self,
|
||||
else
|
||||
res = gtk_accessible_attribute_set_remove (self->properties, property);
|
||||
|
||||
if (res)
|
||||
if (res && self->realized)
|
||||
self->updated_properties |= (1 << property);
|
||||
}
|
||||
|
||||
@@ -1369,9 +1390,25 @@ gtk_at_context_get_text_accumulate (GtkATContext *self,
|
||||
{
|
||||
const char *text = gtk_widget_get_tooltip_text (GTK_WIDGET (self->accessible));
|
||||
if (text && not_just_space (text))
|
||||
if (!check_duplicates || ((property == GTK_ACCESSIBLE_PROPERTY_LABEL && strcmp(text, gtk_at_context_get_description_internal (self, FALSE)) != 0)
|
||||
|| (property == GTK_ACCESSIBLE_PROPERTY_DESCRIPTION && strcmp(text, gtk_at_context_get_name_internal (self, FALSE)) != 0)))
|
||||
append_with_space (res, text);
|
||||
{
|
||||
gboolean append = !check_duplicates;
|
||||
|
||||
if (!append)
|
||||
{
|
||||
char *description = gtk_at_context_get_description_internal (self, FALSE);
|
||||
char *name = gtk_at_context_get_name_internal (self, FALSE);
|
||||
|
||||
append =
|
||||
(property == GTK_ACCESSIBLE_PROPERTY_LABEL && strcmp (text, description) != 0) ||
|
||||
(property == GTK_ACCESSIBLE_PROPERTY_DESCRIPTION && strcmp (text, name) != 0);
|
||||
|
||||
g_free (description);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
if (append)
|
||||
append_with_space (res, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,3 +1545,33 @@ gtk_at_context_announce (GtkATContext *self,
|
||||
|
||||
GTK_AT_CONTEXT_GET_CLASS (self)->announce (self, message, priority);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_at_context_update_caret_position (GtkATContext *self)
|
||||
{
|
||||
if (!self->realized)
|
||||
return;
|
||||
|
||||
GTK_AT_CONTEXT_GET_CLASS (self)->update_caret_position (self);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_at_context_update_selection_bound (GtkATContext *self)
|
||||
{
|
||||
if (!self->realized)
|
||||
return;
|
||||
|
||||
GTK_AT_CONTEXT_GET_CLASS (self)->update_selection_bound (self);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_at_context_update_text_contents (GtkATContext *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
if (!self->realized)
|
||||
return;
|
||||
|
||||
GTK_AT_CONTEXT_GET_CLASS (self)->update_text_contents (self, change, start, end);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "gtkaccessibleprivate.h"
|
||||
#include "gtkaccessibleattributesetprivate.h"
|
||||
#include "gtkaccessibletext.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -131,6 +132,14 @@ struct _GtkATContextClass
|
||||
void (* announce) (GtkATContext *self,
|
||||
const char *message,
|
||||
GtkAccessibleAnnouncementPriority priority);
|
||||
|
||||
/* Text interface */
|
||||
void (* update_caret_position) (GtkATContext *self);
|
||||
void (* update_selection_bound) (GtkATContext *self);
|
||||
void (* update_text_contents) (GtkATContext *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end);
|
||||
};
|
||||
|
||||
GtkATContext * gtk_at_context_clone (GtkATContext *self,
|
||||
@@ -200,5 +209,14 @@ gtk_at_context_set_next_accessible_sibling (GtkATContext *self,
|
||||
void gtk_at_context_announce (GtkATContext *self,
|
||||
const char *message,
|
||||
GtkAccessibleAnnouncementPriority priority);
|
||||
void
|
||||
gtk_at_context_update_caret_position (GtkATContext *self);
|
||||
void
|
||||
gtk_at_context_update_selection_bound (GtkATContext *self);
|
||||
void
|
||||
gtk_at_context_update_text_contents (GtkATContext *self,
|
||||
GtkAccessibleTextContentChange change,
|
||||
unsigned int start,
|
||||
unsigned int end);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
+53
-3
@@ -99,9 +99,7 @@
|
||||
* Objects are described by `<object>` elements, which can contain
|
||||
* `<property>` elements to set properties, `<signal>` elements which
|
||||
* connect signals to handlers, and `<child>` elements, which describe
|
||||
* child objects (most often widgets inside a container, but also e.g.
|
||||
* actions in an action group, or columns in a tree model). A `<child>`
|
||||
* element contains an `<object>` element which describes the child object.
|
||||
* child objects.
|
||||
*
|
||||
* Typically, the specific kind of object represented by an `<object>`
|
||||
* element is specified by the “class” attribute. If the type has not
|
||||
@@ -173,6 +171,53 @@
|
||||
* exception to this rule is that an object has to be constructed before
|
||||
* it can be used as the value of a construct-only property.
|
||||
*
|
||||
* ### Child objects
|
||||
*
|
||||
* Many widgets have properties for child widgets, such as
|
||||
* [property@Gtk.Expander:child]. In this case, the preferred way to
|
||||
* specify the child widget in a ui file is to simply set the property:
|
||||
*
|
||||
* ```xml
|
||||
* <object class="GtkExpander">
|
||||
* <property name="child">
|
||||
* <object class="GtkLabel">
|
||||
* ...
|
||||
* </object>
|
||||
* </property>
|
||||
* </object>
|
||||
* ```
|
||||
*
|
||||
* Generic containers that can contain an arbitrary number of children,
|
||||
* such as [class@Gtk.Box] instead use the `<child>` element. A `<child>`
|
||||
* element contains an `<object>` element which describes the child object.
|
||||
* Most often, child objects are widgets inside a container, but they can
|
||||
* also be, e.g., actions in an action group, or columns in a tree model.
|
||||
*
|
||||
* Any object type that implements the [iface@Gtk.Buildable] interface can
|
||||
* specify how children may be added to it. Since many objects and widgets that
|
||||
* are included with GTK already implement the `GtkBuildable` interface,
|
||||
* typically child objects can be added using the `<child>` element without
|
||||
* having to be concerned about the underlying implementation.
|
||||
*
|
||||
* See the [`GtkWidget` documentation](class.Widget.html#gtkwidget-as-gtkbuildable)
|
||||
* for many examples of using `GtkBuilder` with widgets, including setting
|
||||
* child objects using the `<child>` element.
|
||||
*
|
||||
* A noteworthy special case to the general rule that only objects implementing
|
||||
* `GtkBuildable` may specify how to handle the `<child>` element is that
|
||||
* `GtkBuilder` provides special support for adding objects to a
|
||||
* [class@Gio.ListStore] by using the `<child>` element. For instance:
|
||||
*
|
||||
* ```xml
|
||||
* <object class="GListStore">
|
||||
* <property name="item-type">MyObject</property>
|
||||
* <child>
|
||||
* <object class="MyObject" />
|
||||
* </child>
|
||||
* ...
|
||||
* </object>
|
||||
* ```
|
||||
*
|
||||
* ### Property bindings
|
||||
*
|
||||
* It is also possible to bind a property value to another object's
|
||||
@@ -208,6 +253,11 @@
|
||||
* For more information, see the documentation of the
|
||||
* [method@GObject.Object.bind_property] method.
|
||||
*
|
||||
* Please note that another way to set up bindings between objects in .ui files
|
||||
* is to use the `GtkExpression` methodology. See the
|
||||
* [`GtkExpression` documentation](class.Expression.html#gtkexpression-in-ui-files)
|
||||
* for more information.
|
||||
*
|
||||
* ### Internal children
|
||||
*
|
||||
* Sometimes it is necessary to refer to widgets which have implicitly
|
||||
|
||||
@@ -482,8 +482,13 @@ gtk_editable_insert_text (GtkEditable *editable,
|
||||
int *position)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_EDITABLE (editable));
|
||||
g_return_if_fail (text != NULL);
|
||||
g_return_if_fail (length >= -1);
|
||||
g_return_if_fail (position != NULL);
|
||||
|
||||
if (text == NULL)
|
||||
text = "";
|
||||
|
||||
if (length < 0)
|
||||
length = strlen (text);
|
||||
|
||||
@@ -511,6 +516,8 @@ gtk_editable_delete_text (GtkEditable *editable,
|
||||
int end_pos)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_EDITABLE (editable));
|
||||
g_return_if_fail (start_pos >= 0);
|
||||
g_return_if_fail (end_pos == -1 || end_pos >= start_pos);
|
||||
|
||||
GTK_EDITABLE_GET_IFACE (editable)->do_delete_text (editable, start_pos, end_pos);
|
||||
}
|
||||
@@ -544,6 +551,8 @@ gtk_editable_get_chars (GtkEditable *editable,
|
||||
int start_index,end_index;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
|
||||
g_return_val_if_fail (start_pos >= 0, NULL);
|
||||
g_return_val_if_fail (end_pos == -1 || end_pos >= start_pos, NULL);
|
||||
|
||||
text = GTK_EDITABLE_GET_IFACE (editable)->get_text (editable);
|
||||
length = g_utf8_strlen (text, -1);
|
||||
@@ -594,6 +603,7 @@ gtk_editable_set_text (GtkEditable *editable,
|
||||
int pos;
|
||||
|
||||
g_return_if_fail (GTK_IS_EDITABLE (editable));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (editable));
|
||||
gtk_editable_delete_text (editable, 0, -1);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user