Compare commits

..

22 Commits

Author SHA1 Message Date
Matthias Clasen
e5d0f32d8c css: Improve error reporting for variables
Emit errors for all the variables that were being expanded
if an error occurs while parsing a property value at compute time.

Include the variables that are being expanded in the error message.
2024-05-09 23:13:53 -04:00
Matthias Clasen
e825fd901f css parser: Keep variables for tokenizers
Add a function that gets the names of the variables that the
parser is currently in the process of expanding. This will
be used for error reporting.
2024-05-09 23:13:53 -04:00
Matthias Clasen
e3543f37d3 css parser: Inline the tokenizer array
This is in preparation of associating more data with the token streams.
2024-05-09 23:13:53 -04:00
Matthias Clasen
e9bf0322ac css provider: Set bytes on sections
Pass the bytes we're parsing to the sections, and keep a pointer
to them around, so we can compare them in the has_section
implementation.

This commit also corrects some of the location information that
we add into the section for variables to be more accurate.
2024-05-09 23:13:53 -04:00
Matthias Clasen
6d5cb0a083 css parser: Add gtk_css_parser_get_bytes
Gets the bytes that the parser is operating on.
2024-05-09 23:13:53 -04:00
Matthias Clasen
8b5aab459a css provider: Set sections on all variable values
We were doing it in one case, but forgetting it in another.
These sections are necessary to report meaningful error locations
when parsing property values at compute time.
2024-05-09 23:13:53 -04:00
Matthias Clasen
8da3cc10fd style cascade: Propagate errors
When we compute values, the provider we use ends up being the
style cascade. If we hit a parser error when parsing variable-bearing
property values at compute time, we emit the error on that provider.

By making the cascade propagate the error back to the proper css
provider that contains the section in question, we get it reported
back to the css editor in the inspector.
2024-05-09 23:13:53 -04:00
Matthias Clasen
f48a4e84af style provider: Add a has_section api
Add gtk_style_provider_has_section and implement it for
GtkCssProvider. This will be used later to direct error
emissions to the right provider.
2024-05-09 23:13:53 -04:00
Matthias Clasen
09c76208a2 css parser: Add bytes to sections
We will use this later to link sections back to the providers
they come from.
2024-05-09 23:13:53 -04:00
Matthias Clasen
62b1d21556 css parser: Add gtk_css_parser_skip_whitespace
Does what it says.
2024-05-09 23:13:53 -04:00
Matthias Clasen
8fba58eaa9 css: Don't accept junk
Check that there is no junk at the end of the property value
when parsing variable-bearing properties at compute time.
2024-05-09 23:13:52 -04:00
Alice Mikhaylenko
b4890edd64 inspector: Sort GTK CSS properties between standard and custom ones 2024-05-08 19:03:45 +04:00
Alice Mikhaylenko
93b9388180 inspector: Show custom properties for css nodes 2024-05-08 19:03:45 +04:00
Alice Mikhaylenko
76b2609ad5 testsuite: Add css variables tests 2024-05-08 19:03:44 +04:00
Alice Mikhaylenko
a37a0711ad csskeyframes: Support variables 2024-05-08 19:03:44 +04:00
Alice Mikhaylenko
23dbb7122c cssanimation: Recompute values while playing
This will be necessary for supporting variables in animations.

For this we need to pass all the gtk_css_value_compute() parameters into
GtkCssAnimatedStyle: parent style and provider.
2024-05-08 19:03:44 +04:00
Alice Mikhaylenko
e04ab263f9 cssstaticstyle: Split property lists into a separate header
We'll need to use them in GtkCssAnimatedStyle too.
2024-05-08 19:03:44 +04:00
Alice Mikhaylenko
5e6e808a55 cssvalue: Pass an extra GtkCssVariableSet to compute()
We'll need this to support variables in @keyframes, since styles will
need to combine their own variables and the ones from the keyframes.

See the next commit, this one is split out to avoid a huge diff.
2024-05-08 19:03:44 +04:00
Alice Mikhaylenko
6eaf6e2f7d Implement basic support for CSS variables 2024-05-08 19:03:43 +04:00
Alice Mikhaylenko
e4a4a0f6dd cssvalue: Add contains_variables()
We'll need this to know which values to recompute for animations.

It will be used in the next commit, it's separate to avoid the diff
being too large.
2024-05-08 19:00:40 +04:00
Alice Mikhaylenko
f301ea7936 csstokenizer: Add save() and restore()
We'll need that to check if property values contain variables.
2024-05-08 19:00:40 +04:00
Alice Mikhaylenko
a3e9ecd199 cssprovider: Copy bytes when loading
We'll need to keep accessing them later to compute values with variables,
so we can't avoid this anymore.
2024-05-08 19:00:40 +04:00
1161 changed files with 50815 additions and 111826 deletions

View File

@@ -26,8 +26,7 @@ variables:
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true" BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled" FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3 MESON_TEST_TIMEOUT_MULTIPLIER: 3
MESON_TEST_MAX_PROCESSES: 8 FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v49"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v52"
workflow: workflow:
rules: rules:
@@ -68,6 +67,7 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/report-x11.xml" - "${CI_PROJECT_DIR}/_build/report-x11.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland.xml" - "${CI_PROJECT_DIR}/_build/report-wayland.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland_gl.xml" - "${CI_PROJECT_DIR}/_build/report-wayland_gl.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland_gles2.xml"
- "${CI_PROJECT_DIR}/_build/report-broadway.xml" - "${CI_PROJECT_DIR}/_build/report-broadway.xml"
name: "gtk-${CI_COMMIT_REF_NAME}" name: "gtk-${CI_COMMIT_REF_NAME}"
paths: paths:
@@ -117,12 +117,10 @@ release-build:
EXTRA_MESON_FLAGS: "--buildtype=release" EXTRA_MESON_FLAGS: "--buildtype=release"
script: script:
- .gitlab-ci/show-info-linux.sh - .gitlab-ci/show-info-linux.sh
- mkdir _install - export PATH="$HOME/.local/bin:$PATH"
# don't use catch by default, since it causes sporadic test failures
# - export PATH="$HOME/.local/bin:${CI_PROJECT_DIR}/_install/bin:$PATH"
# - .gitlab-ci/install-meson-project.sh --prefix ${CI_PROJECT_DIR}/_install https://gitlab.gnome.org/jadahl/catch.git main
- meson subprojects download - meson subprojects download
- meson subprojects update --reset - meson subprojects update --reset
- mkdir _install
- meson setup - meson setup
--prefix=${CI_PROJECT_DIR}/_install --prefix=${CI_PROJECT_DIR}/_install
${COMMON_MESON_FLAGS} ${COMMON_MESON_FLAGS}
@@ -135,6 +133,8 @@ release-build:
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello - PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello - LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
- .gitlab-ci/run-tests.sh _build wayland gtk - .gitlab-ci/run-tests.sh _build wayland gtk
# only repeat test runs that are likely affected by test setups
- .gitlab-ci/run-tests.sh _build wayland_gles2 gtk:gdk,gtk:gsk-gl
fedora-clang: fedora-clang:
extends: .build-fedora-default extends: .build-fedora-default
@@ -413,12 +413,11 @@ static-scan:
# Run tests with the address sanitizer. We need to turn off introspection # Run tests with the address sanitizer. We need to turn off introspection
# and f16c, since they are incompatible with asan # and f16c, since they are incompatible with asan
asan-build: asan-build:
extends: .build-fedora-default image: $FEDORA_IMAGE
tags: [ asan ] tags: [ asan ]
stage: analysis stage: analysis
needs: [] needs: []
variables: variables:
MESON_TEST_MAX_PROCESSES: 4
script: script:
- export PATH="$HOME/.local/bin:$PATH" - export PATH="$HOME/.local/bin:$PATH"
- CC=clang meson setup - CC=clang meson setup
@@ -446,10 +445,9 @@ reference:
--force-fallback-for=gdk-pixbuf,pango --force-fallback-for=gdk-pixbuf,pango
-Dintrospection=enabled -Dintrospection=enabled
-Ddocumentation=true -Ddocumentation=true
-Dman-pages=true
-Dgdk-pixbuf:gtk_doc=true -Dgdk-pixbuf:gtk_doc=true
-Dpango:documentation=true -Dpango:documentation=true
-Dbuild-demos=true -Dbuild-demos=false
-Dbuild-examples=false -Dbuild-examples=false
-Dbuild-tests=false -Dbuild-tests=false
-Dbuild-testsuite=false -Dbuild-testsuite=false
@@ -461,7 +459,6 @@ reference:
- mv _build/docs/reference/gdk/gdk4-wayland/ _reference/gdk4-wayland/ - mv _build/docs/reference/gdk/gdk4-wayland/ _reference/gdk4-wayland/
- mv _build/docs/reference/gsk/gsk4/ _reference/gsk4/ - mv _build/docs/reference/gsk/gsk4/ _reference/gsk4/
- mv _build/docs/reference/gtk/gtk4/ _reference/gtk4/ - mv _build/docs/reference/gtk/gtk4/ _reference/gtk4/
- mv _build/docs/reference/gtk/*.html _reference/gtk4/
- mv _build/subprojects/pango/docs/Pango/ _reference/Pango/ - mv _build/subprojects/pango/docs/Pango/ _reference/Pango/
- mv _build/subprojects/pango/docs/PangoCairo/ _reference/PangoCairo/ - mv _build/subprojects/pango/docs/PangoCairo/ _reference/PangoCairo/
- mv _build/subprojects/pango/docs/PangoFc/ _reference/PangoFc/ - mv _build/subprojects/pango/docs/PangoFc/ _reference/PangoFc/

View File

@@ -1,4 +1,4 @@
FROM fedora:40 FROM fedora:39
RUN dnf -y install \ RUN dnf -y install \
adwaita-icon-theme \ adwaita-icon-theme \
@@ -99,11 +99,8 @@ RUN dnf -y install \
which \ which \
wireplumber \ wireplumber \
xorg-x11-server-Xvfb \ xorg-x11-server-Xvfb \
&& dnf -y update \
&& dnf clean all && dnf clean all
RUN rm /usr/share/vulkan/icd.d/powervr_mesa_icd.x86_64.json
# Enable sudo for wheel users # Enable sudo for wheel users
RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers

View File

@@ -1,91 +0,0 @@
#!/bin/bash
set -e
usage() {
cat <<-EOF
Usage: $(basename $0) [OPTION…] REPO_URL COMMIT
Check out and install a meson project
Options:
-Dkey=val Option to pass on to meson
--prefix Prefix to install to
--subdir Build subdirectory instead of whole project
--prepare Script to run before build
-h, --help Display this help
EOF
}
TEMP=$(getopt \
--name=$(basename $0) \
--options='D:h' \
--longoptions='prefix:' \
--longoptions='subdir:' \
--longoptions='prepare:' \
--longoptions='help' \
-- "$@")
eval set -- "$TEMP"
unset TEMP
MESON_OPTIONS=()
PREFIX=/usr
SUBDIR=.
PREPARE=:
while true; do
case "$1" in
-D)
MESON_OPTIONS+=( -D$2 )
shift 2
;;
--prefix)
PREFIX=$2
shift 2
;;
--subdir)
SUBDIR=$2
shift 2
;;
--prepare)
PREPARE=$2
shift 2
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
esac
done
if [[ $# -lt 2 ]]; then
usage
exit 1
fi
REPO_URL="$1"
COMMIT="$2"
CHECKOUT_DIR=$(mktemp --directory)
trap "rm -rf $CHECKOUT_DIR" EXIT
git clone --depth 1 "$REPO_URL" -b "$COMMIT" "$CHECKOUT_DIR"
pushd "$CHECKOUT_DIR/$SUBDIR"
sh -c "$PREPARE"
meson setup --prefix "$PREFIX" _build "${MESON_OPTIONS[@]}"
meson compile -C _build
meson install -C _build
popd

View File

@@ -8,19 +8,17 @@ builddir=$1
setup=$2 setup=$2
suite=$3 suite=$3
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1} multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
n_processes=${MESON_TEST_MAX_PROCESSES:-1}
# Ignore memory leaks lower in dependencies # Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1 export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
export G_SLICE=always-malloc
case "${setup}" in case "${setup}" in
x11*) x11*)
dbus-run-session -- \ xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
meson test -C ${builddir} \ meson test -C ${builddir} \
--quiet \ --quiet \
--timeout-multiplier "${multiplier}" \ --timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--print-errorlogs \ --print-errorlogs \
--setup=${setup} \ --setup=${setup} \
--suite=${suite//,/ --suite=} \ --suite=${suite//,/ --suite=} \
@@ -42,11 +40,9 @@ case "${setup}" in
compositor=$! compositor=$!
export WAYLAND_DISPLAY=wayland-5 export WAYLAND_DISPLAY=wayland-5
dbus-run-session -- \ meson test -C ${builddir} \
meson test -C ${builddir} \
--quiet \ --quiet \
--timeout-multiplier "${multiplier}" \ --timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--print-errorlogs \ --print-errorlogs \
--setup=${setup} \ --setup=${setup} \
--suite=${suite//,/ --suite=} \ --suite=${suite//,/ --suite=} \
@@ -67,11 +63,9 @@ case "${setup}" in
server=$! server=$!
export BROADWAY_DISPLAY=:5 export BROADWAY_DISPLAY=:5
dbus-run-session -- \ meson test -C ${builddir} \
meson test -C ${builddir} \
--quiet \ --quiet \
--timeout-multiplier "${multiplier}" \ --timeout-multiplier "${multiplier}" \
--num-processes "${n_processes}" \
--print-errorlogs \ --print-errorlogs \
--setup=${setup} \ --setup=${setup} \
--suite=${suite//,/ --suite=} \ --suite=${suite//,/ --suite=} \

View File

@@ -34,9 +34,7 @@
<!-- <!--
- Which version of GTK you are using - Which version of GTK you are using
- What operating system and version - What operating system and version
- What windowing system (X11 or Wayland) - For Linux, which distribution
- What graphics driver / mesa version
- For Linux, which distribution
- If you built GTK yourself, the list of options used to configure the build - If you built GTK yourself, the list of options used to configure the build
--> -->

View File

@@ -100,16 +100,14 @@ development tools appropriate for your operating system, including:
- Meson - Meson
- Ninja - Ninja
- Gettext (19.7 or newer) - Gettext (19.7 or newer)
- a [C99 compatible compiler][glib-toolchain-reqs] - a [C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
Up-to-date instructions about developing GNOME applications and libraries Up-to-date instructions about developing GNOME applications and libraries
can be found on [the GNOME Developer Center](https://developer.gnome.org). can be found on [the GNOME Developer Center](https://developer.gnome.org).
The GTK project uses GitLab for code hosting and for tracking issues. More The GTK project uses GitLab for code hosting and for tracking issues. More
information about using GitLab can be found on [the GNOME handbook][handbook]. information about using GitLab can be found [on the GNOME
wiki](https://wiki.gnome.org/GitLab).
[glib-toolchain-reqs]: https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/toolchain-requirements.md
[handbook]: https://handbook.gnome.org/infrastructure/gitlab.html
### Dependencies ### Dependencies
@@ -133,7 +131,7 @@ GTK will attempt to download and build some of these dependencies if it
cannot find them on your system. cannot find them on your system.
Additionally, you may want to look at projects that create a development Additionally, you may want to look at projects that create a development
environment for you, like [jhbuild](https://gitlab.gnome.org/GNOME/jhbuild) environment for you, like [jhbuild](https://wiki.gnome.org/HowDoI/Jhbuild)
and [gvsbuild](https://github.com/wingtk/gvsbuild). and [gvsbuild](https://github.com/wingtk/gvsbuild).
### Getting started ### Getting started

441
NEWS
View File

@@ -1,436 +1,11 @@
Overview of Changes in 4.17.0, xx-xx-xxxx Overview of Changes in 4.15.1, xx-xx-xxxx
=========================================
Overview of Changes in 4.16.2, 09-25-2024
=========================================
* GtkLabel:
- Fix centered text in RTL
* Gsk:
- Speed up some Vulkan operations
- Improve startup speed by avoiding initialization
of GL and Vulkan in most cases
- Reduce critials at startup to warnings
- Fix a crash on startup with some Vulkan drivers
- Fix a big texture leak in NGL
* Gdk:
- Speed up memory format conversions
* Wayland:
- Be more careful with mimetypes during DND or copy-paste
* Tools:
- builder-tool: Improve conversion of boxes
* Translation updates:
Brazilian Portuguese
Bulgarian
Catalan
Chinese (China)
Georgian
German
Hebrew
Indonesian
Persian
Polish
Portuguese
Slovenian
Spanish
Turkish
Ukrainian
Overview of Changes in 4.16.1, 09-16-2024
=========================================
* GtkFileChooser:
- Plug a memory leak
* GtkCalendar:
- Avoid ending up with invalid dates
* Printing:
- Fix initial printer selection in the print dialog
* Gsk:
- Fix shadows for opaque textures
- Fix a crash in a corner case
* Css:
- Make relative paths work again in theme files
* Accessibility:
- Fix detection of the Flatpak portal
* MacOS:
- Fix keyboard input in popovers
- Keep DND icons above regular windows
- Ignore events from DND icons
* Translation updates
Basque
British English
Bulgarian
Czech
Danish
Georgian
Hungarian
Lithuanian
Portuguese
Spanish
Swedish
Overview of Changes in 4.16.0, 09-06-2024
=========================================
Note: This release changes the default GSK renderer to be Vulkan,
on Wayland. Other platforms still use ngl. The intent of this change
is to use the best available platform APIs. You can still override
the renderer choice using the GSK_RENDERER environment variable.
We believe that most of the problems reported with the new renderers
during the 4.13 and 4.15 development cycles have been addressed by now.
But the new renderers and dmabuf support are using graphics drivers
in different ways than the old gl renderer, and trigger new driver bugs.
Therefore, it is recommended to use the latest mesa release (24.2)
with the new renderers.
* GtkScale:
- Fix positioning of scale values
* GtkEmojiChooser:
- Make Control-clicks work for the recent section
* GtkPopover:
- Make sure focus lands on the right widget when cascading
* GtkSpinButton:
- Disable Emoji input for numeric spin buttons
* GtkSingleSelection:
- Implement unselect_all
* Accssibility:
- Fix roles for radio buttons
- Check if ATs are listening before exporting trees
- Add a check for sandboxed accessibility bus
- Fix handling of the error message relation
- Turn criticals into debug messages
- Set expanded states properly in menus
* CSS:
- Fix a few issues on bigendian systems
- Avoid a crash with relative colors
* GSK:
- Use the right GL context when exporting textures
- Don't let colors influence depth decisions
- Allow uploading of mipmap levels when tiling textures
* GDK:
- Update keysyms from libX11 1.8.10
- Implement cpu-side mipmapping
- Use a thread pool for color conversions and mipmapping
* Vulkan:
- Fix drag surface offsets
* Wayland:
- Fix a crash
- Associate EGL windows with context later
* X11:
- Fix initial EGL context creation
- Fix a problem with GL context creation
* Broadway:
- Implement compute_size and request_layout
* MacOS:
- Set transparent backgroiund for toplevel windows
* Windows:
- Improve debug output
- Detect Mesas d3d12 driver and request GDI compat
* Demos:
- Set window icons in demos
- Add a 64k x 64k image to the image scaling demo
* Translation updates
Belarusian
Brazilian Portuguese
Catalan
Czech
Galician
German
Hebrew
Indonesian
Korean
Lithuanian
Persian
Polish
Portuguese
Slovenian
Spanish
Turkish
Ukrainian
Overview of Changes in 4.15.6, 08-26-2024
=========================================
* GtkCheckButton:
- Add a grouped style class for radio buttons
* GtkScale:
- Fix alignment and positioning problems
* Css:
- Fix crashes in the variable support
* Gsk:
- Make graphics offloading work better with kwin
- Make colorstate transfer functions more robust
- GC dead textures more agressively
- Only use a single render pass per frame
* GL:
- Round damage rectangles properly
- Use the shared context when creating textures
- Fix a file descriptor leak in dmabuf export
* Vulkan:
- Round damage rectangles properly
* Wayland:
- Work with the kwin implementation of xx-color-management-v4
* Windows:
- Make gtk_show_uri use SHOpenWithDialog()
- Enable incremental rendering with WGL
* Macos:
- Open context menus on Ctrl-left click
* Debugging:
- Show color state information in the inspector
- Collect input event traces in the recorder
- Add shortcuts for toggling recording: Super-r
and for screenshots: Super-c
- Split the GDK_DEBUG env var into GDK_DEBUG and GDK_DISABLE
- Add GDK_DISABLE=color-mgmt and GDK_DISABLE=offload
* Tools:
- Add a 'Paste as node' action in gtk4-node-editor
* Translations updates
Basque
Belarusian
Brazilian Portuguese
Chinese (China)
Georgian
Hebrew
Hindi
Russian
Slovenian
Turkish
Ukrainian
Overview of Changes in 4.15.5, 11-08-2024
=========================================
* GtkTextView:
- ADd GtkTextBufferCommitNotify
* CSS:
- Propagate color state information to GSK for many features:
colors, borders, shadows, text
* Gdk:
- Fix an fd leak in the Vulkan code
- Fix a leak of EGLSurfaces and DMA buffers
- Set the opaque region of surfaces automatically based on their content
* Gsk:
- Fix Emoji rendering in Vulkan
- Rework color handling to take color states into account
- Implement more powerful occlusion culling
- Minimize our use of renderpasses
* Macos:
- Fix window transparency
* Debugging:
- The inspector shows details about color states
* Deprecations:
- gdk_draw_context_begin/end_frame
- gdk_surface_set_opaque_region
* Build:
- Require gstreamer 1.24
* Translation updates
Romanian
Overview of Changes in 4.15.4, 30-07-2024
=========================================
* GtkPopover:
- Fix size allocation with wrapping labels
* GtkColumnView:
- Check column visibility when measuring
* CSS:
- Fix fallout from recent changes
- Make implementation of currentcolor inheritance match browsers
* Gdk:
- Introduce GdkColorState for encoding color space information
Currently, we support srgb, srgb-linear, rec2100-pq and rec2100-linear
- Add color states to GdkTexture, as well as to the texture builder
and downloader objects, and convert as necessary
- Add GdkMemoryTextureBuilder
- Attach color states when loading or saving textures
- Add GdkCicpParams to create color state objects for cicp tuples
- Drop GDK_DEBUG=vulkan-validate
Use VK_INSTEANCE_LAYERS=VK_LAYER_KHRONOS_validation instead
* Gsk:
- Improve caching of glyphs and textures
- Remove the uber shader
- Numerous bug fixes
- Fix corner cases in offload handling
- Implement occlusion culling for opaque content
- Allow offloading (some) transformed textures
- Take colorstate into account when compositing
- Add GDK_DEBUG=linear to opt into linear compositing
- Implement tiling for large textures
- Stop using descriptors and go back to simpler texture
management that should work better with older GL
- Use correct shader clip mode for glyphs
- Improve shadow rendering
* Media:
- Attach color states to textures obtained from gstreamer
* Wayland:
- Allow offloading GL textures via dmabuf export
- Suppot the xx-color-management-v4 protocol
* Deprecations:
- GskGLShader and the render node
* Tools:
- Improve the rendernode tool extract command
- Add an image tool that is about manipulating textures
* Build:
- GTK now requires a C11 compiler
* Translation updates
Georgian
Hebrew
Hindi
Occitan
Slovenian
Overview of Changes in 4.15.3, 29-06-2024
=========================================
* Accessibility:
- Only emit notifications when cursor positions change in GtkText
- Fix handling of help text properties
* CSS:
- Fix some crashes introduced in recent currentcolor changes
* DND:
- Avoid a critical
* Documentation:
- Fix many oversights and missing docs
* maxOS:
- Add native keyboard shortcuts
Overview of Changes in 4.15.2, 28-06-2024
=========================================
* GtkFileChooserWidget:
- Plug some memory leaks
- Make Ctrl-Shift-N create a new folder
* GtkPopover:
- Handle resizing and position changes better
* CSS:
- Support color(), oklab(), etc (https://www.w3.org/TR/css-color-4/)
- Support color-mix() (https://www.w3.org/TR/css-color-5/)
- Support relative colors (https://www.w3.org/TR/css-color-5/)
- Support more colorspaces in color()
- Allow percentages for opacity
- Handle currentcolor more correctly
* Accessibility:
- Avoid markup when reading labels
* GSK:
- Subset fonts when serializing node trees
- Make ngl export render_texture results as dmabufs
* Wayland:
- Use xdg-dialog protocol for attached dialogs
* Windows:
- Build with UNICODE
* macOS:
- Implement fullscreen-on-monitor
* Documentation:
- Widget shortcuts and actions are now described in the docs
* Debugging:
- Add GTK_DEBUG=css for warning about deprecated css syntax
* Tools:
- rendernode-tool: Add an extract command for data urls
* Deprecations:
- CSS Color functions shade(), lighter(), darker(), alpha(), mix()
* Translation updates:
Czech
Hebrew
Serbian
Overview of Changes in 4.15.1, 21-05-2024
========================================= =========================================
* GtkGraphicsOffload: * GtkGraphicsOffload:
- Don't crash without a child - Don't crash without a child
* GtkSpinner:
- Don't animate when unmapped
* CSS: * CSS:
- Support the :root selector - Support the :root selector
- Support variables and custom properties (https://www.w3.org/TR/css-variables-1/)
- Implement math functions (https://www.w3.org/TR/css-values-4/)
- Support modern syntax and calc in rgb() and hsl()
* Icontheme: * Icontheme:
- Make symbolic svg loading more efficient - Make symbolic svg loading more efficient
@@ -439,22 +14,19 @@ Overview of Changes in 4.15.1, 21-05-2024
* Accessibility: * Accessibility:
- Make the gtk-demo sidebar search more accessible - Make the gtk-demo sidebar search more accessible
- Stop emitting focus events - Stop emitting focus events
- Realize child contexts when necessary
* GDK: * GDK:
- Support XDG_ACTIVATION_TOKEN - Support XDG_ACTIVATION_TOKEN
- dmabuf: Be more defensive when importing unknown formats to GL - dmabuf: Be more defensive when importing unknown formats to GL
- dmabuf: Use narrow range for YUV - dmabuf: Use narrow range for YUV
- vulkan: Recreate swapchains when necessary or beneficial
* GSK: * GSK:
- Improve logging for GDK_DEBUG=offload - Improve logging for GDK_DEBUG=offload
- Improve logging for GSK_DEBUG=renderer - Improve logging for GSK_DEBUG=renderer
- gpu: Warn about inefficient texture import - gpu: Warn about inefficient texture import
- gpu: Handle tiny offscreens correctly - gpu: Handle tiny offscreens correctly
- vulkan: Add profiler marks in various places - vulkan: Add profiler marks in various places
- vulkan: Fix a problem with imported dmabufs showing up black - vulkan: Fix a problem with imported dmabufs showing up black
- cairo: Speed up mask nodes, since we use them for symbolic icons
* Wayland: * Wayland:
- Use wl_compositor version 6 - Use wl_compositor version 6
@@ -467,22 +39,13 @@ Overview of Changes in 4.15.1, 21-05-2024
* Debugging: * Debugging:
- Show more texture details in the recorder - Show more texture details in the recorder
- Use GTK_DEBUG=css to see CSS deprecations
* macOS: * macOS:
- Fix problems with events handed back to the OS - Fix problems with events handed back to the OS
- Respect GDK_DEBUG=default-settings - Respect GDK_DEBUG=default-settings
- Allow applictions to handle Dock > Quit
* Deprecations:
- Use of @name colors in CSS
* Translation updates: * Translation updates:
Catalan
Georgian
Hungarian
Korean Korean
Portuguese
Turkish Turkish

View File

@@ -39,21 +39,18 @@ Nightly documentation can be found at
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk4/ - Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk4/
Nightly flatpaks of our demos can be installed from the Nightly flatpaks of our demos can be installed from the
[GNOME Nightly](https://nightly.gnome.org/) repository: [GNOME Nightly](https://wiki.gnome.org/Apps/Nightly) repository:
- `flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo`
```sh - `flatpak install gnome-nightly org.gtk.Demo4`
flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo - `flatpak install gnome-nightly org.gtk.WidgetFactory4`
flatpak install gnome-nightly org.gtk.Demo4 - `flatpak install gnome-nightly org.gtk.IconBrowser4`
flatpak install gnome-nightly org.gtk.WidgetFactory4
flatpak install gnome-nightly org.gtk.IconBrowser4
```
Building and installing Building and installing
----------------------- -----------------------
In order to build GTK you will need: In order to build GTK you will need:
- [a C11 compatible compiler](https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/toolchain-requirements.md) - [a C99 compatible compiler](https://wiki.gnome.org/Projects/GLib/CompilerRequirements)
- [Python 3](https://www.python.org/) - [Python 3](https://www.python.org/)
- [Meson](http://mesonbuild.com) - [Meson](http://mesonbuild.com)
- [Ninja](https://ninja-build.org) - [Ninja](https://ninja-build.org)
@@ -136,13 +133,9 @@ In the bug report please include:
- which version of GTK you are using - which version of GTK you are using
- what operating system and version - what operating system and version
- what windowing system (X11 or Wayland)
- what graphics driver / mesa version
- for Linux, which distribution - for Linux, which distribution
- if you built GTK, the list of options used to configure the build - if you built GTK, the list of options used to configure the build
Most of this information can be found in the GTK inspector.
And anything else you think is relevant. And anything else you think is relevant.
* How to reproduce the bug. * How to reproduce the bug.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
uniform float u_time;
void
mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
vec2 pos = (fragCoord.xy * 2.0 - resolution.xy)/ min (resolution.x, resolution.y) ;
float t0 = sin ((u_time + 0.00)*1.0);
float t1 = sin ((u_time + 0.30)*0.4);
float t2 = cos ((u_time + 0.23)*0.9);
float t3 = cos ((u_time + 0.41)*0.6);
float t4 = cos ((u_time + 0.11)*0.3);
vec2 p0 = vec2 (t1, t0) ;
vec2 p1 = vec2 (t2, t3) ;
vec2 p2 = vec2 (t4, t3) ;
float r = 1.0/distance (pos, p0);
float g = 1.0/distance (pos, p1);
float b = 1.0/distance (pos, p2);
float sum = r + g + b;
float alpha = 1.0 - pow (1.0/(sum), 40.0)*pow (10.0, 40.0*0.7);
fragColor = vec4 (r*0.5, g*0.5, b*0.5, 1.0) * alpha;
}

226
demos/gtk-demo/cogs2.glsl Normal file
View File

@@ -0,0 +1,226 @@
uniform float iTime;
// Originally from: https://www.shadertoy.com/view/3ljyDD
// License CC0: Hexagonal tiling + cog wheels
// Nothing fancy, just hexagonal tiling + cog wheels
#define PI 3.141592654
#define TAU (2.0*PI)
#define MROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
float hash(in vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
float pcos(float a) {
return 0.5 + 0.5*cos(a);
}
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(c*p.x + s*p.y, -s*p.x + c*p.y);
}
float modPolar(inout vec2 p, float repetitions) {
float angle = 2.0*PI/repetitions;
float a = atan(p.y, p.x) + angle/2.;
float r = length(p);
float c = floor(a/angle);
a = mod(a,angle) - angle/2.;
p = vec2(cos(a), sin(a))*r;
// For an odd number of repetitions, fix cell index of the cell in -x direction
// (cell index would be e.g. -5 and 5 in the two halves of the cell):
if (abs(c) >= (repetitions/2.0)) c = abs(c);
return c;
}
float pmin(float a, float b, float k) {
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
const vec2 sz = vec2(1.0, sqrt(3.0));
const vec2 hsz = 0.5*sz;
const float smallCount = 16.0;
vec2 hextile(inout vec2 p) {
// See Art of Code: Hexagonal Tiling Explained!
// https://www.youtube.com/watch?v=VmrIDyYiJBA
vec2 p1 = mod(p, sz)-hsz;
vec2 p2 = mod(p - hsz*1.0, sz)-hsz;
vec2 p3 = mix(p2, p1, vec2(length(p1) < length(p2)));
vec2 n = p3 - p;
p = p3;
return n;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float box(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
float unevenCapsule(vec2 p, float r1, float r2, float h) {
p.x = abs(p.x);
float b = (r1-r2)/h;
float a = sqrt(1.0-b*b);
float k = dot(p,vec2(-b,a));
if( k < 0.0 ) return length(p) - r1;
if( k > a*h ) return length(p-vec2(0.0,h)) - r2;
return dot(p, vec2(a,b) ) - r1;
}
float cogwheel(vec2 p, float innerRadius, float outerRadius, float cogs, float holes) {
float cogWidth = 0.25*innerRadius*TAU/cogs;
float d0 = circle(p, innerRadius);
vec2 icp = p;
modPolar(icp, holes);
icp -= vec2(innerRadius*0.55, 0.0);
float d1 = circle(icp, innerRadius*0.25);
vec2 cp = p;
modPolar(cp, cogs);
cp -= vec2(innerRadius, 0.0);
float d2 = unevenCapsule(cp.yx, cogWidth, cogWidth*0.75, (outerRadius-innerRadius));
float d3 = circle(p, innerRadius*0.20);
float d = 1E6;
d = min(d, d0);
d = pmin(d, d2, 0.5*cogWidth);
d = min(d, d2);
d = max(d, -d1);
d = max(d, -d3);
return d;
}
float ccell1(vec2 p, float r) {
float d = 1E6;
const float bigCount = 60.0;
vec2 cp0 = p;
rot(cp0, -iTime*TAU/bigCount);
float d0 = cogwheel(cp0, 0.36, 0.38, bigCount, 5.0);
vec2 cp1 = p;
float nm = modPolar(cp1, 6.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
d = min(d, d0);
d = min(d, d1);
return d;
}
float ccell2(vec2 p, float r) {
float d = 1E6;
vec2 cp0 = p;
float nm = modPolar(cp0, 6.0);
vec2 cp1 = cp0;
const float off = 0.275;
const float count = smallCount + 2.0;
cp0 -= vec2(off, 0.0);
rot(cp0, 0.+TAU*nm/2.0 - iTime*TAU/count);
float d0 = cogwheel(cp0, 0.09, 0.105, count, 5.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
float l = length(p);
float d2 = l - (off+0.055);
float d3 = d2 + 0.020;;
vec2 tp0 = p;
modPolar(tp0, 60.0);
tp0.x -= off;
float d4 = box(tp0, vec2(0.0125, 0.005));
float ctime = -(iTime*0.05 + r)*TAU;
vec2 tp1 = p;
rot(tp1, ctime*12.0);
tp1.x -= 0.13;
float d5 = box(tp1, vec2(0.125, 0.005));
vec2 tp2 = p;
rot(tp2, ctime);
tp2.x -= 0.13*0.5;
float d6 = box(tp2, vec2(0.125*0.5, 0.0075));
float d7 = l - 0.025;
float d8 = l - 0.0125;
d = min(d, d0);
d = min(d, d1);
d = min(d, d2);
d = max(d, -d3);
d = min(d, d4);
d = min(d, d5);
d = min(d, d6);
d = min(d, d7);
d = max(d, -d8);
return d;
}
float df(vec2 p, float scale, inout vec2 nn) {
p /= scale;
nn = hextile(p);
nn = floor(nn + 0.5);
float r = hash(nn);
float d;;
if (r < 0.5) {
d = ccell1(p, r);
} else {
d = ccell2(p, r);
}
return d*scale;
}
vec3 postProcess(vec3 col, vec2 q) {
//col = saturate(col);
col=pow(clamp(col,0.0,1.0),vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
return col;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) {
vec2 q = fragCoord/resolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= resolution.x/resolution.y;
float tm = iTime*0.1;
p += vec2(cos(tm), sin(tm*sqrt(0.5)));
float z = mix(0.5, 1.0, pcos(tm*sqrt(0.3)));
float aa = 4.0 / resolution.y;
vec2 nn = vec2(0.0);
float d = df(p, z, nn);
vec3 col = vec3(160.0)/vec3(255.0);
vec3 baseCol = vec3(0.3);
vec4 logoCol = vec4(baseCol, 1.0)*smoothstep(-aa, 0.0, -d);
col = mix(col, logoCol.xyz, pow(logoCol.w, 8.0));
col += 0.4*pow(abs(sin(20.0*d)), 0.6);
col = postProcess(col, q);
fragColor = vec4(col, 1.0);
}

View File

@@ -0,0 +1,27 @@
uniform float progress;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
vec4 getFromColor (vec2 uv) {
return GskTexture(u_texture1, uv);
}
vec4 getToColor (vec2 uv) {
return GskTexture(u_texture2, uv);
}
// Source: https://gl-transitions.com/editor/crosswarp
// Author: Eke Péter <peterekepeter@gmail.com>
// License: MIT
vec4 transition(vec2 p) {
float x = progress;
x=smoothstep(.0,1.0,(x*2.0+p.x-1.0));
return mix(getFromColor((p-.5)*(1.-x)+.5), getToColor((p-.5)*x+.5), x);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
fragColor = transition(uv);
}

View File

@@ -146,6 +146,21 @@
<file>cogs.glsl</file> <file>cogs.glsl</file>
<file>glowingstars.glsl</file> <file>glowingstars.glsl</file>
</gresource> </gresource>
<gresource prefix="/gltransition">
<file>gtkshaderstack.c</file>
<file>gtkshaderstack.h</file>
<file>gtkshaderbin.h</file>
<file>gtkshaderbin.c</file>
<file>gskshaderpaintable.h</file>
<file>gskshaderpaintable.c</file>
<file>wind.glsl</file>
<file>radial.glsl</file>
<file>crosswarp.glsl</file>
<file>kaleidoscope.glsl</file>
<file>cogs2.glsl</file>
<file>ripple.glsl</file>
<file>background.glsl</file>
</gresource>
<gresource prefix="/iconscroll"> <gresource prefix="/iconscroll">
<file>iconscroll.ui</file> <file>iconscroll.ui</file>
</gresource> </gresource>
@@ -281,6 +296,7 @@
<file>gears.c</file> <file>gears.c</file>
<file>gestures.c</file> <file>gestures.c</file>
<file>glarea.c</file> <file>glarea.c</file>
<file>gltransition.c</file>
<file>headerbar.c</file> <file>headerbar.c</file>
<file>hypertext.c</file> <file>hypertext.c</file>
<file>iconscroll.c</file> <file>iconscroll.c</file>
@@ -438,10 +454,6 @@
<file>icons/16x16/categories/applications-other.png</file> <file>icons/16x16/categories/applications-other.png</file>
<file>icons/48x48/status/starred.png</file> <file>icons/48x48/status/starred.png</file>
<file alias="icons/scalable/apps/org.gtk.Demo4.svg">data/scalable/apps/org.gtk.Demo4.svg</file> <file alias="icons/scalable/apps/org.gtk.Demo4.svg">data/scalable/apps/org.gtk.Demo4.svg</file>
<file>portland-rose-thumbnail.png</file>
<file>large-image-thumbnail.png</file>
<file compressed="true">large-image.png</file>
<file compressed="true">Moby-Dick.txt</file>
</gresource> </gresource>
<gresource prefix="/org/gtk/Demo4/gtk"> <gresource prefix="/org/gtk/Demo4/gtk">
<file preprocess="xml-stripblanks">help-overlay.ui</file> <file preprocess="xml-stripblanks">help-overlay.ui</file>

View File

@@ -55,7 +55,7 @@ mode_switch_state_set (GtkSwitch *sw,
{ {
gtk_widget_set_visible (label, TRUE); gtk_widget_set_visible (label, TRUE);
gtk_accessible_update_relation (GTK_ACCESSIBLE (sw), gtk_accessible_update_relation (GTK_ACCESSIBLE (sw),
GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE, label, NULL, GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE, label,
-1); -1);
gtk_accessible_update_state (GTK_ACCESSIBLE (sw), gtk_accessible_update_state (GTK_ACCESSIBLE (sw),
GTK_ACCESSIBLE_STATE_INVALID, GTK_ACCESSIBLE_INVALID_TRUE, GTK_ACCESSIBLE_STATE_INVALID, GTK_ACCESSIBLE_INVALID_TRUE,

View File

@@ -9,6 +9,7 @@
#include "gtkfishbowl.h" #include "gtkfishbowl.h"
#include "gtkgears.h" #include "gtkgears.h"
#include "gskshaderpaintable.h"
#include "nodewidget.h" #include "nodewidget.h"
#include "graphwidget.h" #include "graphwidget.h"
@@ -151,6 +152,44 @@ create_switch (void)
return w; return w;
} }
static gboolean
update_paintable (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GskShaderPaintable *paintable;
gint64 frame_time;
paintable = GSK_SHADER_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget)));
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
gsk_shader_paintable_update_time (paintable, 0, frame_time);
return G_SOURCE_CONTINUE;
}
static GtkWidget *
create_cogs (void)
{
GtkWidget *picture;
static GskGLShader *cog_shader = NULL;
GdkPaintable *paintable;
if (cog_shader == NULL)
cog_shader = gsk_gl_shader_new_from_resource ("/gltransition/cogs2.glsl");
paintable = gsk_shader_paintable_new (g_object_ref (cog_shader), NULL);
picture = gtk_picture_new_for_paintable (paintable);
gtk_widget_set_size_request (picture, 150, 75);
gtk_widget_add_tick_callback (picture, update_paintable, NULL, NULL);
return picture;
}
static gboolean
check_cogs (GtkFishbowl *fb)
{
return GSK_IS_GL_RENDERER (gtk_native_get_renderer (gtk_widget_get_native (GTK_WIDGET (fb))));
}
static void static void
mapped (GtkWidget *w) mapped (GtkWidget *w)
{ {
@@ -200,6 +239,7 @@ static const struct {
{ "Gears", create_gears, NULL }, { "Gears", create_gears, NULL },
{ "Switch", create_switch, NULL }, { "Switch", create_switch, NULL },
{ "Menubutton", create_menu_button, NULL }, { "Menubutton", create_menu_button, NULL },
{ "Shader", create_cogs, check_cogs },
{ "Tiger", create_tiger, NULL }, { "Tiger", create_tiger, NULL },
{ "Graph", create_graph, NULL }, { "Graph", create_graph, NULL },
}; };

View File

@@ -276,7 +276,7 @@ gtk_font_plane_class_init (GtkFontPlaneClass *class)
GtkWidget * GtkWidget *
gtk_font_plane_new (GtkAdjustment *weight_adj, gtk_font_plane_new (GtkAdjustment *weight_adj,
GtkAdjustment *width_adj) GtkAdjustment *width_adj)
{ {
return g_object_new (GTK_TYPE_FONT_PLANE, return g_object_new (GTK_TYPE_FONT_PLANE,
"weight-adjustment", weight_adj, "weight-adjustment", weight_adj,

View File

@@ -55,7 +55,7 @@ struct _GtkFontPlaneClass
GType gtk_font_plane_get_type (void) G_GNUC_CONST; GType gtk_font_plane_get_type (void) G_GNUC_CONST;
GtkWidget * gtk_font_plane_new (GtkAdjustment *weight_adj, GtkWidget * gtk_font_plane_new (GtkAdjustment *width_adj,
GtkAdjustment *width_adj); GtkAdjustment *weight_adj);
G_END_DECLS G_END_DECLS

View File

@@ -0,0 +1,362 @@
/* OpenGL/Transitions and Effects
* #Keywords: OpenGL, shader, effect
*
* Create transitions between pages using a custom fragment shader.
*
* The example transitions here are taken from gl-transitions.com, and you
* can edit the shader code itself on the last page of the stack.
*
* The transitions work with arbitrary content. We use images, shaders
* GL areas and plain old widgets to demonstrate this.
*
* The demo also shows some over-the-top effects like wobbly widgets,
* and animated backgrounds.
*/
#include <math.h>
#include <gtk/gtk.h>
#include "gtkshaderstack.h"
#include "gtkshaderbin.h"
#include "gtkshadertoy.h"
#include "gskshaderpaintable.h"
static GtkWidget *demo_window = NULL;
static void
close_window (GtkWidget *widget)
{
/* Reset the state */
demo_window = NULL;
}
static void
text_changed (GtkTextBuffer *buffer,
GtkWidget *button)
{
gtk_widget_set_visible (button, TRUE);
}
static void
apply_text (GtkWidget *button,
GtkTextBuffer *buffer)
{
GtkWidget *stack;
GskGLShader *shader;
GtkTextIter start, end;
char *text;
stack = g_object_get_data (G_OBJECT (button), "the-stack");
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
GBytes *bytes = g_bytes_new_take (text, strlen (text));
shader = gsk_gl_shader_new_from_bytes (bytes);
gtk_shader_stack_set_shader (GTK_SHADER_STACK (stack), shader);
g_object_unref (shader);
g_bytes_unref (bytes);
gtk_widget_set_visible (button, FALSE);
}
static void
go_back (GtkWidget *button,
GtkWidget *stack)
{
gtk_shader_stack_transition (GTK_SHADER_STACK (stack), FALSE);
}
static void
go_forward (GtkWidget *button,
GtkWidget *stack)
{
gtk_shader_stack_transition (GTK_SHADER_STACK (stack), TRUE);
}
static void
clicked_cb (GtkGestureClick *gesture,
guint n_pressed,
double x,
double y,
gpointer data)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}
static GtkWidget *
ripple_bin_new (void)
{
GtkWidget *bin = gtk_shader_bin_new ();
static GskGLShader *shader = NULL;
if (shader == NULL)
shader = gsk_gl_shader_new_from_resource ("/gltransition/ripple.glsl");
gtk_shader_bin_add_shader (GTK_SHADER_BIN (bin), shader, GTK_STATE_FLAG_PRELIGHT, GTK_STATE_FLAG_PRELIGHT, 20);
return bin;
}
static GtkWidget *
new_shadertoy (const char *path)
{
GBytes *shader;
GtkWidget *toy;
toy = gtk_shadertoy_new ();
shader = g_resources_lookup_data (path, 0, NULL);
gtk_shadertoy_set_image_shader (GTK_SHADERTOY (toy),
g_bytes_get_data (shader, NULL));
g_bytes_unref (shader);
return toy;
}
static gboolean
update_paintable (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GskShaderPaintable *paintable;
gint64 frame_time;
paintable = GSK_SHADER_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget)));
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
gsk_shader_paintable_update_time (paintable, 0, frame_time);
return G_SOURCE_CONTINUE;
}
static GtkWidget *
make_shader_stack (const char *name,
const char *resource_path,
int active_child,
GtkWidget *scale)
{
GtkWidget *stack, *child, *widget, *vbox, *hbox, *bin;
GtkWidget *label, *button, *tv;
GskGLShader *shader;
GObjectClass *class;
GParamSpecFloat *pspec;
GtkAdjustment *adjustment;
GtkTextBuffer *buffer;
GBytes *bytes;
GtkEventController *controller;
GdkPaintable *paintable;
stack = gtk_shader_stack_new ();
shader = gsk_gl_shader_new_from_resource (resource_path);
gtk_shader_stack_set_shader (GTK_SHADER_STACK (stack), shader);
g_object_unref (shader);
child = gtk_picture_new_for_resource ("/css_blendmodes/ducky.png");
gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
shader = gsk_gl_shader_new_from_resource ("/gltransition/cogs2.glsl");
paintable = gsk_shader_paintable_new (shader, NULL);
child = gtk_picture_new_for_paintable (paintable);
gtk_widget_add_tick_callback (child, update_paintable, NULL, NULL);
gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
child = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
child = new_shadertoy ("/shadertoy/neon.glsl");
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
class = g_type_class_ref (GTK_TYPE_SHADER_STACK);
pspec = G_PARAM_SPEC_FLOAT (g_object_class_find_property (class, "duration"));
adjustment = gtk_range_get_adjustment (GTK_RANGE (scale));
if (gtk_adjustment_get_lower (adjustment) == 0.0 &&
gtk_adjustment_get_upper (adjustment) == 0.0)
{
gtk_adjustment_configure (adjustment,
pspec->default_value,
pspec->minimum,
pspec->maximum,
0.1, 0.5, 0);
}
g_type_class_unref (class);
g_object_bind_property (adjustment, "value",
stack, "duration",
G_BINDING_DEFAULT);
widget = gtk_scrolled_window_new ();
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (widget), TRUE);
gtk_widget_set_hexpand (widget, TRUE);
gtk_widget_set_vexpand (widget, TRUE);
controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
g_signal_connect (controller, "released", G_CALLBACK (clicked_cb), NULL);
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
gtk_widget_add_controller (GTK_WIDGET (widget), controller);
tv = gtk_text_view_new ();
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (tv), 4);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (tv), 4);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (tv), 4);
gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (tv), 4);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
bytes = g_resources_lookup_data (resource_path, 0, NULL);
gtk_text_buffer_set_text (buffer,
(const char *)g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (widget), tv);
gtk_box_append (GTK_BOX (child), widget);
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
gtk_shader_stack_set_active (GTK_SHADER_STACK (stack), active_child);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
widget = gtk_center_box_new ();
label = gtk_label_new (name);
gtk_widget_add_css_class (label, "title-4");
gtk_widget_set_size_request (label, -1, 26);
gtk_center_box_set_center_widget (GTK_CENTER_BOX (widget), label);
button = gtk_button_new_from_icon_name ("view-refresh-symbolic");
g_signal_connect (buffer, "changed", G_CALLBACK (text_changed), button);
g_object_set_data (G_OBJECT (button), "the-stack", stack);
g_signal_connect (button, "clicked", G_CALLBACK (apply_text), buffer);
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_widget_add_css_class (button, "small");
gtk_widget_set_visible (button, FALSE);
gtk_center_box_set_end_widget (GTK_CENTER_BOX (widget), button);
gtk_box_append (GTK_BOX (vbox), widget);
GtkWidget *bin2 = ripple_bin_new ();
gtk_shader_bin_set_child (GTK_SHADER_BIN (bin2), stack);
gtk_box_append (GTK_BOX (vbox), bin2);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_set_halign (hbox, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (vbox), hbox);
button = gtk_button_new_from_icon_name ("go-previous-symbolic");
g_signal_connect (button, "clicked", G_CALLBACK (go_back), stack);
bin = ripple_bin_new ();
gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
gtk_box_append (GTK_BOX (hbox), bin);
button = gtk_button_new_from_icon_name ("go-next-symbolic");
g_signal_connect (button, "clicked", G_CALLBACK (go_forward), stack);
bin = ripple_bin_new ();
gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
gtk_box_append (GTK_BOX (hbox), bin);
return vbox;
}
static void
remove_provider (gpointer data)
{
GtkStyleProvider *provider = GTK_STYLE_PROVIDER (data);
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
g_object_unref (provider);
}
static GtkWidget *
create_gltransition_window (GtkWidget *do_widget)
{
GtkWidget *window, *headerbar, *scale, *outer_grid, *grid, *background;
GdkPaintable *paintable;
GtkCssProvider *provider;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Transitions and Effects");
headerbar = gtk_header_bar_new ();
scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, NULL);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_widget_set_size_request (scale, 100, -1);
gtk_widget_set_tooltip_text (scale, "Transition duration");
gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), scale);
gtk_window_set_titlebar (GTK_WINDOW (window), headerbar);
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
outer_grid = gtk_grid_new ();
gtk_window_set_child (GTK_WINDOW (window), outer_grid);
paintable = gsk_shader_paintable_new (gsk_gl_shader_new_from_resource ("/gltransition/background.glsl"), NULL);
background = gtk_picture_new_for_paintable (paintable);
gtk_widget_add_tick_callback (background, update_paintable, NULL, NULL);
gtk_grid_attach (GTK_GRID (outer_grid),
background,
0, 0, 1, 1);
grid = gtk_grid_new ();
gtk_grid_attach (GTK_GRID (outer_grid),
grid,
0, 0, 1, 1);
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
gtk_widget_set_valign (grid, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start (grid, 12);
gtk_widget_set_margin_end (grid, 12);
gtk_widget_set_margin_top (grid, 12);
gtk_widget_set_margin_bottom (grid, 12);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE);
gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
gtk_grid_attach (GTK_GRID (grid),
make_shader_stack ("Wind", "/gltransition/wind.glsl", 0, scale),
0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid),
make_shader_stack ("Radial", "/gltransition/radial.glsl", 1, scale),
1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid),
make_shader_stack ("Crosswarp", "/gltransition/crosswarp.glsl", 2, scale),
0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid),
make_shader_stack ("Kaleidoscope", "/gltransition/kaleidoscope.glsl", 3, scale),
1, 1, 1, 1);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_string (provider, "button.small { padding: 0; }");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_set_data_full (G_OBJECT (window), "provider", provider, remove_provider);
return window;
}
GtkWidget *
do_gltransition (GtkWidget *do_widget)
{
if (!demo_window)
demo_window = create_gltransition_window (do_widget);
if (!gtk_widget_get_visible (demo_window))
gtk_widget_set_visible (demo_window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (demo_window));
return demo_window;
}

View File

@@ -0,0 +1,334 @@
/*
* Copyright © 2020 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gskshaderpaintable.h"
/**
* GskShaderPaintable:
*
* `GskShaderPaintable` is an implementation of the `GdkPaintable` interface
* that uses a `GskGLShader` to create pixels.
*
* You can set the uniform data that the shader needs for rendering
* using gsk_shader_paintable_set_args(). This function can
* be called repeatedly to change the uniform data for the next
* snapshot.
*
* Commonly, time is passed to shaders as a float uniform containing
* the elapsed time in seconds. The convenience API
* gsk_shader_paintable_update_time() can be called from a `GtkTickCallback`
* to update the time based on the frame time of the frame clock.
*/
struct _GskShaderPaintable
{
GObject parent_instance;
GskGLShader *shader;
GBytes *args;
gint64 start_time;
};
struct _GskShaderPaintableClass
{
GObjectClass parent_class;
};
enum {
PROP_0,
PROP_SHADER,
PROP_ARGS,
N_PROPS,
};
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gsk_shader_paintable_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (paintable);
gtk_snapshot_push_gl_shader (snapshot, self->shader, &GRAPHENE_RECT_INIT(0, 0, width, height), g_bytes_ref (self->args));
gtk_snapshot_pop (snapshot);
}
static void
gsk_shader_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gsk_shader_paintable_paintable_snapshot;
}
G_DEFINE_TYPE_EXTENDED (GskShaderPaintable, gsk_shader_paintable, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gsk_shader_paintable_paintable_init))
static void
gsk_shader_paintable_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
switch (prop_id)
{
case PROP_SHADER:
gsk_shader_paintable_set_shader (self, g_value_get_object (value));
break;
case PROP_ARGS:
gsk_shader_paintable_set_args (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gsk_shader_paintable_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
switch (prop_id)
{
case PROP_SHADER:
g_value_set_object (value, self->shader);
break;
case PROP_ARGS:
g_value_set_boxed (value, self->args);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gsk_shader_paintable_finalize (GObject *object)
{
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
g_clear_pointer (&self->args, g_bytes_unref);
g_clear_object (&self->shader);
G_OBJECT_CLASS (gsk_shader_paintable_parent_class)->finalize (object);
}
static void
gsk_shader_paintable_class_init (GskShaderPaintableClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gsk_shader_paintable_get_property;
gobject_class->set_property = gsk_shader_paintable_set_property;
gobject_class->finalize = gsk_shader_paintable_finalize;
properties[PROP_SHADER] =
g_param_spec_object ("shader", "Shader", "The shader",
GSK_TYPE_GL_SHADER,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_ARGS] =
g_param_spec_boxed ("args", "Arguments", "The uniform arguments",
G_TYPE_BYTES,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gsk_shader_paintable_init (GskShaderPaintable *self)
{
}
/**
* gsk_shader_paintable_new:
* @shader: (transfer full) (nullable): the shader to use
* @data: (transfer full) (nullable): uniform data
*
* Creates a paintable that uses the @shader to create
* pixels. The shader must not require input textures.
* If @data is %NULL, all uniform values are set to zero.
*
* Returns: (transfer full): a new `GskShaderPaintable`
*/
GdkPaintable *
gsk_shader_paintable_new (GskGLShader *shader,
GBytes *data)
{
GdkPaintable *ret;
g_return_val_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader), NULL);
if (shader && !data)
{
int size = gsk_gl_shader_get_args_size (shader);
data = g_bytes_new_take (g_new0 (guchar, size), size);
}
ret = g_object_new (GSK_TYPE_SHADER_PAINTABLE,
"shader", shader,
"args", data,
NULL);
g_clear_object (&shader);
g_clear_pointer (&data, g_bytes_unref);
return ret;
}
/**
* gsk_shader_paintable_set_shader:
* @self: a `GskShaderPaintable`
* @shader: the `GskGLShader` to use
*
* Sets the shader that the paintable will use
* to create pixels. The shader must not require
* input textures.
*/
void
gsk_shader_paintable_set_shader (GskShaderPaintable *self,
GskGLShader *shader)
{
g_return_if_fail (GSK_IS_SHADER_PAINTABLE (self));
g_return_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader));
g_return_if_fail (shader == NULL || gsk_gl_shader_get_n_textures (shader) == 0);
if (!g_set_object (&self->shader, shader))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHADER]);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
g_clear_pointer (&self->args, g_bytes_unref);
}
/**
* gsk_shader_paintable_get_shader:
* @self: a `GskShaderPaintable`
*
* Returns the shader that the paintable is using.
*
* Returns: (transfer none): the `GskGLShader` that is used
*/
GskGLShader *
gsk_shader_paintable_get_shader (GskShaderPaintable *self)
{
g_return_val_if_fail (GSK_IS_SHADER_PAINTABLE (self), NULL);
return self->shader;
}
/**
* gsk_shader_paintable_set_args:
* @self: a `GskShaderPaintable`
* @data: Data block with uniform data for the shader
*
* Sets the uniform data that will be passed to the
* shader when rendering. The @data will typically
* be produced by a `GskUniformDataBuilder`.
*
* Note that the @data should be considered immutable
* after it has been passed to this function.
*/
void
gsk_shader_paintable_set_args (GskShaderPaintable *self,
GBytes *data)
{
g_return_if_fail (GSK_IS_SHADER_PAINTABLE (self));
g_return_if_fail (data == NULL || g_bytes_get_size (data) == gsk_gl_shader_get_args_size (self->shader));
g_clear_pointer (&self->args, g_bytes_unref);
if (data)
self->args = g_bytes_ref (data);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ARGS]);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
/**
* gsk_shader_paintable_get_args:
* @self: a `GskShaderPaintable`
*
* Returns the uniform data set with
* gsk_shader_paintable_get_args().
*
* Returns: (transfer none): the uniform data
*/
GBytes *
gsk_shader_paintable_get_args (GskShaderPaintable *self)
{
g_return_val_if_fail (GSK_IS_SHADER_PAINTABLE (self), NULL);
return self->args;
}
/**
* gsk_shader_paintable_update_time:
* @self: a `GskShaderPaintable`
* @time_idx: the index of the uniform for time in seconds as float
* @frame_time: the current frame time, as returned by `GdkFrameClock`
*
* This function is a convenience wrapper for
* gsk_shader_paintable_set_args() that leaves all
* uniform values unchanged, except for the uniform with
* index @time_idx, which will be set to the elapsed time
* in seconds, since the first call to this function.
*
* This function is usually called from a `GtkTickCallback`.
*/
void
gsk_shader_paintable_update_time (GskShaderPaintable *self,
int time_idx,
gint64 frame_time)
{
GskShaderArgsBuilder *builder;
GBytes *args;
float time;
if (self->start_time == 0)
self->start_time = frame_time;
time = (frame_time - self->start_time) / (float)G_TIME_SPAN_SECOND;
builder = gsk_shader_args_builder_new (self->shader, self->args);
gsk_shader_args_builder_set_float (builder, time_idx, time);
args = gsk_shader_args_builder_free_to_args (builder);
gsk_shader_paintable_set_args (self, args);
g_bytes_unref (args);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright © 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#pragma once
#include <gdk/gdk.h>
#include <gsk/gsk.h>
G_BEGIN_DECLS
#define GSK_TYPE_SHADER_PAINTABLE (gsk_shader_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GskShaderPaintable, gsk_shader_paintable, GSK, SHADER_PAINTABLE, GObject)
GdkPaintable * gsk_shader_paintable_new (GskGLShader *shader,
GBytes *data);
GskGLShader * gsk_shader_paintable_get_shader (GskShaderPaintable *self);
void gsk_shader_paintable_set_shader (GskShaderPaintable *self,
GskGLShader *shader);
GBytes * gsk_shader_paintable_get_args (GskShaderPaintable *self);
void gsk_shader_paintable_set_args (GskShaderPaintable *self,
GBytes *data);
void gsk_shader_paintable_update_time (GskShaderPaintable *self,
int time_idx,
gint64 frame_time);
G_END_DECLS

View File

@@ -55,7 +55,7 @@ void gtk_fishbowl_set_animating (GtkFishbowl *fishbowl,
gboolean animating); gboolean animating);
gboolean gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl); gboolean gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl);
void gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl, void gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl,
gboolean benchmark); gboolean animating);
double gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl); double gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl);
gint64 gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl); gint64 gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl);
void gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl, void gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl,

View File

@@ -0,0 +1,264 @@
#include "gtkshaderbin.h"
typedef struct {
GskGLShader *shader;
GtkStateFlags state;
GtkStateFlags state_mask;
float extra_border;
gboolean compiled;
gboolean compiled_ok;
} ShaderInfo;
struct _GtkShaderBin
{
GtkWidget parent_instance;
GtkWidget *child;
ShaderInfo *active_shader;
GPtrArray *shaders;
guint tick_id;
float time;
float mouse_x, mouse_y;
gint64 first_frame_time;
};
struct _GtkShaderBinClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GtkShaderBin, gtk_shader_bin, GTK_TYPE_WIDGET)
static void
shader_info_free (ShaderInfo *info)
{
g_object_unref (info->shader);
g_free (info);
}
static void
gtk_shader_bin_finalize (GObject *object)
{
GtkShaderBin *self = GTK_SHADER_BIN (object);
g_ptr_array_free (self->shaders, TRUE);
G_OBJECT_CLASS (gtk_shader_bin_parent_class)->finalize (object);
}
static void
gtk_shader_bin_dispose (GObject *object)
{
GtkShaderBin *self = GTK_SHADER_BIN (object);
g_clear_pointer (&self->child, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_shader_bin_parent_class)->dispose (object);
}
static gboolean
gtk_shader_bin_tick (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer unused)
{
GtkShaderBin *self = GTK_SHADER_BIN (widget);
gint64 frame_time;
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
if (self->first_frame_time == 0)
self->first_frame_time = frame_time;
self->time = (frame_time - self->first_frame_time) / (float)G_USEC_PER_SEC;
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
motion_cb (GtkEventControllerMotion *controller,
double x,
double y,
GtkShaderBin *self)
{
self->mouse_x = x;
self->mouse_y = y;
}
static void
gtk_shader_bin_init (GtkShaderBin *self)
{
GtkEventController *controller;
self->shaders = g_ptr_array_new_with_free_func ((GDestroyNotify)shader_info_free);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "motion", G_CALLBACK (motion_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
void
gtk_shader_bin_update_active_shader (GtkShaderBin *self)
{
GtkStateFlags new_state = gtk_widget_get_state_flags (GTK_WIDGET (self));
ShaderInfo *new_shader = NULL;
for (int i = 0; i < self->shaders->len; i++)
{
ShaderInfo *info = g_ptr_array_index (self->shaders, i);
if ((info->state_mask & new_state) == info->state)
{
new_shader = info;
break;
}
}
if (self->active_shader == new_shader)
return;
self->active_shader = new_shader;
self->first_frame_time = 0;
if (self->active_shader)
{
if (self->tick_id == 0)
self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self),
gtk_shader_bin_tick,
NULL, NULL);
}
else
{
if (self->tick_id != 0)
{
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick_id);
self->tick_id = 0;
}
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
gtk_shader_bin_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state_flags)
{
GtkShaderBin *self = GTK_SHADER_BIN (widget);
gtk_shader_bin_update_active_shader (self);
}
void
gtk_shader_bin_add_shader (GtkShaderBin *self,
GskGLShader *shader,
GtkStateFlags state,
GtkStateFlags state_mask,
float extra_border)
{
ShaderInfo *info = g_new0 (ShaderInfo, 1);
info->shader = g_object_ref (shader);
info->state = state;
info->state_mask = state_mask;
info->extra_border = extra_border;
g_ptr_array_add (self->shaders, info);
gtk_shader_bin_update_active_shader (self);
}
void
gtk_shader_bin_set_child (GtkShaderBin *self,
GtkWidget *child)
{
if (self->child == child)
return;
g_clear_pointer (&self->child, gtk_widget_unparent);
if (child)
{
self->child = child;
gtk_widget_set_parent (child, GTK_WIDGET (self));
}
}
GtkWidget *
gtk_shader_bin_get_child (GtkShaderBin *self)
{
return self->child;
}
static void
gtk_shader_bin_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkShaderBin *self = GTK_SHADER_BIN (widget);
int width, height;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
if (self->active_shader)
{
if (!self->active_shader->compiled)
{
GtkNative *native = gtk_widget_get_native (widget);
GskRenderer *renderer = gtk_native_get_renderer (native);
GError *error = NULL;
self->active_shader->compiled = TRUE;
self->active_shader->compiled_ok =
gsk_gl_shader_compile (self->active_shader->shader,
renderer, &error);
if (!self->active_shader->compiled_ok)
{
g_warning ("GtkShaderBin failed to compile shader: %s", error->message);
g_error_free (error);
}
}
if (self->active_shader->compiled_ok)
{
float border = self->active_shader->extra_border;
graphene_vec2_t mouse;
graphene_vec2_init (&mouse, self->mouse_x + border, self->mouse_y + border);
gtk_snapshot_push_gl_shader (snapshot, self->active_shader->shader,
&GRAPHENE_RECT_INIT(-border, -border, width+2*border, height+2*border),
gsk_gl_shader_format_args (self->active_shader->shader,
"u_time", self->time,
"u_mouse", &mouse,
NULL));
gtk_widget_snapshot_child (widget, self->child, snapshot);
gtk_snapshot_gl_shader_pop_texture (snapshot);
gtk_snapshot_pop (snapshot);
return;
}
}
/* Non-shader fallback */
gtk_widget_snapshot_child (widget, self->child, snapshot);
}
static void
gtk_shader_bin_class_init (GtkShaderBinClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_shader_bin_finalize;
object_class->dispose = gtk_shader_bin_dispose;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
widget_class->snapshot = gtk_shader_bin_snapshot;
widget_class->state_flags_changed = gtk_shader_bin_state_flags_changed;
}
GtkWidget *
gtk_shader_bin_new (void)
{
GtkShaderBin *self;
self = g_object_new (GTK_TYPE_SHADER_BIN, NULL);
return GTK_WIDGET (self);
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHADER_BIN (gtk_shader_bin_get_type ())
G_DECLARE_FINAL_TYPE (GtkShaderBin, gtk_shader_bin, GTK, SHADER_BIN, GtkWidget)
GtkWidget *gtk_shader_bin_new (void);
void gtk_shader_bin_add_shader (GtkShaderBin *self,
GskGLShader *shader,
GtkStateFlags state,
GtkStateFlags state_mask,
float extra_border);
void gtk_shader_bin_set_child (GtkShaderBin *self,
GtkWidget *child);
GtkWidget *gtk_shader_bin_get_child (GtkShaderBin *self);
G_END_DECLS

View File

@@ -0,0 +1,361 @@
#include "gtkshaderstack.h"
struct _GtkShaderStack
{
GtkWidget parent_instance;
GskGLShader *shader;
GPtrArray *children;
int current;
int next;
gboolean backwards;
guint tick_id;
float time;
float duration;
gint64 start_time;
};
struct _GtkShaderStackClass
{
GtkWidgetClass parent_class;
};
enum {
PROP_DURATION = 1,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
G_DEFINE_TYPE (GtkShaderStack, gtk_shader_stack, GTK_TYPE_WIDGET)
static void
gtk_shader_stack_finalize (GObject *object)
{
GtkShaderStack *self = GTK_SHADER_STACK (object);
g_object_unref (self->shader);
G_OBJECT_CLASS (gtk_shader_stack_parent_class)->finalize (object);
}
static void
update_child_visible (GtkShaderStack *self)
{
int i;
for (i = 0; i < self->children->len; i++)
{
GtkWidget *child = g_ptr_array_index (self->children, i);
gtk_widget_set_child_visible (child,
i == self->current || i == self->next);
}
}
static gboolean
transition_cb (GtkWidget *widget,
GdkFrameClock *clock,
gpointer unused)
{
GtkShaderStack *self = GTK_SHADER_STACK (widget);
gint64 frame_time;
frame_time = gdk_frame_clock_get_frame_time (clock);
if (self->start_time == 0)
self->start_time = frame_time;
self->time = (frame_time - self->start_time) / (float)G_USEC_PER_SEC;
gtk_widget_queue_draw (widget);
if (self->time >= self->duration)
{
self->current = self->next;
self->next = -1;
update_child_visible (self);
return G_SOURCE_REMOVE;
}
else
return G_SOURCE_CONTINUE;
}
static void
start_transition (GtkShaderStack *self)
{
self->start_time = 0;
self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self),
transition_cb,
NULL, NULL);
}
static void
stop_transition (GtkShaderStack *self)
{
if (self->tick_id != 0)
{
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick_id);
self->tick_id = 0;
}
if (self->next != -1)
self->current = self->next;
self->next = -1;
update_child_visible (self);
}
static void
gtk_shader_stack_dispose (GObject *object)
{
GtkShaderStack *self = GTK_SHADER_STACK (object);
stop_transition (self);
g_clear_pointer (&self->children, g_ptr_array_unref);
G_OBJECT_CLASS (gtk_shader_stack_parent_class)->dispose (object);
}
void
gtk_shader_stack_transition (GtkShaderStack *self,
gboolean forward)
{
stop_transition (self);
self->backwards = !forward;
if (self->backwards)
self->next = (self->current + self->children->len - 1) % self->children->len;
else
self->next = (self->current + 1) % self->children->len;
update_child_visible (self);
start_transition (self);
}
static void
gtk_shader_stack_init (GtkShaderStack *self)
{
self->children = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_widget_unparent);
self->current = -1;
self->next = -1;
self->backwards = FALSE;
self->duration = 1.0;
}
static void
gtk_shader_stack_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkShaderStack *self = GTK_SHADER_STACK (widget);
int i;
*minimum = 0;
*natural = 0;
for (i = 0; i < self->children->len; i++)
{
GtkWidget *child = g_ptr_array_index (self->children, i);
int child_min, child_nat;
if (gtk_widget_get_visible (child))
{
gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL);
*minimum = MAX (*minimum, child_min);
*natural = MAX (*natural, child_nat);
}
}
}
static void
gtk_shader_stack_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkShaderStack *self = GTK_SHADER_STACK (widget);
GtkAllocation child_allocation;
GtkWidget *child;
int i;
child_allocation.x = 0;
child_allocation.y = 0;
child_allocation.width = width;
child_allocation.height = height;
for (i = 0; i < self->children->len; i++)
{
child = g_ptr_array_index (self->children, i);
if (gtk_widget_get_visible (child))
gtk_widget_size_allocate (child, &child_allocation, -1);
}
}
static void
gtk_shader_stack_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkShaderStack *self = GTK_SHADER_STACK (widget);
int width, height;
GtkWidget *current, *next;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
current = g_ptr_array_index (self->children, self->current);
if (self->next == -1)
{
gtk_widget_snapshot_child (widget, current, snapshot);
}
else
{
GtkNative *native = gtk_widget_get_native (widget);
GskRenderer *renderer = gtk_native_get_renderer (native);
float progress;
next = g_ptr_array_index (self->children, self->next);
progress = self->time / self->duration;
if (self->backwards)
{
GtkWidget *tmp = next;
next = current;
current = tmp;
progress = 1. - progress;
}
if (gsk_gl_shader_compile (self->shader, renderer, NULL))
{
gtk_snapshot_push_gl_shader (snapshot,
self->shader,
&GRAPHENE_RECT_INIT(0, 0, width, height),
gsk_gl_shader_format_args (self->shader,
"progress", progress,
NULL));
gtk_widget_snapshot_child (widget, current, snapshot);
gtk_snapshot_gl_shader_pop_texture (snapshot); /* current child */
gtk_widget_snapshot_child (widget, next, snapshot);
gtk_snapshot_gl_shader_pop_texture (snapshot); /* next child */
gtk_snapshot_pop (snapshot);
}
else
{
/* Non-shader fallback */
gtk_widget_snapshot_child (widget, current, snapshot);
}
}
}
static void
gtk_shader_stack_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkShaderStack *self = GTK_SHADER_STACK (object);
switch (prop_id)
{
case PROP_DURATION:
g_value_set_float (value, self->duration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_shader_stack_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkShaderStack *self = GTK_SHADER_STACK (object);
switch (prop_id)
{
case PROP_DURATION:
self->duration = g_value_get_float (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_shader_stack_class_init (GtkShaderStackClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_shader_stack_finalize;
object_class->dispose = gtk_shader_stack_dispose;
object_class->get_property = gtk_shader_stack_get_property;
object_class->set_property = gtk_shader_stack_set_property;
widget_class->snapshot = gtk_shader_stack_snapshot;
widget_class->measure = gtk_shader_stack_measure;
widget_class->size_allocate = gtk_shader_stack_size_allocate;
properties[PROP_DURATION] =
g_param_spec_float ("duration", "Duration", "Duration",
0.1, 3.0, 1.0,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
GtkWidget *
gtk_shader_stack_new (void)
{
return g_object_new (GTK_TYPE_SHADER_STACK, NULL);
}
void
gtk_shader_stack_set_shader (GtkShaderStack *self,
GskGLShader *shader)
{
g_set_object (&self->shader, shader);
}
void
gtk_shader_stack_add_child (GtkShaderStack *self,
GtkWidget *child)
{
g_ptr_array_add (self->children, child);
gtk_widget_set_parent (child, GTK_WIDGET (self));
gtk_widget_queue_resize (GTK_WIDGET (self));
if (self->current == -1)
self->current = 0;
else
gtk_widget_set_child_visible (child, FALSE);
}
void
gtk_shader_stack_set_active (GtkShaderStack *self,
int index)
{
stop_transition (self);
self->current = MIN (index, self->children->len);
update_child_visible (self);
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHADER_STACK (gtk_shader_stack_get_type ())
G_DECLARE_FINAL_TYPE (GtkShaderStack, gtk_shader_stack, GTK, SHADER_STACK, GtkWidget)
GtkWidget * gtk_shader_stack_new (void);
void gtk_shader_stack_set_shader (GtkShaderStack *self,
GskGLShader *shader);
void gtk_shader_stack_add_child (GtkShaderStack *self,
GtkWidget *child);
void gtk_shader_stack_transition (GtkShaderStack *self,
gboolean forward);
void gtk_shader_stack_set_active (GtkShaderStack *self,
int index);
G_END_DECLS

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <gdk/gdk.h>
typedef struct _GdkHSLA GdkHSLA; typedef struct _GdkHSLA GdkHSLA;
struct _GdkHSLA { struct _GdkHSLA {

View File

@@ -13,7 +13,7 @@ static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow; static GtkWidget *scrolledwindow;
static int selected; static int selected;
#define N_WIDGET_TYPES 9 #define N_WIDGET_TYPES 8
static int hincrement = 5; static int hincrement = 5;
@@ -73,77 +73,30 @@ populate_icons (void)
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), grid); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), grid);
} }
static char *content;
static gsize content_len;
extern void fontify (const char *format, GtkTextBuffer *buffer); extern void fontify (const char *format, GtkTextBuffer *buffer);
enum {
PLAIN_TEXT,
HIGHLIGHTED_TEXT,
UNDERLINED_TEXT,
};
static void static void
underlinify (GtkTextBuffer *buffer) populate_text (gboolean highlight)
{
GtkTextTagTable *tags;
GtkTextTag *tag[3];
GtkTextIter start, end;
tags = gtk_text_buffer_get_tag_table (buffer);
tag[0] = gtk_text_tag_new ("error");
tag[1] = gtk_text_tag_new ("strikeout");
tag[2] = gtk_text_tag_new ("double");
g_object_set (tag[0], "underline", PANGO_UNDERLINE_ERROR, NULL);
g_object_set (tag[1], "strikethrough", TRUE, NULL);
g_object_set (tag[2],
"underline", PANGO_UNDERLINE_DOUBLE,
"underline-rgba", &(GdkRGBA){0., 1., 1., 1. },
NULL);
gtk_text_tag_table_add (tags, tag[0]);
gtk_text_tag_table_add (tags, tag[1]);
gtk_text_tag_table_add (tags, tag[2]);
gtk_text_buffer_get_start_iter (buffer, &end);
while (TRUE)
{
gtk_text_iter_forward_word_end (&end);
start = end;
gtk_text_iter_backward_word_start (&start);
gtk_text_buffer_apply_tag (buffer, tag[g_random_int_range (0, 3)], &start, &end);
if (!gtk_text_iter_forward_word_ends (&end, 3))
break;
}
}
static void
populate_text (const char *resource, int kind)
{ {
GtkWidget *textview; GtkWidget *textview;
GtkTextBuffer *buffer; GtkTextBuffer *buffer;
char *content;
gsize content_len;
GBytes *bytes;
bytes = g_resources_lookup_data (resource, 0, NULL); if (!content)
content = g_bytes_unref_to_data (bytes, &content_len); {
GBytes *bytes;
bytes = g_resources_lookup_data ("/sources/font_features.c", 0, NULL);
content = g_bytes_unref_to_data (bytes, &content_len);
}
buffer = gtk_text_buffer_new (NULL); buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_set_text (buffer, content, (int)content_len); gtk_text_buffer_set_text (buffer, content, (int)content_len);
switch (kind) if (highlight)
{ fontify ("c", buffer);
case HIGHLIGHTED_TEXT:
fontify ("c", buffer);
break;
case UNDERLINED_TEXT:
underlinify (buffer);
break;
case PLAIN_TEXT:
default:
break;
}
textview = gtk_text_view_new (); textview = gtk_text_view_new ();
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer); gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
@@ -202,6 +155,14 @@ populate_image (void)
{ {
GtkWidget *image; GtkWidget *image;
if (!content)
{
GBytes *bytes;
bytes = g_resources_lookup_data ("/sources/font_features.c", 0, NULL);
content = g_bytes_unref_to_data (bytes, &content_len);
}
image = gtk_picture_new_for_resource ("/sliding_puzzle/portland-rose.jpg"); image = gtk_picture_new_for_resource ("/sliding_puzzle/portland-rose.jpg");
gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE); gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE);
@@ -294,40 +255,35 @@ set_widget_type (int type)
case 1: case 1:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling plain text"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling plain text");
populate_text ("/sources/font_features.c", PLAIN_TEXT); populate_text (FALSE);
break; break;
case 2: case 2:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling colored text"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling complex text");
populate_text ("/sources/font_features.c", HIGHLIGHTED_TEXT); populate_text (TRUE);
break; break;
case 3: case 3:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling text with underlines");
populate_text ("/org/gtk/Demo4/Moby-Dick.txt", UNDERLINED_TEXT);
break;
case 4:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling text with Emoji"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling text with Emoji");
populate_emoji_text (); populate_emoji_text ();
break; break;
case 5: case 4:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a big image"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling a big image");
populate_image (); populate_image ();
break; break;
case 6: case 5:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list");
populate_list (); populate_list ();
break; break;
case 7: case 6:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a columned list"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling a columned list");
populate_list2 (); populate_list2 ();
break; break;
case 8: case 7:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid"); gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid");
populate_grid (); populate_grid ();
break; break;

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<object class="GtkWindow" id="window"> <object class="GtkWindow" id="window">
<property name="resizable">1</property> <property name="resizable">0</property>
<property name="default-width">500</property> <property name="default-width">500</property>
<property name="default-height">500</property> <property name="default-height">500</property>
<child type="titlebar"> <child type="titlebar">

View File

@@ -14,103 +14,6 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "demo3widget.h" #include "demo3widget.h"
static GtkWidget *window = NULL;
static GCancellable *cancellable = NULL;
static void
load_texture (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cable)
{
GFile *file = task_data;
GdkTexture *texture;
GError *error = NULL;
texture = gdk_texture_new_from_file (file, &error);
if (texture)
g_task_return_pointer (task, texture, g_object_unref);
else
g_task_return_error (task, error);
}
static void
set_wait_cursor (GtkWidget *widget)
{
gtk_widget_set_cursor_from_name (GTK_WIDGET (gtk_widget_get_root (widget)), "wait");
}
static void
unset_wait_cursor (GtkWidget *widget)
{
gtk_widget_set_cursor (GTK_WIDGET (gtk_widget_get_root (widget)), NULL);
}
static void
texture_loaded (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkTexture *texture;
GError *error = NULL;
texture = g_task_propagate_pointer (G_TASK (result), &error);
if (!texture)
{
g_print ("%s\n", error->message);
g_error_free (error);
return;
}
if (!window)
{
g_object_unref (texture);
return;
}
unset_wait_cursor (GTK_WIDGET (data));
g_object_set (G_OBJECT (data), "texture", texture, NULL);
}
static void
open_file_async (GFile *file,
GtkWidget *demo)
{
GTask *task;
set_wait_cursor (demo);
task = g_task_new (demo, cancellable, texture_loaded, demo);
g_task_set_task_data (task, g_object_ref (file), g_object_unref);
g_task_run_in_thread (task, load_texture);
g_object_unref (task);
}
static void
open_portland_rose (GtkWidget *button,
GtkWidget *demo)
{
GFile *file;
file = g_file_new_for_uri ("resource:///transparent/portland-rose.jpg");
open_file_async (file, demo);
g_object_unref (file);
}
static void
open_large_image (GtkWidget *button,
GtkWidget *demo)
{
GFile *file;
file = g_file_new_for_uri ("resource:///org/gtk/Demo4/large-image.png");
open_file_async (file, demo);
g_object_unref (file);
}
static void static void
file_opened (GObject *source, file_opened (GObject *source,
GAsyncResult *result, GAsyncResult *result,
@@ -118,6 +21,7 @@ file_opened (GObject *source,
{ {
GFile *file; GFile *file;
GError *error = NULL; GError *error = NULL;
GdkTexture *texture;
file = gtk_file_dialog_open_finish (GTK_FILE_DIALOG (source), result, &error); file = gtk_file_dialog_open_finish (GTK_FILE_DIALOG (source), result, &error);
@@ -128,9 +32,17 @@ file_opened (GObject *source,
return; return;
} }
open_file_async (file, data); texture = gdk_texture_new_from_file (file, &error);
g_object_unref (file); g_object_unref (file);
if (!texture)
{
g_print ("%s\n", error->message);
g_error_free (error);
return;
}
g_object_set (G_OBJECT (data), "texture", texture, NULL);
g_object_unref (texture);
} }
static void static void
@@ -204,26 +116,11 @@ transform_from (GBinding *binding,
return TRUE; return TRUE;
} }
static void
free_cancellable (gpointer data)
{
g_cancellable_cancel (cancellable);
g_clear_object (&cancellable);
}
static gboolean
cancel_load (GtkWidget *widget,
GVariant *args,
gpointer data)
{
unset_wait_cursor (widget);
g_cancellable_cancel (G_CANCELLABLE (data));
return TRUE;
}
GtkWidget * GtkWidget *
do_image_scaling (GtkWidget *do_widget) do_image_scaling (GtkWidget *do_widget)
{ {
static GtkWidget *window = NULL;
if (!window) if (!window)
{ {
GtkWidget *box; GtkWidget *box;
@@ -233,7 +130,6 @@ do_image_scaling (GtkWidget *do_widget)
GtkWidget *scale; GtkWidget *scale;
GtkWidget *dropdown; GtkWidget *dropdown;
GtkWidget *button; GtkWidget *button;
GtkEventController *controller;
window = gtk_window_new (); window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Image Scaling"); gtk_window_set_title (GTK_WINDOW (window), "Image Scaling");
@@ -242,20 +138,6 @@ do_image_scaling (GtkWidget *do_widget)
gtk_widget_get_display (do_widget)); gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
cancellable = g_cancellable_new ();
g_object_set_data_full (G_OBJECT (window), "cancellable",
cancellable, free_cancellable);
controller = gtk_shortcut_controller_new ();
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (
gtk_keyval_trigger_new (GDK_KEY_Escape, 0),
gtk_callback_action_new (cancel_load, cancellable, NULL)
));
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
GTK_SHORTCUT_SCOPE_GLOBAL);
gtk_widget_add_controller (window, controller);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box); gtk_window_set_child (GTK_WINDOW (window), box);
@@ -274,22 +156,6 @@ do_image_scaling (GtkWidget *do_widget)
g_signal_connect (button, "clicked", G_CALLBACK (open_file), widget); g_signal_connect (button, "clicked", G_CALLBACK (open_file), widget);
gtk_box_append (GTK_BOX (box2), button); gtk_box_append (GTK_BOX (box2), button);
button = gtk_button_new ();
gtk_button_set_child (GTK_BUTTON (button),
gtk_image_new_from_resource ("/org/gtk/Demo4/portland-rose-thumbnail.png"));
gtk_widget_add_css_class (button, "image-button");
gtk_widget_set_tooltip_text (button, "Portland Rose");
g_signal_connect (button, "clicked", G_CALLBACK (open_portland_rose), widget);
gtk_box_append (GTK_BOX (box2), button);
button = gtk_button_new ();
gtk_button_set_child (GTK_BUTTON (button),
gtk_image_new_from_resource ("/org/gtk/Demo4/large-image-thumbnail.png"));
gtk_widget_add_css_class (button, "image-button");
gtk_widget_set_tooltip_text (button, "Large image");
g_signal_connect (button, "clicked", G_CALLBACK (open_large_image), widget);
gtk_box_append (GTK_BOX (box2), button);
button = gtk_button_new_from_icon_name ("object-rotate-right-symbolic"); button = gtk_button_new_from_icon_name ("object-rotate-right-symbolic");
gtk_widget_set_tooltip_text (button, "Rotate"); gtk_widget_set_tooltip_text (button, "Rotate");
g_signal_connect (button, "clicked", G_CALLBACK (rotate), widget); g_signal_connect (button, "clicked", G_CALLBACK (rotate), widget);
@@ -325,9 +191,7 @@ do_image_scaling (GtkWidget *do_widget)
if (!gtk_widget_get_visible (window)) if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE); gtk_widget_set_visible (window, TRUE);
else else
{ gtk_window_destroy (GTK_WINDOW (window));
gtk_window_destroy (GTK_WINDOW (window));
}
return window; return window;
} }

View File

@@ -0,0 +1,41 @@
uniform float progress;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
vec4 getFromColor (vec2 uv) {
return GskTexture(u_texture1, uv);
}
vec4 getToColor (vec2 uv) {
return GskTexture(u_texture2, uv);
}
// Source: https://gl-transitions.com/editor/kaleidoscope
// Author: nwoeanhinnogaehr
// License: MIT
const float speed = 1.0;
const float angle = 1.0;
const float power = 1.5;
vec4 transition(vec2 uv) {
vec2 p = uv.xy / vec2(1.0).xy;
vec2 q = p;
float t = pow(progress, power)*speed;
p = p -0.5;
for (int i = 0; i < 7; i++) {
p = vec2(sin(t)*p.x + cos(t)*p.y, sin(t)*p.y - cos(t)*p.x);
t += angle;
p = abs(mod(p, 2.0) - 1.0);
}
abs(mod(p, 1.0));
return mix(
mix(getFromColor(q), getToColor(q), progress),
mix(getFromColor(p), getToColor(p), progress), 1.0 - 2.0*abs(progress - 0.5));
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
fragColor = transition(uv);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 KiB

View File

@@ -355,28 +355,28 @@ create_clocks_model (void)
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
/* A bunch of timezones with GTK hackers */ /* A bunch of timezones with GTK hackers */
clock = gtk_clock_new ("San Francisco", g_time_zone_new_identifier ("America/Los_Angeles")); clock = gtk_clock_new ("San Francisco", g_time_zone_new ("America/Los_Angeles"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("Xalapa", g_time_zone_new_identifier ("America/Mexico_City")); clock = gtk_clock_new ("Xalapa", g_time_zone_new ("America/Mexico_City"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("Boston", g_time_zone_new_identifier ("America/New_York")); clock = gtk_clock_new ("Boston", g_time_zone_new ("America/New_York"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("London", g_time_zone_new_identifier ("Europe/London")); clock = gtk_clock_new ("London", g_time_zone_new ("Europe/London"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("Berlin", g_time_zone_new_identifier ("Europe/Berlin")); clock = gtk_clock_new ("Berlin", g_time_zone_new ("Europe/Berlin"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("Moscow", g_time_zone_new_identifier ("Europe/Moscow")); clock = gtk_clock_new ("Moscow", g_time_zone_new ("Europe/Moscow"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("New Delhi", g_time_zone_new_identifier ("Asia/Kolkata")); clock = gtk_clock_new ("New Delhi", g_time_zone_new ("Asia/Kolkata"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);
clock = gtk_clock_new ("Shanghai", g_time_zone_new_identifier ("Asia/Shanghai")); clock = gtk_clock_new ("Shanghai", g_time_zone_new ("Asia/Shanghai"));
g_list_store_append (result, clock); g_list_store_append (result, clock);
g_object_unref (clock); g_object_unref (clock);

View File

@@ -156,6 +156,11 @@ gtk_demo_run (GtkDemo *self,
if (result == NULL) if (result == NULL)
return FALSE; return FALSE;
if (GTK_IS_WINDOW (result))
{
gtk_window_set_transient_for (GTK_WINDOW (result), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (result), TRUE);
}
return TRUE; return TRUE;
} }
@@ -827,6 +832,9 @@ static gboolean
demo_can_run (GtkWidget *window, demo_can_run (GtkWidget *window,
const char *name) const char *name)
{ {
if (name != NULL && strcmp (name, "gltransition") == 0)
return GSK_IS_GL_RENDERER (gtk_native_get_renderer (GTK_NATIVE (window)));
return TRUE; return TRUE;
} }
@@ -928,7 +936,7 @@ search_results_update (GObject *filter_model,
char *text; char *text;
if (n_items > 0) if (n_items > 0)
text = g_strdup_printf (ngettext ("%ld search result", "%ld search results", (long) n_items), (long) n_items); text = g_strdup_printf (ngettext ("%ld search result", "%ld search results", n_items), n_items);
else else
text = g_strdup (_("No search results")); text = g_strdup (_("No search results"));
@@ -1060,8 +1068,6 @@ command_line (GApplication *app,
window = gtk_application_get_windows (GTK_APPLICATION (app))->data; window = gtk_application_get_windows (GTK_APPLICATION (app))->data;
gtk_window_set_icon_name (GTK_WINDOW (window), "org.gtk.Demo4");
if (name == NULL) if (name == NULL)
goto out; goto out;

View File

@@ -33,6 +33,7 @@ demos = files([
'gears.c', 'gears.c',
'gestures.c', 'gestures.c',
'glarea.c', 'glarea.c',
'gltransition.c',
'headerbar.c', 'headerbar.c',
'hypertext.c', 'hypertext.c',
'iconscroll.c', 'iconscroll.c',
@@ -116,7 +117,10 @@ extra_demo_sources = files([
'gtkfishbowl.c', 'gtkfishbowl.c',
'fontplane.c', 'fontplane.c',
'gtkgears.c', 'gtkgears.c',
'gtkshaderbin.c',
'gtkshadertoy.c', 'gtkshadertoy.c',
'gtkshaderstack.c',
'gskshaderpaintable.c',
'hsla.c', 'hsla.c',
'puzzlepiece.c', 'puzzlepiece.c',
'bluroverlay.c', 'bluroverlay.c',

View File

@@ -5,4 +5,4 @@
#define NODE_TYPE_WIDGET (node_widget_get_type ()) #define NODE_TYPE_WIDGET (node_widget_get_type ())
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget) G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
GtkWidget * node_widget_new (const char *resource); GtkWidget * node_widget_new (const char *file);

View File

@@ -225,8 +225,7 @@ print_ready (GObject *source,
if (!g_output_stream_close (stream, NULL, &error)) if (!g_output_stream_close (stream, NULL, &error))
{ {
if (!g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED)) g_print ("Error from close: %s\n", error->message);
g_print ("Error from close: %s\n", error->message);
g_error_free (error); g_error_free (error);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,34 @@
uniform float progress;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
vec4 getFromColor (vec2 uv) {
return GskTexture(u_texture1, uv);
}
vec4 getToColor (vec2 uv) {
return GskTexture(u_texture2, uv);
}
// Source: https://gl-transitions.com/editor/Radial
// License: MIT
// Author: Xaychru
const float smoothness = 1.0;
const float PI = 3.141592653589;
vec4 transition(vec2 p) {
vec2 rp = p*2.-1.;
return mix(
getToColor(p),
getFromColor(p),
smoothstep(0., smoothness, atan(rp.y,rp.x) - (progress-.5) * PI * 2.5)
);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
fragColor = transition(uv);
}

View File

@@ -0,0 +1,43 @@
uniform float u_time;
uniform vec2 u_mouse;
uniform sampler2D u_texture1;
#define PI 3.141592654
float decay(float v, float t)
{
return v * (1.0 / (1.0 + t*t));
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
// Temporary to loop time every 1 sec
float time = u_time;
// we normalize all the effects according to the min height/width
float size = min(resolution.x, resolution.y);
// Animate one wave over size in 0.3 sec
float wave_speed = size / 0.3;
float wave_length = size / 1.0;
float wave_height = size * 0.1;
vec2 center = u_mouse;
vec2 direction_from_center = fragCoord - center;
float distance_from_center = length(direction_from_center);
/* Normalize direction */
direction_from_center = direction_from_center / distance_from_center;
float propagation_length = time * wave_speed;
float t = (propagation_length - distance_from_center) / wave_length;
float offset_magnitude = 0.0;
if (t > 0.0)
offset_magnitude = decay(wave_height * sin(t * 2.0 * PI), t);
vec2 offset = direction_from_center * min(offset_magnitude, distance_from_center);
vec2 source = fragCoord - offset;
vec2 uv2 = source / resolution;
fragColor = GskTexture(u_texture1, vec2(uv2.x, 1.0-uv2.y));
}

View File

@@ -43,7 +43,7 @@ GtkListItemFactory *
suggestion_entry_get_factory (SuggestionEntry *self); suggestion_entry_get_factory (SuggestionEntry *self);
void suggestion_entry_set_use_filter (SuggestionEntry *self, void suggestion_entry_set_use_filter (SuggestionEntry *self,
gboolean use_filter); gboolean use_ilter);
gboolean suggestion_entry_get_use_filter (SuggestionEntry *self); gboolean suggestion_entry_get_use_filter (SuggestionEntry *self);
void suggestion_entry_set_expression (SuggestionEntry *self, void suggestion_entry_set_expression (SuggestionEntry *self,

33
demos/gtk-demo/wind.glsl Normal file
View File

@@ -0,0 +1,33 @@
uniform float progress;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
vec4 getFromColor (vec2 uv) {
return GskTexture(u_texture1, uv);
}
vec4 getToColor (vec2 uv) {
return GskTexture(u_texture2, uv);
}
// Source: https://gl-transitions.com/editor/wind
// Author: gre
// License: MIT
const float size = 0.2;
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
vec4 transition(vec2 p) {
float r = rand(vec2(0, p.y));
float m = smoothstep(0.0, -size, p.x*(1.0-size) + size*r - (progress * (1.0 + size)));
return mix(getFromColor(p), getToColor(p), m);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
fragColor = transition(uv);
}

View File

@@ -139,8 +139,6 @@ icon_browser_app_activate (GApplication *app)
if (g_strcmp0 (PROFILE, "devel") == 0) if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (win), "devel"); gtk_widget_add_css_class (GTK_WIDGET (win), "devel");
gtk_window_set_icon_name (GTK_WINDOW (win), "org.gtk.IconBrowser4");
gtk_window_present (GTK_WINDOW (win)); gtk_window_present (GTK_WINDOW (win));
} }

View File

@@ -219,8 +219,6 @@ node_editor_application_activate (GApplication *app)
if (g_strcmp0 (PROFILE, "devel") == 0) if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (win), "devel"); gtk_widget_add_css_class (GTK_WIDGET (win), "devel");
gtk_window_set_icon_name (GTK_WINDOW (win), "org.gtk.gtk4.NodeEditor");
gtk_window_present (GTK_WINDOW (win)); gtk_window_present (GTK_WINDOW (win));
} }
@@ -301,7 +299,7 @@ node_editor_application_new (void)
app = g_object_new (NODE_EDITOR_APPLICATION_TYPE, app = g_object_new (NODE_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.NodeEditor", "application-id", "org.gtk.gtk4.NodeEditor",
"flags", G_APPLICATION_HANDLES_OPEN | G_APPLICATION_NON_UNIQUE, "flags", G_APPLICATION_HANDLES_OPEN,
NULL); NULL);
g_application_add_main_option (G_APPLICATION (app), "version", 0, 0,G_OPTION_ARG_NONE, "Show program version", NULL); g_application_add_main_option (G_APPLICATION (app), "version", 0, 0,G_OPTION_ARG_NONE, "Show program version", NULL);

View File

@@ -925,7 +925,7 @@ export_image_response_cb (GObject *source,
GdkTexture *texture; GdkTexture *texture;
GskRenderer *renderer; GskRenderer *renderer;
renderer = gsk_ngl_renderer_new (); renderer = gsk_gl_renderer_new ();
if (!gsk_renderer_realize_for_display (renderer, gdk_display_get_default (), NULL)) if (!gsk_renderer_realize_for_display (renderer, gdk_display_get_default (), NULL))
{ {
g_object_unref (renderer); g_object_unref (renderer);
@@ -1205,19 +1205,6 @@ node_editor_window_add_renderer (NodeEditorWindow *self,
g_object_unref (paintable); g_object_unref (paintable);
} }
static void
update_paste_action (GdkClipboard *clipboard,
GParamSpec *pspec,
gpointer data)
{
GtkWidget *widget = GTK_WIDGET (data);
gboolean has_node;
has_node = gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (clipboard), "application/x-gtk-render-node");
gtk_widget_action_set_enabled (widget, "paste-node", has_node);
}
static void static void
node_editor_window_realize (GtkWidget *widget) node_editor_window_realize (GtkWidget *widget)
{ {
@@ -1255,7 +1242,6 @@ node_editor_window_realize (GtkWidget *widget)
self->after_paint_handler = g_signal_connect (frameclock, "after-paint", self->after_paint_handler = g_signal_connect (frameclock, "after-paint",
G_CALLBACK (after_paint), self); G_CALLBACK (after_paint), self);
g_signal_connect (gtk_widget_get_clipboard (widget), "notify::formats", G_CALLBACK (update_paste_action), widget);
} }
static void static void
@@ -1265,8 +1251,6 @@ node_editor_window_unrealize (GtkWidget *widget)
GdkFrameClock *frameclock; GdkFrameClock *frameclock;
guint i; guint i;
g_signal_handlers_disconnect_by_func (gtk_widget_get_clipboard (widget), update_paste_action, widget);
frameclock = gtk_widget_get_frame_clock (widget); frameclock = gtk_widget_get_frame_clock (widget);
g_signal_handler_disconnect (frameclock, self->after_paint_handler); g_signal_handler_disconnect (frameclock, self->after_paint_handler);
self->after_paint_handler = 0; self->after_paint_handler = 0;
@@ -1631,41 +1615,6 @@ edit_action_cb (GtkWidget *widget,
node_editor_window_edit (self, &start); node_editor_window_edit (self, &start);
} }
static void
text_received (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
NodeEditorWindow *self = NODE_EDITOR_WINDOW (data);
char *text;
text = gdk_clipboard_read_text_finish (clipboard, result, NULL);
if (text)
{
GtkTextBuffer *buffer;
GtkTextIter start, end;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->text_view));
gtk_text_buffer_begin_user_action (buffer);
gtk_text_buffer_get_bounds (buffer, &start, &end);
gtk_text_buffer_delete (buffer, &start, &end);
gtk_text_buffer_insert (buffer, &start, text, -1);
gtk_text_buffer_end_user_action (buffer);
g_free (text);
}
}
static void
paste_node_cb (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
gdk_clipboard_read_text_async (clipboard, NULL, text_received, widget);
}
static void static void
node_editor_window_set_property (GObject *object, node_editor_window_set_property (GObject *object,
guint prop_id, guint prop_id,
@@ -1778,13 +1727,6 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
action = gtk_named_action_new ("smart-edit"); action = gtk_named_action_new ("smart-edit");
shortcut = gtk_shortcut_new (trigger, action); shortcut = gtk_shortcut_new (trigger, action);
gtk_widget_class_add_shortcut (widget_class, shortcut); gtk_widget_class_add_shortcut (widget_class, shortcut);
gtk_widget_class_install_action (widget_class, "paste-node", NULL, paste_node_cb);
trigger = gtk_keyval_trigger_new (GDK_KEY_v, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
action = gtk_named_action_new ("paste-node");
shortcut = gtk_shortcut_new (trigger, action);
gtk_widget_class_add_shortcut (widget_class, shortcut);
} }
static GtkWidget * static GtkWidget *

View File

@@ -22,10 +22,6 @@
</menu> </menu>
<menu id="extra_menu"> <menu id="extra_menu">
<section> <section>
<item>
<attribute name="label" translatable="yes">Paste _Node</attribute>
<attribute name="action">paste-node</attribute>
</item>
<item> <item>
<attribute name="label" translatable="yes">Assisted _Edit</attribute> <attribute name="label" translatable="yes">Assisted _Edit</attribute>
<attribute name="action">smart-edit</attribute> <attribute name="action">smart-edit</attribute>

View File

@@ -3,7 +3,7 @@
<gresource prefix="/org/gtk/gtk4/node-editor"> <gresource prefix="/org/gtk/gtk4/node-editor">
<file preprocess="xml-stripblanks">node-editor-window.ui</file> <file preprocess="xml-stripblanks">node-editor-window.ui</file>
<file preprocess="xml-stripblanks">help-window.ui</file> <file preprocess="xml-stripblanks">help-window.ui</file>
<file alias='node-format.md'>../../docs/reference/gtk/node-format.md</file> <file>node-format.md</file>
<file alias='icons/apps/org.gtk.gtk4.NodeEditor.svg'>data/scalable/apps/org.gtk.gtk4.NodeEditor.svg</file> <file alias='icons/apps/org.gtk.gtk4.NodeEditor.svg'>data/scalable/apps/org.gtk.gtk4.NodeEditor.svg</file>
</gresource> </gresource>
</gresources> </gresources>

View File

@@ -1,15 +1,13 @@
Title: The Node file format # The Node file format
GSK render nodes can be serialized and deserialized using APIs such as `gsk_render_node_serialize()` and `gsk_render_node_deserialize()`. The intended use for this is development - primarily the development of GTK - by allowing things such as creating testsuites and benchmarks, exchanging nodes in bug reports. GTK includes the `gtk4-node-editor` application for creating such test files. GSK render nodes can be serialized and deserialized using APIs such as `gsk_render_node_serialize()` and `gsk_render_node_deserialize()`. The intended use for this is development - primarily the development of GTK - by allowing things such as creating testsuites and benchmarks, exchanging nodes in bug reports. GTK includes the `gtk4-node-editor` application for creating such test files.
The format is a text format that follows the [CSS syntax rules](https://drafts.csswg.org/css-syntax-3/). In particular, this means that every array of bytes will produce a render node when parsed, as there is a defined error recovery method. For more details on error handling, please refer to the documentation of the parsing APIs. The format is a text format that follows the [CSS syntax rules](https://drafts.csswg.org/css-syntax-3/). In particular, this means that every array of bytes will produce a render node when parsed, as there is a defined error recovery method. For more details on error handling, please refer to the documentation of the parsing APIs.
The grammar of a node text representation using [the CSS value definition syntax](https://drafts.csswg.org/css-values-3/#value-defs) looks like this: The grammar of a node text representation using [the CSS value definition syntax](https://drafts.csswg.org/css-values-3/#value-defs) looks like this:
**document**: `<node>\*`
document: <@-rule>*<node> **node**: container [ "name" ] { <document> } | `<node-type> [ "name" ] { <property>* }` | "name"
@-rule: @cicp "name" { <property>* } **property**: `<property-name>: <node> | <value> ;`
node: container [ "name" ] { <document> } | <node-type> [ "name" ] { <property>* } | "name"
property: <property-name>: <node> | <value> ;
Each node has its own `<node-type>` and supports a custom set of properties, each with their own `<property-name>` and syntax. The following paragraphs document each of the nodes and their properties. Each node has its own `<node-type>` and supports a custom set of properties, each with their own `<property-name>` and syntax. The following paragraphs document each of the nodes and their properties.
@@ -27,59 +25,6 @@ Nodes can be given a name by adding a string after the `<node-type>` in their de
Just like nodes, textures can be referenced by name. When defining a named texture, the name has to be placed in front of the URL. Just like nodes, textures can be referenced by name. When defining a named texture, the name has to be placed in front of the URL.
# Color states
Color states are represented either by an ident (for builtin ones) or a string
(for custom ones):
color-state: <ident> | <string>
Custom color states can be defined at the beginning of the document, with an @cicp rule.
The format for @cicp rules is
@cicp "name" {
...
}
The following properties can be set for custom color states:
| property | syntax | default | printed |
| --------- | ---------------- | -------- | ----------- |
| primaries | `<integer>` | 2 | always |
| transfer | `<integer>` | 2 | always |
| matrix | `<integer>` | 2 | always |
| range | `<range>` | full | non-default |
Note that the primaries, transfer and matrix properties always need
to be specified, since GTK does not allow creating color state objects
with these being set to 2 (== unspecified).
Range can have the following values:
range: narrow | full
# Colors
Colors can be specified with a variation of the modern CSS color syntax:
color(<color-state> <number> <number> <number> ["/" <number>])
The traditional syntax for sRGB colors still works as well:
rgba(<number>, <number>, <number>, <number)
rgb(<number, <number>, <number>)
# Rectangles
Rectangles can be specified just as four integers for x, y, width and height:
rect: <number> <number> <number> <number>
Rounded rectangles use a CSS-like syntax:
rounded-rect: <rect> [ "/" <number>{1,4} [ "/" <number>{1,4} ] ]
# Nodes # Nodes
### container ### container
@@ -96,13 +41,6 @@ The **container** node is a special node that allows specifying a list of child
Creates a node like `gsk_blend_node_new()` with the given properties. Creates a node like `gsk_blend_node_new()` with the given properties.
Possible values for the mode property are:
blend-mode: normal | multiply | screen | overlay | darken |
lighten | color-dodge | color-burn | hard-light |
soft-light | difference | exclusion | color |
hue | saturation | luminosity
### blur ### blur
| property | syntax | default | printed | | property | syntax | default | printed |
@@ -181,21 +119,15 @@ matrix3d() production to specify all 16 values individually.
### conic-gradient ### conic-gradient
| property | syntax | default | printed | | property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- | | -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always | | bounds | `<rect>` | 50 | always |
| center | `<point>` | 25, 25 | always | | center | `<point>` | 25, 25 | always |
| rotation | `<number>` | 0 | always | | rotation | `<number>` | 0 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always | | stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_conic_gradient_node_new()` with the given properties. Creates a node like `gsk_conic_gradient_node_new()` with the given properties.
Possible values for the hue-interpolation property are:
hue-interpolation: shorter | longer | increasing | decreasing
### cross-fade ### cross-fade
| property | syntax | default | printed | | property | syntax | default | printed |
@@ -228,10 +160,6 @@ Creates a node like `gsk_fill_node_new()` with the given properties.
The default child node is the default color node, but created with the The default child node is the default color node, but created with the
bounds of the path. bounds of the path.
Possible values for the fill-rule property are:
fill-rule: winding | even-odd
### glshader ### glshader
| property | syntax | default | printed | | property | syntax | default | printed |
@@ -264,14 +192,12 @@ Creates a node like `gsk_inset_shadow_node_new()` with the given properties.
### linear-gradient ### linear-gradient
| property | syntax | default | printed | | property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- | | -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always | | bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always | | start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always | | end | `<point>` | 0 50 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always | | stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_linear_gradient_node_new()` with the given properties. Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
@@ -285,10 +211,6 @@ Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
Creates a node like `gsk_mask_node_new()` with the given properties. Creates a node like `gsk_mask_node_new()` with the given properties.
Possible values for the mode property are:
mask-mode: alpha | inverted-alpha | luminance | inverted-luminance
### opacity ### opacity
| property | syntax | default | printed | | property | syntax | default | printed |
@@ -313,27 +235,25 @@ Creates a node like `gsk_outset_shadow_node_new()` with the given properties.
### radial-gradient ### radial-gradient
| property | syntax | default | printed | | property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- | | -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always | | bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always | | center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always | | hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always | | vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always | | start | `<number>` | 0 | always |
| end | `<number>` | 1 | always | | end | `<number>` | 1 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always | | stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_radial_gradient_node_new()` with the given properties. Creates a node like `gsk_radial_gradient_node_new()` with the given properties.
### repeat ### repeat
| property | syntax | default | printed | | property | syntax | default | printed |
| ------------ | ---------- | ---------------------- | ----------- | | ----------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | *bounds of child node* | non-default | | bounds | `<rect>` | *bounds of child node* | non-default |
| child | `<node>` | color { } | always | | child | `<node>` | color { } | always |
| child-bounds | `<rect>` | *bounds of child node* | non-default | | child-bounds| `<rect>` | *bounds of child node* | non-default |
Creates a node like `gsk_repeat_node_new()` with the given properties. Creates a node like `gsk_repeat_node_new()` with the given properties.
@@ -400,14 +320,6 @@ Creates a node like `gsk_stroke_node_new()` with the given properties.
The default child node is the default color node, but created with the The default child node is the default color node, but created with the
stroke bounds of the path. stroke bounds of the path.
Possible values for the line-cap property are:
line-cap: butt | round | square
Possible values for the line-join property are:
line-join: miter | round | bevel
### text ### text
| property | syntax | default | printed | | property | syntax | default | printed |
@@ -416,9 +328,9 @@ Possible values for the line-join property are:
| font | `<string>` `<url>`? | "Cantarell 15px" | always | | font | `<string>` `<url>`? | "Cantarell 15px" | always |
| glyphs | `<glyphs>` | "Hello" | always | | glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default | | offset | `<point>` | 0 0 | non-default |
| hint-style | `<hint-style>` | slight | non-default | | hint-style | `<hint style>` | slight | non-default |
| antialias | `<antialias>` | gray | non-default | | antialias | `<antialias>` | gray | non-default |
| hint-metrics | `<hint-metrics>` | off | non-default | | hint-metrics | `<hint metrics>` | off | non-default |
Creates a node like `gsk_text_node_new()` with the given properties. Creates a node like `gsk_text_node_new()` with the given properties.
@@ -433,17 +345,9 @@ 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 If the given font does not exist or the given glyphs are invalid for the given
font, an error node will be returned. font, an error node will be returned.
Possible values for the hint-style property are: Possible values for hint-style are none, slight or full.
Possible value for antialias are none or gray.
hint-style: none | slight | full Possible value for hint-metrics are on or off.
Possible value for the antialias property are:
antialias: none | gray
Possible value for hint-metrics are:
hint-metrics: on | off
### texture ### texture
@@ -469,15 +373,14 @@ representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANS
| -------- | ---------------- | ---------------------- | ----------- | | -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always | | bounds | `<rect>` | 50 | always |
| texture | `<url>` | *see below* | always | | texture | `<url>` | *see below* | always |
| filter | `filter` | linear | non-default | | filter | `filter` | *see below* | non-default |
Creates a node like `gsk_texture_scale_node_new()` with the given properties. Creates a node like `gsk_texture_scale_node_new()` with the given properties.
The default texture is a 10x10 checkerboard, just like for texture. The default texture is a 10x10 checkerboard, just like for texture.
Possible values for the filter property are: The possible filter values are `linear`, `nearest` and `trilinear`, with
`linear` being the default.
filter: linear | nearest | trilinear
### transform ### transform

View File

@@ -798,7 +798,7 @@ activate (GApplication *app)
if (g_strcmp0 (PROFILE, "devel") == 0) if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (main_window), "devel"); gtk_widget_add_css_class (GTK_WIDGET (main_window), "devel");
gtk_window_set_icon_name (GTK_WINDOW (main_window), "org.gtk.PrintEditor4"); gtk_window_set_icon_name (GTK_WINDOW (main_window), "text-editor");
gtk_window_set_default_size (GTK_WINDOW (main_window), 400, 600); gtk_window_set_default_size (GTK_WINDOW (main_window), 400, 600);
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (main_window), TRUE); gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (main_window), TRUE);
update_title (GTK_WINDOW (main_window)); update_title (GTK_WINDOW (main_window));

View File

@@ -2241,7 +2241,6 @@ activate (GApplication *app)
if (g_strcmp0 (PROFILE, "devel") == 0) if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (window), "devel"); gtk_widget_add_css_class (GTK_WIDGET (window), "devel");
gtk_window_set_icon_name (window, "org.gtk.WidgetFactory4");
gtk_application_add_window (GTK_APPLICATION (app), window); gtk_application_add_window (GTK_APPLICATION (app), window);
g_action_map_add_action_entries (G_ACTION_MAP (window), g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries), win_entries, G_N_ELEMENTS (win_entries),

View File

@@ -151,11 +151,10 @@ Checks whether the widget is set to be visible or not.
- Methods are special functions whose first argument is always the instance - Methods are special functions whose first argument is always the instance
of a certain class. The instance argument for newly written code should be of a certain class. The instance argument for newly written code should be
called `self`. called `self`.
- If a method is a setter or a getter for an object property - If a method is a setter or a getter for an object property, you should
`GtkClassName:prop-name`, and if its name does not match the naming scheme add an `(attributes org.gtk.Method.set_property=property-name)` or a
`gtk_class_name_{g,s}et_prop_name`, you should add a `(set-property an `(attributes org.gtk.Method.get_property=property-name)` annotation
prop-name)` or a `(get-property prop-name)` annotation to the method's to the method's identifier
identifier
- If a method changes one or more properties as side effect, link those - If a method changes one or more properties as side effect, link those
properties in the method's description properties in the method's description
- If a method is a signal emitter, you should use the - If a method is a signal emitter, you should use the
@@ -193,10 +192,9 @@ Checks whether the widget is set to be visible or not.
purposes. purposes.
- Always note if setting a property has side effects, like causing another - Always note if setting a property has side effects, like causing another
property to change state. property to change state.
- If a property `GtkClassName:prop-name` has a public getter or setter, and - If the property has public accessors you should annotate it with
they do not match the naming scheme `gtk_class_name_{g,s}et_prop_name` you the `(attributes org.gtk.Property.set=setter_function)` and
should annotate it with the `(setter setter_function)` and `(getter `(attributes org.gtk.Property.get=getter_function)` attributes
getter_function)`.
- The syntax for property documentation is: - The syntax for property documentation is:
```c ```c

View File

@@ -111,11 +111,3 @@ content_images = [
] ]
content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gdk/" content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gdk/"
urlmap_file = "urlmap.js" urlmap_file = "urlmap.js"
[[object]]
name = "DECLARE_INTERNAL_TYPE"
hidden = true
[[object]]
pattern = "KEY_*"
check_ignore = true

View File

@@ -29,18 +29,6 @@ if get_option('documentation')
install_dir: docs_dir, install_dir: docs_dir,
) )
test('doc-check-gdk',
gidocgen,
args: [
'check',
'--config', gdk4_toml,
'--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gtk'),
gdk_gir[0],
],
depends: gdk_gir[0],
suite: ['docs', 'failing'],
)
if x11_enabled if x11_enabled
gdk4x11_toml = configure_file( gdk4x11_toml = configure_file(
input: 'gdk4-x11.toml.in', input: 'gdk4-x11.toml.in',
@@ -99,17 +87,5 @@ if get_option('documentation')
install: true, install: true,
install_dir: docs_dir, install_dir: docs_dir,
) )
test('doc-check-gdk-wayland',
gidocgen,
args: [
'check',
'--config', gdk4wayland_toml,
'--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gtk'),
gdk_wayland_gir[0],
],
depends: gdk_wayland_gir[0],
suite: ['docs'],
)
endif endif
endif endif

View File

@@ -66,7 +66,3 @@ content_images = [
] ]
content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gsk/" content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gsk/"
urlmap_file = "urlmap.js" urlmap_file = "urlmap.js"
[[object]]
name = "INCLUDE_WARNING"
hidden = true

View File

@@ -30,16 +30,4 @@ if get_option('documentation')
install: true, install: true,
install_dir: docs_dir, install_dir: docs_dir,
) )
test('doc-check-gsk',
gidocgen,
args: [
'check',
'--config', gsk4_toml,
'--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gtk'),
gsk_gir[0],
],
depends: gsk_gir[0],
suite: ['docs'],
)
endif endif

View File

@@ -1,16 +1,12 @@
Title: The Broadway windowing system Title: The Broadway windowing system
Slug: broadway Slug: broadway
## Using GTK with Broadway
The GDK Broadway backend provides support for displaying GTK applications in The GDK Broadway backend provides support for displaying GTK applications in
a web browser, using HTML5 and web sockets. a web browser, using HTML5 and web sockets.
Broadway was written as an experiment and is not the most actively developed To run your application in this way, first run the broadway server,
backend. It supports the features that were required of GDK backends in GTK 4.0,
but may not be up-to-date with the latest developments.
## Using GTK with Broadway
To run your application under Broadway, first run the broadway server,
`gtk-broadwayd`, that ships with GTK: `gtk-broadwayd`, that ships with GTK:
``` ```

View File

@@ -140,7 +140,7 @@ Other libraries are maintained separately.
file formats. It is available [here](ttps://download.gnome.org/sources/gdk-pixbuf/). file formats. It is available [here](ttps://download.gnome.org/sources/gdk-pixbuf/).
- [Pango](http://www.pango.org) is a library for internationalized - [Pango](http://www.pango.org) is a library for internationalized
text handling. It is available [here](https://download.gnome.org/sources/pango/). text handling. It is available [here](https://download.gnome.org/sources/pango/).
- [GObject Introspection](https://gitlab.gnome.org/GNOME/gobject-introspection) - [GObject Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection)
is a framework for making introspection data available to language is a framework for making introspection data available to language
bindings. It is available [here](https://download.gnome.org/sources/gobject-introspection/). bindings. It is available [here](https://download.gnome.org/sources/gobject-introspection/).
- The [GNU libiconv](https://www.gnu.org/software/libiconv/) library - The [GNU libiconv](https://www.gnu.org/software/libiconv/) library

View File

@@ -15,16 +15,16 @@ spec.
The following units are supported for basic datatypes: The following units are supported for basic datatypes:
Length Length
: px, pt, em, ex, rem, pc, in, cm, mm : px, pt, em, ex, rem, pc, in, cm, mm, calc()
Percentage Percentage
: % : %, calc()
Angle Angle
: deg, rad, grad, turn : deg, grad, turn, calc()
Time Time
: s, ms : s, ms, calc()
Length values with the em or ex units are resolved using the font Length values with the em or ex units are resolved using the font
size value, unless they occur in setting the font-size itself, in size value, unless they occur in setting the font-size itself, in
@@ -33,15 +33,11 @@ which case they are resolved using the inherited font size value.
The rem unit is resolved using the initial font size value, which is The rem unit is resolved using the initial font size value, which is
not quite the same as the CSS definition of rem. not quite the same as the CSS definition of rem.
Length values using physical units (pt, pc, in, cm, mm) are translated The calc() notation adds considerable expressive power. There are limits
to px using the dpi value specified by the -gtk-dpi property, which is on what types can be combined in such an expression (e.g. it does not make
different from the CSS definition, which uses a fixed dpi of 96. sense to add a number and a time). For the full details, see the
[CSS3 Values and Units](https://www.w3.org/TR/css3-values/#calc-notation)
The calc() notation adds considerable expressive power to all of these spec.
datatypes. There are limits on what types can be combined in such an
expression (e.g. it does not make sense to add a number and a time).
For the full details, see the
[CSS Values and Units](https://www.w3.org/TR/css-values-4/) spec.
A common pattern among shorthand properties (called 'four sides') is one A common pattern among shorthand properties (called 'four sides') is one
where one to four values can be specified, to determine a value for each where one to four values can be specified, to determine a value for each
@@ -86,54 +82,36 @@ color: var(--prop, green);
## Colors ## Colors
### CSS Colors GTK extends the CSS syntax with several additional ways to specify colors.
Colors can be expressed in numerous ways in CSS (see the
[Color Module](https://www.w3.org/TR/css-color-5/). GTK supports
many (but not all) of these.
You can use rgb(), rgba(), hsl() with both the legacy or the modern CSS
syntax, and calc() can be used as well in color expressions. hwb(), oklab(),
oklch(), color(), color-mix() and relative colors are supported as well.
### Non-CSS Colors
GTK extends the CSS syntax with several additional ways to specify colors.
These extensions are deprecated and should be replaced by the equivalent
standard CSS notions.
The first is a reference to a color defined via a @define-color rule in CSS. The first is a reference to a color defined via a @define-color rule in CSS.
The syntax for @define-color rules is as follows: The syntax for @define-color rules is as follows:
``` ```
@define-color name color @define-color Name Color
``` ```
To refer to the color defined by a @define-color rule, prefix the name with @. To refer to the color defined by a @define-color rule, prefix the name with @.
The standard CSS mechanisms that should be used instead of @define-color are
custom properties, :root and var().
GTK also supports color expressions, which allow colors to be transformed to GTK also supports color expressions, which allow colors to be transformed to
new ones. Color expressions can be nested, providing a rich language to new ones. Color expressions can be nested, providing a rich language to
define colors. Color expressions resemble functions, taking 1 or more colors define colors. Color expressions resemble functions, taking 1 or more colors
and in some cases a number as arguments. and in some cases a number as arguments.
`lighter(color)` `lighter(Color)`
: produces a brighter variant of `color`. : produces a brighter variant of Color
`darker(color)` `darker(Color)`
: produces a darker variant of `color`. : produces a darker variant of Color
`shade(color, number)` `shade(Color, Number)`
: changes the lightness of `color`. The `number` ranges from 0 for black to 2 for white. : changes the lightness of Color. The number ranges from 0 for black to 2 for white.
`alpha(color, number)` `alpha(Color, Number)`
: multiplies the alpha value of `color` by `number` (between 0 and 1). : replaces the alpha value of color with number (between 0 and 1)
`mix(color1, color2, number)` `mix(Color1, Color2, Number)`
: interpolates between the two colors. : interpolates between the two colors
## Images ## Images
@@ -141,7 +119,7 @@ GTK extends the CSS syntax for images and also uses it for specifying icons.
To load a themed icon, use To load a themed icon, use
``` ```
-gtk-icontheme(name) -gtk-icontheme(Name)
``` ```
The specified icon name is used to look up a themed icon, while taking into The specified icon name is used to look up a themed icon, while taking into
@@ -170,14 +148,14 @@ and the
syntax makes this available. -gtk-recolor requires a url as first argument. syntax makes this available. -gtk-recolor requires a url as first argument.
The remaining arguments specify the color palette to use. If the palette is The remaining arguments specify the color palette to use. If the palette is
not explicitly specified, the current value of the -gtk-icon-palette property not explicitly specified, the current value of the -gtk-icon-palette property
is used. is used.
GTK supports scaled rendering on hi-resolution displays. This works best if GTK supports scaled rendering on hi-resolution displays. This works best if
images can specify normal and hi-resolution variants. From CSS, this can be images can specify normal and hi-resolution variants. From CSS, this can be
done with done with
``` ```
-gtk-scaled(image1, image2) -gtk-scaled(Image1, Image2)
``` ```
## GTK CSS Properties ## GTK CSS Properties

View File

@@ -66,8 +66,8 @@ The clock has several phases:
- Layout - Layout
- Paint - Paint
The phases happen in this order and all phases will always run The phases happens in this order and we will always run each
through before going back to the start. phase through before going back to the start.
The Events phase is a stretch of time between each redraw where The Events phase is a stretch of time between each redraw where
GTK processes input events from the user and other events GTK processes input events from the user and other events
@@ -99,15 +99,16 @@ reaches the requested phase. However, in practice most things
happen at higher levels: happen at higher levels:
- If you are doing an animation, you can use - If you are doing an animation, you can use
[method@Gtk.Widget.add_tick_callback] which will cause a regular gtk_widget_add_tick_callback() which will cause a regular
beating of the clock with a callback in the Update phase beating of the clock with a callback in the Update phase
until you stop the tick. until you stop the tick.
- If some state changes that causes the size of your widget to - If some state changes that causes the size of your widget to
change you call [method@Gtk.Widget.queue_resize] which will request change you call gtk_widget_queue_resize() which will request
a Layout phase and mark your widget as needing relayout. a Layout phase and mark your widget as needing relayout.
- If some state changes so you need to redraw your widget you - If some state changes so you need to redraw some area of
use [method@Gtk.Widget.queue_draw] to request a Paint phase for your widget you use the normal gtk_widget_queue_draw()
your widget. set of functions. These will request a Paint phase and
mark the region as needing redraw.
There are also a lot of implicit triggers of these from the There are also a lot of implicit triggers of these from the
CSS layer (which does animations, resizes and repaints as needed). CSS layer (which does animations, resizes and repaints as needed).

View File

@@ -66,6 +66,10 @@ You can compile the program above with GCC using:
gcc $( pkg-config --cflags gtk4 ) -o example-0 example-0.c $( pkg-config --libs gtk4 ) gcc $( pkg-config --cflags gtk4 ) -o example-0 example-0.c $( pkg-config --libs gtk4 )
``` ```
**Note**: If the above compilation does not work due to an error regarding `G_APPLICATION_DEFAULT_FLAGS`
this could be due to your OS providing an older version of GLib. For GLib versions older than 2.74 you
will need to replace `G_APPLICATION_DEFAULT_FLAGS` with `G_APPLICATION_FLAGS_NONE` in this example, and
others in this documentation.
For more information on how to compile a GTK application, please For more information on how to compile a GTK application, please
refer to the [Compiling GTK Applications](compiling.html) refer to the [Compiling GTK Applications](compiling.html)
section in this reference. section in this reference.
@@ -241,6 +245,9 @@ to connect the "clicked" signal with [method@Gtk.Window.destroy], then the funct
would be called on `button` (which would not go well, since the function expects would be called on `button` (which would not go well, since the function expects
a `GtkWindow` as argument). a `GtkWindow` as argument).
More information about creating buttons can be found
[here](https://wiki.gnome.org/HowDoI/Buttons).
The rest of the code in `example-1.c` is identical to `example-0.c`. The next The rest of the code in `example-1.c` is identical to `example-0.c`. The next
section will elaborate further on how to add several [class@Gtk.Widget]s to your section will elaborate further on how to add several [class@Gtk.Widget]s to your
GTK application. GTK application.

View File

@@ -1,97 +0,0 @@
.. _gtk4-image-tool(1):
====================
gtk4-image-tool
====================
-----------------------
Image Utility
-----------------------
:Version: GTK
:Manual section: 1
:Manual group: GTK commands
SYNOPSIS
--------
| **gtk4-image-tool** <COMMAND> [OPTIONS...] <FILE>...
|
| **gtk4-image-tool** compare [OPTIONS...] <FILE1> <FILE2>
| **gtk4-image-tool** convert [OPTIONS...] <FILE1> <FILE2>
| **gtk4-image-tool** info [OPTIONS...] <FILE>
| **gtk4-image-tool** relabel [OPTIONS...] <FILE1> <FILE2>
| **gtk4-image-tool** show [OPTIONS...] <FILE>...
DESCRIPTION
-----------
``gtk4-image-tool`` can perform various operations on images.
COMMANDS
--------
Information
^^^^^^^^^^^
The ``info`` command shows general information about the image, such
as its format and color state.
Showing
^^^^^^^
The ``show`` command displays one or more images, side-by-side.
``--undecorated``
Removes window decorations. This is meant for rendering of exactly the image
without any titlebar.
Compare
^^^^^^^
The ``compare`` command compares two images. If any differences are found,
the exit code is 1. If the images are identical, it is 0.
``--output=FILE``
Save the differences as a png image in ``FILE``.
``--quiet``
Don't write results to stdout.
Conversion
^^^^^^^^^^
The ``convert`` command converts the image to a different format or color state.
``--format=FORMAT``
Convert to the given format. The supported formats can be listed
with ``--format=list``.
``--color-state=COLORSTATE``
Convert to the given color state. The supported color states can be
listed with ``--format=list``.
``--cicp=CICP``
Convert to a color state that is specified as a cicp tuple. The cicp tuple
must be specified as four numbers, separated by /, e.g. 1/13/6/0.
Relabeling
^^^^^^^^^^
The ``relabel`` command changes the color state of an image without conversion.
This can be useful to produce wrong color renderings for diagnostics.
``--color-state=COLORSTATE``
Relabel to the given color state. The supported color states can be
listed with ``--format=list``.
``--cicp=CICP``
Relabel to a color state that is specified as a cicp tuple. The cicp tuple
must be specified as four numbers, separated by /, e.g. 1/13/6/0.

View File

@@ -18,7 +18,6 @@ SYNOPSIS
| |
| **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE> | **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** compare [OPTIONS...] <FILE1> <FILE2> | **gtk4-rendernode-tool** compare [OPTIONS...] <FILE1> <FILE2>
| **gtk4-rendernode-tool** extract [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** info [OPTIONS...] <FILE> | **gtk4-rendernode-tool** info [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>] | **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>]
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE> | **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
@@ -100,15 +99,3 @@ exit code is 1. If the images are identical, it is 0.
``--quiet`` ``--quiet``
Don't write results to stdout. Don't write results to stdout.
Extract
^^^^^^^
The ``extract`` command saves all the data urls found in a node file to a given
directory. The file names for the extracted files are derived from the mimetype
of the url.
``--dir=DIRECTORY``
Save extracted files in ``DIRECTORY`` (defaults to the current directory).

View File

@@ -77,15 +77,12 @@ content_files = [
"section-tree-widget.md", "section-tree-widget.md",
"migrating-2to4.md", "migrating-2to4.md",
"migrating-3to4.md", "migrating-3to4.md",
"migrating-4to5.md",
"broadway.md", "broadway.md",
"osx.md", "osx.md",
"wayland.md", "wayland.md",
"windows.md", "windows.md",
"x11.md", "x11.md",
"tools.md",
"visual_index.md", "visual_index.md",
"node-format.md",
] ]
content_images = [ content_images = [
"../images/favicon.svg", "../images/favicon.svg",
@@ -252,12 +249,3 @@ content_images = [
] ]
content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gtk/" content_base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/docs/reference/gtk/"
urlmap_file = "urlmap.js" urlmap_file = "urlmap.js"
[[object]]
name = "StyleProvider"
[[object.signal]]
name = "gtk-private-changed"
hidden = true
[check]
ignore_deprecated = true

View File

@@ -140,11 +140,6 @@ capture phase, and key bindings locally, during the target phase.
Under the hood, all shortcuts are represented as instances of `GtkShortcut`, Under the hood, all shortcuts are represented as instances of `GtkShortcut`,
and they are managed by `GtkShortcutController`. and they are managed by `GtkShortcutController`.
Note that GTK does not do anything to map the primary shortcut modifier
to <kbd>Command</kbd> on macOS. If you want to let your application to follow
macOS user experience conventions, you must create macOS-specific keyboard shortcuts.
The <kbd>Command</kbd> is named `Meta` (`GDK_META_MASK`) in GTK.
## Text input ## Text input
When actual text input is needed (i.e. not just keyboard shortcuts), When actual text input is needed (i.e. not just keyboard shortcuts),

View File

@@ -14,7 +14,6 @@ expand_content_md_files = [
'running.md', 'running.md',
'migrating-2to4.md', 'migrating-2to4.md',
'migrating-3to4.md', 'migrating-3to4.md',
'migrating-4to5.md',
'actions.md', 'actions.md',
'input-handling.md', 'input-handling.md',
'drawing-model.md', 'drawing-model.md',
@@ -26,8 +25,7 @@ expand_content_md_files = [
'section-tree-widget.md', 'section-tree-widget.md',
'section-list-widget.md', 'section-list-widget.md',
'question_index.md', 'question_index.md',
'visual_index.md', 'visual_index.md'
'tools.md',
] ]
gtk_images = [] gtk_images = []
@@ -62,52 +60,39 @@ if get_option('documentation')
build_by_default: true, build_by_default: true,
install: true, install: true,
install_dir: docs_dir, install_dir: docs_dir,
install_tag: 'doc',
)
test('doc-check-gtk',
gidocgen,
args: [
'check',
'--config', gtk4_toml,
'--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gtk'),
gtk_gir[0],
],
depends: gtk_gir[0],
suite: ['docs', 'failing'],
) )
endif endif
rst2man = find_program('rst2man', 'rst2man.py', required: get_option('man-pages')) rst2man = find_program('rst2man', 'rst2man.py', required: false)
rst2html5 = find_program('rst2html5', 'rst2html5.py', required: get_option('documentation')) if get_option('man-pages') and not rst2man.found()
error('No rst2man found, but man pages were explicitly enabled')
endif
rst_files = [ if get_option('man-pages') and rst2man.found()
[ 'gtk4-broadwayd', '1' ], rst_files = [
[ 'gtk4-builder-tool', '1' ], [ 'gtk4-broadwayd', '1' ],
[ 'gtk4-encode-symbolic-svg', '1', ], [ 'gtk4-builder-tool', '1' ],
[ 'gtk4-image-tool', '1' ], [ 'gtk4-encode-symbolic-svg', '1', ],
[ 'gtk4-launch', '1', ], [ 'gtk4-launch', '1', ],
[ 'gtk4-query-settings', '1', ], [ 'gtk4-query-settings', '1', ],
[ 'gtk4-rendernode-tool', '1' ], [ 'gtk4-rendernode-tool', '1' ],
[ 'gtk4-update-icon-cache', '1', ], [ 'gtk4-update-icon-cache', '1', ],
[ 'gtk4-path-tool', '1', ], [ 'gtk4-path-tool', '1', ],
]
if get_option('build-demos')
rst_files += [
[ 'gtk4-demo', '1', ],
[ 'gtk4-demo-application', '1', ],
[ 'gtk4-widget-factory', '1', ],
[ 'gtk4-icon-browser', '1', ],
[ 'gtk4-node-editor', '1', ],
] ]
endif
rst2x_flags = [ if get_option('build-demos')
'--syntax-highlight=none', rst_files += [
] [ 'gtk4-demo', '1', ],
[ 'gtk4-demo-application', '1', ],
[ 'gtk4-widget-factory', '1', ],
[ 'gtk4-icon-browser', '1', ],
[ 'gtk4-node-editor', '1', ],
]
endif
if get_option('man-pages') rst2man_flags = [
'--syntax-highlight=none',
]
foreach rst: rst_files foreach rst: rst_files
man_name = rst[0] man_name = rst[0]
@@ -118,34 +103,12 @@ if get_option('man-pages')
output: '@0@.@1@'.format(man_name, man_section), output: '@0@.@1@'.format(man_name, man_section),
command: [ command: [
rst2man, rst2man,
rst2x_flags, rst2man_flags,
'@INPUT@', '@INPUT@',
], ],
capture: true, capture: true,
install: true, install: true,
install_dir: get_option('mandir') / 'man@0@'.format(man_section), install_dir: get_option('mandir') / 'man@0@'.format(man_section),
install_tag: 'doc',
)
endforeach
endif
if get_option('documentation')
foreach rst: rst_files
man_name = rst[0]
custom_target(
input: '@0@.rst'.format(man_name),
output: '@0@.html'.format(man_name),
command: [
rst2html5,
rst2x_flags,
'@INPUT@',
],
capture: true,
install: true,
install_dir: docs_dir / 'gtk4',
install_tag: 'doc',
) )
endforeach endforeach
endif endif

View File

@@ -451,11 +451,11 @@ hint about how modifiers are expected to be used. It also promoted
the use of `<Primary>` instead of `<Control>` to specify accelerators that the use of `<Primary>` instead of `<Control>` to specify accelerators that
adapt to platform conventions. adapt to platform conventions.
In GTK 4, the meaning of modifiers has been fixed, and applications are In GTK 4, the meaning of modifiers has been fixed, and backends are
expected to map the platform conventions to the existing modifiers. expected to map the platform conventions to the existing modifiers.
The expected use of modifiers in GTK 4 is: The expected use of modifiers in GTK 4 is:
`GDK_CONTROL_MASK` (`GDK_META_MASK` on macOS) `GDK_CONTROL_MASK`
: Primary accelerators : Primary accelerators
`GDK_ALT_MASK` `GDK_ALT_MASK`
@@ -464,7 +464,7 @@ The expected use of modifiers in GTK 4 is:
`GDK_SHIFT_MASK` `GDK_SHIFT_MASK`
: Extending selections : Extending selections
`GDK_CONTROL_MASK` (`GDK_META_MASK` on macOS) `GDK_CONTROL_MASK`
: Modifying selections : Modifying selections
`GDK_CONTROL_MASK|GDK_ALT_MASK` `GDK_CONTROL_MASK|GDK_ALT_MASK`
@@ -473,15 +473,9 @@ The expected use of modifiers in GTK 4 is:
Consequently, `GdkModifierIntent` and related APIs have been removed, Consequently, `GdkModifierIntent` and related APIs have been removed,
and `<Control>` is preferred over `<Primary>` in accelerators. and `<Control>` is preferred over `<Primary>` in accelerators.
In GTK 3 on macOS, the `<Primary>` modifier mapped to the <kbd>Command</kbd> key.
In GTK 4, this is no longer the case: `<Primary>` is synonymous to `<Control>`.
If you want to make your application to feel native on macOS,
you need to add accelerators for macOS that use the `<Meta>` modifier.
A related change is that GTK 4 no longer supports the use of archaic A related change is that GTK 4 no longer supports the use of archaic
X11 'real' modifiers with the names Mod1,..., Mod5, and `GDK_MOD1_MASK` X11 'real' modifiers with the names Mod1,..., Mod5, and `GDK_MOD1_MASK`
has been renamed to `GDK_ALT_MASK` and `GDK_MOD2_MASK` has been renamed to has been renamed to `GDK_ALT_MASK`.
`GDK_META_MASK`.
### Replace `GtkClipboard` with `GdkClipboard` ### Replace `GtkClipboard` with `GdkClipboard`

View File

@@ -24,180 +24,83 @@ the motivation and goals of larger API changes.
## Cell renderers are going away ## Cell renderers are going away
Cell renderers were introduced in GTK 2 to support rendering of Cell renderers were introduced in GTK 2 to support rendering of
big data UIs, in particular treeviews. Over the years, more "big data" UIs, in particular treeviews. Over the years, more
data-like widgets have started to use them, and cell renderers "data-like" widgets have started to use them, and cell renderers
have grown into a shadowy, alternative rendering infrastructure have grown into a shadowy, alternative rendering infrastructure
that duplicates much of what widgets do, while duplicating the that duplicates much of what widgets do, while duplicating the
code and adding their own dose of bugs. code and adding their own dose of bugs.
In GTK 4, replacement widgets for `GtkTreeView`, `GtkIconView` and In GTK 4, replacement widgets for GtkTreeView, GtkIconView and
`GtkComboBox` have appeared: [class@Gtk.ListView], [class@Gtk.ColumnView], [class@Gtk.GridView] GtkComboBox have appeared: GtkListView, GtkColumnView, GtkGridView
and [class@Gtk.DropDown]. For GTK 5, we will take the next step and remove and GtkDropDown. For GTK 5, we will take the next step and remove
all cell renderer-based widgets. all cell renderer-based widgets.
## Themed rendering APIs are going away ## Themed rendering APIs are going away
The old GTK 2 era rendering APIs for theme components like The old GTK 2 era rendering APIs for theme components like
`gtk_render_frame()` or `gtk_render_check()` have not been used by gtk_render_frame() or gtk_render_check() have not been used by
GTK itself even in later GTK 3, but they have been kept around GTK itself even in later GTK 3, but they have been kept around
for the benefit of external drawing users applications that for the benefit of "external drawing" users - applications that
want their controls to look like GTK without using widgets. want their controls to look like GTK without using widgets.
Supporting this is increasingly getting in the way of making Supporting this is increasingly getting in the way of making
the GTK CSS machinery fast and correct. One notable problem is the GTK CSS machinery fast and correct. One notable problem is
that temporary style changes (using `gtk_style_context_save()`) that temporary style changes (using gtk_style_context_save())
is breaking animations. Therefore, these APIs will be going away is breaking animations. Therefore, these APIs will be going away
in GTK 5, together with their more modern [class@Gtk.Snapshot] variants in GTK 5, together with their more modern GtkSnapshot variants
like `gtk_snapshot_render_background()` or `gtk_snapshot_render_focus()`. like gtk_snapshot_render_background() or gtk_snapshot_render_focus().
The best way to render parts of your widget using CSS styling The best way to render parts of your widget using CSS styling
is to use subwidgets. For example, to show a piece of text with is to use subwidgets. For example, to show a piece of text with
fonts, effects and shadows according to the current CSS style, fonts, effects and shadows according to the current CSS style,
use a [class@Gtk.Label]. use a GtkLabel.
If you have a need for custom drawing that fits into the current If you have a need for custom drawing that fits into the current
(dark or light) theme, e.g. for rendering a graph, you can still (dark or light) theme, e.g. for rendering a graph, you can still
get the current style foreground color, using get the current style foreground color, using
[method@Gtk.Widget.get_color]. [method@Gtk.Widget.get_style_color].
## Local stylesheets are going away ## Local stylesheets are going away
The cascading part of GTKs CSS implementation is complicated by The cascading part of GTK's CSS implementation is complicated by
the existence of local stylesheets (i.e. those added with the existence of local stylesheets (i.e. those added with
`gtk_style_context_add_provider()`). And local stylesheets are gtk_style_context_add_provider()). And local stylesheets are
unintuitive in that they do not apply to the whole subtree of unintuitive in that they do not apply to the whole subtree of
widgets, but just to the one widget where the stylesheet was widgets, but just to the one widget where the stylesheet was
added. added.
GTK 5 will no longer provide this functionality. The recommendation GTK 5 will no longer provide this functionality. The recommendations
is to use a global stylesheet (i.e. [func@Gtk.StyleContext.add_provider_for_display]) is to use a global stylesheet (i.e. gtk_style_context_add_provider_for_display())
and rely on style classes to make your CSS apply only where desired. and rely on style classes to make your CSS apply only where desired.
## Non-standard CSS extensions are going away
GTKs CSS machinery has a some non-standard extensions around colors:
named colors with `@define-color` and color functions: `lighter()`, `darker()`,
`shade()`, `alpha()`, `mix()`.
GTK now implements equivalent functionality from the CSS specs.
### `@define-color` is going away
`@define-color` should be replaced by custom properties in the `:root` scope.
Instead of
```
@define-color fg_color #2e3436
...
box {
color: @fg_color;
}
```
use
```
:root {
--fg-color: #2e3436;
}
...
box {
color: var(--fg-color);
}
```
For more information about custom CSS properties and variables, see the
[CSS Custom Properties for Cascading Variables](https://www.w3.org/TR/css-variables-1/)
spec.
### Color expressions are going away
The color functions can all be replaced by combinations of `calc()` and `color-mix()`.
`lighter(c)` and `darker(c)` are just `shade(c, 1.3)` or `shade(c, 0.7)`, respectively, and
thus can be handled the same way as shade in the examples below.
Replace
```
a {
color: mix(red, green, 0.8);
}
b {
color: alpha(green, 0.6);
}
c {
color: shade(red, 1.3);
}
d {
color: shade(red, 0.7);
}
```
with
```
a {
color: color-mix(in srgb, red, green 80%);
}
b {
color: rgb(from green, r g b / calc(alpha * 0.6));
}
c {
color: hsl(from red, h calc(s * 1.3) calc(l * 1.3));
}
d {
color: hsl(from red, h calc(s * 0.7) calc(l * 0.7));
}
```
Variations of these replacements are possible.
Note that GTK has historically computed `mix()` and `shade()` values in the SRGB and HSL
colorspaces, but using OKLAB instead might yield slightly better results.
For more information about color-mix(), see the
[CSS Color](https://drafts.csswg.org/css-color-5) spec.
## Chooser interfaces are going away ## Chooser interfaces are going away
The `GtkColorChooser`, `GtkFontChooser`, `GtkFileChooser` and `GtkAppChooser` The GtkColorChooser, GtkFontChooser, GtkFileChooser and GtkAppChooser
interfaces and their implementations as dialogs, buttons and widgets interfaces and their implementations as dialogs, buttons and widgets
are phased out. The are being replaced by a new family of async APIs are phased out. The are being replaced by a new family of async APIs
that will be more convenient to use from language bindings, in particular that will be more convenient to use from language bindings, in particular
for languages that have concepts like promises. The new APIs are for languages that have concepts like promises. The new APIs are
[class@Gtk.ColorDialog], [class@Gtk.FontDialog] and [class@Gtk.FileDialog], [class@Gtk.ColorDialog], [class@Gtk.FontDialog] and [class@Gtk.FileDialog],
There are also equivalents for some of the button widgets: There are also equivalents for some of the 'button' widgets:
[class@Gtk.ColorDialogButton], [class@Gtk.FontDialogButton]. [class@Gtk.ColorDialogButton], [class@Gtk.FontDialogButton].
## GtkMessageDialog is going away ## GtkMessageDialog is going away
Like the Chooser interfaces, `GtkMessageDialog` has been replaced by Like the Chooser interfaces, GtkMessageDialog has been replaced by
a new async API that will be more convenient, in particular for a new async API that will be more convenient, in particular for
language binding. The new API is [class@Gtk.AlertDialog]. language binding. The new API is [class@Gtk.AlertDialog].
## GtkDialog is going away ## GtkDialog is going away
After `gtk_dialog_run()` was removed, the usefulness of `GtkDialog` After gtk_dialog_run() was removed, the usefulness of GtkDialog
is much reduced, and it has awkward, archaic APIs. Therefore, is much reduced, and it has awkward, archaice APIs. Therefore,
it is dropped. The recommended replacement is to just create it is dropped. The recommended replacement is to just create
your own window and add buttons as required, either in the header your own window and add buttons as required, either in the header
or elsewhere. or elsewhere.
## GtkInfoBar is going away ## GtkInfoBar is going away
`GtkInfoBar` had a dialog API, and with dialogs going away, it was time to GtkInfoBar had a dialog API, and with dialogs going away, it was time to
retire it. If you need such a widget, it is relatively trivial to create one retire it. If you need such a widget, it is relatively trivial to create one
using a [class@Gtk.Revealer] with labels and buttons. using a [class@Gtk.Revealer] with labels and buttons.
@@ -205,11 +108,11 @@ Other libraries, such as libadwaita, may provide replacements as well.
## gtk_show_uri is being replaced ## gtk_show_uri is being replaced
Instead of `gtk_show_uri()`, you should use [class@Gtk.UriLauncher]or [class@Gtk.FileLauncher]. Instead of gtk_show_uri(), you should use GtkUriLauncher or GtkFileLauncher.
## GtkStatusbar is going away ## GtkStatusbar is going away
This is an old fashioned widget that does not do all that much any more, since This is an oldfashioned widget that does not do all that much anymore, since
it no longer has a resize handle for the window. it no longer has a resize handle for the window.
## GtkLockButton and GtkVolumeButton are going away ## GtkLockButton and GtkVolumeButton are going away
@@ -217,22 +120,22 @@ it no longer has a resize handle for the window.
These are very specialized widgets that should better live with the application These are very specialized widgets that should better live with the application
where they are used. where they are used.
## Widget size API changes ## Widget size api changes
The functions `gtk_widget_get_allocated_width()` and `gtk_widget_get_allocated_height()` The functions gtk_widget_get_allocated_width() and gtk_widget_get_allocated_height()
are going away. In most cases, [method@Gtk.Widget.get_width] and [method@Gtk.Widget.get_height] are going away. In most cases, [method@Gtk.Widget.get_width] and [method@Gtk.Widget.get_height]
are suitable replacements. Note that the semantics are slightly different though: are suitable replacements. Note that the semantics are slightly different though:
the old functions return the size of the CSS border area, while the new functions return the old functions return the size of the CSS border area, while the new functions return
the size of the widgets content area. In places where this difference matters, you can the size of the widgets content area. In places where this difference matters, you can
use `gtk_widget_compute_bounds (widget, widget, &bounds)` instead. use `gtk_widget_compute_bounds (widget, widget, &bounds)` instead.
The function `gtk_widget_get_allocation()` is also going away. It does not have a direct The function gtk_widget_get_allocation() is also going away. It does not have a direct
replacement, but the previously mentioned alternatives can be used for it too. replacement, but the previously mentioned alternatives can be used for it too.
The function `gtk_widget_get_allocated_baseline()` has been renamed to [method@Gtk.Widget.get_baseline]. The function gtk_widget_get_allocated_baseline() has been renamed to [method@Gtk.Widget.get_baseline].
## Stop using GdkPixbuf ## Stop using GdkPixbuf
GTK is moving away from `GdkPixbuf` as the primary API for transporting image data, in favor GTK is moving away from GdkPixbuf as the primary API for transporting image data, in favor
of [class@Gdk.Texture]. APIs that are accepting or returning `GdkPixbuf`s are being replaced by equivalent of GdkTexture. APIs that are accepting or returning GdkPixbufs are being replaced by equivalent
APIs using `GdkTexture` or [iface@Gdk.Paintable] objects. APIs using GdkTexture or GdkPaintable objects.

View File

@@ -7,5 +7,5 @@ on top of the Quartz API.
Currently, the macOS port does not use any additional commandline options Currently, the macOS port does not use any additional commandline options
or environment variables. or environment variables.
For up-to-date information on building, installation, and bundling, see the For up-to-date information about the current status of this port, see the
[GTK website](https://www.gtk.org/docs/installations/macos). [project page](https://wiki.gnome.org/Projects/GTK/OSX).

View File

@@ -64,6 +64,6 @@ GTK is divided into three parts:
[cairo]: https://www.cairographics.org/manual/ [cairo]: https://www.cairographics.org/manual/
[opengl]: https://www.opengl.org/about/ [opengl]: https://www.opengl.org/about/
[vulkan]: https://www.vulkan.org/ [vulkan]: https://www.vulkan.org/
[pango]: https://docs.gtk.org/Pango/ [pango]: https://docs.gtk.org/pango/
[gdkpixbuf]: https://docs.gtk.org/gdk-pixbuf/ [gdkpixbuf]: https://docs.gtk.org/gdk-pixbuf/
[graphene]: https://ebassi.github.io/graphene/ [graphene]: https://ebassi.github.io/graphene/

View File

@@ -5,12 +5,10 @@ Slug: gtk-running
GTK inspects a number of environment variables in addition to GTK inspects a number of environment variables in addition to
standard variables like `LANG`, `PATH`, `HOME` or `DISPLAY`; mostly standard variables like `LANG`, `PATH`, `HOME` or `DISPLAY`; mostly
to determine paths to look for certain files. The to determine paths to look for certain files. The [X11](#x11-envar),
[X11](https://docs.gtk.org/gtk4/x11.html#x11-specific-environment-variables), [Wayland](#wayland-envar), [Windows](#win32-envar) and
[Wayland](https://docs.gtk.org/gtk4/wayland.html#wayland-specific-environment-variables), [Broadway](#broadway-envar) GDK backends use some additional
[Windows](https://docs.gtk.org/gtk4/windows.html#windows-specific-environment-variables) and environment variables.
[Broadway](https://docs.gtk.org/gtk4/broadway.html#broadway-specific-environment-variables)
GDK backends use some additional environment variables.
Note that environment variables are generally used for debugging Note that environment variables are generally used for debugging
purposes. They are not guaranteed to be API stable, and should not purposes. They are not guaranteed to be API stable, and should not
@@ -19,7 +17,8 @@ be used for end-user configuration and customization.
### `GTK_DEBUG` ### `GTK_DEBUG`
This variable can be set to a list of debug options, which cause GTK to This variable can be set to a list of debug options, which cause GTK to
print out different types of debugging information. print out different types of debugging information. Some of these options
are only available when GTK has been configured with `-Ddebug=true`.
`actions` `actions`
: Actions and menu models : Actions and menu models
@@ -64,7 +63,7 @@ print out different types of debugging information.
: Layout managers : Layout managers
`accessibility` `accessibility`
: Accessibility state changes : Accessibility state changs
A number of keys are influencing behavior instead of just logging: A number of keys are influencing behavior instead of just logging:
@@ -168,7 +167,8 @@ The `loaders.cache` file is generated by the
### `GDK_DEBUG` ### `GDK_DEBUG`
This variable can be set to a list of debug options, which cause GDK to This variable can be set to a list of debug options, which cause GDK to
print out different types of debugging information. print out different types of debugging information. Some of these options
are only available when GTK has been configured with `-Ddebug=true`.
`misc` `misc`
: Miscellaneous information : Miscellaneous information
@@ -221,15 +221,36 @@ A number of options affect behavior instead of logging:
: Force graphics offload for all textures, even when slower. This allows : Force graphics offload for all textures, even when slower. This allows
to debug offloading in the absence of dmabufs. to debug offloading in the absence of dmabufs.
`gl-disable`
: Disable OpenGL support
`gl-no-fractional` `gl-no-fractional`
: Disable fractional scaling for OpenGL. : Disable fractional scaling for OpenGL.
`gl-debug` `gl-debug`
: Insert debugging information in OpenGL : Insert debugging information in OpenGL
`gl-disable-gl`
: Don't allow the use of OpenGL GL API. This forces GLES to be used
`gl-disable-gles`
: Don't allow the use of OpenGL GLES API. This forces GL to be used
`gl-prefer-gl` `gl-prefer-gl`
: Prefer OpenGL over OpenGL ES. This was the default behavior before GTK 4.14. : Prefer OpenGL over OpenGL ES. This was the default behavior before GTK 4.14.
`gl-egl`
: Use an EGL context on X11 or Windows
`gl-glx`
: Use GLX on X11
`gl-wgl`
: Use WGL on Windows
`vulkan-disable`
: Disable Vulkan support
`vulkan-validate` `vulkan-validate`
: Load the Vulkan validation layer, if available : Load the Vulkan validation layer, if available
@@ -239,26 +260,27 @@ A number of options affect behavior instead of logging:
`high-depth` `high-depth`
: Use high bit depth rendering if possible : Use high bit depth rendering if possible
`linear`
: Enable linear rendering
`hdr`
: Force HDR rendering
`no-vsync` `no-vsync`
: Repaint instantly (uses 100% CPU with animations) : Repaint instantly (uses 100% CPU with animations)
`dmabuf-disable`
: Disable dmabuf support
The special value `all` can be used to turn on all debug options. The special The special value `all` can be used to turn on all debug options. The special
value `help` can be used to obtain a list of all supported debug options. value `help` can be used to obtain a list of all supported debug options.
### `GSK_DEBUG` ### `GSK_DEBUG`
This variable can be set to a list of debug options, which cause GSK to This variable can be set to a list of debug options, which cause GSK to
print out different types of debugging information. print out different types of debugging information. Some of these options
are only available when GTK has been configured with `-Ddebug=true`.
`renderer` `renderer`
: General renderer information : General renderer information
`opengl`
: OpenGL renderer information
`vulkan` `vulkan`
: Check Vulkan errors : Check Vulkan errors
@@ -268,8 +290,8 @@ print out different types of debugging information.
`fallback` `fallback`
: Information about fallback usage in renderers : Information about fallback usage in renderers
`cache` `glyphcache`
: Information about caching : Information about glyph caching
`verbose` `verbose`
: Print verbose output while rendering : Print verbose output while rendering
@@ -285,12 +307,12 @@ A number of options affect behavior instead of logging:
`staging` `staging`
: Use a staging image for texture upload (Vulkan only) : Use a staging image for texture upload (Vulkan only)
`offload-disable`
: Disable graphics offload to subsurfaces
`cairo` `cairo`
: Overlay error pattern over cairo drawing (finds fallbacks) : Overlay error pattern over cairo drawing (finds fallbacks)
`occlusion`
: Overlay highlight over areas optimized via occlusion culling
The special value `all` can be used to turn on all debug options. The special The special value `all` can be used to turn on all debug options. The special
value `help` can be used to obtain a list of all supported debug options. value `help` can be used to obtain a list of all supported debug options.
@@ -323,41 +345,6 @@ a `*`, which means: try all remaining backends. The special value
backends. For more information about selecting backends, backends. For more information about selecting backends,
see the [func@Gdk.DisplayManager.get] function. see the [func@Gdk.DisplayManager.get] function.
### `GDK_DISABLE`
This variable can be set to a list of values, which cause GDK to
disable certain features.
`gl`
: Disable OpenGL support
`gl-api`
: Don't allow the use of OpenGL GL API. This forces GLES to be used
`gles-api`
: Don't allow the use of OpenGL GLES API. This forces GL to be used
`egl`
: Don't allow the use of an EGL context
`glx`
: Don't allow the use of GLX
`wgl`
: Don't allow the use of WGL
`vulkan`
: Disable Vulkan support
`dmabuf`
: Disable dmabuf support
`offload`
: Disable graphics offload to subsurfaces
`color-mgmt`
: Disable color management
### `GDK_GL_DISABLE` ### `GDK_GL_DISABLE`
This variable can be set to a list of values, which cause GDK to This variable can be set to a list of values, which cause GDK to
@@ -380,6 +367,13 @@ does not support them.
`base-instance` `base-instance`
:GL_EXT_base_instance :GL_EXT_base_instance
### `GDK_VULKAN_DEVICE`
This variable can be set to the index of a Vulkan device to override
the default selection of the device that is used for Vulkan rendering.
The special value `list` can be used to obtain a list of all Vulkan
devices.
### `GDK_VULKAN_DISABLE` ### `GDK_VULKAN_DISABLE`
This variable can be set to a list of values, which cause GDK to This variable can be set to a list of values, which cause GDK to
@@ -393,6 +387,15 @@ does not support them.
`ycbr` `ycbr`
: Do not support Ycbcr textures : Do not support Ycbcr textures
`descriptor-indexing`
: Force slow descriptor set layout codepath
`dynamic-indexing`
: Hardcode small number of buffer and texture arrays
`nonuniform-indexing`
: Split draw calls to ensure uniform texture accesses
`semaphore-export` `semaphore-export`
: Disable sync of exported dmabufs : Disable sync of exported dmabufs
@@ -402,9 +405,6 @@ does not support them.
`incremental-present` `incremental-present`
: Do not send damage regions : Do not send damage regions
`swapchain-maintenance`
: Do not use advanced swapchain features
The special value `all` can be used to turn on all values. The special The special value `all` can be used to turn on all values. The special
value `help` can be used to obtain a list of all supported values. value `help` can be used to obtain a list of all supported values.
@@ -423,8 +423,14 @@ using and the GDK backend supports them:
`cairo` `cairo`
: Selects the fallback Cairo renderer : Selects the fallback Cairo renderer
`opengl`
: Selects the default OpenGL renderer
`gl`
: Selects the "gl" OpenGL renderer
`ngl` `ngl`
: Selects the OpenGL renderer : Selects the "ngl" OpenGL renderer
`vulkan` `vulkan`
: Selects the Vulkan renderer : Selects the Vulkan renderer
@@ -453,12 +459,12 @@ using and the GDK backend supports them:
This variable can be set to a list of values, which cause GSK to This variable can be set to a list of values, which cause GSK to
disable certain optimizations of the "ngl" and "vulkan" renderer. disable certain optimizations of the "ngl" and "vulkan" renderer.
`uber`
: Don't use the uber shader
`clear` `clear`
: Use shaders instead of vkCmdClearAttachment()/glClear() : Use shaders instead of vkCmdClearAttachment()/glClear()
`merge`
: USe one vkCmdDraw()/glDrawArrays() per operation
`blit` `blit`
: Use shaders instead of vkCmdBlit()/glBlitFramebuffer() : Use shaders instead of vkCmdBlit()/glBlitFramebuffer()
@@ -468,13 +474,6 @@ disable certain optimizations of the "ngl" and "vulkan" renderer.
`mipmap` `mipmap`
: Avoid creating mipmaps : Avoid creating mipmaps
`to-image`
: Don't fast-path creation of images for nodes
`occlusion`
: Disable occlusion culling via opacity tracking
The special value `all` can be used to turn on all values. The special The special value `all` can be used to turn on all values. The special
value `help` can be used to obtain a list of all supported values. value `help` can be used to obtain a list of all supported values.
@@ -562,12 +561,6 @@ To enable the GTK inspector, you can use the <kbd>Control</kbd>+<kbd>Shift</kbd>
<kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> keyboard shortcuts, or <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> keyboard shortcuts, or
set the `GTK_DEBUG=interactive` environment variable. set the `GTK_DEBUG=interactive` environment variable.
After opening the inspector, it listens for a few keyboard shortcuts that
let you use its frame and event recording functionality without moving the
focus away from the application window: <kbd>Super</kbd>+<kbd>R</kbd> turns
the recording on and off, and <kbd>Super</kbd>+<kbd>C</kbd> records a single
frame.
There are a few more environment variables that can be set to influence There are a few more environment variables that can be set to influence
how the inspector renders its UI. `GTK_INSPECTOR_DISPLAY` and how the inspector renders its UI. `GTK_INSPECTOR_DISPLAY` and
`GTK_INSPECTOR_RENDERER` determine the GDK display and the GSK `GTK_INSPECTOR_RENDERER` determine the GDK display and the GSK
@@ -578,7 +571,6 @@ the GTK inspector. The keyboard shortcuts can be disabled with the
`enable-inspector-keybinding` key in the `org.gtk.Settings.Debug` `enable-inspector-keybinding` key in the `org.gtk.Settings.Debug`
GSettings schema. GSettings schema.
## Profiling ## Profiling
GTK supports profiling with sysprof. It exports timing information GTK supports profiling with sysprof. It exports timing information

View File

@@ -171,7 +171,7 @@ Each relation name is part of the `GtkAccessibleRelation` enumeration.
| %GTK_ACCESSIBLE_RELATION_CONTROLS | “aria-controls” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_CONTROLS | “aria-controls” | a list of `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_DESCRIBED_BY | “aria-describedby” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_DESCRIBED_BY | “aria-describedby” | a list of `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_DETAILS | “aria-details” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_DETAILS | “aria-details” | a list of `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE | “aria-errormessage” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE | “aria-errormessage” | `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_FLOW_TO | “aria-flowto” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_FLOW_TO | “aria-flowto” | a list of `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_LABELLED_BY | “aria-labelledby” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_LABELLED_BY | “aria-labelledby” | a list of `GtkAccessible` |
| %GTK_ACCESSIBLE_RELATION_OWNS | “aria-owns” | a list of `GtkAccessible` | | %GTK_ACCESSIBLE_RELATION_OWNS | “aria-owns” | a list of `GtkAccessible` |
@@ -300,7 +300,7 @@ The attributes can also enhance the UI:
```c ```c
gtk_button_set_label (GTK_BUTTON (button), "Download"); gtk_button_set_label (GTK_BUTTON (button), "Download");
gtk_box_append (GTK_BOX (box), button); gtk_box_append (GTK_BOX (button), button);
gtk_label_set_text (GTK_LABEL (label), "Final report.pdf"); gtk_label_set_text (GTK_LABEL (label), "Final report.pdf");
gtk_box_append (GTK_BOX (box), label); gtk_box_append (GTK_BOX (box), label);

View File

@@ -1,19 +0,0 @@
Title: Tools and Demos
GTK ships with a number of tools and demos that come with their own
documentation in the form of man pages.
- [gtk4-broadwayd](gtk4-broadwayd.html)
- [gtk4-builder-tool](gtk4-builder-tool.html)
- [gtk4-demo](gtk4-demo.html)
- [gtk4-demo-application](gtk4-demo-application.html)
- [gtk4-encode-symbolic-svg](gtk4-encode-symbolic-svg.html)
- [gtk4-icon-browser](gtk4-icon-browser.html)
- [gtk4-image-tool](gtk4-image-tool.html)
- [gtk4-launch](gtk4-launch.html)
- [gtk4-node-editor](gtk4-node-editor.html)
- [gtk4-path-tool](gtk4-path-tool.html)
- [gtk4-query-settings](gtk4-query-settings.html)
- [gtk4-rendernode-tool](gtk4-rendernode-tool.html)
- [gtk4-update-icon-cache](gtk4-update-icon-cache.html)
- [gtk4-widget-factory](gtk4-widget-factory.html)

View File

@@ -43,7 +43,7 @@ X11 details, in particular the ICCCM and the Extended Window Manager
Hints specifications. [freedesktop.org](http://www.freedesktop.org/standards/) Hints specifications. [freedesktop.org](http://www.freedesktop.org/standards/)
has links to many relevant specifications. has links to many relevant specifications.
The GDK manual covers [using Xlib in a GTK program](https://docs.gtk.org/gdk4/x11.html). The GDK manual covers [using Xlib in a GTK program](#gdk-X-Window-System-Interaction).
### Server, client, window manager ### Server, client, window manager

View File

@@ -49,7 +49,7 @@ main (int argc,
g_chdir (GTK_SRCDIR); g_chdir (GTK_SRCDIR);
#endif #endif
GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv); int status = g_application_run (G_APPLICATION (app), argc, argv);

View File

@@ -173,7 +173,7 @@ main (int argc,
GtkApplication *app; GtkApplication *app;
int status; int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv); status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app); g_object_unref (app);

View File

@@ -60,7 +60,7 @@ main (int argc,
GtkApplication *app; GtkApplication *app;
int status; int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv); status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app); g_object_unref (app);

View File

@@ -37,8 +37,10 @@ main (int argc,
{ {
GtkApplication *app; GtkApplication *app;
app = gtk_application_new ("org.gtk.Example.GtkSearchBar", G_APPLICATION_DEFAULT_FLAGS); app = gtk_application_new ("org.gtk.Example.GtkSearchBar",
g_signal_connect (app, "activate", G_CALLBACK (activate_cb), NULL); G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate",
G_CALLBACK (activate_cb), NULL);
return g_application_run (G_APPLICATION (app), argc, argv); return g_application_run (G_APPLICATION (app), argc, argv);
} }

View File

@@ -19,7 +19,7 @@ main (int argc,
GtkApplication *app; GtkApplication *app;
int status; int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv); status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app); g_object_unref (app);

View File

@@ -111,7 +111,7 @@ gboolean broadway_server_surface_translate (BroadwayServer *
int dx, int dx,
int dy); int dy);
guint32 broadway_server_upload_texture (BroadwayServer *server, guint32 broadway_server_upload_texture (BroadwayServer *server,
GBytes *bytes); GBytes *texture);
void broadway_server_release_texture (BroadwayServer *server, void broadway_server_release_texture (BroadwayServer *server,
guint32 id); guint32 id);
cairo_surface_t * broadway_server_create_surface (int width, cairo_surface_t * broadway_server_create_surface (int width,

View File

@@ -33,11 +33,9 @@ gdk_broadway_cairo_context_dispose (GObject *object)
} }
static void static void
gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context, gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
GdkMemoryDepth depth, GdkMemoryDepth depth,
cairo_region_t *region, cairo_region_t *region)
GdkColorState **out_color_state,
GdkMemoryDepth *out_depth)
{ {
GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context); GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context);
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self)); GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
@@ -61,9 +59,6 @@ gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_fill (cr); cairo_fill (cr);
cairo_destroy (cr); cairo_destroy (cr);
*out_color_state = GDK_COLOR_STATE_SRGB;
*out_depth = gdk_color_state_get_depth (GDK_COLOR_STATE_SRGB);
} }
static void static void

View File

@@ -33,11 +33,9 @@ gdk_broadway_draw_context_dispose (GObject *object)
} }
static void static void
gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context, gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context,
GdkMemoryDepth depth, GdkMemoryDepth depth,
cairo_region_t *region, cairo_region_t *region)
GdkColorState **out_color_state,
GdkMemoryDepth *out_depth)
{ {
GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context); GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context);
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self)); GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
@@ -54,9 +52,6 @@ gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context,
self->nodes = g_array_new (FALSE, FALSE, sizeof(guint32)); self->nodes = g_array_new (FALSE, FALSE, sizeof(guint32));
self->node_textures = g_ptr_array_new_with_free_func (g_object_unref); self->node_textures = g_ptr_array_new_with_free_func (g_object_unref);
*out_color_state = GDK_COLOR_STATE_SRGB;
*out_depth = gdk_color_state_get_depth (GDK_COLOR_STATE_SRGB);
} }
static void static void

View File

@@ -56,7 +56,7 @@ void _gdk_broadway_surface_translate (GdkSurface *surface,
int dx, int dx,
int dy); int dy);
gboolean _gdk_broadway_moveresize_handle_event (GdkDisplay *display, gboolean _gdk_broadway_moveresize_handle_event (GdkDisplay *display,
BroadwayInputMsg *event); BroadwayInputMsg *msg);
gboolean _gdk_broadway_moveresize_configure_done (GdkDisplay *display, gboolean _gdk_broadway_moveresize_configure_done (GdkDisplay *display,
GdkSurface *surface); GdkSurface *surface);
void _gdk_broadway_roundtrip_notify (GdkSurface *surface, void _gdk_broadway_roundtrip_notify (GdkSurface *surface,

View File

@@ -49,135 +49,6 @@
G_DEFINE_TYPE (GdkBroadwaySurface, gdk_broadway_surface, GDK_TYPE_SURFACE) G_DEFINE_TYPE (GdkBroadwaySurface, gdk_broadway_surface, GDK_TYPE_SURFACE)
static void
gdk_broadway_surface_toplevel_resize (GdkSurface *surface,
int width,
int height);
static void
gdk_broadway_surface_set_geometry_hints (GdkSurface *surface,
const GdkGeometry *geometry,
GdkSurfaceHints geom_mask);
static void
gdk_broadway_surface_move_resize_internal (GdkSurface *surface,
gboolean with_move,
int x,
int y,
int width,
int height);
static void
compute_toplevel_size (GdkSurface *surface,
gboolean resizible,
int *width,
int *height)
{
GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
GdkDisplay *display = gdk_surface_get_display (surface);
GdkMonitor *monitor;
GdkToplevelSize size;
int bounds_width, bounds_height;
GdkGeometry geometry;
GdkSurfaceHints mask;
monitor = gdk_display_get_monitor_at_surface (display, surface);
if (monitor)
{
GdkRectangle monitor_geometry;
gdk_monitor_get_geometry (monitor, &monitor_geometry);
bounds_width = monitor_geometry.width;
bounds_height = monitor_geometry.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);
*width = size.width;
*height = size.height;
impl->resizible = (impl->resizible && resizible);
if (impl->resizible)
{
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;
}
gdk_broadway_surface_set_geometry_hints (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)))
{
gdk_surface_constrain_size (&geometry, mask,
size.width, size.height,
&size.width, &size.height);
if (impl->last_computed_width != size.width ||
impl->last_computed_height != size.height)
{
*width = size.width;
*height = size.height;
impl->last_computed_width = size.width;
impl->last_computed_height = size.height;
gdk_broadway_surface_toplevel_resize (surface, *width, *height);
}
}
if (size.shadow.is_valid)
{
impl->shadow_left = size.shadow.left;
impl->shadow_right = size.shadow.right;
impl->shadow_top = size.shadow.top;
impl->shadow_bottom = size.shadow.bottom;
}
}
static gboolean
compute_size_idle (gpointer user_data)
{
GdkSurface *surface = user_data;
GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
int width, height;
impl->compute_size_source_id = 0;
compute_toplevel_size (surface, TRUE, &width, &height);
return G_SOURCE_REMOVE;
}
static void
on_frame_clock_after_update (GdkFrameClock *clock,
GdkSurface *surface)
{
GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
if (impl->compute_size_source_id)
{
g_clear_handle_id (&impl->compute_size_source_id, g_source_remove);
compute_size_idle (surface);
}
}
/* We need to flush in an idle rather than AFTER_PAINT, as the clock /* We need to flush in an idle rather than AFTER_PAINT, as the clock
is frozen during e.g. surface resizes so the paint will not happen is frozen during e.g. surface resizes so the paint will not happen
and the surface resize request is never flushed. */ and the surface resize request is never flushed. */
@@ -241,8 +112,6 @@ connect_frame_clock (GdkSurface *surface)
g_signal_connect (frame_clock, "before-paint", g_signal_connect (frame_clock, "before-paint",
G_CALLBACK (on_frame_clock_before_paint), surface); G_CALLBACK (on_frame_clock_before_paint), surface);
g_signal_connect_after (frame_clock, "update",
G_CALLBACK (on_frame_clock_after_update), surface);
g_signal_connect (frame_clock, "after-paint", g_signal_connect (frame_clock, "after-paint",
G_CALLBACK (on_frame_clock_after_paint), surface); G_CALLBACK (on_frame_clock_after_paint), surface);
} }
@@ -254,8 +123,6 @@ disconnect_frame_clock (GdkSurface *surface)
g_signal_handlers_disconnect_by_func (frame_clock, g_signal_handlers_disconnect_by_func (frame_clock,
on_frame_clock_before_paint, surface); on_frame_clock_before_paint, surface);
g_signal_handlers_disconnect_by_func (frame_clock,
on_frame_clock_after_update, surface);
g_signal_handlers_disconnect_by_func (frame_clock, g_signal_handlers_disconnect_by_func (frame_clock,
on_frame_clock_after_paint, surface); on_frame_clock_after_paint, surface);
} }
@@ -270,7 +137,6 @@ gdk_broadway_surface_constructed (GObject *object)
if (!surface->parent) if (!surface->parent)
broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, self); broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, self);
self->resizible = TRUE;
self->id = _gdk_broadway_server_new_surface (broadway_display->server, self->id = _gdk_broadway_server_new_surface (broadway_display->server,
self->root_x, self->root_x,
self->root_y, self->root_y,
@@ -450,7 +316,6 @@ gdk_broadway_surface_hide (GdkSurface *surface)
_gdk_broadway_surface_grab_check_unmap (surface, _gdk_broadway_surface_grab_check_unmap (surface,
_gdk_broadway_server_get_next_serial (broadway_display->server)); _gdk_broadway_server_get_next_serial (broadway_display->server));
g_clear_handle_id (&impl->compute_size_source_id, g_source_remove);
if (_gdk_broadway_server_surface_hide (broadway_display->server, impl->id)) if (_gdk_broadway_server_surface_hide (broadway_display->server, impl->id))
queue_flush (surface); queue_flush (surface);
@@ -1144,8 +1009,6 @@ _gdk_broadway_moveresize_configure_done (GdkDisplay *display,
BroadwayInputMsg *tmp_event; BroadwayInputMsg *tmp_event;
MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
gdk_surface_request_layout (surface);
if (!mv_resize || surface != mv_resize->moveresize_surface) if (!mv_resize || surface != mv_resize->moveresize_surface)
return FALSE; return FALSE;
@@ -1305,43 +1168,6 @@ gdk_broadway_surface_beep (GdkSurface *surface)
return FALSE; return FALSE;
} }
static void
gdk_broadway_surface_request_layout (GdkSurface *surface)
{
GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
if (!impl->compute_size_source_id &&
GDK_IS_TOPLEVEL (surface))
{
impl->compute_size_source_id = g_idle_add_full (G_PRIORITY_HIGH - 10,
compute_size_idle,
surface,
NULL);
}
}
static gboolean
gdk_broadway_surface_compute_size (GdkSurface *surface)
{
int width, height;
if (GDK_IS_TOPLEVEL (surface))
{
compute_toplevel_size (surface, TRUE, &width, &height);
}
else
{
width = gdk_surface_get_width(surface);
height = gdk_surface_get_height(surface);
gdk_broadway_surface_move_resize_internal (surface, FALSE,
0, 0,
width,
height);
}
return FALSE;
}
static void static void
gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass) gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
{ {
@@ -1361,8 +1187,6 @@ gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
impl_class->destroy_notify = gdk_broadway_surface_destroy_notify; impl_class->destroy_notify = gdk_broadway_surface_destroy_notify;
impl_class->drag_begin = _gdk_broadway_surface_drag_begin; impl_class->drag_begin = _gdk_broadway_surface_drag_begin;
impl_class->get_scale = gdk_broadway_surface_get_scale; impl_class->get_scale = gdk_broadway_surface_get_scale;
impl_class->request_layout = gdk_broadway_surface_request_layout;
impl_class->compute_size = gdk_broadway_surface_compute_size;
} }
#define LAST_PROP 1 #define LAST_PROP 1
@@ -1680,12 +1504,55 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel,
GdkToplevelLayout *layout) GdkToplevelLayout *layout)
{ {
GdkSurface *surface = GDK_SURFACE (toplevel); GdkSurface *surface = GDK_SURFACE (toplevel);
GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
GdkDisplay *display = gdk_surface_get_display (surface);
GdkMonitor *monitor;
GdkToplevelSize size;
int bounds_width, bounds_height;
int width, height; int width, height;
GdkGeometry geometry;
GdkSurfaceHints mask;
gboolean maximize; gboolean maximize;
gdk_broadway_surface_unminimize (surface); gdk_broadway_surface_unminimize (surface);
compute_toplevel_size (surface, gdk_toplevel_layout_get_resizable (layout), &width, &height); monitor = gdk_display_get_monitor_at_surface (display, surface);
if (monitor)
{
GdkRectangle monitor_geometry;
gdk_monitor_get_geometry (monitor, &monitor_geometry);
bounds_width = monitor_geometry.width;
bounds_height = monitor_geometry.height;
}
else
{
bounds_width = G_MAXINT;
bounds_height = G_MAXINT;
}
gdk_toplevel_size_init (&size, bounds_width, bounds_height);
gdk_toplevel_notify_compute_size (toplevel, &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))
{
geometry.min_width = size.min_width;
geometry.min_height = size.min_height;
mask = GDK_HINT_MIN_SIZE;
}
else
{
geometry.max_width = geometry.min_width = width;
geometry.max_height = geometry.min_height = height;
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
}
gdk_broadway_surface_set_geometry_hints (surface, &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
gdk_broadway_surface_toplevel_resize (surface, width, height);
if (gdk_toplevel_layout_get_maximized (layout, &maximize)) if (gdk_toplevel_layout_get_maximized (layout, &maximize))
{ {
@@ -1695,7 +1562,14 @@ gdk_broadway_toplevel_present (GdkToplevel *toplevel,
gdk_broadway_surface_unmaximize (surface); gdk_broadway_surface_unmaximize (surface);
} }
gdk_surface_request_layout (surface); if (size.shadow.is_valid)
{
impl->shadow_left = size.shadow.left;
impl->shadow_right = size.shadow.right;
impl->shadow_top = size.shadow.top;
impl->shadow_bottom = size.shadow.bottom;
}
show_surface (surface); show_surface (surface);
} }

View File

@@ -76,13 +76,6 @@ struct _GdkBroadwaySurface
int shadow_right; int shadow_right;
int shadow_top; int shadow_top;
int shadow_bottom; int shadow_bottom;
int last_computed_width;
int last_computed_height;
guint compute_size_source_id;
gboolean resizible;
}; };
struct _GdkBroadwaySurfaceClass struct _GdkBroadwaySurfaceClass

View File

@@ -17,7 +17,6 @@
#pragma once #pragma once
#include <gio/gio.h>
void file_transfer_portal_register (void); void file_transfer_portal_register (void);

View File

@@ -43,14 +43,6 @@
#include <fribidi.h> #include <fribidi.h>
/* GTK has a general architectural assumption that gsize is pointer-sized
* (equivalent to uintptr_t), making it non-portable to architectures like
* CHERI where that isn't true. If a future release relaxes that
* assumption, changes will be needed in numerous places.
* See also https://gitlab.gnome.org/GNOME/glib/-/issues/2842 for the
* equivalent in GLib, which would be a prerequisite. */
G_STATIC_ASSERT (sizeof (gsize) == sizeof (void *));
G_STATIC_ASSERT (G_ALIGNOF (gsize) == G_ALIGNOF (void *));
/** /**
* GDK_WINDOWING_X11: * GDK_WINDOWING_X11:
@@ -128,40 +120,26 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "dmabuf", GDK_DEBUG_DMABUF, "Information about dmabuf buffers" }, { "dmabuf", GDK_DEBUG_DMABUF, "Information about dmabuf buffers" },
{ "offload", GDK_DEBUG_OFFLOAD, "Information about subsurfaces and graphics offload" }, { "offload", GDK_DEBUG_OFFLOAD, "Information about subsurfaces and graphics offload" },
{ "linear", GDK_DEBUG_LINEAR, "Enable linear rendering" },
{ "hdr", GDK_DEBUG_HDR, "Force HDR rendering" },
{ "portals", GDK_DEBUG_PORTALS, "Force use of portals" }, { "portals", GDK_DEBUG_PORTALS, "Force use of portals" },
{ "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals" }, { "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals" },
{ "force-offload", GDK_DEBUG_FORCE_OFFLOAD, "Force graphics offload for all textures" }, { "force-offload", GDK_DEBUG_FORCE_OFFLOAD, "Force graphics offload for all textures" },
{ "gl-disable", GDK_DEBUG_GL_DISABLE, "Disable OpenGL support" },
{ "gl-no-fractional", GDK_DEBUG_GL_NO_FRACTIONAL, "Disable fractional scaling for OpenGL" }, { "gl-no-fractional", GDK_DEBUG_GL_NO_FRACTIONAL, "Disable fractional scaling for OpenGL" },
{ "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" }, { "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" },
{ "gl-disable-gl", GDK_DEBUG_GL_DISABLE_GL, "Only allow OpenGL GLES API" },
{ "gl-disable-gles", GDK_DEBUG_GL_DISABLE_GLES, "Don't allow OpenGL GLES API" },
{ "gl-prefer-gl", GDK_DEBUG_GL_PREFER_GL, "Prefer GL over GLES API" }, { "gl-prefer-gl", GDK_DEBUG_GL_PREFER_GL, "Prefer GL over GLES API" },
{ "gl-egl", GDK_DEBUG_GL_EGL, "Use EGL on X11 or Windows" },
{ "gl-glx", GDK_DEBUG_GL_GLX, "Use GLX on X11" },
{ "gl-wgl", GDK_DEBUG_GL_WGL, "Use WGL on Windows" },
{ "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" },
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" },
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings" }, { "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings" },
{ "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible" }, { "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible" },
{ "no-vsync", GDK_DEBUG_NO_VSYNC, "Repaint instantly (uses 100% CPU with animations)" }, { "no-vsync", GDK_DEBUG_NO_VSYNC, "Repaint instantly (uses 100% CPU with animations)" },
{ "dmabuf-disable", GDK_DEBUG_DMABUF_DISABLE, "Disable dmabuf support" },
}; };
static const GdkDebugKey gdk_feature_keys[] = {
{ "gl", GDK_FEATURE_OPENGL, "Disable OpenGL support" },
{ "gl-api", GDK_FEATURE_GL_API, "Disable non-GLES GL API" },
{ "gles-api", GDK_FEATURE_GLES_API, "Disable GLES GL API" },
{ "egl", GDK_FEATURE_EGL, "Disable EGL" },
{ "glx", GDK_FEATURE_GLX, "Disable GLX" },
{ "wgl", GDK_FEATURE_WGL, "Disable WGL" },
{ "vulkan", GDK_FEATURE_VULKAN, "Disable Vulkan support" },
{ "dmabuf", GDK_FEATURE_DMABUF, "Disable dmabuf support" },
{ "offload", GDK_FEATURE_OFFLOAD, "Disable graphics offload" },
{ "color-mgmt", GDK_FEATURE_COLOR_MANAGEMENT, "Disable color management" },
};
static GdkFeatures gdk_features;
gboolean
gdk_has_feature (GdkFeatures features)
{
return (features & gdk_features) == features;
}
#ifdef G_HAS_CONSTRUCTORS #ifdef G_HAS_CONSTRUCTORS
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
@@ -229,7 +207,6 @@ gdk_ensure_resources (void)
guint guint
gdk_parse_debug_var (const char *variable, gdk_parse_debug_var (const char *variable,
const char *docs,
const GdkDebugKey *keys, const GdkDebugKey *keys,
guint nkeys) guint nkeys)
{ {
@@ -290,7 +267,6 @@ gdk_parse_debug_var (const char *variable,
max_width = MAX (max_width, strlen (keys[i].key)); max_width = MAX (max_width, strlen (keys[i].key));
max_width += 4; max_width += 4;
fprintf (stderr, "%s\n", docs);
fprintf (stderr, "Supported %s values:\n", variable); fprintf (stderr, "Supported %s values:\n", variable);
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
fprintf (stderr, " %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help); fprintf (stderr, " %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
@@ -318,26 +294,21 @@ gdk_parse_debug_var (const char *variable,
void void
gdk_pre_parse (void) gdk_pre_parse (void)
{ {
GdkFeatures disabled_features;
gdk_initialized = TRUE; gdk_initialized = TRUE;
gdk_ensure_resources (); gdk_ensure_resources ();
_gdk_debug_flags = gdk_parse_debug_var ("GDK_DEBUG", _gdk_debug_flags = gdk_parse_debug_var ("GDK_DEBUG",
"GDK_DEBUG can be set to values that make GDK print out different\n" gdk_debug_keys,
"types of debugging information or change the behavior of GDK for\n" G_N_ELEMENTS (gdk_debug_keys));
"debugging purposes.\n",
gdk_debug_keys,
G_N_ELEMENTS (gdk_debug_keys));
disabled_features = gdk_parse_debug_var ("GDK_DISABLE", /* These are global */
"GDK_DISABLE can be set to values which cause GDK to disable\n" if (_gdk_debug_flags & GDK_DEBUG_GL_EGL)
"certain features.\n", gdk_gl_backend_use (GDK_GL_EGL);
gdk_feature_keys, else if (_gdk_debug_flags & GDK_DEBUG_GL_GLX)
G_N_ELEMENTS (gdk_feature_keys)); gdk_gl_backend_use (GDK_GL_GLX);
else if (_gdk_debug_flags & GDK_DEBUG_GL_WGL)
gdk_features = GDK_ALL_FEATURES & ~disabled_features; gdk_gl_backend_use (GDK_GL_WGL);
#ifndef G_HAS_CONSTRUCTORS #ifndef G_HAS_CONSTRUCTORS
stash_and_unset_environment (); stash_and_unset_environment ();

View File

@@ -29,9 +29,7 @@
#include <gdk/gdkapplaunchcontext.h> #include <gdk/gdkapplaunchcontext.h>
#include <gdk/gdkcairo.h> #include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h> #include <gdk/gdkcairocontext.h>
#include <gdk/gdkcicpparams.h>
#include <gdk/gdkclipboard.h> #include <gdk/gdkclipboard.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkconfig.h> #include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h> #include <gdk/gdkcontentdeserializer.h>
#include <gdk/gdkcontentformats.h> #include <gdk/gdkcontentformats.h>
@@ -63,7 +61,6 @@
#include <gdk/gdkkeys.h> #include <gdk/gdkkeys.h>
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#include <gdk/gdkmemorytexture.h> #include <gdk/gdkmemorytexture.h>
#include <gdk/gdkmemorytexturebuilder.h>
#include <gdk/gdkmonitor.h> #include <gdk/gdkmonitor.h>
#include <gdk/gdkpaintable.h> #include <gdk/gdkpaintable.h>
#include <gdk/gdkpango.h> #include <gdk/gdkpango.h>

View File

@@ -120,7 +120,7 @@ gdk_app_launch_context_class_init (GdkAppLaunchContextClass *klass)
context_class->launch_failed = gdk_app_launch_context_launch_failed; context_class->launch_failed = gdk_app_launch_context_launch_failed;
/** /**
* GdkAppLaunchContext:display: * GdkAppLaunchContext:display: (attributes org.gtk.Property.get=gdk_app_launch_context_get_display)
* *
* The display that the `GdkAppLaunchContext` is on. * The display that the `GdkAppLaunchContext` is on.
*/ */
@@ -169,7 +169,7 @@ gdk_app_launch_context_get_display_name (GAppLaunchContext *context,
} }
/** /**
* gdk_app_launch_context_get_display: * gdk_app_launch_context_get_display: (attributes org.gtk.Method.get_property=display)
* @context: a `GdkAppLaunchContext` * @context: a `GdkAppLaunchContext`
* *
* Gets the `GdkDisplay` that @context is for. * Gets the `GdkDisplay` that @context is for.

View File

@@ -41,10 +41,8 @@ G_BEGIN_DECLS
#ifdef GDK_ARRAY_NULL_TERMINATED #ifdef GDK_ARRAY_NULL_TERMINATED
#define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1) #define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1)
#define GDK_ARRAY_MAX_SIZE (G_MAXSIZE / sizeof (_T_) - 1)
#else #else
#define GDK_ARRAY_REAL_SIZE(_size) (_size) #define GDK_ARRAY_REAL_SIZE(_size) (_size)
#define GDK_ARRAY_MAX_SIZE (G_MAXSIZE / sizeof (_T_))
#endif #endif
/* make this readable */ /* make this readable */
@@ -179,23 +177,18 @@ G_GNUC_UNUSED static inline void
gdk_array(reserve) (GdkArray *self, gdk_array(reserve) (GdkArray *self,
gsize n) gsize n)
{ {
gsize new_capacity, size, capacity; gsize new_size, size;
if (G_UNLIKELY (n > GDK_ARRAY_MAX_SIZE)) if (n <= gdk_array(get_capacity) (self))
g_error ("requesting array size of %zu, but maximum size is %zu", n, GDK_ARRAY_MAX_SIZE); return;
capacity = gdk_array(get_capacity) (self);
if (n <= capacity)
return;
size = gdk_array(get_size) (self); size = gdk_array(get_size) (self);
/* capacity * 2 can overflow, that's why we MAX() */ new_size = ((gsize) 1) << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
new_capacity = MAX (GDK_ARRAY_REAL_SIZE (n), capacity * 2);
#ifdef GDK_ARRAY_PREALLOC #ifdef GDK_ARRAY_PREALLOC
if (self->start == self->preallocated) if (self->start == self->preallocated)
{ {
self->start = g_new (_T_, new_capacity); self->start = g_new (_T_, new_size);
memcpy (self->start, self->preallocated, sizeof (_T_) * GDK_ARRAY_REAL_SIZE (size)); memcpy (self->start, self->preallocated, sizeof (_T_) * GDK_ARRAY_REAL_SIZE (size));
} }
else else
@@ -203,15 +196,15 @@ gdk_array(reserve) (GdkArray *self,
#ifdef GDK_ARRAY_NULL_TERMINATED #ifdef GDK_ARRAY_NULL_TERMINATED
if (self->start == NULL) if (self->start == NULL)
{ {
self->start = g_new (_T_, new_capacity); self->start = g_new (_T_, new_size);
*self->start = *(_T_[1]) { 0 }; *self->start = *(_T_[1]) { 0 };
} }
else else
#endif #endif
self->start = g_renew (_T_, self->start, new_capacity); self->start = g_renew (_T_, self->start, new_size);
self->end = self->start + size; self->end = self->start + size;
self->end_allocation = self->start + new_capacity; self->end_allocation = self->start + new_size;
#ifdef GDK_ARRAY_NULL_TERMINATED #ifdef GDK_ARRAY_NULL_TERMINATED
self->end_allocation--; self->end_allocation--;
#endif #endif
@@ -319,7 +312,6 @@ gdk_array(get) (const GdkArray *self,
#undef gdk_array_paste #undef gdk_array_paste
#undef gdk_array #undef gdk_array
#undef GDK_ARRAY_REAL_SIZE #undef GDK_ARRAY_REAL_SIZE
#undef GDK_ARRAY_MAX_SIZE
#undef GDK_ARRAY_BY_VALUE #undef GDK_ARRAY_BY_VALUE
#undef GDK_ARRAY_ELEMENT_TYPE #undef GDK_ARRAY_ELEMENT_TYPE

View File

@@ -82,10 +82,8 @@ gdk_cairo_context_cairo_create (GdkCairoContext *self)
draw_context = GDK_DRAW_CONTEXT (self); draw_context = GDK_DRAW_CONTEXT (self);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (!gdk_draw_context_is_in_frame (draw_context)) if (!gdk_draw_context_is_in_frame (draw_context))
return NULL; return NULL;
G_GNUC_END_IGNORE_DEPRECATIONS
cr = GDK_CAIRO_CONTEXT_GET_CLASS (self)->cairo_create (self); cr = GDK_CAIRO_CONTEXT_GET_CLASS (self)->cairo_create (self);

View File

@@ -1,171 +0,0 @@
#pragma once
#include "gdkcolorstateprivate.h"
#include "gdkcolorprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytexture.h"
#include <cairo.h>
#include <graphene.h>
static inline cairo_format_t
gdk_cairo_format_for_depth (GdkMemoryDepth depth)
{
switch (depth)
{
case GDK_MEMORY_NONE:
case GDK_MEMORY_U8:
return CAIRO_FORMAT_ARGB32;
case GDK_MEMORY_U8_SRGB:
case GDK_MEMORY_U16:
case GDK_MEMORY_FLOAT16:
case GDK_MEMORY_FLOAT32:
return CAIRO_FORMAT_RGBA128F;
case GDK_N_DEPTHS:
default:
g_return_val_if_reached (CAIRO_FORMAT_ARGB32);
}
}
static inline GdkMemoryDepth
gdk_cairo_depth_for_format (cairo_format_t format)
{
switch (format)
{
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_A8:
return GDK_MEMORY_U8;
case CAIRO_FORMAT_RGB30:
return GDK_MEMORY_U16;
case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGBA128F:
return GDK_MEMORY_FLOAT32;
case CAIRO_FORMAT_INVALID:
default:
g_assert_not_reached ();
return GDK_MEMORY_NONE;
}
}
static GdkMemoryFormat
gdk_cairo_format_to_memory_format (cairo_format_t format)
{
switch (format)
{
case CAIRO_FORMAT_ARGB32:
return GDK_MEMORY_DEFAULT;
case CAIRO_FORMAT_RGB24:
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
return GDK_MEMORY_B8G8R8X8;
#elif G_BYTE_ORDER == G_BIG_ENDIAN
return GDK_MEMORY_X8R8G8B8;
#else
#error "Unknown byte order for Cairo format"
#endif
case CAIRO_FORMAT_A8:
return GDK_MEMORY_A8;
case CAIRO_FORMAT_RGB96F:
return GDK_MEMORY_R32G32B32_FLOAT;
case CAIRO_FORMAT_RGBA128F:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_A1:
default:
g_assert_not_reached ();
return GDK_MEMORY_DEFAULT;
}
}
static inline void
gdk_cairo_set_source_color (cairo_t *cr,
GdkColorState *ccs,
const GdkColor *color)
{
float c[4];
gdk_color_to_float (color, ccs, c);
cairo_set_source_rgba (cr, c[0], c[1], c[2], c[3]);
}
static inline void
gdk_cairo_set_source_rgba_ccs (cairo_t *cr,
GdkColorState *ccs,
const GdkRGBA *rgba)
{
GdkColor c;
gdk_color_init_from_rgba (&c, rgba);
gdk_cairo_set_source_color (cr, ccs, &c);
gdk_color_finish (&c);
}
static inline void
gdk_cairo_pattern_add_color_stop_rgba_ccs (cairo_pattern_t *pattern,
GdkColorState *ccs,
double offset,
const GdkRGBA *rgba)
{
float color[4];
gdk_color_state_from_rgba (ccs, rgba, color);
cairo_pattern_add_color_stop_rgba (pattern, offset, color[0], color[1], color[2], color[3]);
}
static inline void
gdk_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
GdkColorState *ccs,
double offset,
const GdkColor *color)
{
float values[4];
gdk_color_to_float (color, ccs, values);
cairo_pattern_add_color_stop_rgba (pattern, offset, values[0], values[1], values[2], values[3]);
}
static inline void
gdk_cairo_rect (cairo_t *cr,
const graphene_rect_t *rect)
{
cairo_rectangle (cr,
rect->origin.x, rect->origin.y,
rect->size.width, rect->size.height);
}
static inline void
gdk_cairo_surface_convert_color_state (cairo_surface_t *surface,
GdkColorState *source,
GdkColorState *target)
{
cairo_surface_t *image_surface;
if (gdk_color_state_equal (source, target))
return;
image_surface = cairo_surface_map_to_image (surface, NULL);
gdk_memory_convert_color_state (cairo_image_surface_get_data (image_surface),
cairo_image_surface_get_stride (image_surface),
gdk_cairo_format_to_memory_format (cairo_image_surface_get_format (image_surface)),
source,
target,
cairo_image_surface_get_width (image_surface),
cairo_image_surface_get_height (image_surface));
cairo_surface_mark_dirty (image_surface);
cairo_surface_unmap_image (surface, image_surface);
/* https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/487 */
cairo_surface_mark_dirty (surface);
}

View File

@@ -1,481 +0,0 @@
/* gdkcicpparams.c
*
* Copyright 2024 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkcicpparamsprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkenumtypes.h"
/**
* GdkCicpParams:
*
* The `GdkCicpParams` struct contains the parameters that define
* a colorstate according to the ITU-T H.273
* [specification](https://www.itu.int/rec/T-REC-H.273/en).
*
* See the documentation of individual properties for supported values.
*
* The 'unspecified' value (2) is not treated in any special way, and
* must be replaced by a different value before creating a color state.
*
* `GdkCicpParams` can be used as a builder object to construct a color
* state from Cicp data with [method@Gdk.CicpParams.build_color_state].
* The function will return an error if the given parameters are not
* supported.
*
* You can obtain a `GdkCicpParams` object from a color state with
* [method@Gdk.ColorState.create_cicp_params]. This can be used to
* create a variant of a color state, by changing just one of the cicp
* parameters, or just to obtain information about the color state.
*
* Since: 4.16
*/
/* {{{ GObject boilerplate */
struct _GdkCicpParams
{
GObject parent_instance;
GdkCicp cicp;
};
struct _GdkCicpParamsClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (GdkCicpParams, gdk_cicp_params, G_TYPE_OBJECT)
enum
{
PROP_COLOR_PRIMARIES = 1,
PROP_TRANSFER_FUNCTION,
PROP_MATRIX_COEFFICIENTS,
PROP_RANGE,
N_PROPERTIES,
};
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void
gdk_cicp_params_init (GdkCicpParams *self)
{
self->cicp.color_primaries = 2;
self->cicp.transfer_function = 2;
self->cicp.matrix_coefficients = 2;
self->cicp.range = GDK_CICP_RANGE_NARROW;
}
static void
gdk_cicp_params_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GdkCicpParams *self = GDK_CICP_PARAMS (object);
switch (property_id)
{
case PROP_COLOR_PRIMARIES:
g_value_set_uint (value, self->cicp.color_primaries);
break;
case PROP_TRANSFER_FUNCTION:
g_value_set_uint (value, self->cicp.transfer_function);
break;
case PROP_MATRIX_COEFFICIENTS:
g_value_set_uint (value, self->cicp.matrix_coefficients);
break;
case PROP_RANGE:
g_value_set_enum (value, self->cicp.range);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_cicp_params_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GdkCicpParams *self = GDK_CICP_PARAMS (object);
switch (property_id)
{
case PROP_COLOR_PRIMARIES:
gdk_cicp_params_set_color_primaries (self, g_value_get_uint (value));
break;
case PROP_TRANSFER_FUNCTION:
gdk_cicp_params_set_transfer_function (self, g_value_get_uint (value));
break;
case PROP_MATRIX_COEFFICIENTS:
gdk_cicp_params_set_matrix_coefficients (self, g_value_get_uint (value));
break;
case PROP_RANGE:
gdk_cicp_params_set_range (self, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_cicp_params_class_init (GdkCicpParamsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdk_cicp_params_get_property;
object_class->set_property = gdk_cicp_params_set_property;
/**
* GdkCicpParams:color-primaries:
*
* The color primaries to use.
*
* Supported values:
*
* - 1: BT.709 / sRGB
* - 2: unspecified
* - 5: PAL
* - 6,7: BT.601 / NTSC
* - 9: BT.2020
* - 12: Display P3
*
* Since: 4.16
*/
properties[PROP_COLOR_PRIMARIES] =
g_param_spec_uint ("color-primaries", NULL, NULL,
0, 255, 2,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkCicpParams:transfer-function:
*
* The transfer function to use.
*
* Supported values:
*
* - 1,6,14,15: BT.709, BT.601, BT.2020
* - 2: unspecified
* - 4: gamma 2.2
* - 5: gamma 2.8
* - 8: linear
* - 13: sRGB
* - 16: BT.2100 PQ
* - 18: BT.2100 HLG
*
* Since: 4.16
*/
properties[PROP_TRANSFER_FUNCTION] =
g_param_spec_uint ("transfer-function", NULL, NULL,
0, 255, 2,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkCicpParams:matrix-coefficients:
*
* The matrix coefficients (for YUV to RGB conversion).
*
* Supported values:
*
* - 0: RGB
* - 2: unspecified
*
* Since: 4.16
*/
properties[PROP_MATRIX_COEFFICIENTS] =
g_param_spec_uint ("matrix-coefficients", NULL, NULL,
0, 255, 2,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkCicpParams:range:
*
* Whether the data is using the full range of values.
*
* The range of the data.
*
* Since: 4.16
*/
properties[PROP_RANGE] =
g_param_spec_enum ("range", NULL, NULL,
GDK_TYPE_CICP_RANGE,
GDK_CICP_RANGE_NARROW,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
}
/* }}} */
/* {{{ Public API */
/**
* gdk_cicp_params_new:
*
* Creates a new `GdkCicpParams` object.
*
* The initial values of the properties are the values for "undefined"
* and need to be set before a color state object can be built.
*
* Returns: (transfer full): a new `GdkCicpParams`
*
* Since: 4.16
*/
GdkCicpParams *
gdk_cicp_params_new (void)
{
return g_object_new (GDK_TYPE_CICP_PARAMS, NULL);
}
/**
* gdk_cicp_params_get_color_primaries:
* @self: a `GdkCicpParams`
*
* Returns the value of the color-primaries property
* of @self.
*
* Returns: the color-primaries value
*
* Since: 4.16
*/
guint
gdk_cicp_params_get_color_primaries (GdkCicpParams *self)
{
g_return_val_if_fail (GDK_IS_CICP_PARAMS (self), 0);
return self->cicp.color_primaries;
}
/**
* gdk_cicp_params_set_color_primaries:
* @self: a `GdkCicpParams`
* @color_primaries: the new color primaries value
*
* Sets the color-primaries property of @self.
*
* Since: 4.16
*/
void
gdk_cicp_params_set_color_primaries (GdkCicpParams *self,
guint color_primaries)
{
g_return_if_fail (GDK_IS_CICP_PARAMS (self));
if (self->cicp.color_primaries == color_primaries)
return;
self->cicp.color_primaries = color_primaries;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_PRIMARIES]);
}
/**
* gdk_cicp_params_get_transfer_function:
* @self: a `GdkCicpParams`
*
* Gets the transfer-function property of @self.
*
* Returns: the transfer-function value
*
* Since: 4.16
*/
guint
gdk_cicp_params_get_transfer_function (GdkCicpParams *self)
{
g_return_val_if_fail (GDK_IS_CICP_PARAMS (self), 0);
return self->cicp.transfer_function;
}
/**
* gdk_cicp_params_set_transfer_function:
* @self: a `GdkCicpParams`
* @transfer_function: the new transfer-function value
*
* Sets the transfer-function property of @self.
*
* Since: 4.16
*/
void
gdk_cicp_params_set_transfer_function (GdkCicpParams *self,
guint transfer_function)
{
g_return_if_fail (GDK_IS_CICP_PARAMS (self));
if (self->cicp.transfer_function == transfer_function)
return;
self->cicp.transfer_function = transfer_function;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRANSFER_FUNCTION]);
}
/**
* gdk_cicp_params_get_matrix_coefficients:
* @self: a `GdkCicpParams`
*
* Gets the matrix-coefficients property of @self.
*
* Returns: the matrix-coefficients value
*
* Since: 4.16
*/
guint
gdk_cicp_params_get_matrix_coefficients (GdkCicpParams *self)
{
g_return_val_if_fail (GDK_IS_CICP_PARAMS (self), 0);
return self->cicp.matrix_coefficients;
}
/**
* gdk_cicp_params_set_matrix_coefficients:
* @self a `GdkCicpParams`
* @matrix_coefficients: the new matrix-coefficients value
*
* Sets the matrix-coefficients property of @self.
*
* Since: 4.16
*/
void
gdk_cicp_params_set_matrix_coefficients (GdkCicpParams *self,
guint matrix_coefficients)
{
g_return_if_fail (GDK_IS_CICP_PARAMS (self));
if (self->cicp.matrix_coefficients == matrix_coefficients)
return;
self->cicp.matrix_coefficients = matrix_coefficients;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MATRIX_COEFFICIENTS]);
}
/**
* gdk_cicp_params_get_range:
* @self: a `GdkCicpParams`
*
* Gets the range property of @self.
*
* Returns: the range value
*
* Since: 4.16
*/
GdkCicpRange
gdk_cicp_params_get_range (GdkCicpParams *self)
{
g_return_val_if_fail (GDK_IS_CICP_PARAMS (self), GDK_CICP_RANGE_NARROW);
return self->cicp.range;
}
/**
* gdk_cicp_params_set_range:
* @self: a `GdkCipParams`
* @range: the range value
*
* Sets the range property of @self
*
* Since: 4.16
*/
void
gdk_cicp_params_set_range (GdkCicpParams *self,
GdkCicpRange range)
{
g_return_if_fail (GDK_IS_CICP_PARAMS (self));
if (self->cicp.range == range)
return;
self->cicp.range = range;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RANGE]);
}
/**
* gdk_cicp_params_build_color_state:
* @self: a `GdkCicpParams`
* @error: return location for errors
*
* Creates a new `GdkColorState` object for the cicp parameters in @self.
*
* Note that this may fail if the cicp parameters in @self are not
* supported by GTK. In that case, `NULL` is returned, and @error is set
* with an error message that can be presented to the user.
*
* Returns: (transfer full) (nullable): A newly allocated `GdkColorState`
*
* Since: 4.16
*/
GdkColorState *
gdk_cicp_params_build_color_state (GdkCicpParams *self,
GError **error)
{
return gdk_color_state_new_for_cicp (gdk_cicp_params_get_cicp (self), error);
}
/* }}} */
/* {{{ Private API */
/*< private >
* gdk_cicp_params_new_for_cicp:
* @cicp: a GdkCicp struct
*
* Create a `GdkCicpParams` from the values in @cicp.
*
* Returns: (transfer full): a new `GdkCicpParams` object
*/
GdkCicpParams *
gdk_cicp_params_new_for_cicp (const GdkCicp *cicp)
{
return g_object_new (GDK_TYPE_CICP_PARAMS,
"color-primaries", cicp->color_primaries,
"transfer-function", cicp->transfer_function,
"matrix-coefficients", cicp->matrix_coefficients,
"range", cicp->range,
NULL);
}
/*< private >
* gdk_cicp_params_get_cicp:
* @self: a `GdkCicpParams` object
*
* Gets the `GdkCicp` struct of @self.
*
* Returns: (transfer none): a `GdkCicp` struct containing
* the values of @self
*/
const GdkCicp *
gdk_cicp_params_get_cicp (GdkCicpParams *self)
{
return &self->cicp;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -1,90 +0,0 @@
/* gdkcicpparams.h
*
* Copyright 2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_CICP_PARAMS (gdk_cicp_params_get_type ())
GDK_AVAILABLE_IN_4_16
GDK_DECLARE_INTERNAL_TYPE (GdkCicpParams, gdk_cicp_params, GDK, CICP_PARAMS, GObject)
GDK_AVAILABLE_IN_4_16
GdkCicpParams *gdk_cicp_params_new (void);
GDK_AVAILABLE_IN_4_16
guint gdk_cicp_params_get_color_primaries (GdkCicpParams *self);
GDK_AVAILABLE_IN_4_16
void gdk_cicp_params_set_color_primaries (GdkCicpParams *self,
guint color_primaries);
GDK_AVAILABLE_IN_4_16
guint gdk_cicp_params_get_transfer_function (GdkCicpParams *self);
GDK_AVAILABLE_IN_4_16
void gdk_cicp_params_set_transfer_function (GdkCicpParams *self,
guint transfer_function);
GDK_AVAILABLE_IN_4_16
guint gdk_cicp_params_get_matrix_coefficients (GdkCicpParams *self);
GDK_AVAILABLE_IN_4_16
void gdk_cicp_params_set_matrix_coefficients (GdkCicpParams *self,
guint matrix_coefficients);
/**
* GdkCicpRange:
* @GDK_CICP_RANGE_NARROW: The values use the range of 16-235 (for Y) and 16-240 for u and v.
* @GDK_CICP_RANGE_FULL: The values use the full range.
*
* The values of this enumeration describe whether image data uses
* the full range of 8-bit values.
*
* In digital broadcasting, it is common to reserve the lowest and
* highest values. Typically the allowed values for the narrow range
* are 16-235 for Y and 16-240 for u,v (when dealing with YUV data).
*
* Since: 4.16
*/
typedef enum
{
GDK_CICP_RANGE_NARROW,
GDK_CICP_RANGE_FULL,
} GdkCicpRange;
GDK_AVAILABLE_IN_4_16
GdkCicpRange gdk_cicp_params_get_range (GdkCicpParams *self);
GDK_AVAILABLE_IN_4_16
void gdk_cicp_params_set_range (GdkCicpParams *self,
GdkCicpRange range);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_cicp_params_build_color_state (GdkCicpParams *self,
GError **error);
G_END_DECLS

View File

@@ -1,84 +0,0 @@
#pragma once
#include "gdkcicpparams.h"
typedef struct _GdkCicp GdkCicp;
struct _GdkCicp
{
guint color_primaries;
guint transfer_function;
guint matrix_coefficients;
GdkCicpRange range;
};
/*< private >
* gdk_cicp_equal:
* @p1: a `GdkCicp`
* @p2: another `GdkCicp`
*
* Compare two cicp tuples for equality.
*
* Note that several cicp values are 'functionally equivalent'.
* If you are interested in that notion, use gdk_cicp_equivalent().
*
* Returns: whether @p1 and @p2 are equal
*/
static inline gboolean
gdk_cicp_equal (const GdkCicp *p1,
const GdkCicp *p2)
{
return p1->color_primaries == p2->color_primaries &&
p1->transfer_function == p2->transfer_function &&
p1->matrix_coefficients == p2->matrix_coefficients &&
p1->range == p2->range;
}
static inline void
gdk_cicp_normalize (const GdkCicp *orig,
GdkCicp *out)
{
memcpy (out, orig, sizeof (GdkCicp));
/* ntsc */
if (out->color_primaries == 6)
out->color_primaries = 5;
/* bt709 */
if (out->transfer_function == 6 ||
out->transfer_function == 14 ||
out->transfer_function == 15)
out->transfer_function = 1;
/* bt601 */
if (out->matrix_coefficients == 6)
out->matrix_coefficients = 5;
}
/*< private >
* gdk_cicp_equivalent:
* @p1: a `GdkCicp`
* @p2: another `GdkCicp`
*
* Determine whether two cicp tuples are functionally equivalent.
*
* Returns: whether @p1 and @p2 are functionally equivalent
*/
static inline gboolean
gdk_cicp_equivalent (const GdkCicp *p1,
const GdkCicp *p2)
{
GdkCicp n1, n2;
if (gdk_cicp_equal (p1, p2))
return TRUE;
gdk_cicp_normalize (p1, &n1);
gdk_cicp_normalize (p2, &n2);
return gdk_cicp_equal (&n1, &n2);
}
const GdkCicp * gdk_cicp_params_get_cicp (GdkCicpParams *self);
GdkCicpParams * gdk_cicp_params_new_for_cicp (const GdkCicp *cicp);

View File

@@ -353,7 +353,7 @@ gdk_clipboard_class_init (GdkClipboardClass *class)
class->read_finish = gdk_clipboard_read_local_finish; class->read_finish = gdk_clipboard_read_local_finish;
/** /**
* GdkClipboard:display: * GdkClipboard:display: (attributes org.gtk.Property.get=gdk_clipboard_get_display)
* *
* The `GdkDisplay` that the clipboard belongs to. * The `GdkDisplay` that the clipboard belongs to.
*/ */
@@ -366,7 +366,7 @@ gdk_clipboard_class_init (GdkClipboardClass *class)
G_PARAM_EXPLICIT_NOTIFY); G_PARAM_EXPLICIT_NOTIFY);
/** /**
* GdkClipboard:formats: * GdkClipboard:formats: (attributes org.gtk.Property.get=gdk_clipboard_get_formats)
* *
* The possible formats that the clipboard can provide its data in. * The possible formats that the clipboard can provide its data in.
*/ */
@@ -378,7 +378,7 @@ gdk_clipboard_class_init (GdkClipboardClass *class)
G_PARAM_EXPLICIT_NOTIFY); G_PARAM_EXPLICIT_NOTIFY);
/** /**
* GdkClipboard:local: (getter is_local) * GdkClipboard:local: (attributes org.gtk.Property.get=gdk_clipboard_is_local)
* *
* %TRUE if the contents of the clipboard are owned by this process. * %TRUE if the contents of the clipboard are owned by this process.
*/ */
@@ -390,7 +390,7 @@ gdk_clipboard_class_init (GdkClipboardClass *class)
G_PARAM_EXPLICIT_NOTIFY); G_PARAM_EXPLICIT_NOTIFY);
/** /**
* GdkClipboard:content: * GdkClipboard:content: (attributes org.gtk.Property.get=gdk_clipboard_get_content)
* *
* The `GdkContentProvider` or %NULL if the clipboard is empty or contents are * The `GdkContentProvider` or %NULL if the clipboard is empty or contents are
* provided otherwise. * provided otherwise.
@@ -429,7 +429,7 @@ gdk_clipboard_init (GdkClipboard *clipboard)
} }
/** /**
* gdk_clipboard_get_display: * gdk_clipboard_get_display: (attributes org.gtk.Method.get_property=display)
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* *
* Gets the `GdkDisplay` that the clipboard was created for. * Gets the `GdkDisplay` that the clipboard was created for.
@@ -447,7 +447,7 @@ gdk_clipboard_get_display (GdkClipboard *clipboard)
} }
/** /**
* gdk_clipboard_get_formats: * gdk_clipboard_get_formats: (attributes org.gtk.Method.get_property=formats)
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* *
* Gets the formats that the clipboard can provide its current contents in. * Gets the formats that the clipboard can provide its current contents in.
@@ -465,7 +465,7 @@ gdk_clipboard_get_formats (GdkClipboard *clipboard)
} }
/** /**
* gdk_clipboard_is_local: (get-property local) * gdk_clipboard_is_local: (attributes org.gtk.Method.get_property=local)
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* *
* Returns if the clipboard is local. * Returns if the clipboard is local.
@@ -489,7 +489,7 @@ gdk_clipboard_is_local (GdkClipboard *clipboard)
} }
/** /**
* gdk_clipboard_get_content: * gdk_clipboard_get_content: (attributes org.gtk.Method.get_property=content)
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* *
* Returns the `GdkContentProvider` currently set on @clipboard. * Returns the `GdkContentProvider` currently set on @clipboard.
@@ -515,13 +515,15 @@ gdk_clipboard_get_content (GdkClipboard *clipboard)
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* @io_priority: the I/O priority of the request * @io_priority: the I/O priority of the request
* @cancellable: (nullable): optional `GCancellable` object * @cancellable: (nullable): optional `GCancellable` object
* @callback: (scope async) (closure user_data): callback to call when the request is satisfied * @callback: (scope async): callback to call when the request is satisfied
* @user_data:: the data to pass to callback function * @user_data: (closure): the data to pass to callback function
* *
* Asynchronously instructs the @clipboard to store its contents remotely. * Asynchronously instructs the @clipboard to store its contents remotely.
* *
* If the clipboard is not local, this function does nothing but report success. * If the clipboard is not local, this function does nothing but report success.
* *
* The @callback must call [method@Gdk.Clipboard.store_finish].
*
* The purpose of this call is to preserve clipboard contents beyond the * The purpose of this call is to preserve clipboard contents beyond the
* lifetime of an application, so this function is typically called on * lifetime of an application, so this function is typically called on
* exit. Depending on the platform, the functionality may not be available * exit. Depending on the platform, the functionality may not be available
@@ -630,12 +632,15 @@ gdk_clipboard_read_internal (GdkClipboard *clipboard,
* @mime_types: (array zero-terminated=1): a %NULL-terminated array of mime types to choose from * @mime_types: (array zero-terminated=1): a %NULL-terminated array of mime types to choose from
* @io_priority: the I/O priority of the request * @io_priority: the I/O priority of the request
* @cancellable: (nullable): optional `GCancellable` object * @cancellable: (nullable): optional `GCancellable` object
* @callback: (scope async) (closure user_data): callback to call when the request is satisfied * @callback: (scope async): callback to call when the request is satisfied
* @user_data: the data to pass to callback function * @user_data: (closure): the data to pass to callback function
* *
* Asynchronously requests an input stream to read the @clipboard's * Asynchronously requests an input stream to read the @clipboard's
* contents from. * contents from.
* *
* When the operation is finished @callback will be called. You must then
* call [method@Gdk.Clipboard.read_finish] to get the result of the operation.
*
* The clipboard will choose the most suitable mime type from the given list * The clipboard will choose the most suitable mime type from the given list
* to fulfill the request, preferring the ones listed first. * to fulfill the request, preferring the ones listed first.
*/ */
@@ -823,12 +828,15 @@ gdk_clipboard_read_value_internal (GdkClipboard *clipboard,
* @type: a `GType` to read * @type: a `GType` to read
* @io_priority: the I/O priority of the request * @io_priority: the I/O priority of the request
* @cancellable: (nullable): optional `GCancellable` object * @cancellable: (nullable): optional `GCancellable` object
* @callback: (scope async) (closure user_data): callback to call when the request is satisfied * @callback: (scope async): callback to call when the request is satisfied
* @user_data: the data to pass to callback function * @user_data: (closure): the data to pass to callback function
* *
* Asynchronously request the @clipboard contents converted to the given * Asynchronously request the @clipboard contents converted to the given
* @type. * @type.
* *
* When the operation is finished @callback will be called. You must then call
* [method@Gdk.Clipboard.read_value_finish] to get the resulting `GValue`.
*
* For local clipboard contents that are available in the given `GType`, * For local clipboard contents that are available in the given `GType`,
* the value will be copied directly. Otherwise, GDK will try to use * the value will be copied directly. Otherwise, GDK will try to use
* [func@content_deserialize_async] to convert the clipboard's data. * [func@content_deserialize_async] to convert the clipboard's data.
@@ -882,11 +890,14 @@ gdk_clipboard_read_value_finish (GdkClipboard *clipboard,
* gdk_clipboard_read_texture_async: * gdk_clipboard_read_texture_async:
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* @cancellable: (nullable): optional `GCancellable` object, %NULL to ignore. * @cancellable: (nullable): optional `GCancellable` object, %NULL to ignore.
* @callback: (scope async) (closure user_data): callback to call when the request is satisfied * @callback: (scope async): callback to call when the request is satisfied
* @user_data: the data to pass to callback function * @user_data: (closure): the data to pass to callback function
* *
* Asynchronously request the @clipboard contents converted to a `GdkPixbuf`. * Asynchronously request the @clipboard contents converted to a `GdkPixbuf`.
* *
* When the operation is finished @callback will be called. You must then
* call [method@Gdk.Clipboard.read_texture_finish] to get the result.
*
* This is a simple wrapper around [method@Gdk.Clipboard.read_value_async]. * This is a simple wrapper around [method@Gdk.Clipboard.read_value_async].
* Use that function or [method@Gdk.Clipboard.read_async] directly if you * Use that function or [method@Gdk.Clipboard.read_async] directly if you
* need more control over the operation. * need more control over the operation.
@@ -944,11 +955,14 @@ gdk_clipboard_read_texture_finish (GdkClipboard *clipboard,
* gdk_clipboard_read_text_async: * gdk_clipboard_read_text_async:
* @clipboard: a `GdkClipboard` * @clipboard: a `GdkClipboard`
* @cancellable: (nullable): optional `GCancellable` object * @cancellable: (nullable): optional `GCancellable` object
* @callback: (scope async) (closure user_data): callback to call when the request is satisfied * @callback: (scope async): callback to call when the request is satisfied
* @user_data: the data to pass to callback function * @user_data: (closure): the data to pass to callback function
* *
* Asynchronously request the @clipboard contents converted to a string. * Asynchronously request the @clipboard contents converted to a string.
* *
* When the operation is finished @callback will be called. You must then
* call [method@Gdk.Clipboard.read_text_finish] to get the result.
*
* This is a simple wrapper around [method@Gdk.Clipboard.read_value_async]. * This is a simple wrapper around [method@Gdk.Clipboard.read_value_async].
* Use that function or [method@Gdk.Clipboard.read_async] directly if you * Use that function or [method@Gdk.Clipboard.read_async] directly if you
* need more control over the operation. * need more control over the operation.

View File

@@ -1,287 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkcolorprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkrgbaprivate.h"
/*< private >
* GdkColor:
* @color_state: the color state to interpret the values in
* @values: the 3 coordinates that define the color, followed
* by the alpha value
*
* A `GdkColor` represents a color.
*
* The color state defines the meaning and range of the values.
* E.g., the srgb color state has r, g, b components representing
* red, green and blue with a range of [0,1], while the oklch color
* state has l, c, h components representing luminosity, chromaticity
* and hue, with l ranging from 0 to 1 and c from 0 to about 0.4, while
* h is interpreted as angle in degrees.
*
* value[3] is always the alpha value with a range of [0,1].
*
* The values are also available under the names red, green, blue
* and alpha, or r, g, b and a.
*/
/*< private >
* gdk_color_init:
* @self: the `GdkColor` struct to initialize
* @color_state: the color state
* @values: the values
*
* Initializes the `GdkColor` with the given color state
* and values.
*
* Note that this takes a reference on @color_state that
* must be freed by calling [function@Gdk.Color.finish]
* when the `GdkColor` is no longer needed.
*/
void
(gdk_color_init) (GdkColor *self,
GdkColorState *color_state,
const float values[4])
{
_gdk_color_init (self, color_state, values);
}
/*< private >
* gdk_color_init_copy:
* @self: the `GdkColor` struct to initialize
* @color: the `GdkColor` to copy
*
* Initializes the `GdkColor` by copying the contents
* of another `GdkColor`.
*
* Note that this takes a reference on the color state
* that must be freed by calling [function@Gdk.Color.finish]
* when the `GdkColor` is no longer needed.
*/
void
(gdk_color_init_copy) (GdkColor *self,
const GdkColor *color)
{
_gdk_color_init_copy (self, color);
}
/*< private >
* gdk_color_init_from_rgba:
* @self: the `GdkColor` struct to initialize
* @rgba: the `GdkRGBA` to copy
*
* Initializes the `GdkColor` by copying the contents
* of a `GdkRGBA`.
*
* Note that `GdkRGBA` colors are always in the sRGB
* color state.
*
* Note that this takes a reference on the color state
* that must be freed by calling [function@Gdk.Color.finish]
* when the `GdkColor` is no longer needed.
*/
void
(gdk_color_init_from_rgba) (GdkColor *self,
const GdkRGBA *rgba)
{
_gdk_color_init_from_rgba (self, rgba);
}
/*< private >
* @self: a `GdkColor`
*
* Drop the reference on the color state of @self.
*
* After this, @self is empty and can be initialized again
* with [function@Gdk.Color.init] and its variants.
*/
void
(gdk_color_finish) (GdkColor *self)
{
_gdk_color_finish (self);
}
/*< private >
* gdk_color_equal:
* @self: a `GdkColor`
* @other: another `GdkColor`
*
* Compares two `GdkColor` structs for equality.
*
* Returns: `TRUE` if @self and @other are equal
*/
gboolean
(gdk_color_equal) (const GdkColor *self,
const GdkColor *other)
{
return _gdk_color_equal (self, other);
}
/*< private >
* gdk_color_is_clear:
* @self: a `GdkColor`
*
* Returns whether @self is fully transparent.
*
* Returns: `TRUE` if @self is transparent
*/
gboolean
(gdk_color_is_clear) (const GdkColor *self)
{
return _gdk_color_is_clear (self);
}
/*< private >
* gdk_color_is_opaque:
* @self: a `GdkColor`
*
* Returns whether @self is fully opaque.
*
* Returns: `TRUE` if @self if opaque
*/
gboolean
(gdk_color_is_opaque) (const GdkColor *self)
{
return _gdk_color_is_opaque (self);
}
/*< private >
* gdk_color_convert:
* @self: the `GdkColor` to store the result in
* @color_state: the target color start
* @other: the `GdkColor` to convert
*
* Converts a given `GdkColor` to another color state.
*
* After the conversion, @self will represent the same
* color as @other in @color_state, to the degree possible.
*
* Different color states have different gamuts of colors
* they can represent, and converting a color to a color
* state with a smaller gamut may yield an 'out of gamut'
* result.
*/
void
(gdk_color_convert) (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other)
{
gdk_color_convert (self, color_state, other);
}
/*< private >
* gdk_color_to_float:
* @self: a `GdkColor`
* @target: the color state to convert to
* @values: the location to store the result in
*
* Converts a given `GdkColor to another color state
* and stores the result in a `float[4]`.
*/
void
(gdk_color_to_float) (const GdkColor *self,
GdkColorState *target,
float values[4])
{
gdk_color_to_float (self, target, values);
}
/*< private >
* gdk_color_from_rgba:
* @self: the `GdkColor` to store the result in
* @color_state: the target color state
* @rgba: the `GdkRGBA` to convert
*
* Converts a given `GdkRGBA` to the target @color_state.
*/
void
gdk_color_from_rgba (GdkColor *self,
GdkColorState *color_state,
const GdkRGBA *rgba)
{
GdkColor tmp = {
.color_state = GDK_COLOR_STATE_SRGB,
.r = rgba->red,
.g = rgba->green,
.b = rgba->blue,
.a = rgba->alpha
};
gdk_color_convert (self, color_state, &tmp);
gdk_color_finish (&tmp);
}
/*< private >
* gdk_color_print:
* @self: the `GdkColor` to print
* @string: the string to print to
*
* Appends a representation of @self to @string.
*
* The representation is inspired by CSS3 colors,
* but not 100% identical, and looks like this:
*
* color(NAME R G B / A)
*
* where `NAME` identifies color state, and
* `R`, `G`, `B` and `A` are the components of the color.
*
* The alpha may be omitted if it is 1.
*/
void
gdk_color_print (const GdkColor *self,
GString *string)
{
if (gdk_color_state_equal (self->color_state, GDK_COLOR_STATE_SRGB))
{
gdk_rgba_print ((const GdkRGBA *) self->values, string);
}
else
{
g_string_append_printf (string, "color(%s %g %g %g",
gdk_color_state_get_name (self->color_state),
self->r, self->g, self->b);
if (self->a < 1)
g_string_append_printf (string, " / %g", self->a);
g_string_append_c (string, ')');
}
}
/*< private >
* gdk_color_print:
* @self: the `GdkColor` to print
*
* Create a string representation of @self.
*
* See [method@Gdk.Color.print] for details about
* the format.
* Returns: (transfer full): a newly-allocated string
*/
char *
gdk_color_to_string (const GdkColor *self)
{
GString *string = g_string_new ("");
gdk_color_print (self, string);
return g_string_free (string, FALSE);
}

View File

@@ -1,285 +0,0 @@
/* gdkcolordefs.h
*
* Copyright 2024 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Note that this header is shared between the color state implementation
* and tests, and must not include other headers.
*/
#include <glib.h>
#include <math.h>
static inline int
sign (float v)
{
return v < 0 ? -1 : 1;
}
static inline float
srgb_oetf (float v)
{
if (fabsf (v) > 0.0031308f)
return sign (v) * (1.055f * powf (fabsf (v), 1.f / 2.4f) - 0.055f);
else
return 12.92f * v;
}
static inline float
srgb_eotf (float v)
{
if (fabsf (v) >= 0.04045f)
return sign (v) * powf (((fabsf (v) + 0.055f) / (1.f + 0.055f)), 2.4f);
else
return v / 12.92f;
}
static inline float
gamma22_oetf (float v)
{
return sign (v) * powf (fabsf (v), 1.f / 2.2f);
}
static inline float
gamma22_eotf (float v)
{
return sign (v) * powf (fabsf (v), 2.2f);
}
static inline float
gamma28_oetf (float v)
{
return sign (v) * powf (fabsf (v), 1.f / 2.8f);
}
static inline float
gamma28_eotf (float v)
{
return sign (v) * powf (fabsf (v), 2.8f);
}
static inline float
pq_eotf (float v)
{
float ninv = (1 << 14) / 2610.0;
float minv = (1 << 5) / 2523.0;
float c1 = 3424.0 / (1 << 12);
float c2 = 2413.0 / (1 << 7);
float c3 = 2392.0 / (1 << 7);
float x = powf (fabsf (v), minv);
x = powf (MAX ((x - c1), 0) / (c2 - (c3 * x)), ninv);
return sign (v) * x * 10000 / 203.0;
}
static inline float
pq_oetf (float v)
{
float x = v * 203.0 / 10000.0;
float n = 2610.0 / (1 << 14);
float m = 2523.0 / (1 << 5);
float c1 = 3424.0 / (1 << 12);
float c2 = 2413.0 / (1 << 7);
float c3 = 2392.0 / (1 << 7);
x = powf (fabsf (x), n);
return sign (v) * powf (((c1 + (c2 * x)) / (1 + (c3 * x))), m);
}
static inline float
bt709_eotf (float v)
{
const float a = 1.099;
const float d = 0.0812;
if (fabsf (v) < d)
return v / 4.5f;
else
return sign (v) * powf ((fabsf (v) + (a - 1)) / a, 1 / 0.45f);
}
static inline float
bt709_oetf (float v)
{
const float a = 1.099;
const float b = 0.018;
if (fabsf (v) < b)
return v * 4.5f;
else
return sign (v) * (a * powf (fabsf (v), 0.45f) - (a - 1));
}
static inline float
hlg_eotf (float v)
{
const float a = 0.17883277;
const float b = 0.28466892;
const float c = 0.55991073;
if (fabsf (v) <= 0.5)
return sign (v) * (v * v) / 3;
else
return sign (v) * (expf ((fabsf (v) - c) / a) + b) / 12.0;
}
static inline float
hlg_oetf (float v)
{
const float a = 0.17883277;
const float b = 0.28466892;
const float c = 0.55991073;
if (fabsf (v) <= 1/12.0)
return sign (v) * sqrtf (3 * fabsf (v));
else
return sign (v) * (a * logf (12 * fabsf (v) - b) + c);
}
/* See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
* for how to derive the abc_to_xyz matrices from chromaticity coordinates.
*/
static const float identity[9] = {
1, 0, 0,
0, 1, 0,
0, 0, 1,
};
static const float srgb_to_xyz[9] = {
0.4124564, 0.3575761, 0.1804375,
0.2126729, 0.7151522, 0.0721750,
0.0193339, 0.1191920, 0.9503041,
};
static const float xyz_to_srgb[9] = {
3.2404542, -1.5371385, -0.4985314,
-0.9692660, 1.8760108, 0.0415560,
0.0556434, -0.2040259, 1.0572252,
};
static const float rec2020_to_xyz[9] = {
0.6369580, 0.1446169, 0.1688810,
0.2627002, 0.6779981, 0.0593017,
0.0000000, 0.0280727, 1.0609851,
};
static const float xyz_to_rec2020[9] = {
1.7166512, -0.3556708, -0.2533663,
-0.6666844, 1.6164812, 0.0157685,
0.0176399, -0.0427706, 0.9421031,
};
static const float pal_to_xyz[9] = {
0.4305538, 0.3415498, 0.1783523,
0.2220043, 0.7066548, 0.0713409,
0.0201822, 0.1295534, 0.9393222,
};
static const float xyz_to_pal[9] = {
3.0633611, -1.3933902, -0.4758237,
-0.9692436, 1.8759675, 0.0415551,
0.0678610, -0.2287993, 1.0690896,
};
static const float ntsc_to_xyz[9] = {
0.3935209, 0.3652581, 0.1916769,
0.2123764, 0.7010599, 0.0865638,
0.0187391, 0.1119339, 0.9583847,
};
static const float xyz_to_ntsc[9] = {
3.5060033, -1.7397907, -0.5440583,
-1.0690476, 1.9777789, 0.0351714,
0.0563066, -0.1969757, 1.0499523,
};
static const float p3_to_xyz[9] = {
0.4865709, 0.2656677, 0.1982173,
0.2289746, 0.6917385, 0.0792869,
0.0000000, 0.0451134, 1.0439444,
};
static const float xyz_to_p3[9] = {
2.4934969, -0.9313836, -0.4027108,
-0.8294890, 1.7626641, 0.0236247,
0.0358458, -0.0761724, 0.9568845,
};
/* premultiplied matrices for default conversions */
static const float rec2020_to_srgb[9] = {
1.660227, -0.587548, -0.072838,
-0.124553, 1.132926, -0.008350,
-0.018155, -0.100603, 1.118998,
};
static const float srgb_to_rec2020[9] = {
0.627504, 0.329275, 0.043303,
0.069108, 0.919519, 0.011360,
0.016394, 0.088011, 0.895380,
};
/* oklab conversion */
static float
from_oklab_nl (float v)
{
return v * v * v;
}
static float
to_oklab_nl (float v)
{
return cbrtf (v);
}
static const float oklab_to_lms[9] = {
1, 0.3963377774, 0.2158037573,
1, -0.1055613458, -0.0638541728,
1, -0.0894841775, -1.2914855480
};
static const float lms_to_srgb[9] = {
4.0767416621, -3.3077115913, 0.2309699292,
-1.2684380046, 2.6097574011, -0.3413193965,
-0.0041960863, -0.7034186147, 1.7076147010,
};
static const float srgb_to_lms[9] = {
0.4122214708, 0.5363325363, 0.0514459929,
0.2119034982, 0.6806995451, 0.1073969566,
0.0883024619, 0.2817188376, 0.6299787005,
};
static const float lms_to_oklab[9] = {
0.2104542553, 0.7936177850, -0.0040720468,
1.9779984951, -2.4285922050, 0.4505937099,
0.0259040371, 0.7827717662, -0.8086757660,
};
static const float rec2020_to_lms[9] = {
0.616645, 0.360250, 0.023064,
0.265075, 0.635874, 0.099059,
0.100076, 0.203907, 0.696161,
};
static const float lms_to_rec2020[9] = {
2.140325, -1.246734, 0.106491,
-0.884665, 2.163141, -0.278489,
-0.048559, -0.454366, 1.502711,
};

View File

@@ -1,133 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "gdkcolorprivate.h"
#include "gdkcolorstateprivate.h"
#define gdk_color_init(...) _gdk_color_init (__VA_ARGS__)
static inline void
_gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float values[4])
{
self->color_state = gdk_color_state_ref (color_state);
memcpy (self->values, values, sizeof (float) * 4);
}
#define gdk_color_init_copy(self, color) _gdk_color_init_copy ((self), (color))
static inline void
_gdk_color_init_copy (GdkColor *self,
const GdkColor *color)
{
_gdk_color_init (self, color->color_state, color->values);
}
#define gdk_color_init_from_rgb(self, rgba) _gdk_color_init_from_rgba ((self), (rgba))
static inline void
_gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba)
{
_gdk_color_init (self, GDK_COLOR_STATE_SRGB, (const float *) rgba);
}
#define gdk_color_finish(self) _gdk_color_finish ((self))
static inline void
_gdk_color_finish (GdkColor *self)
{
gdk_color_state_unref (self->color_state);
self->color_state = NULL;
}
#define gdk_color_get_color_state(self) _gdk_color_get_color_state ((self))
static inline GdkColorState *
_gdk_color_get_color_state (const GdkColor *self)
{
return self->color_state;
}
#define gdk_color_equal(self, other) _gdk_color_equal ((self), (other))
static inline gboolean
_gdk_color_equal (const GdkColor *self,
const GdkColor *other)
{
return self->values[0] == other->values[0] &&
self->values[1] == other->values[1] &&
self->values[2] == other->values[2] &&
self->values[3] == other->values[3] &&
gdk_color_state_equal (self->color_state, other->color_state);
}
#define gdk_color_is_clear(self) _gdk_color_is_clear ((self))
static inline gboolean
_gdk_color_is_clear (const GdkColor *self)
{
return self->alpha < (255.f / 65535.f);
}
#define gdk_color_is_opaque(self) _gdk_color_is_opaque ((self))
static inline gboolean
_gdk_color_is_opaque (const GdkColor *self)
{
return self->alpha > (65280.f / 65535.f);
}
#define gdk_color_convert(self, cs, other) _gdk_color_convert ((self), (cs), (other))
static inline void
_gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other)
{
if (gdk_color_state_equal (color_state, other->color_state))
{
gdk_color_init_copy (self, other);
return;
}
self->color_state = gdk_color_state_ref (color_state);
gdk_color_state_convert_color (other->color_state,
other->values,
self->color_state,
self->values);
}
#define gdk_color_to_float(self, cs, values) _gdk_color_to_float ((self), (cs), (values))
static inline void
_gdk_color_to_float (const GdkColor *self,
GdkColorState *color_state,
float values[4])
{
if (gdk_color_state_equal (self->color_state, color_state))
{
values[0] = self->values[0];
values[1] = self->values[1];
values[2] = self->values[2];
values[3] = self->values[3];
return;
}
gdk_color_state_convert_color (self->color_state,
self->values,
color_state,
values);
}

View File

@@ -1,106 +0,0 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gdk/gdktypes.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkrgba.h>
#include <gdk/gdkmemoryformatprivate.h>
typedef struct _GdkColor GdkColor;
/* The interpretation of the first 3 components depends on the color state.
* values[3] is always alpha.
*/
struct _GdkColor
{
GdkColorState *color_state;
union {
float values[4];
struct {
float r;
float g;
float b;
float a;
};
struct {
float red;
float green;
float blue;
float alpha;
};
};
};
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, r) == G_STRUCT_OFFSET (GdkColor, red));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, g) == G_STRUCT_OFFSET (GdkColor, green));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, b) == G_STRUCT_OFFSET (GdkColor, blue));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, a) == G_STRUCT_OFFSET (GdkColor, alpha));
/* The committee notes that since all known implementations but one "get it right"
* this may well not be a defect at all.
* https://open-std.org/JTC1/SC22/WG14/www/docs/n2396.htm#dr_496
*/
#ifndef _MSC_VER
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, r) == G_STRUCT_OFFSET (GdkColor, values[0]));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, g) == G_STRUCT_OFFSET (GdkColor, values[1]));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, b) == G_STRUCT_OFFSET (GdkColor, values[2]));
G_STATIC_ASSERT (G_STRUCT_OFFSET (GdkColor, a) == G_STRUCT_OFFSET (GdkColor, values[3]));
#endif
#define GDK_COLOR_SRGB(r,g,b,a) (GdkColor) { \
.color_state = GDK_COLOR_STATE_SRGB, \
.values = { (r), (g), (b), (a) } \
}
void gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float values[4]);
void gdk_color_init_copy (GdkColor *self,
const GdkColor *color);
void gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba);
void gdk_color_finish (GdkColor *self);
gboolean gdk_color_equal (const GdkColor *self,
const GdkColor *other);
gboolean gdk_color_is_clear (const GdkColor *self);
gboolean gdk_color_is_opaque (const GdkColor *self);
void gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other);
void gdk_color_to_float (const GdkColor *self,
GdkColorState *target,
float values[4]);
void gdk_color_from_rgba (GdkColor *self,
GdkColorState *color_state,
const GdkRGBA *rgba);
void gdk_color_print (const GdkColor *self,
GString *string);
char * gdk_color_to_string (const GdkColor *self);
#include "gdkcolorimpl.h"
G_END_DECLS

File diff suppressed because it is too large Load Diff

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