Compare commits

..

86 Commits

Author SHA1 Message Date
Matthias Clasen
7e4745202c Add some more text rendering tests 2024-01-29 18:29:35 -05:00
Matthias Clasen
1564d768d3 Accept font options in node files
The goal is to fix all the context that influences the rendering
of text nodes in the node file. This includes the relevant parts
of cairo_font_options_t (via pango_cairo_context_set_font_options)
as well as the dpi (via pango_cairo_font_map_set_resolution).

The default values we use match the default of the gsettings backing
our GtkSettings:

hint-metrics: off;
hint-style: slight;
antialias: on;
dpi: 96;

This will help with better font testing.

Parser test included.
2024-01-29 18:29:35 -05:00
Matthias Clasen
e80acf53fd node-editor: Drop a duplicated menu item 2024-01-29 18:29:35 -05:00
Benjamin Otte
1ffa01b38a Merge branch 'contentview-step1-finished' into 'main'
[macos] Use system shadow on macOS

Closes #6255

See merge request GNOME/gtk!6785
2024-01-29 18:09:33 +00:00
Matthias Clasen
f93601ed2b Merge branch 'cache-weak-unref' into 'main'
gpu: Fix a problem with texture caches

Closes #6377

See merge request GNOME/gtk!6824
2024-01-29 13:24:56 +00:00
Matthias Clasen
e1722777e5 Merge branch 'drag-out-of-fullscreen' into 'main'
gtk: Make window handles work when attached to fullscreen windows

See merge request GNOME/gtk!6825
2024-01-29 13:15:46 +00:00
Matthias Clasen
24850dff0e Merge branch 'fix-gc-context' into 'main'
gpu: Call make current before gc

Closes #6366

See merge request GNOME/gtk!6826
2024-01-29 13:13:43 +00:00
Matthias Clasen
d790268031 gsk: Move gc calls
maybe_gc() may make a different context current, so do it before
the renderer has made its own context current.
2024-01-29 08:12:27 -05:00
Matthias Clasen
89712fc750 gpu: Fix syntax confusion. 2024-01-29 08:12:27 -05:00
Matthias Clasen
9b62a5c931 gpu: Drop an unused argument
The timestamp wasn't used in atlas creation.
2024-01-29 08:12:27 -05:00
Matthias Clasen
fbf3836502 gpu: Drop excessive logging
This was logging every frame, which is too much.
2024-01-29 08:12:27 -05:00
Matthias Clasen
8d80f97597 gpu: free non-atlased glyphs
"Only free glyphs when their atlas is freed" works great for
glyphs that are on an atlas. Don't forget the others.
2024-01-29 08:12:27 -05:00
Matthias Clasen
e6ec8133a5 gpu: Don't weak unref too much
We can reach the code that removes the item from the hash table
before or after the weak unref has triggered. Just leave the
weakref in place and let it do its thing, if it hasn't gone
off yet. That matches what we do in free.

Fixes: #6377
2024-01-29 08:11:25 -05:00
Matthias Clasen
6b436fdbbb gsk: Move gc calls
maybe_gc() may make a different context current, so do it before
the renderer has made its own context current.
2024-01-29 07:49:59 -05:00
Matthias Clasen
7b2b5469eb gpu: Call make current before gc
We do gc in a timeout, when an arbitrary GL context might be
current, so we need to make sure its ours and we don't free
random textures in another context.

Fixes: #6366
2024-01-29 07:39:57 -05:00
Benjamin Otte
3fc325d799 Merge branch 'dmabuf-texture-gst-v4l2' into 'main'
gstsink: Add support for DMABuf import and graphics offload

See merge request GNOME/gtk!6618
2024-01-29 11:06:11 +00:00
Ben Mather
dee6742931 gtk: Allow windows to be dragged out of fullscreen using a window handle
Window handles allow windows to be dragged from maximized to restored,
but when the window is fullscreen they do nothing.  With this change,
windows will be unfullscreened when dragged.
2024-01-29 09:51:16 +00:00
Robert Mader
d2097d0449 gstsink: Add support for DMABuf import and graphics offload
By implementing support for `GdkDmabufTextureBuilder` and
`GstVideoInfoDmaDrm`. This allows zero-copy video playback on Wayland
when paired with hardware video decoding.

Can be tested with `gtk4-demo --run=video_player`
2024-01-28 19:09:41 +01:00
Matthias Clasen
c7f00d51eb Merge branch 'wayland-empty-frame' into 'main'
wayland: Add a way to check if a surface is dirty

See merge request GNOME/gtk!6822
2024-01-28 17:02:29 +00:00
Matthias Clasen
f5308dfbec wayland: Commit empty frames if needed
If we have outstanding double-buffered state (other than the
buffer itself), commit a frame even if its 'empty'.
2024-01-28 11:44:16 -05:00
Matthias Clasen
1097e1349c wayland: Add a way to check if a surface is dirty
We keep various pieces of double-buffered state on our side,
and then explicitly sync it over to the Wayland side.

Add a function to find out if we have any.
2024-01-28 11:44:16 -05:00
Benjamin Otte
d577e4421e Merge branch 'gpu-cache-fixes' into 'main'
gpu: Caching fixes

See merge request GNOME/gtk!6817
2024-01-28 16:13:25 +00:00
Matthias Clasen
1bac8b439a gpu: Be more aggressive about cache gc
Count dead pixels in textures (ie the number of pixels in GPU
textures that are no longer backed by an alive GdkTexture object),
and when the there's too many, do a gc before rendering the next
frame.
2024-01-28 11:00:07 -05:00
Matthias Clasen
ee52e98b7d gpu: Redo texture caching
Count the uses of cached texture - from the device (via the linked
list) and from the texture (via render data / weak ref), and only
free the item once the use count reaches zero.
2024-01-28 10:50:46 -05:00
Matthias Clasen
5e4eda15c9 gpu: Trigger cache gc from the renderer
Instead of forever running a timeout to do gc, ensure the timeout
is scheduled whenever we render a frame (this is done by calling
gsk_gpu_device_maybe_gc () before gsk_gpu_frame_render (), and
gsk_gpu_device_queue_gc () after).
2024-01-28 10:50:19 -05:00
Matthias Clasen
e861ea4bd2 gpu: Add a knob for cache GC
Read the GSK_CACHE_TIMEOUT environment variable to override the
default 15s timeout for cache gc. This is mainly meant for debugging.

Since we don't really need two knobs, reuse the gc timeout value
for the max age of items too.
2024-01-28 10:49:57 -05:00
Matthias Clasen
8009ed3a3c gpu: Add more details to debug spew
Print the number of items in the cache hash tables.
2024-01-27 19:50:45 -05:00
Matthias Clasen
1d95a171f6 gpu: Don't forget to unage cached textures
Whenever we successfully looking up a cached item, we need to
call use() on it to mark it as fresh.
2024-01-27 19:50:41 -05:00
Matthias Clasen
e0136b283a Cosmetics 2024-01-27 19:49:58 -05:00
Matthias Clasen
42867c7a3c Cosmetics 2024-01-27 19:49:57 -05:00
Ekaterine Papava
40f20fee3d Update Georgian translation 2024-01-27 17:15:52 +00:00
Matthias Clasen
63e814a45f Merge branch 'matthiasc/for-main' into 'main'
node-editor: Make the crash warning work

Closes #6370

See merge request GNOME/gtk!6820
2024-01-27 16:43:08 +00:00
Matthias Clasen
c1270cf52b gpu: Fix a crash in vulkan
The node processing wasn't skipping 0-size nodes when using the
uber shader, leading to assertions down the road. Since the ngl
renderer doesn't use uber shaders, this only affects vulkan.

Test included.

Fixes: #6370
2024-01-27 10:30:38 -05:00
Matthias Clasen
f2ec2f2a58 node-editor: Make the crash warning work
In some cases, we leave behind both an autosave and an
autosave-unsafe file, so check for the unsafe one first.
2024-01-27 10:21:26 -05:00
Benjamin Otte
e67bb62b1f Merge branch 'wip/otte/6363' into 'main'
gpu: Add support for MacOS default framebuffer

See merge request GNOME/gtk!6815
2024-01-27 15:15:38 +00:00
Matthias Clasen
ee8a800763 Merge branch 'matthiasc/for-main' into 'main'
nodeparser: Fix a font handling mishap

See merge request GNOME/gtk!6818
2024-01-27 08:30:37 +00:00
Matthias Clasen
746cfe48b0 nodeparser: Fix a font handling mishap
When we don't have an embedded font file via a url, then we want
to parse fonts "as normal", i.e. allow fallback for aliases like
"Monospace 10". This was broken when the url support was added.
Make it work again.

Update affected tests. In particular, the output of the text-fail
test goes back to be the same it was before the url changes.
2024-01-26 23:54:58 -05:00
Benjamin Otte
3a93d52718 gpu: Add support for MacOS default framebuffer
This adds the same code as the GL renderer used to allow backends to
redirect rendering to a different framebuffer.

Related: #6363
2024-01-26 16:55:49 +01:00
Benjamin Otte
1994e1940c Merge branch 'wip/otte/6363' into 'main'
gpu: Don't use layout binding in old GL versions

Closes #6363

See merge request GNOME/gtk!6814
2024-01-26 15:46:08 +00:00
Benjamin Otte
d74855fe9f gpu: Don't use layout binding in old GL versions
GL needs version 4.2 before it supports explicit bindings. We use GLES
usually, and Mesa supports GL 4.6, so we didn't hit this case before.

However, MacOS does use GL and Mac OS is stuck on GL 4.1.

Fixes #6363
2024-01-26 14:17:16 +01:00
Emmanuele Bassi
979749a3bc Merge branch 'ewlsh/add-accessible-relation-list' into 'main'
gtk: Add AccessibleList to enable relations in bindings

Closes #6358

See merge request GNOME/gtk!6807
2024-01-26 10:52:26 +00:00
Fran Dieguez
29c7725416 Update Galician translation 2024-01-26 09:57:16 +00:00
Matthias Clasen
3abf6acb16 Post-release version bump 2024-01-25 16:25:26 -05:00
Matthias Clasen
df8cf0e030 Use software rendering for testsuite runs
We need to force software rendering, or test failures will cause
meson dist to fail.
2024-01-25 16:25:26 -05:00
Matthias Clasen
7952b2a0bc 4.13.6 2024-01-25 16:25:26 -05:00
Matthias Clasen
c98e568583 Merge branch 'ngl-by-default' into 'main'
gsk: Change the default renderer

See merge request GNOME/gtk!6809
2024-01-25 20:41:32 +00:00
Matthias Clasen
f90e77d173 gdk: Enable fractional scaling for GL by default
The ngl renderer has good support for fractional scaling, so we
can enable this by default now.

If you are using the gl renderer, you can disable fractional
scaling with the

GDK_DEBUG=gl-no-fractional

environment variable.
2024-01-25 14:41:04 -05:00
Matthias Clasen
98e3fca284 gsk: Change the default renderer
The intent of this change to get wider testing and verify that the
new renderers are production-ready. If significant problems show
up, we will revert this change for 4.14.

The new preference order is ngl > gl > vulkan > cairo.

The gl renderer is still there because we need it to support gles2
systems, and vulkan still has some rough edges in application support
(no gl area support, webkit only works with gl).

If you need to override the default renderer choice, you can
still use the GSK_RENDERER environment variable.
2024-01-25 14:41:04 -05:00
Benjamin Otte
a7c98227e6 Merge branch 'wip/antoniof/fix-section-tiles' into 'main'
gtklistitemmanager fixes

See merge request GNOME/gtk!6805
2024-01-25 19:31:35 +00:00
Benjamin Otte
f2856e494c Merge branch 'wip/otte/for-main' into 'main'
gpu: Fix variable

See merge request GNOME/gtk!6812
2024-01-25 19:26:44 +00:00
Benjamin Otte
dc1f12682c testsuite: Add a test for zero width borders
See previous commit for an explanation of the problem.

This test actually draws a rounded border, but the rounding is clipped
away. What is remaining is the 4 corners of the border, where the
top/bottom color is red and the left/right color is green. But because
the bottom/right side has a width of zero, the result should be all red.
2024-01-25 19:39:34 +01:00
Benjamin Otte
502fb250ab gpu: Fix zero-width border corner rendering
When a border side has a width of 0 but we're having rounded corners, we
draw content in the edges of that side, and naturally pick its color.
That is wrong though, when the width is zero, we're supposed to keep
using the color of the other side in that corner.

So do that.

Fixes the border-corner-zero-width-rendering.ui reftest.
2024-01-25 19:39:34 +01:00
Benjamin Otte
7d7d3ff35c gpu: Fix variable
I had a test that allocated over 4GB of ops and...
2024-01-25 19:08:32 +01:00
António Fernandes
9fb449793d listitemmanager: Fix section change handler mistake
The statement is not doing what it was meant to do.

gtk_list_item_manager_get_nth (self, position, &offset) returns the
tile for a given position, and if the tile maps to more than 1 item,
the offset indicates how far into that tile the given position is.

So position - offset would give us the position of this tile. It
doesn't make sense to subtract it from n_items.

Instead, we should be adding the offset to compensate for having
landed too early in the list, such that we successfully reach
position + n_items.
2024-01-25 17:35:56 +00:00
António Fernandes
3d88c44803 listitemmanager: Don't doubly-recycle widget
When there is a duplicate item in the hash table of deleted items, we:

1. Unparent the unparent the old `widget` value (gtk_widget_unparent is
   passed as `GDestroyNotify value_destroy_func` for the hastable).
2. Set the new `widget` value in the hashtable.
3. Also set the same `widget` in the recycled queue.

This means the same widget is found in the 2 containers and, therefore,
the same widget may be returned twice by gtk_list_item_change_get().
Alternatively, this means we may reuse the item by taking it from the
hashtable and reassigning it to a tile, but then it ends up getting
unparented by gtk_list_item_change_finish(). Or we don't take it at
all and end up calling gtk_widget_unparent()` on it twice, which may
result in use-after-free on the second call the parent was holding the
last reference.

This was introduced by 76d601631d

Previously, gtk_list_item_manager_release_list_item() would just emit
the warning but otherwise do nothing. Let's restore that behavior.
2024-01-25 17:35:56 +00:00
António Fernandes
b05000d8bd listitemmanager: Remove section when adding at its end
We are failing to go from this:

    [ BLUE ] [ RED ]

...to this:

    [ BLUE GREEN YELLOW ] [ RED ]

...where '[' and ']' represent section header and footer.

Instead, the result is...

    [ BLUE ] [ GREEN YELLOW ] [ RED ]

... despite the first 3 items belonging to the same section according
to the section model. This leaves the view in an inconsistent state
and, ultimately, to crashes the non-removed footer.

Indeed, when receiving items-changed(1,0,2), we call `append_items()`
which inserts a new tile before the tile at `1` (which was RED), and
then notices there is a HEADER right befo-re it, so it flags both it
and the corresponding FOOTER as unmatched:

    [ BLUE ] ( GREEN-YELLOW RED )

... where '(' and ')' represent unmatched header and footer.

Problem is subsequent code in `release_items()` doesn't even touch
the section boundary footer-header pair ('] ('), because they are
belong in the tracked interval (visible items). And `ensure_items()`
proceeds to match the header with a new footer, producing the result
described above.

To handle this correctly, `append_items()` must delete the section
boundary, and flag as unmatched both the HEADER of the section before
and the FOOTER of section after (whose respective footer and header
has been marked for removal):

    ( BLUE . . GREEN-YELLOW RED )

... where '.' represents tiles marked for removal.

This way, `release_items()` will release the removed footer-header
section boundary, and `ensure_items()` is going to reinstate new
section remove the section boundary at the correct place, resulting
in the expected behavior:

    [ BLUE GREEN YELLOW ] [ RED ]
2024-01-25 17:22:32 +00:00
António Fernandes
4b45adaf39 testsuite: Test inserting items at sections
We are not catching bugs when inserting if we're right at a boundary.

This because we never add or remove items from a section. We only ever
add or remove whole sections.

Introduce a test which inserts items at a random position inside of a
section.
2024-01-25 17:16:00 +00:00
Maximiliano Sandoval
6f2d33369b docs: Add favicons
Requires gi-docgen main.
2024-01-25 17:06:24 +01:00
Matthias Clasen
e08727fa47 Merge branch 'gpu-cache-stats' into 'main'
gpu: cache eviction

Closes #6346

See merge request GNOME/gtk!6784
2024-01-25 15:08:36 +00:00
Matthias Clasen
7624e6621a gpu: Add profiler marks around cache gc 2024-01-25 09:41:49 -05:00
Matthias Clasen
cdddb6cb96 gpu: Print more detailed cache statistics
Print out stale glyphs and dead pixel ratios.
2024-01-25 09:41:49 -05:00
Matthias Clasen
f6c01a7674 gpu: Fix ordering problem in clear_cache()
We must free the glyphs before their atlases, since we now maintain
the dead pixel count of the atlas when glyphs are freed.
2024-01-25 09:41:49 -05:00
Matthias Clasen
ffa5bf1b7d gpu: Fix atlas freeing
We need to unset current_atlas if we free that one.
2024-01-25 09:41:49 -05:00
Matthias Clasen
4c6e623ec5 gpu: Keep track of atlas use
Count how many dead pixels we have, and free the atlas if more than
half of its pixels are dead.

As part of this, change when glyphs are freed. We now keep them
in the hash table until their atlas is freed and we only do dead
pixel accounting when should_collect is called. This keeps the
glyphs available for use from the cache as long as are in the atlas.

If a stale glyph is sused, we 'revive' it by removing its pixels
from the dead.

This matches more closely what the gl renderer does.
2024-01-25 09:41:48 -05:00
Matthias Clasen
621ef0703a gpu: Make atlas freeing more robust
Currently, we don't free an atlas before all its glyphs are gone,
but we might revisit that in the future, so be prepared for it.
2024-01-25 09:40:58 -05:00
Matthias Clasen
f514caadb0 gpu: Evict stale glyphs from the cache
Same story as for textures: if it hasn't been used for 4 seconds,
it is stale and can go.
2024-01-25 09:40:58 -05:00
Matthias Clasen
4d92093c67 gpu: Fix texture eviction
If we gc a cached texture for which the GdkTexture is still alive,
the cached texture object will remain accessible via the render
data, so need to make sure not to leave a dangling pointer behind
here.
2024-01-25 09:40:58 -05:00
Matthias Clasen
bd9ea05ebb gpu: Evict stale textures from the cache
This is straightforward. If a texture hasn't been used for 4 seconds,
we consider it stale, and drop it the next time gc comes around.

The choice of 4 seconds is arbitrary.

Fixes: #6346
2024-01-25 09:40:58 -05:00
Matthias Clasen
e8599bd36e gpu: Start doing cache gc
Call the gc function periodically from a timeout to collect
stale cached items.
2024-01-25 09:40:58 -05:00
Matthias Clasen
1accd0c1ba gpu: Print some cache stats
This reuses the GLYPHCACHE debug flag that is used for the same
purpose in the gl renderer.
2024-01-25 09:40:58 -05:00
Matthias Clasen
14488041bc gpu: Add a static assertion
Stating the obvious, maybe.
2024-01-25 09:40:58 -05:00
Emmanuele Bassi
c11b29583e Merge branch 'gbsneto/a11y-cleanups-1' into 'main'
Unassorted a11y cleanups

See merge request GNOME/gtk!6808
2024-01-25 12:58:34 +00:00
Arjan Molenaar
9467243ac3 Properly unset the use_client_shadow flag 2024-01-25 13:11:13 +01:00
Evan Welsh
32f1f7280b gtk: Add AccessibleList to enable relations in bindings
Bindings need a boxed type to "wrap" lists of Gtk.Accessible objects.

Closes #6358
2024-01-25 03:39:49 -08:00
Yosef Or Boczko
ff81104834 Update Hebrew translation 2024-01-25 11:35:41 +00:00
Arjan Molenaar
6e7893d527 Let GdkDisplay decide if shadows should be drawn
Replace the `#ifdef` blocks by a backend call.
2024-01-25 12:09:10 +01:00
Arjan Molenaar
6efe5eefd3 Differentiate between compositing and frame extents support
* If the WM supports compositing, we can use CSD with rounded corners.
* If the WM supports frame extents, we can use client side shadows.
2024-01-24 21:57:44 +01:00
Georges Basile Stavracas Neto
d337eed643 a11y/atspicontext: Remove empty constructed override
It does nothing.
2024-01-23 19:09:57 -03:00
Georges Basile Stavracas Neto
296d44159b a11y/atspi/root: Chain up to finalize
The gtk_at_spi_root_finalize() function currently chains up to
dispose(),
which is probably a copy-paste mistake since gtk_at_spi_root_dispose()
exists and also chains up to dispose().

Chain up to finalize().
2024-01-23 19:09:57 -03:00
Georges Basile Stavracas Neto
4ce9f9b3ac gtk/atcontext: Cleanup a11y backends list
Declaring a separate entry for Wayland and X11 is not very useful when
both just end up calling the same constructor. Also, in theory, this
can cause the Wayland entry to be picked up on X11 if both backends
are enabled (which is the common case).

Not that it matters, since the 'name' field is unused.

Nonetheless, clean it up to be a single entry
2024-01-23 19:09:57 -03:00
Georges Basile Stavracas Neto
9fb37229a1 atcontext: Remove end sentinel from array
This array is iterated using G_N_ELEMENTS(), which means it always
iterates a well known number of times.

Remove the sentinel.
2024-01-23 19:09:57 -03:00
Georges Basile Stavracas Neto
c8299f5b3e atcontext: Move variable declaration to top
This conforms better to the GTK C coding style.
2024-01-23 19:09:57 -03:00
Georges Basile Stavracas Neto
f019a325ef atcontext: Use size_t for loop iterator
G_N_ELEMENTS() returns a division of two size_t values, which results
in a size_t value.

This is just a cleanup, no functional change.
2024-01-23 19:09:57 -03:00
Arjan Molenaar
f947aafc2e Reset window transparency and shadow properties
... so that if a window is unrealized and realized again
that you end up in a stable form.
2024-01-22 16:22:56 +01:00
Arjan Molenaar
3e9f2aa4bb Differentiate between transparency and client side shadows
Transparency we need to support rounded corners. Client-side
shadows we need on platforms where the window manager does not
do them (mainly Wayland and X11). On platforms that support shadows
by default (macOS, Windows), we can just use them.
2024-01-22 16:22:56 +01:00
Paul Rouget
a6ce506714 [macos] Use FullSizeContent for CSD 2024-01-22 16:22:36 +01:00
80 changed files with 1560 additions and 1418 deletions

80
NEWS
View File

@@ -1,6 +1,84 @@
Overview of Changes in 4.13.6, xx-xx-xxxx
Overview of Changes in 4.13.7, xx-xx-xxxx
=========================================
Overview of Changes in 4.13.6, 25-01-2024
=========================================
This release changes the ngl renderer to be the default renderer.
The intent of this change is to get wider testing and verify that
the new renderers are production-ready. If significant problems
show up, we will revert this change for 4.14.
You can still override the renderer choice using the GSK_RENDERER
environment variable.
Since ngl can handle fractional scaling much better than the old gl
renderer, we allow fractional scaling by default with gl now. If you
are using the old gl renderer (e.g. because your system is limited to
GLES2), you can disable fractional scaling by setting the GDK_DEBUG
environment variable to include the gl-no-fractional key.
* GtkColumnView:
- Fix infinite loops in dispose
- Fix problems with weak ref cycles in GtkExpression
* GtkListView:
- Fix some corner cases with sections during insertions and deletions
- Don't double-recycle widgets
* GtkStack:
- Add automatic cleanup for GtkStackPage
* GDK:
- Use standard cursor names for drag cursors
- Enable fractional scaling with gl by default
* GSK:
- Many fixes and improvements to the unified renderers:
- Fix text rendering with the uber shader
- Fix rounding issues with fractional scales
- Fix some memory leaks
- Many text rendering fixes
- Implement subpixel positioning for glyphs
- Support custom fonts in node files
- Add tests for font rendering
- Fix drawing of repeat nodes
- Implement subpixels positioning
- Evict stale textures, glyphs and atlases from the cache
- Some fixes and improvements to the GL renderer:
- Fix problems with GLES on Nvidia
- Avoid a crash in the mask demo
- Respect opacity of the first child node in containers
- Some fixes and improvements to the fallback renderer:
- Fix drawing of repeat nodes
- Make ngl the default renderer
* Wayland:
- Fix problems with tablet cursors
- Fix problems without seats
* Accessibility:
- Respect a separate "show-status-shapes setting
- Fix change notification for accessible names on some widgets
* Inspector:
- Show the git commit in devel builds
* Tools:
- Make gtk4-node-editor autosave its contents
- Add a benchmark command to gtk4-rendernode-tool
* Translation updates:
French
Galician
Georgian
Occitan
Persian
Russian
Vietnamese
Overview of Changes in 4.13.5, 07-01-2024
=========================================

View File

@@ -1746,16 +1746,16 @@ set_initial_text (NodeEditorWindow *self)
path = get_autosave_path (NULL);
path1 = get_autosave_path ("-unsafe");
if (g_file_get_contents (path, &initial_text, &len, NULL))
{
gtk_text_buffer_set_text (self->text_buffer, initial_text, len);
g_free (initial_text);
}
else if (g_file_get_contents (path1, &initial_text, &len, NULL))
if (g_file_get_contents (path1, &initial_text, &len, NULL))
{
self->auto_reload = FALSE;
gtk_revealer_set_reveal_child (GTK_REVEALER (self->crash_warning), TRUE);
gtk_text_buffer_set_text (self->text_buffer, initial_text, len);
g_free (initial_text);
}
else if (g_file_get_contents (path, &initial_text, &len, NULL))
{
gtk_text_buffer_set_text (self->text_buffer, initial_text, len);
g_free (initial_text);
}

View File

@@ -10,10 +10,6 @@
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">app.help</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">app.help</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Inspector</attribute>
<attribute name="action">app.inspector</attribute>

View File

@@ -322,12 +322,16 @@ stroke bounds of the path.
### text
| property | syntax | default | printed |
| -------- | ------------------- | ------------------- | ----------- |
| color | `<color>` | black | non-default |
| font | `<string>` `<url>`? | "Cantarell 11" | always |
| glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default |
| property | syntax | default | printed |
| ------------ | ------------------- | ------------------- | ----------- |
| color | `<color>` | black | non-default |
| font | `<string>` `<url>`? | "Cantarell 11" | always |
| glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default |
| hint-metrics | `<hint metrics>` | off | non-default |
| hint-style | `<hint style>` | slight | non-default |
| antialias | `<antialias>` | on | non-default |
| dpi | `<number>` | 96 | non-default |
Creates a node like `gsk_text_node_new()` with the given properties.

View File

@@ -25,6 +25,8 @@ base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
[extra]
content_images = [
"../images/favicon.svg",
"../images/favicon-192x192.png",
"images/gtk-logo.svg",
]
urlmap_file = "urlmap.js"

View File

@@ -24,6 +24,8 @@ base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
[extra]
content_images = [
"../images/favicon.svg",
"../images/favicon-192x192.png",
"images/gtk-logo.svg",
]
urlmap_file = "urlmap.js"

View File

@@ -67,6 +67,8 @@ content_files = [
"macos.md",
]
content_images = [
"../images/favicon.svg",
"../images/favicon-192x192.png",
"images/gtk-logo.svg",
"images/rotated-text.png",
"images/default_cursor.png",

View File

@@ -36,6 +36,8 @@ content_files = [
"paths.md",
]
content_images = [
"../images/favicon.svg",
"../images/favicon-192x192.png",
"gtk-logo.svg",
"images/arc-dark.png",
"images/arc-light.png",

View File

@@ -85,6 +85,8 @@ content_files = [
"visual_index.md",
]
content_images = [
"../images/favicon.svg",
"../images/favicon-192x192.png",
"images/aboutdialog.png",
"images/action-bar.png",
"images/appchooserbutton.png",

View File

@@ -220,8 +220,8 @@ A number of options affect behavior instead of logging:
`gl-disable`
: Disable OpenGL support
`gl-fractional`
: Enable fractional scaling for OpenGL. This is experimental
`gl-no-fractional`
: Disable fractional scaling for OpenGL.
`gl-debug`
: Insert debugging information in OpenGL
@@ -460,6 +460,13 @@ disable certain optimizations of the "ngl" and "vulkan" renderer.
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.
### `GSK_CACHE_TIMEOUT`
Overrides the timeout for cache GC in the "ngl" and "vulkan" renderers.
The value can be -1 to disable GC entirely, 0 to force GC to happen
before every frame, or a positive number to do GC in a timeout every
n seconds. The default timeout is 15 seconds.
### `GSK_MAX_TEXTURE_SIZE`
Limit texture size to the minimum of this value and the OpenGL limit

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="88.572334" height="96.050743" id="svg6843">
<defs id="defs6845"/>
<g transform="translate(-19.822308,-16.115941)" id="layer1">
<path d="M 20.88413,30.82696 53.816977,55.527708 107.33282,39.060543 70.587303,17.177763 20.88413,30.82696 z" id="path6976" style="fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"/>
<path d="m 22.94243,82.287118 -2.0583,-51.460158 32.932847,24.700748 0,55.577152 L 22.94243,82.287118 z" id="path6978" style="fill:#e40000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"/>
<path d="m 53.816977,111.10486 49.399213,-20.58416 4.11663,-51.460157 -53.515843,16.467165 0,55.577152 z" id="path6980" style="fill:#7fe719;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"/>
<path d="M 23.216626,81.319479 70.48573,67.361442 103.38422,90.444516" id="path6982" style="fill:none;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/>
<path d="m 70.434539,17.875593 0,49.109284" id="path6984" style="fill:#babdb6;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -123,7 +123,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "portals", GDK_DEBUG_PORTALS, "Force use of portals" },
{ "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals" },
{ "gl-disable", GDK_DEBUG_GL_DISABLE, "Disable OpenGL support" },
{ "gl-fractional", GDK_DEBUG_GL_FRACTIONAL, "Enable fractional scaling for OpenGL (experimental)" },
{ "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-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" },

View File

@@ -43,7 +43,7 @@ typedef enum {
GDK_DEBUG_PORTALS = 1 << 14,
GDK_DEBUG_NO_PORTALS = 1 << 15,
GDK_DEBUG_GL_DISABLE = 1 << 16,
GDK_DEBUG_GL_FRACTIONAL = 1 << 17,
GDK_DEBUG_GL_NO_FRACTIONAL= 1 << 17,
GDK_DEBUG_GL_DISABLE_GL = 1 << 19,
GDK_DEBUG_GL_DISABLE_GLES = 1 << 20,

View File

@@ -77,6 +77,7 @@ enum
PROP_0,
PROP_COMPOSITED,
PROP_RGBA,
PROP_SHADOW_WIDTH,
PROP_INPUT_SHAPES,
PROP_DMABUF_FORMATS,
LAST_PROP
@@ -111,6 +112,7 @@ struct _GdkDisplayPrivate {
guint rgba : 1;
guint composited : 1;
guint shadow_width: 1;
guint input_shapes : 1;
GdkDebugFlags debug_flags;
@@ -144,6 +146,10 @@ gdk_display_get_property (GObject *object,
g_value_set_boolean (value, gdk_display_is_rgba (display));
break;
case PROP_SHADOW_WIDTH:
g_value_set_boolean (value, gdk_display_supports_shadow_width (display));
break;
case PROP_INPUT_SHAPES:
g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
break;
@@ -243,6 +249,18 @@ gdk_display_class_init (GdkDisplayClass *class)
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkDisplay:shadow-width: (attributes org.gtk.Property.get=gdk_display_supports_shadow_width)
*
* %TRUE if the display supports extensible frames.
*
* Since: 4.14
*/
props[PROP_SHADOW_WIDTH] =
g_param_spec_boolean ("shadow-width", NULL, NULL,
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkDisplay:input-shapes: (attributes org.gtk.Property.get=gdk_display_supports_input_shapes)
*
@@ -391,6 +409,7 @@ gdk_display_init (GdkDisplay *display)
priv->composited = TRUE;
priv->rgba = TRUE;
priv->shadow_width = TRUE;
priv->input_shapes = TRUE;
}
@@ -2122,6 +2141,46 @@ gdk_display_set_rgba (GdkDisplay *display,
g_object_notify_by_pspec (G_OBJECT (display), props[PROP_RGBA]);
}
/**
* gdk_display_supports_shadow_width: (attributes org.gtk.Method.get_property=shadow-width)
* @display: a `GdkDisplay`
*
* Returns whether it's possible for a surface to draw outside of the window area.
*
* If %TRUE is returned the application decides if it wants to draw shadows.
* If %FALSE is returned, the compositor decides if it wants to draw shadows.
*
* Returns: %TRUE if surfaces can draw shadows or
* %FALSE if the display does not support this functionality.
*
* Since: 4.14
*/
gboolean
gdk_display_supports_shadow_width (GdkDisplay *display)
{
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
return priv->shadow_width;
}
void
gdk_display_set_shadow_width (GdkDisplay *display,
gboolean shadow_width)
{
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
g_return_if_fail (GDK_IS_DISPLAY (display));
if (priv->shadow_width == shadow_width)
return;
priv->shadow_width = shadow_width;
g_object_notify_by_pspec (G_OBJECT (display), props[PROP_SHADOW_WIDTH]);
}
static void
device_removed_cb (GdkSeat *seat,
GdkDevice *device,

View File

@@ -63,6 +63,8 @@ GDK_AVAILABLE_IN_ALL
gboolean gdk_display_is_composited (GdkDisplay *display);
GDK_AVAILABLE_IN_ALL
gboolean gdk_display_is_rgba (GdkDisplay *display);
GDK_AVAILABLE_IN_4_14
gboolean gdk_display_supports_shadow_width (GdkDisplay *display);
GDK_AVAILABLE_IN_ALL
gboolean gdk_display_supports_input_shapes (GdkDisplay *display);

View File

@@ -257,6 +257,8 @@ void gdk_display_set_composited (GdkDisplay *display
gboolean composited);
void gdk_display_set_input_shapes (GdkDisplay *display,
gboolean input_shapes);
void gdk_display_set_shadow_width (GdkDisplay *display,
gboolean shadow_width);
void gdk_display_add_seat (GdkDisplay *display,
GdkSeat *seat);

View File

@@ -593,7 +593,7 @@ gdk_gl_context_get_scale (GdkGLContext *self)
scale = gdk_surface_get_scale (surface);
display = gdk_gl_context_get_display (self);
if (!(gdk_display_get_debug_flags (display) & GDK_DEBUG_GL_FRACTIONAL))
if (gdk_display_get_debug_flags (display) & GDK_DEBUG_GL_NO_FRACTIONAL)
scale = ceil (scale);
return scale;

View File

@@ -142,6 +142,9 @@ gdk_toplevel_size_set_min_size (GdkToplevelSize *size,
* The shadow width corresponds to the part of the computed surface size
* that would consist of the shadow margin surrounding the window, would
* there be any.
*
* Shadow width should only be set if
* [method@Gtk.Display.supports_shadow_width] is %TRUE.
*/
void
gdk_toplevel_size_set_shadow_width (GdkToplevelSize *size,

View File

@@ -398,8 +398,7 @@ typedef NSString *CALayerContentsGravity;
* in from a display-side change. We need to request a layout in
* addition to the configure event.
*/
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface) &&
GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface)->decorated)
if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface))
gdk_surface_request_layout (GDK_SURFACE (gdk_surface));
}
@@ -875,12 +874,21 @@ typedef NSString *CALayerContentsGravity;
{
NSWindowStyleMask style_mask = [self styleMask];
[self setHasShadow:decorated];
if (decorated)
style_mask |= NSWindowStyleMaskTitled;
{
style_mask &= ~NSWindowStyleMaskFullSizeContentView;
[self setTitleVisibility:NSWindowTitleVisible];
}
else
style_mask &= ~NSWindowStyleMaskTitled;
{
style_mask |= NSWindowStyleMaskFullSizeContentView;
[self setTitleVisibility:NSWindowTitleHidden];
}
[self setTitlebarAppearsTransparent:!decorated];
[[self standardWindowButton:NSWindowCloseButton] setHidden:!decorated];
[[self standardWindowButton:NSWindowMiniaturizeButton] setHidden:!decorated];
[[self standardWindowButton:NSWindowZoomButton] setHidden:!decorated];
[self setStyleMask:style_mask];
}

View File

@@ -625,6 +625,7 @@ gdk_macos_display_init (GdkMacosDisplay *self)
gdk_display_set_composited (GDK_DISPLAY (self), TRUE);
gdk_display_set_input_shapes (GDK_DISPLAY (self), FALSE);
gdk_display_set_rgba (GDK_DISPLAY (self), TRUE);
gdk_display_set_shadow_width (GDK_DISPLAY (self), FALSE);
}
GdkDisplay *

View File

@@ -87,9 +87,8 @@ static void
gdk_wayland_gl_context_empty_frame (GdkDrawContext *draw_context)
{
GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
if (impl->has_pending_subsurface_commits)
if (gdk_wayland_surface_needs_commit (surface))
{
gdk_wayland_surface_sync (surface);
gdk_wayland_surface_request_frame (surface);

View File

@@ -129,6 +129,7 @@ guint _gdk_wayland_cursor_get_next_image_index (GdkWaylandDisplay *display,
guint *next_image_delay);
void gdk_wayland_surface_sync (GdkSurface *surface);
gboolean gdk_wayland_surface_needs_commit (GdkSurface *surface);
void gdk_wayland_surface_commit (GdkSurface *surface);
void gdk_wayland_surface_notify_committed (GdkSurface *surface);
void gdk_wayland_surface_request_frame (GdkSurface *surface);

View File

@@ -199,20 +199,20 @@ get_egl_window_size (GdkSurface *surface,
GdkDisplay *display = gdk_surface_get_display (surface);
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_FRACTIONAL))
{
GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window", gdk_fractional_scale_to_double (&impl->scale));
*width = gdk_fractional_scale_scale (&impl->scale, surface->width),
*height = gdk_fractional_scale_scale (&impl->scale, surface->height);
}
else
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_NO_FRACTIONAL))
{
GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window", gdk_fractional_scale_to_int (&impl->scale));
*width = surface->width * gdk_fractional_scale_to_int (&impl->scale);
*height = surface->height * gdk_fractional_scale_to_int (&impl->scale);
}
else
{
GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window", gdk_fractional_scale_to_double (&impl->scale));
*width = gdk_fractional_scale_scale (&impl->scale, surface->width),
*height = gdk_fractional_scale_scale (&impl->scale, surface->height);
}
}
void
@@ -746,6 +746,18 @@ gdk_wayland_surface_sync (GdkSurface *surface)
gdk_wayland_surface_sync_viewport (surface);
}
gboolean
gdk_wayland_surface_needs_commit (GdkSurface *surface)
{
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
return self->has_pending_subsurface_commits ||
self->opaque_region_dirty ||
self->input_region_dirty ||
self->buffer_scale_dirty ||
self->viewport_dirty;
}
static void
gdk_wayland_surface_fractional_scale_preferred_scale_cb (void *data,
struct wp_fractional_scale_v1 *fractional_scale,

View File

@@ -1064,6 +1064,7 @@ gdk_win32_display_check_composited (GdkWin32Display *display)
}
gdk_display_set_composited (GDK_DISPLAY (display), composited);
gdk_display_set_shadow_width (GDK_DISPLAY (display), composited);
}
static void

View File

@@ -1429,6 +1429,7 @@ gdk_x11_display_open (const char *display_name)
int ignore;
int maj, min;
char *cm_name;
gboolean frame_extents;
XInitThreads ();
@@ -1643,6 +1644,10 @@ gdk_x11_display_open (const char *display_name)
gdk_x11_get_xatom_by_name_for_display (display, cm_name)) != None);
g_free (cm_name);
frame_extents = gdk_x11_screen_supports_net_wm_hint (gdk_x11_display_get_screen (display),
g_intern_static_string ("_GTK_FRAME_EXTENTS"));
gdk_display_set_shadow_width (display, frame_extents);
gdk_display_emit_opened (display);
return display;

View File

@@ -1,479 +0,0 @@
#pragma once
#include <graphene.h>
#include <math.h>
#include "gsktypesprivate.h"
#include "scaleprivate.h"
#include "pointprivate.h"
#ifndef USE_SIMD
struct _Box
{
float x0, y0, x1, y1;
};
static inline float
box_x0 (const Box box)
{
return box.x0;
}
static inline float
box_y0 (const Box box)
{
return box.y0;
}
static inline float
box_x1 (const Box box)
{
return box.x1;
}
static inline float
box_y1 (const Box box)
{
return box.y1;
}
static inline float
box_width (const Box box)
{
return box.x1 - box.x0;
}
static inline float
box_height (const Box box)
{
return box.y1 - box.y0;
}
/* Assumes x0 <= x1 && y0 <= y1 */
static inline Box
box (float x0,
float y0,
float x1,
float y1)
{
return (Box) { .x0 = x0, .y0 = y0, .x1 = x1, .y1 = y1 };
}
static inline Box
box_from_rect (float x,
float y,
float w,
float h)
{
return box (x, y, x + w, y + h);
}
static inline Box
box_from_graphene (const graphene_rect_t *rect)
{
return box_from_rect (rect->origin.x,
rect->origin.y,
rect->size.width,
rect->size.height);
}
/* Assumes p0.x <= p1.x && p0.y <= p1.y */
static inline Box
box_from_points (Point p0,
Point p1)
{
return box (p0.x, p0.y, p1.x, p1.y);
}
static inline Point
box_origin (const Box box)
{
return point (box.x0, box.y0);
}
static inline Point
box_opposite (const Box box)
{
return point (box.x1, box.y1);
}
static inline void
box_to_float (const Box box,
float v[4])
{
v[0] = box.x0;
v[1] = box.y0;
v[2] = box.x1 - box.x0;
v[3] = box.y1 - box.y0;
}
static inline Box
box_inset (const Box box,
float dx,
float dy)
{
return (Box) { .x0 = box.x0 + dx, .y0 = box.y0 + dy,
.x1 = box.x1 - dx, .y1 = box.y1 - dy };
}
static inline gboolean
box_intersect (const Box box1,
const Box box2,
Box *box)
{
Box b;
b.x0 = MAX (box1.x0, box2.x0);
b.y0 = MAX (box1.y0, box2.y0);
b.x1 = MIN (box1.x1, box2.x1);
b.y1 = MIN (box1.y1, box2.y1);
if (b.x0 <= b.x1 && b.y0 <= b.x1)
{
if (box)
*box = b;
return TRUE;
}
return FALSE;
}
static inline gboolean
box_equal (const Box box1,
const Box box2)
{
return memcmp (&box1, &box2, sizeof (Box)) == 0;
}
static inline gboolean
box_contains (const Box box1,
const Box box2)
{
Box box;
if (box_intersect (box1, box2, &box))
return box_equal (box, box2);
return FALSE;
}
static inline gboolean
box_empty (const Box box)
{
return box.x0 == box.x1 || box.y0 == box.y1;
}
static inline Box
box_add (const Box box,
const Point offset)
{
return (Box) { .x0 = box.x0 + offset.x, .y0 = box.y0 + offset.y,
.x1 = box.x1 + offset.x, .y1 = box.y1 + offset.y };
}
static inline Box
box_sub (const Box box,
const Point offset)
{
return (Box) { .x0 = box.x0 - offset.x, .y0 = box.y0 - offset.y,
.x1 = box.x1 - offset.x, .y1 = box.y1 - offset.y };
}
static inline Box
box_mul (const Box box,
const Scale scale)
{
Box b = (Box) { .x0 = box.x0 * scale.x, .y0 = box.y0 * scale.y,
.x1 = box.x1 * scale.x, .y1 = box.y1 * scale.y };
if (G_UNLIKELY (scale.x < 0 || scale.y < 0))
return (Box) { .x0 = MIN (b.x0, b.x1), .y0 = MIN (b.y0, b.y1),
.x1 = MAX (b.x0, b.x1), .y1 = MAX (b.y0, b.y1) };
return b;
}
static inline Box
box_div (const Box box,
const Scale scale)
{
return box_mul (box, scale_inv (scale));
}
static inline void
box_offset_to_float (const Box box,
const Point offset,
float v[4])
{
box_to_float (box_add (box, offset), v);
}
static inline Box
box_round_larger (const Box box)
{
return (Box) { .x0 = floorf (box.x0), .y0 = floorf (box.y0),
.x1 = ceilf (box.x1), .y1 = ceilf (box.y1) };
}
static inline Box
box_round_to_pixels (const Box box,
const Scale scale,
const Point offset)
{
return box_sub (box_div (box_round_larger (box_mul (box_add (box, offset), scale)), scale), offset);
}
#else /* USE_SIMD */
struct _Box
{
GRAPHENE_ALIGNED_DECL (graphene_simd4f_t v, 16);
};
static inline float
box_x0 (const Box box)
{
return graphene_simd4f_get_x (box.v);
}
static inline float
box_y0 (const Box box)
{
return graphene_simd4f_get_y (box.v);
}
static inline float
box_x1 (const Box box)
{
return graphene_simd4f_get_z (box.v);
}
static inline float
box_y1 (const Box box)
{
return graphene_simd4f_get_w (box.v);
}
static inline float
box_width (const Box box)
{
return box_x1 (box) - box_x0 (box);
}
static inline float
box_height (const Box box)
{
return box_y1 (box) - box_y0 (box);
}
static inline Box
box (float x0,
float y0,
float x1,
float y1)
{
return (Box) { .v = graphene_simd4f_init (x0, y0, x1, y1) };
}
static inline Box
box_from_rect (float x,
float y,
float w,
float h)
{
return box (x, y, x + w, y + h);
}
static inline Box
box_from_graphene (const graphene_rect_t *rect)
{
return box_from_rect (rect->origin.x,
rect->origin.y,
rect->size.width,
rect->size.height);
}
/* { a[0], a[1], b[0], b[1] } */
# define graphene_simd4f_splat_xyxy(a,b) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_shuffle_ps ((a), (b), _MM_SHUFFLE (1, 0, 1, 0)); \
}))
static inline Box
box_from_points (Point p0,
Point p1)
{
return (Box) { .v = graphene_simd4f_splat_xyxy (p0.v, p1.v) };
}
static inline Point
box_origin (const Box box)
{
return (Point) { .v = graphene_simd4f_zero_zw (box.v) };
}
static inline Point
box_opposite (const Box box)
{
return (Point) { .v = graphene_simd4f_zero_zw (graphene_simd4f_shuffle_zwxy (box.v)) };
}
static inline void
box_to_float (const Box box,
float v[4])
{
graphene_simd4f_dup_4f (box.v, v);
v[2] -= v[0];
v[3] -= v[1];
}
static inline Box
box_inset (const Box box,
float dx,
float dy)
{
return (Box) { .v = graphene_simd4f_add (box.v, graphene_simd4f_init (dx, dy, -dx, -dy)) };
}
/* return a[0] < b[0] && a[1] < b[1] */
#ifndef graphene_simd4f_cmple_xy
# define graphene_simd4f_cmple_xy(a,b) \
(__extension__ ({ \
__m128i __res = (__m128i) _mm_cmple_ps ((a), (b)); \
(bool) ((_mm_movemask_epi8 (__res) & 0xff) == 0xff); \
}))
#endif
static inline gboolean
box_intersect (const Box box1,
const Box box2,
Box *box)
{
graphene_simd4f_t s, t, t1;
s = graphene_simd4f_max (box1.v, box2.v);
t = graphene_simd4f_min (box1.v, box2.v);
t1 = graphene_simd4f_shuffle_zwxy (t);
if (graphene_simd4f_cmple_xy (s, t1))
{
if (box)
box->v = graphene_simd4f_splat_xyxy (s, t);
return TRUE;
}
return FALSE;
}
static inline gboolean
box_equal (const Box box1,
const Box box2)
{
return (gboolean) !!graphene_simd4f_cmp_eq (box1.v, box2.v);
}
static inline gboolean
box_contains (const Box box1,
const Box box2)
{
Box box;
if (box_intersect (box1, box2, &box))
return box_equal (box, box2);
return FALSE;
}
static inline gboolean
box_empty (const Box box)
{
/* FIXME simd */
return box_x0 (box) == box_x1 (box) || box_y0 (box) == box_y1 (box);
}
/* a splat variation */
#ifndef graphene_simd4f_shuffle_xyxy
# define graphene_simd4f_shuffle_xyxy(v) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (1, 0, 1, 0)); \
}))
#endif
static inline Box
box_add (const Box box,
const Point offset)
{
return (Box) { .v = graphene_simd4f_add (box.v, graphene_simd4f_shuffle_xyxy (offset.v)) };
}
static inline Box
box_sub (const Box box,
const Point offset)
{
return (Box) { .v = graphene_simd4f_sub (box.v, graphene_simd4f_shuffle_xyxy (offset.v)) };
}
static inline Box
box_mul (const Box box,
const Scale scale)
{
Box b = (Box) { .v = graphene_simd4f_mul (box.v, graphene_simd4f_shuffle_xyxy (scale.v)) };
if (G_UNLIKELY (!graphene_simd4f_cmple_xy (graphene_simd4f_init (0, 0, 0, 0), scale.v)))
{
graphene_simd4f_t v = graphene_simd4f_shuffle_zwxy (b.v);
graphene_simd4f_t s = graphene_simd4f_min (b.v, v);
graphene_simd4f_t t = graphene_simd4f_max (b.v, v);
return (Box) { .v = graphene_simd4f_splat_xyxy (s, t) };
}
return b;
}
static inline Box
box_div (const Box box,
const Scale scale)
{
return box_mul (box, scale_inv (scale));
}
static inline void
box_offset_to_float (const Box box,
const Point offset,
float v[4])
{
box_to_float (box_add (box, offset), v);
}
#ifdef __SSE4_1__
static inline Box
box_round_larger (const Box box)
{
return { (Box) .v = graphene_simd4f_splat_xyxy (graphene_simd4f_floor (b.v), graphene_simd4f_ceil (b.v)) };
}
#else
static inline Box
box_round_larger (const Box b)
{
return box (floorf (box_x0 (b)),
floorf (box_y0 (b)),
ceilf (box_x1 (b)),
ceilf (box_y1 (b)));
}
#endif
static inline Box
box_round_to_pixels (const Box box,
const Scale scale,
const Point offset)
{
return box_sub (box_div (box_round_larger (box_mul (box_add (box, offset), scale)), scale), offset);
}
#endif

View File

@@ -125,6 +125,12 @@ gsk_gl_device_create_atlas_image (GskGpuDevice *device,
height);
}
static void
gsk_gl_device_make_current (GskGpuDevice *device)
{
gdk_gl_context_make_current (gdk_display_get_gl_context (gsk_gpu_device_get_display (device)));
}
static void
gsk_gl_device_finalize (GObject *object)
{
@@ -151,6 +157,7 @@ gsk_gl_device_class_init (GskGLDeviceClass *klass)
gpu_device_class->create_atlas_image = gsk_gl_device_create_atlas_image;
gpu_device_class->create_upload_image = gsk_gl_device_create_upload_image;
gpu_device_class->create_download_image = gsk_gl_device_create_download_image;
gpu_device_class->make_current = gsk_gl_device_make_current;
object_class->finalize = gsk_gl_device_finalize;
}

View File

@@ -43,7 +43,7 @@ gsk_gl_image_finalize (GObject *object)
{
GskGLImage *self = GSK_GL_IMAGE (object);
if (self->framebuffer_id)
if (self->texture_id && self->framebuffer_id)
glDeleteFramebuffers (1, &self->framebuffer_id);
if (self->owns_texture)
@@ -70,6 +70,7 @@ gsk_gl_image_init (GskGLImage *self)
GskGpuImage *
gsk_gl_image_new_backbuffer (GskGLDevice *device,
GdkGLContext *context,
GdkMemoryFormat format,
gsize width,
gsize height)
@@ -95,6 +96,13 @@ gsk_gl_image_new_backbuffer (GskGLDevice *device,
/* texture_id == 0 means backbuffer */
/* Check for non-standard framebuffer binding as we might not be using
* the default framebuffer on systems like macOS where we've bound an
* IOSurface to a GL_TEXTURE_RECTANGLE. Otherwise, no scissor clip will
* be applied in the command queue causing overdrawing.
*/
self->framebuffer_id = GDK_GL_CONTEXT_GET_CLASS (context)->get_default_framebuffer (context);
return GSK_GPU_IMAGE (self);
}

View File

@@ -11,6 +11,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GskGLImage, gsk_gl_image, GSK, GL_IMAGE, GskGpuImage)
GskGpuImage * gsk_gl_image_new_backbuffer (GskGLDevice *device,
GdkGLContext *context,
GdkMemoryFormat format,
gsize width,
gsize height);

View File

@@ -301,42 +301,3 @@ gsk_gpu_clip_get_shader_clip (const GskGpuClip *self,
return GSK_GPU_SHADER_CLIP_ROUNDED;
}
gboolean
gsk_gpu_clip_contains_box (const GskGpuClip *self,
const Point *offset,
const Box *box)
{
Box b = box_add (*box, *offset);
switch (self->type)
{
default:
g_assert_not_reached();
case GSK_GPU_CLIP_ALL_CLIPPED:
return FALSE;
case GSK_GPU_CLIP_NONE:
case GSK_GPU_CLIP_CONTAINED:
case GSK_GPU_CLIP_RECT:
return box_contains (box_from_graphene (&self->rect.bounds), b);
case GSK_GPU_CLIP_ROUNDED:
return gsk_rounded_rect_contains_rect (&self->rect, &GRAPHENE_RECT_INIT (box_x0 (b), box_y0 (b), box_width (b), box_height (b)));
}
}
GskGpuShaderClip
gsk_gpu_clip_get_shader_clip2 (const GskGpuClip *self,
const Point *offset,
const Box *box)
{
if (self->type == GSK_GPU_CLIP_NONE ||
self->type == GSK_GPU_CLIP_CONTAINED ||
gsk_gpu_clip_contains_box (self, offset, box))
return GSK_GPU_SHADER_CLIP_NONE;
else if (self->type == GSK_GPU_CLIP_RECT)
return GSK_GPU_SHADER_CLIP_RECT;
else
return GSK_GPU_SHADER_CLIP_ROUNDED;
}

View File

@@ -5,7 +5,6 @@
#include <gdk/gdk.h>
#include <graphene.h>
#include <gsk/gskroundedrect.h>
#include "boxprivate.h"
G_BEGIN_DECLS
@@ -66,16 +65,9 @@ gboolean gsk_gpu_clip_contains_rect (const G
gboolean gsk_gpu_clip_may_intersect_rect (const GskGpuClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
GskGpuShaderClip gsk_gpu_clip_get_shader_clip (const GskGpuClip *self,
GskGpuShaderClip gsk_gpu_clip_get_shader_clip (const GskGpuClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect);
gboolean gsk_gpu_clip_contains_box (const GskGpuClip *self,
const Point *offset,
const Box *box) G_GNUC_WARN_UNUSED_RESULT;
GskGpuShaderClip gsk_gpu_clip_get_shader_clip2 (const GskGpuClip *self,
const Point *offset,
const Box *box);
G_END_DECLS

View File

@@ -3,10 +3,14 @@
#include "gskgpudeviceprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuimageprivate.h"
#include "gskgpuuploadopprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkprofilerprivate.h"
#include "gsk/gskdebugprivate.h"
#define MAX_SLICES_PER_ATLAS 64
@@ -14,6 +18,13 @@
#define MAX_ATLAS_ITEM_SIZE 256
#define MAX_DEAD_PIXELS (ATLAS_SIZE * ATLAS_SIZE / 2)
#define CACHE_TIMEOUT 15 /* seconds */
G_STATIC_ASSERT (MAX_ATLAS_ITEM_SIZE < ATLAS_SIZE);
G_STATIC_ASSERT (MAX_DEAD_PIXELS < ATLAS_SIZE * ATLAS_SIZE);
typedef struct _GskGpuCached GskGpuCached;
typedef struct _GskGpuCachedClass GskGpuCachedClass;
typedef struct _GskGpuCachedAtlas GskGpuCachedAtlas;
@@ -29,11 +40,14 @@ struct _GskGpuDevicePrivate
GskGpuCached *first_cached;
GskGpuCached *last_cached;
guint cache_gc_source;
int cache_timeout; /* in seconds, or -1 to disable gc */
GHashTable *texture_cache;
GHashTable *glyph_cache;
GskGpuCachedAtlas *current_atlas;
/* atomic */ gsize dead_texture_pixels;
};
G_DEFINE_TYPE_WITH_PRIVATE (GskGpuDevice, gsk_gpu_device, G_TYPE_OBJECT)
@@ -54,12 +68,34 @@ struct _GskGpuCachedClass
struct _GskGpuCached
{
const GskGpuCachedClass *class;
GskGpuCachedAtlas *atlas;
GskGpuCached *next;
GskGpuCached *prev;
gint64 timestamp;
gboolean stale;
guint pixels; /* For glyphs and textures, pixels. For atlases, dead pixels */
};
static inline void
mark_as_stale (GskGpuCached *cached,
gboolean stale)
{
if (cached->stale != stale)
{
cached->stale = stale;
if (cached->atlas)
{
if (stale)
((GskGpuCached *) cached->atlas)->pixels += cached->pixels;
else
((GskGpuCached *) cached->atlas)->pixels -= cached->pixels;
}
}
}
static void
gsk_gpu_cached_free (GskGpuDevice *device,
GskGpuCached *cached)
@@ -75,6 +111,8 @@ gsk_gpu_cached_free (GskGpuDevice *device,
else
priv->first_cached = cached->next;
mark_as_stale (cached, TRUE);
cached->class->free (device, cached);
}
@@ -114,7 +152,21 @@ gsk_gpu_cached_use (GskGpuDevice *device,
GskGpuCached *cached,
gint64 timestamp)
{
/* FIXME */
cached->timestamp = timestamp;
mark_as_stale (cached, FALSE);
}
static inline gboolean
gsk_gpu_cached_is_old (GskGpuDevice *device,
GskGpuCached *cached,
gint64 timestamp)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
if (priv->cache_timeout < 0)
return FALSE;
else
return timestamp - cached->timestamp > priv->cache_timeout * G_TIME_SPAN_SECOND;
}
/* }}} */
@@ -137,10 +189,23 @@ static void
gsk_gpu_cached_atlas_free (GskGpuDevice *device,
GskGpuCached *cached)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
GskGpuCachedAtlas *self = (GskGpuCachedAtlas *) cached;
GskGpuCached *c, *next;
/* Free all remaining glyphs on this atlas */
for (c = priv->first_cached; c != NULL; c = next)
{
next = c->next;
if (c->atlas == self)
gsk_gpu_cached_free (device, c);
}
if (priv->current_atlas == self)
priv->current_atlas = NULL;
g_object_unref (self->image);
g_free (self);
}
@@ -149,8 +214,7 @@ gsk_gpu_cached_atlas_should_collect (GskGpuDevice *device,
GskGpuCached *cached,
gint64 timestamp)
{
/* FIXME */
return FALSE;
return cached->pixels > MAX_DEAD_PIXELS;
}
static const GskGpuCachedClass GSK_GPU_CACHED_ATLAS_CLASS =
@@ -178,7 +242,14 @@ struct _GskGpuCachedTexture
{
GskGpuCached parent;
/* atomic */ GdkTexture *texture;
/* atomic */ int use_count; /* We count the use by the device (via the linked
* list) and by the texture (via render data or
* weak ref.
*/
gsize *dead_pixels_counter;
GdkTexture *texture;
GskGpuImage *image;
};
@@ -186,14 +257,37 @@ static void
gsk_gpu_cached_texture_free (GskGpuDevice *device,
GskGpuCached *cached)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
GskGpuCachedTexture *self = (GskGpuCachedTexture *) cached;
gboolean texture_still_alive;
gpointer key, value;
texture_still_alive = g_atomic_pointer_exchange (&self->texture, NULL) != NULL;
g_object_unref (self->image);
if (!texture_still_alive)
g_free (self);
g_clear_object (&self->image);
if (g_hash_table_steal_extended (priv->texture_cache, self->texture, &key, &value))
{
/* If the texture has been reused already, we put the entry back */
if ((GskGpuCached *) value != cached)
g_hash_table_insert (priv->texture_cache, key, value);
}
/* If the cached item itself is still in use by the texture, we leave
* it to the weak ref or render data to free it.
*/
if (g_atomic_int_dec_and_test (&self->use_count))
{
g_free (self);
return;
}
}
static inline gboolean
gsk_gpu_cached_texture_is_invalid (GskGpuCachedTexture *self)
{
/* If the use count is less than 2, the orignal texture has died,
* and the memory may have been reused for a new texture, so we
* can't hand out the image that is for the original texture.
*/
return g_atomic_int_get (&self->use_count) < 2;
}
static gboolean
@@ -201,8 +295,10 @@ gsk_gpu_cached_texture_should_collect (GskGpuDevice *device,
GskGpuCached *cached,
gint64 timestamp)
{
/* FIXME */
return FALSE;
GskGpuCachedTexture *self = (GskGpuCachedTexture *) cached;
return gsk_gpu_cached_is_old (device, cached, timestamp) ||
gsk_gpu_cached_texture_is_invalid (self);
}
static const GskGpuCachedClass GSK_GPU_CACHED_TEXTURE_CLASS =
@@ -212,16 +308,19 @@ static const GskGpuCachedClass GSK_GPU_CACHED_TEXTURE_CLASS =
gsk_gpu_cached_texture_should_collect
};
/* Note: this function can run in an arbitrary thread, so it can
* only access things atomically
*/
static void
gsk_gpu_cached_texture_destroy_cb (gpointer data)
{
GskGpuCachedTexture *cache = data;
gboolean cache_still_alive;
GskGpuCachedTexture *self = data;
cache_still_alive = g_atomic_pointer_exchange (&cache->texture, NULL) != NULL;
if (!gsk_gpu_cached_texture_is_invalid (self))
g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels);
if (!cache_still_alive)
g_free (cache);
if (g_atomic_int_dec_and_test (&self->use_count))
g_free (self);
}
static GskGpuCachedTexture *
@@ -235,18 +334,19 @@ gsk_gpu_cached_texture_new (GskGpuDevice *device,
if (gdk_texture_get_render_data (texture, device))
gdk_texture_clear_render_data (texture);
else if ((self = g_hash_table_lookup (priv->texture_cache, texture)))
{
g_hash_table_remove (priv->texture_cache, texture);
g_object_weak_unref (G_OBJECT (texture), (GWeakNotify) gsk_gpu_cached_texture_destroy_cb, self);
}
g_hash_table_remove (priv->texture_cache, texture);
self = gsk_gpu_cached_new (device, &GSK_GPU_CACHED_TEXTURE_CLASS, NULL);
self->texture = texture;
self->image = g_object_ref (image);
((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image);
self->dead_pixels_counter = &priv->dead_texture_pixels;
self->use_count = 2;
if (!gdk_texture_set_render_data (texture, device, self, gsk_gpu_cached_texture_destroy_cb))
{
g_object_weak_ref (G_OBJECT (texture), (GWeakNotify) gsk_gpu_cached_texture_destroy_cb, self);
g_hash_table_insert (priv->texture_cache, texture, self);
}
@@ -274,8 +374,11 @@ static void
gsk_gpu_cached_glyph_free (GskGpuDevice *device,
GskGpuCached *cached)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
GskGpuCachedGlyph *self = (GskGpuCachedGlyph *) cached;
g_hash_table_remove (priv->glyph_cache, self);
g_object_unref (self->font);
g_object_unref (self->image);
@@ -287,7 +390,15 @@ gsk_gpu_cached_glyph_should_collect (GskGpuDevice *device,
GskGpuCached *cached,
gint64 timestamp)
{
/* FIXME */
if (gsk_gpu_cached_is_old (device, cached, timestamp))
{
if (cached->atlas)
mark_as_stale (cached, TRUE);
else
return TRUE;
}
/* Glyphs are only collected when their atlas is freed */
return FALSE;
}
@@ -325,19 +436,127 @@ static const GskGpuCachedClass GSK_GPU_CACHED_GLYPH_CLASS =
/* }}} */
/* {{{ GskGpuDevice */
void
static void
print_cache_stats (GskGpuDevice *self)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
GskGpuCached *cached;
guint glyphs = 0;
guint stale_glyphs = 0;
guint textures = 0;
guint atlases = 0;
GString *ratios = g_string_new ("");
for (cached = priv->first_cached; cached != NULL; cached = cached->next)
{
if (cached->class == &GSK_GPU_CACHED_GLYPH_CLASS)
{
glyphs++;
if (cached->stale)
stale_glyphs++;
}
else if (cached->class == &GSK_GPU_CACHED_TEXTURE_CLASS)
{
textures++;
}
else if (cached->class == &GSK_GPU_CACHED_ATLAS_CLASS)
{
double ratio;
atlases++;
ratio = (double) cached->pixels / (double) (ATLAS_SIZE * ATLAS_SIZE);
if (ratios->len == 0)
g_string_append (ratios, " (ratios ");
else
g_string_append (ratios, ", ");
g_string_append_printf (ratios, "%.2f", ratio);
}
}
if (ratios->len > 0)
g_string_append (ratios, ")");
gdk_debug_message ("Cached items\n"
" glyphs: %5u (%u stale)\n"
" textures: %5u (%u in hash)\n"
" atlases: %5u%s",
glyphs, stale_glyphs,
textures, g_hash_table_size (priv->texture_cache),
atlases, ratios->str);
g_string_free (ratios, TRUE);
}
static void
gsk_gpu_device_gc (GskGpuDevice *self,
gint64 timestamp)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
GskGpuCached *cached, *next;
GskGpuCached *cached, *prev;
gint64 before G_GNUC_UNUSED = GDK_PROFILER_CURRENT_TIME;
for (cached = priv->first_cached; cached != NULL; cached = next)
gsk_gpu_device_make_current (self);
/* We walk the cache from the end so we don't end up with prev
* being a leftover glyph on the atlas we are freeing
*/
for (cached = priv->last_cached; cached != NULL; cached = prev)
{
next = cached->next;
prev = cached->prev;
if (gsk_gpu_cached_should_collect (self, cached, timestamp))
gsk_gpu_cached_free (self, cached);
}
g_atomic_pointer_set (&priv->dead_texture_pixels, 0);
if (GSK_DEBUG_CHECK (GLYPH_CACHE))
print_cache_stats (self);
gdk_profiler_end_mark (before, "Glyph cache GC", NULL);
}
static gboolean
cache_gc_cb (gpointer data)
{
GskGpuDevice *self = data;
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
GSK_DEBUG (GLYPH_CACHE, "Periodic GC");
gsk_gpu_device_gc (self, g_get_monotonic_time ());
priv->cache_gc_source = 0;
return G_SOURCE_REMOVE;
}
void
gsk_gpu_device_maybe_gc (GskGpuDevice *self)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
gsize dead_texture_pixels;
if (priv->cache_timeout < 0)
return;
dead_texture_pixels = GPOINTER_TO_SIZE (g_atomic_pointer_get (&priv->dead_texture_pixels));
if (priv->cache_timeout == 0 || dead_texture_pixels > 1000000)
{
GSK_DEBUG (GLYPH_CACHE, "Pre-frame GC (%lu dead pixels)", dead_texture_pixels);
gsk_gpu_device_gc (self, g_get_monotonic_time ());
}
}
void
gsk_gpu_device_queue_gc (GskGpuDevice *self)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
if (priv->cache_timeout > 0 && !priv->cache_gc_source)
priv->cache_gc_source = g_timeout_add_seconds (priv->cache_timeout, cache_gc_cb, self);
}
static void
@@ -357,8 +576,9 @@ gsk_gpu_device_clear_cache (GskGpuDevice *self)
g_assert (cached->next->prev == cached);
}
while (priv->first_cached)
gsk_gpu_cached_free (self, priv->first_cached);
/* We clear the cache from the end so glyphs get freed before their atlas */
while (priv->last_cached)
gsk_gpu_cached_free (self, priv->last_cached);
g_assert (priv->last_cached == NULL);
}
@@ -372,6 +592,7 @@ gsk_gpu_device_dispose (GObject *object)
gsk_gpu_device_clear_cache (self);
g_hash_table_unref (priv->glyph_cache);
g_hash_table_unref (priv->texture_cache);
g_clear_handle_id (&priv->cache_gc_source, g_source_remove);
G_OBJECT_CLASS (gsk_gpu_device_parent_class)->dispose (object);
}
@@ -413,9 +634,38 @@ gsk_gpu_device_setup (GskGpuDevice *self,
gsize max_image_size)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
const char *str;
priv->display = g_object_ref (display);
priv->max_image_size = max_image_size;
priv->cache_timeout = CACHE_TIMEOUT;
str = g_getenv ("GSK_CACHE_TIMEOUT");
if (str != NULL)
{
gint64 value;
GError *error = NULL;
if (!g_ascii_string_to_signed (str, 10, -1, G_MAXINT, &value, &error))
{
g_warning ("Failed to parse GSK_CACHE_TIMEOUT: %s", error->message);
g_error_free (error);
}
else
{
priv->cache_timeout = (int) value;
}
}
if (GSK_DEBUG_CHECK (GLYPH_CACHE))
{
if (priv->cache_timeout < 0)
gdk_debug_message ("Cache GC disabled");
else if (priv->cache_timeout == 0)
gdk_debug_message ("Cache GC before every frame");
else
gdk_debug_message ("Cache GC timeout: %d seconds", priv->cache_timeout);
}
}
GdkDisplay *
@@ -454,6 +704,12 @@ gsk_gpu_device_create_upload_image (GskGpuDevice *self,
return GSK_GPU_DEVICE_GET_CLASS (self)->create_upload_image (self, with_mipmap, format, width, height);
}
void
gsk_gpu_device_make_current (GskGpuDevice *self)
{
GSK_GPU_DEVICE_GET_CLASS (self)->make_current (self);
}
GskGpuImage *
gsk_gpu_device_create_download_image (GskGpuDevice *self,
GdkMemoryDepth depth,
@@ -547,8 +803,7 @@ gsk_gpu_cached_atlas_allocate (GskGpuCachedAtlas *atlas,
static void
gsk_gpu_device_ensure_atlas (GskGpuDevice *self,
gboolean recreate,
gint64 timestamp)
gboolean recreate)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
@@ -563,14 +818,13 @@ gsk_gpu_device_get_atlas_image (GskGpuDevice *self)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
gsk_gpu_device_ensure_atlas (self, FALSE, g_get_monotonic_time ());
gsk_gpu_device_ensure_atlas (self, FALSE);
return priv->current_atlas->image;
}
static GskGpuImage *
gsk_gpu_device_add_atlas_image (GskGpuDevice *self,
gint64 timestamp,
gsize width,
gsize height,
gsize *out_x,
@@ -581,21 +835,15 @@ gsk_gpu_device_add_atlas_image (GskGpuDevice *self,
if (width > MAX_ATLAS_ITEM_SIZE || height > MAX_ATLAS_ITEM_SIZE)
return NULL;
gsk_gpu_device_ensure_atlas (self, FALSE, timestamp);
if (gsk_gpu_cached_atlas_allocate (priv->current_atlas, width, height, out_x, out_y))
{
gsk_gpu_cached_use (self, (GskGpuCached *) priv->current_atlas, timestamp);
return priv->current_atlas->image;
}
gsk_gpu_device_ensure_atlas (self, TRUE, timestamp);
gsk_gpu_device_ensure_atlas (self, FALSE);
if (gsk_gpu_cached_atlas_allocate (priv->current_atlas, width, height, out_x, out_y))
{
gsk_gpu_cached_use (self, (GskGpuCached *) priv->current_atlas, timestamp);
return priv->current_atlas->image;
}
return priv->current_atlas->image;
gsk_gpu_device_ensure_atlas (self, TRUE);
if (gsk_gpu_cached_atlas_allocate (priv->current_atlas, width, height, out_x, out_y))
return priv->current_atlas->image;
return NULL;
}
@@ -612,12 +860,12 @@ gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
if (cache == NULL)
cache = g_hash_table_lookup (priv->texture_cache, texture);
if (cache)
{
return g_object_ref (cache->image);
}
if (!cache || !cache->image || gsk_gpu_cached_texture_is_invalid (cache))
return NULL;
return NULL;
gsk_gpu_cached_use (self, (GskGpuCached *) cache, timestamp);
return g_object_ref (cache->image);
}
void
@@ -678,7 +926,6 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
padding = 1;
image = gsk_gpu_device_add_atlas_image (self,
gsk_gpu_frame_get_timestamp (frame),
rect.size.width + 2 * padding, rect.size.height + 2 * padding,
&atlas_x, &atlas_y);
if (image)
@@ -697,14 +944,15 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
cache = gsk_gpu_cached_new (self, &GSK_GPU_CACHED_GLYPH_CLASS, NULL);
}
cache->font = g_object_ref (font),
cache->glyph = glyph,
cache->flags = flags,
cache->scale = scale,
cache->bounds = rect,
cache->image = image,
cache->font = g_object_ref (font);
cache->glyph = glyph;
cache->flags = flags;
cache->scale = scale;
cache->bounds = rect;
cache->image = image;
cache->origin = GRAPHENE_POINT_INIT (- origin.x + subpixel_x,
- origin.y + subpixel_y);
((GskGpuCached *) cache)->pixels = (rect.size.width + 2 * padding) * (rect.size.height + 2 * padding);
gsk_gpu_upload_glyph_op (frame,
cache->image,

View File

@@ -41,6 +41,8 @@ struct _GskGpuDeviceClass
GdkMemoryDepth depth,
gsize width,
gsize height);
void (* make_current) (GskGpuDevice *self);
};
GType gsk_gpu_device_get_type (void) G_GNUC_CONST;
@@ -48,9 +50,8 @@ GType gsk_gpu_device_get_type (void) G
void gsk_gpu_device_setup (GskGpuDevice *self,
GdkDisplay *display,
gsize max_image_size);
void gsk_gpu_device_gc (GskGpuDevice *self,
gint64 timestamp);
void gsk_gpu_device_maybe_gc (GskGpuDevice *self);
void gsk_gpu_device_queue_gc (GskGpuDevice *self);
GdkDisplay * gsk_gpu_device_get_display (GskGpuDevice *self);
gsize gsk_gpu_device_get_max_image_size (GskGpuDevice *self);
GskGpuImage * gsk_gpu_device_get_atlas_image (GskGpuDevice *self);
@@ -69,7 +70,7 @@ GskGpuImage * gsk_gpu_device_create_download_image (GskGpuD
GdkMemoryDepth depth,
gsize width,
gsize height);
void gsk_gpu_device_make_current (GskGpuDevice *self);
GskGpuImage * gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp);

View File

@@ -220,7 +220,7 @@ gsk_gpu_frame_seal_ops (GskGpuFrame *self)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuOp *last, *op;
guint i;
gsize i;
priv->first_op = (GskGpuOp *) gsk_gpu_ops_index (&priv->ops, 0);

View File

@@ -43,10 +43,6 @@
#include "gdk/gdkrgbaprivate.h"
#include "scaleprivate.h"
#include "pointprivate.h"
#include "boxprivate.h"
/* A note about coordinate systems
*
* The rendering code keeps track of multiple coordinate systems to optimize rendering as
@@ -502,18 +498,6 @@ gsk_gpu_pattern_writer_append_rect (GskGpuPatternWriter *self,
gsk_gpu_pattern_writer_append (self, G_ALIGNOF (float), (guchar *) f, sizeof (f));
}
static void
gsk_gpu_pattern_writer_append_box (GskGpuPatternWriter *self,
const Box box,
const Point offset)
{
float f[4];
box_offset_to_float (box, offset, f);
gsk_gpu_pattern_writer_append (self, G_ALIGNOF (float), (guchar *) f, sizeof (f));
}
static void
gsk_gpu_pattern_writer_append_rgba (GskGpuPatternWriter *self,
const GdkRGBA *rgba)
@@ -2990,9 +2974,9 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
GskGpuDevice *device;
const PangoGlyphInfo *glyphs;
PangoFont *font;
Point offset;
Scale scale, s4, pango_scale;
graphene_point_t offset;
guint i, num_glyphs;
float scale, inv_scale;
GdkRGBA color;
gboolean glyph_align;
@@ -3011,33 +2995,31 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
num_glyphs = gsk_text_node_get_num_glyphs (node);
glyphs = gsk_text_node_get_glyphs (node, NULL);
font = gsk_text_node_get_font (node);
offset = *gsk_text_node_get_offset (node);
offset.x += self->offset.x;
offset.y += self->offset.y;
offset = point_add (point_from_graphene (gsk_text_node_get_offset (node)),
point_from_graphene (&self->offset));
scale = scale_max (scale_from_graphene (&self->scale));
s4 = scale_mul (scale, scale_from_float (4));
pango_scale = scale_from_float (PANGO_SCALE);
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
inv_scale = 1.f / scale;
for (i = 0; i < num_glyphs; i++)
{
GskGpuImage *image;
graphene_rect_t glyph_bds;
graphene_point_t glyph_ofs;
Box glyph_bounds, glyph_tex_rect;
Point g_ofs, glyph_origin;
graphene_rect_t glyph_bounds, glyph_tex_rect;
graphene_point_t glyph_offset, glyph_origin;
guint32 descriptor;
GskGpuGlyphLookupFlags flags;
glyph_origin = point_add (offset, point_div (point (glyphs[i].geometry.x_offset, glyphs[i].geometry.y_offset), pango_scale));
glyph_origin = GRAPHENE_POINT_INIT (offset.x + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
offset.y + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
if (glyph_align)
{
glyph_origin = point_round (point_mul (glyph_origin, s4));
flags = ((int) point_x (glyph_origin) & 3) |
(((int) point_y (glyph_origin) & 3) << 2);
glyph_origin = point_div (glyph_origin, s4);
glyph_origin.x = roundf (glyph_origin.x * scale * 4);
glyph_origin.y = roundf (glyph_origin.y * scale * 4);
flags = ((int) glyph_origin.x & 3) |
(((int) glyph_origin.y & 3) << 2);
glyph_origin.x = 0.25 * inv_scale * glyph_origin.x;
glyph_origin.y = 0.25 * inv_scale * glyph_origin.y;
}
else
{
@@ -3049,37 +3031,34 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
font,
glyphs[i].glyph,
flags,
scale_x (scale),
&glyph_bds,
&glyph_ofs);
glyph_tex_rect = box_div (box_from_rect (-glyph_bds.origin.x, -glyph_bds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), scale);
glyph_bounds = box_div (box_from_rect (0, 0, glyph_bds.size.width, glyph_bds.size.height), scale);
g_ofs = point_from_graphene (&glyph_ofs);
glyph_origin = point_sub (glyph_origin, point_div (g_ofs, scale));
scale,
&glyph_bounds,
&glyph_offset);
gsk_rect_scale (&GRAPHENE_RECT_INIT (-glyph_bounds.origin.x, -glyph_bounds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), inv_scale, inv_scale, &glyph_tex_rect);
gsk_rect_scale (&GRAPHENE_RECT_INIT(0, 0, glyph_bounds.size.width, glyph_bounds.size.height), inv_scale, inv_scale, &glyph_bounds);
glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x * inv_scale,
glyph_origin.y - glyph_offset.y * inv_scale);
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
if (glyphs[i].attr.is_color)
gsk_gpu_texture_op (self->frame,
gsk_gpu_clip_get_shader_clip2 (&self->clip, &g_ofs, &glyph_bounds),
gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_offset, &glyph_bounds),
self->desc,
descriptor,
&GRAPHENE_RECT_INIT (box_x0 (glyph_bounds), box_y0 (glyph_bounds), box_width (glyph_bounds), box_height (glyph_bounds)),
&GRAPHENE_POINT_INIT (point_x (glyph_origin), point_y (glyph_origin)),
&GRAPHENE_RECT_INIT (box_x0 (glyph_tex_rect), box_y0 (glyph_tex_rect), box_width (glyph_tex_rect), box_height (glyph_tex_rect)));
&glyph_bounds,
&glyph_origin,
&glyph_tex_rect);
else
gsk_gpu_colorize_op (self->frame,
gsk_gpu_clip_get_shader_clip2 (&self->clip, &g_ofs, &glyph_bounds),
gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_offset, &glyph_bounds),
self->desc,
descriptor,
&GRAPHENE_RECT_INIT (box_x0 (glyph_bounds), box_y0 (glyph_bounds), box_width (glyph_bounds), box_height (glyph_bounds)),
&GRAPHENE_POINT_INIT (point_x (glyph_origin), point_y (glyph_origin)),
&GRAPHENE_RECT_INIT (box_x0 (glyph_tex_rect), box_y0 (glyph_tex_rect), box_width (glyph_tex_rect), box_height (glyph_tex_rect)),
&glyph_bounds,
&glyph_origin,
&glyph_tex_rect,
&color);
offset = point_add (offset, point (glyphs[i].geometry.width / (float)PANGO_SCALE, 0));
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
}
}
@@ -3092,10 +3071,10 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
PangoFont *font;
guint num_glyphs;
gsize i;
Scale scale, pango_scale;
float scale, inv_scale;
guint32 tex_id;
GskGpuImage *last_image;
Point offset;
graphene_point_t offset;
if (gsk_text_node_has_color_glyphs (node))
return FALSE;
@@ -3104,11 +3083,12 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
num_glyphs = gsk_text_node_get_num_glyphs (node);
glyphs = gsk_text_node_get_glyphs (node, NULL);
font = gsk_text_node_get_font (node);
offset = *gsk_text_node_get_offset (node);
offset.x += self->offset.x;
offset.y += self->offset.y;
offset = point_add (point_from_graphene (gsk_text_node_get_offset (node)),
point_from_graphene (&self->offset));
scale = scale_max (scale_from_graphene (&self->scale));
pango_scale = scale_from_float (PANGO_SCALE);
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
inv_scale = 1.f / scale;
gsk_gpu_pattern_writer_append_uint (self, GSK_GPU_PATTERN_GLYPHS);
gsk_gpu_pattern_writer_append_rgba (self, gsk_text_node_get_color (node));
@@ -3118,20 +3098,17 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
for (i = 0; i < num_glyphs; i++)
{
GskGpuImage *image;
graphene_rect_t glyph_bds;
graphene_point_t glyph_ofs;
Point glyph_offset;
Box glyph_bounds;
Box glyph_tex_rect;
graphene_rect_t glyph_bounds;
graphene_point_t glyph_offset;
image = gsk_gpu_device_lookup_glyph_image (device,
self->frame,
font,
glyphs[i].glyph,
0,
scale_x (scale),
&glyph_bds,
&glyph_ofs);
scale,
&glyph_bounds,
&glyph_offset);
if (image != last_image)
{
@@ -3141,15 +3118,28 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
last_image = image;
}
glyph_offset = point_add (point_sub (offset, point_div (glyph_offset, scale)), point_div (point (glyphs[i].geometry.x_offset, glyphs[i].geometry.y_offset), pango_scale));
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
glyph_bounds = box_div (box_from_rect (0, 0, glyph_bds.size.width, glyph_bds.size.height), scale);
glyph_tex_rect = box_div (box_from_rect (-glyph_bds.origin.x, - glyph_bds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), scale);
gsk_gpu_pattern_writer_append_uint (self, tex_id);
gsk_gpu_pattern_writer_append_box (self, glyph_bounds, glyph_offset);
gsk_gpu_pattern_writer_append_box (self, glyph_tex_rect, glyph_offset);
gsk_gpu_pattern_writer_append_rect (self,
&GRAPHENE_RECT_INIT (
0,
0,
glyph_bounds.size.width * inv_scale,
glyph_bounds.size.height * inv_scale
),
&glyph_offset);
gsk_gpu_pattern_writer_append_rect (self,
&GRAPHENE_RECT_INIT (
- glyph_bounds.origin.x * inv_scale,
- glyph_bounds.origin.y * inv_scale,
gsk_gpu_image_get_width (image) * inv_scale,
gsk_gpu_image_get_height (image) * inv_scale
),
&glyph_offset);
offset = point_add (offset, point (glyphs[i].geometry.width / (float)PANGO_SCALE, 0));
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
}
return TRUE;
@@ -3943,9 +3933,11 @@ gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
GskRenderNodeType node_type;
/* This catches the corner cases of empty nodes, so after this check
* there's quaranteed to be at least 1 pixel that needs to be drawn */
* there's quaranteed to be at least 1 pixel that needs to be drawn
*/
if (node->bounds.size.width == 0 || node->bounds.size.height == 0)
return;
if (!gsk_gpu_clip_may_intersect_rect (&self->clip, &self->offset, &node->bounds))
return;
@@ -3990,6 +3982,12 @@ gsk_gpu_node_processor_create_node_pattern (GskGpuPatternWriter *self,
if (!gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_UBER))
return FALSE;
/* This catches the corner cases of empty nodes, so after this check
* there's quaranteed to be at least 1 pixel that needs to be drawn
*/
if (node->bounds.size.width == 0 || node->bounds.size.height == 0)
return TRUE;
node_type = gsk_render_node_get_node_type (node);
if (node_type >= G_N_ELEMENTS (nodes_vtable))
{

View File

@@ -119,7 +119,7 @@ gsk_gpu_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader,
frame = gsk_gpu_renderer_create_frame (self);
gsk_gpu_frame_download_texture (frame,
g_get_monotonic_time(),
g_get_monotonic_time (),
GDK_TEXTURE (texture),
format,
data,
@@ -301,7 +301,7 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
frame = gsk_gpu_renderer_create_frame (self);
gsk_gpu_frame_render (frame,
g_get_monotonic_time(),
g_get_monotonic_time (),
image,
NULL,
root,
@@ -343,6 +343,8 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
GdkTexture *texture;
graphene_rect_t rounded_viewport;
gsk_gpu_device_maybe_gc (priv->device);
gsk_gpu_renderer_make_current (self);
rounded_viewport = GRAPHENE_RECT_INIT (viewport->origin.x,
@@ -353,6 +355,7 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
gsk_render_node_get_preferred_depth (root),
rounded_viewport.size.width,
rounded_viewport.size.height);
if (image == NULL)
return gsk_gpu_renderer_fallback_render_texture (self, root, &rounded_viewport);
@@ -360,7 +363,7 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
texture = NULL;
gsk_gpu_frame_render (frame,
g_get_monotonic_time(),
g_get_monotonic_time (),
image,
NULL,
root,
@@ -370,6 +373,8 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
g_object_unref (frame);
g_object_unref (image);
gsk_gpu_device_queue_gc (priv->device);
/* check that callback setting texture was actually called, as its technically async */
g_assert (texture);
@@ -398,6 +403,8 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
gsk_render_node_get_preferred_depth (root),
region);
gsk_gpu_device_maybe_gc (priv->device);
gsk_gpu_renderer_make_current (self);
backbuffer = GSK_GPU_RENDERER_GET_CLASS (self)->get_backbuffer (self);
@@ -407,7 +414,7 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
surface = gdk_draw_context_get_surface (priv->context);
gsk_gpu_frame_render (frame,
g_get_monotonic_time(),
g_get_monotonic_time (),
backbuffer,
render_region,
root,
@@ -418,6 +425,8 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
),
NULL);
gsk_gpu_device_queue_gc (priv->device);
gdk_draw_context_end_frame (priv->context);
g_clear_pointer (&render_region, cairo_region_destroy);

View File

@@ -99,6 +99,7 @@ gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer)
{
gsk_ngl_renderer_free_backbuffer (self);
self->backbuffer = gsk_gl_image_new_backbuffer (GSK_GL_DEVICE (gsk_gpu_renderer_get_device (renderer)),
GDK_GL_CONTEXT (context),
GDK_MEMORY_DEFAULT /* FIXME */,
ceil (gdk_surface_get_width (surface) * scale),
ceil (gdk_surface_get_height (surface) * scale));

View File

@@ -425,6 +425,11 @@ gsk_vulkan_device_create_download_image (GskGpuDevice *device,
return image;
}
static void
gsk_vulkan_device_make_current (GskGpuDevice *device)
{
}
static void
gsk_vulkan_device_finalize (GObject *object)
{
@@ -493,6 +498,7 @@ gsk_vulkan_device_class_init (GskVulkanDeviceClass *klass)
gpu_device_class->create_atlas_image = gsk_vulkan_device_create_atlas_image;
gpu_device_class->create_upload_image = gsk_vulkan_device_create_upload_image;
gpu_device_class->create_download_image = gsk_vulkan_device_create_download_image;
gpu_device_class->make_current = gsk_vulkan_device_make_current;
object_class->finalize = gsk_vulkan_device_finalize;
}

View File

@@ -1,6 +1,6 @@
precision highp float;
#if defined(GSK_GLES) && __VERSION__ < 310
#if __VERSION__ < 420 || (defined(GSK_GLES) && __VERSION__ < 310)
layout(std140)
#else
layout(std140, binding = 0)
@@ -17,7 +17,7 @@ uniform PushConstants
#define GSK_GLOBAL_CLIP_RECT push.clip[0]
#define GSK_GLOBAL_SCALE push.scale
#if defined(GSK_GLES) && __VERSION__ < 310
#if __VERSION__ < 420 || (defined(GSK_GLES) && __VERSION__ < 310)
layout(std140)
#else
layout(std140, binding = 1)

View File

@@ -18,37 +18,68 @@ vec4
compute_color (void)
{
uint triangle_index = uint (GSK_VERTEX_INDEX) / 3u;
uint index;
uint index, fallback;
switch (triangle_index)
{
case 2u * SLICE_TOP_LEFT + 1u:
index = TOP;
fallback = LEFT;
break;
case 2u * SLICE_TOP:
case 2u * SLICE_TOP + 1u:
index = TOP;
fallback = TOP;
break;
case 2u * SLICE_TOP_RIGHT:
index = TOP;
fallback = RIGHT;
break;
case 2u * SLICE_TOP_RIGHT + 1u:
index = RIGHT;
fallback = TOP;
break;
case 2u * SLICE_RIGHT:
case 2u * SLICE_RIGHT + 1u:
index = RIGHT;
fallback = RIGHT;
break;
case 2u * SLICE_BOTTOM_RIGHT:
index = RIGHT;
fallback = BOTTOM;
break;
case 2u * SLICE_BOTTOM_RIGHT + 1u:
index = BOTTOM;
fallback = RIGHT;
break;
case 2u * SLICE_BOTTOM:
case 2u * SLICE_BOTTOM + 1u:
index = BOTTOM;
fallback = BOTTOM;
break;
case 2u * SLICE_BOTTOM_LEFT:
index = BOTTOM;
fallback = LEFT;
break;
case 2u * SLICE_BOTTOM_LEFT + 1u:
index = LEFT;
fallback = BOTTOM;
break;
case 2u * SLICE_LEFT:
case 2u * SLICE_LEFT + 1u:
index = LEFT;
fallback = LEFT;
break;
case 2u * SLICE_TOP_LEFT:
index = LEFT;
fallback = TOP;
break;
}
return color_premultiply (in_border_colors[index]);
if (in_border_widths[index] > 0.0)
return color_premultiply (in_border_colors[index]);
else
return color_premultiply (in_border_colors[fallback]);
}
void

View File

@@ -632,7 +632,7 @@ get_renderer_for_backend (GdkSurface *surface)
static GType
get_renderer_for_gl (GdkSurface *surface)
{
return GSK_TYPE_GL_RENDERER;
return gsk_ngl_renderer_get_type ();
}
static GType
@@ -645,6 +645,12 @@ get_renderer_for_vulkan (GdkSurface *surface)
#endif
}
static GType
get_renderer_for_gles2 (GdkSurface *surface)
{
return GSK_TYPE_GL_RENDERER;
}
static GType
get_renderer_fallback (GdkSurface *surface)
{
@@ -658,6 +664,7 @@ static struct {
{ get_renderer_for_env_var },
{ get_renderer_for_backend },
{ get_renderer_for_gl },
{ get_renderer_for_gles2 },
{ get_renderer_for_vulkan },
{ get_renderer_fallback },
};

View File

@@ -46,7 +46,9 @@
#include <cairo-script-interpreter.h>
#endif
#include <cairo-gobject.h>
#include <pango/pangocairo.h>
#ifdef HAVE_PANGOFT
#include <pango/pangofc-fontmap.h>
#endif
@@ -86,6 +88,39 @@ context_finish (Context *context)
g_clear_object (&context->fontmap);
}
static gboolean
parse_enum (GtkCssParser *parser,
GType type,
gpointer out_value)
{
GEnumClass *class;
GEnumValue *v;
char *enum_name;
enum_name = gtk_css_parser_consume_ident (parser);
if (enum_name == NULL)
return FALSE;
class = g_type_class_ref (type);
v = g_enum_get_value_by_nick (class, enum_name);
if (v == NULL)
{
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
enum_name, g_type_name (type));
g_free (enum_name);
g_type_class_unref (class);
return FALSE;
}
*(int*)out_value = v->value;
g_free (enum_name);
g_type_class_unref (class);
return TRUE;
}
static gboolean
parse_rect (GtkCssParser *parser,
Context *context,
@@ -854,7 +889,8 @@ parse_mask_mode (GtkCssParser *parser,
static PangoFont *
font_from_string (PangoFontMap *fontmap,
const char *string)
const char *string,
gboolean allow_fallback)
{
PangoFontDescription *desc;
PangoContext *ctx;
@@ -865,7 +901,7 @@ font_from_string (PangoFontMap *fontmap,
font = pango_font_map_load_font (fontmap, ctx, desc);
g_object_unref (ctx);
if (font)
if (font && !allow_fallback)
{
PangoFontDescription *desc2;
const char *family, *family2;
@@ -886,6 +922,77 @@ font_from_string (PangoFontMap *fontmap,
return font;
}
static double
font_get_dpi (PangoFont *font)
{
#ifdef HAVE_PANGOFT
if (PANGO_IS_FC_FONT (font))
{
FcPattern *pattern;
double dpi;
pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font));
if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) == FcResultMatch)
return dpi;
}
#endif
/* FIXME, needs pango api */
return 96.0;
}
static PangoFont *
recreate_font_with_options (PangoFont *font,
cairo_hint_metrics_t hint_metrics,
cairo_hint_style_t hint_style,
cairo_antialias_t antialias,
double dpi)
{
PangoFontMap *fontmap;
PangoFontDescription *desc;
PangoContext *ctx;
cairo_scaled_font_t *sf;
cairo_font_options_t *options;
PangoFont *new_font;
options = cairo_font_options_create ();
sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
cairo_scaled_font_get_font_options (sf, options);
if (cairo_font_options_get_hint_metrics (options) == hint_metrics &&
cairo_font_options_get_hint_style (options) == hint_style &&
cairo_font_options_get_antialias (options) == antialias &&
font_get_dpi (font) == dpi)
{
cairo_font_options_destroy (options);
return font;
}
cairo_font_options_set_hint_metrics (options, hint_metrics);
cairo_font_options_set_hint_style (options, hint_style);
cairo_font_options_set_antialias (options, antialias);
desc = pango_font_describe (font);
fontmap = pango_font_get_font_map (font);
ctx = pango_font_map_create_context (fontmap);
pango_cairo_context_set_font_options (ctx, options);
pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), dpi);
new_font = pango_font_map_load_font (fontmap, ctx, desc);
g_object_unref (ctx);
pango_font_description_free (desc);
cairo_font_options_destroy (options);
g_object_unref (font);
return new_font;
}
#define MIN_ASCII_GLYPH 32
#define MAX_ASCII_GLYPH 127 /* exclusive */
#define N_ASCII_GLYPHS (MAX_ASCII_GLYPH - MIN_ASCII_GLYPH)
@@ -1081,7 +1188,7 @@ parse_font (GtkCssParser *parser,
return FALSE;
if (context->fontmap)
font = font_from_string (context->fontmap, font_name);
font = font_from_string (context->fontmap, font_name, FALSE);
if (gtk_css_parser_has_url (parser))
{
@@ -1140,7 +1247,7 @@ parse_font (GtkCssParser *parser,
if (success)
{
font = font_from_string (context->fontmap, font_name);
font = font_from_string (context->fontmap, font_name, FALSE);
if (!font)
{
gtk_css_parser_error (parser,
@@ -1156,7 +1263,7 @@ parse_font (GtkCssParser *parser,
else
{
if (!font)
font = font_from_string (pango_cairo_font_map_get_default (), font_name);
font = font_from_string (pango_cairo_font_map_get_default (), font_name, TRUE);
if (!font)
gtk_css_parser_error_value (parser, "The font \"%s\" does not exist", font_name);
@@ -2216,6 +2323,60 @@ unpack_glyphs (PangoFont *font,
return TRUE;
}
static gboolean
parse_hint_metrics (GtkCssParser *parser,
Context *context,
gpointer out)
{
if (!parse_enum (parser, CAIRO_GOBJECT_TYPE_HINT_METRICS, out))
return FALSE;
if (*(cairo_hint_metrics_t *) out == CAIRO_HINT_METRICS_DEFAULT)
{
gtk_css_parser_error_value (parser, "Unknown value \"default\" for enum \"%s\"",
g_type_name (CAIRO_GOBJECT_TYPE_HINT_METRICS));
return FALSE;
}
return TRUE;
}
static gboolean
parse_hint_style (GtkCssParser *parser,
Context *context,
gpointer out)
{
if (!parse_enum (parser, CAIRO_GOBJECT_TYPE_HINT_STYLE, out))
return FALSE;
if (*(cairo_hint_style_t *) out == CAIRO_HINT_STYLE_DEFAULT)
{
gtk_css_parser_error_value (parser, "Unknown value \"default\" for enum \"%s\"",
g_type_name (CAIRO_GOBJECT_TYPE_HINT_STYLE));
return FALSE;
}
return TRUE;
}
static gboolean
parse_antialias (GtkCssParser *parser,
Context *context,
gpointer out)
{
if (!parse_enum (parser, CAIRO_GOBJECT_TYPE_ANTIALIAS, out))
return FALSE;
if (*(cairo_antialias_t *) out == CAIRO_ANTIALIAS_DEFAULT)
{
gtk_css_parser_error_value (parser, "Unknown value \"default\" for enum \"%s\"",
g_type_name (CAIRO_GOBJECT_TYPE_ANTIALIAS));
return FALSE;
}
return TRUE;
}
static GskRenderNode *
parse_text_node (GtkCssParser *parser,
Context *context)
@@ -2224,11 +2385,19 @@ parse_text_node (GtkCssParser *parser,
graphene_point_t offset = GRAPHENE_POINT_INIT (0, 0);
GdkRGBA color = GDK_RGBA("000000");
PangoGlyphString *glyphs = NULL;
cairo_hint_metrics_t hint_metrics = CAIRO_HINT_METRICS_OFF;
cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_SLIGHT;
cairo_antialias_t antialias = CAIRO_ANTIALIAS_GRAY;
double dpi = 96.0;
const Declaration declarations[] = {
{ "font", parse_font, clear_font, &font },
{ "offset", parse_point, NULL, &offset },
{ "color", parse_color, NULL, &color },
{ "glyphs", parse_glyphs, clear_glyphs, &glyphs }
{ "glyphs", parse_glyphs, clear_glyphs, &glyphs },
{ "hint-metrics", parse_hint_metrics, NULL, &hint_metrics },
{ "hint-style", parse_hint_style, NULL, &hint_style },
{ "antialias", parse_antialias, NULL, &antialias },
{ "dpi", parse_positive_double, NULL, &dpi },
};
GskRenderNode *result;
@@ -2236,10 +2405,12 @@ parse_text_node (GtkCssParser *parser,
if (font == NULL)
{
font = font_from_string (pango_cairo_font_map_get_default (), "Cantarell 11");
font = font_from_string (pango_cairo_font_map_get_default (), "Cantarell 11", TRUE);
g_assert (font);
}
font = recreate_font_with_options (font, hint_metrics, hint_style, antialias, dpi);
if (!glyphs)
{
const char *text = "Hello";
@@ -2428,39 +2599,6 @@ clear_dash (gpointer inout_array)
g_clear_pointer ((GArray **) inout_array, g_array_unref);
}
static gboolean
parse_enum (GtkCssParser *parser,
GType type,
gpointer out_value)
{
GEnumClass *class;
GEnumValue *v;
char *enum_name;
enum_name = gtk_css_parser_consume_ident (parser);
if (enum_name == NULL)
return FALSE;
class = g_type_class_ref (type);
v = g_enum_get_value_by_nick (class, enum_name);
if (v == NULL)
{
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
enum_name, g_type_name (type));
g_free (enum_name);
g_type_class_unref (class);
return FALSE;
}
*(int*)out_value = v->value;
g_free (enum_name);
g_type_class_unref (class);
return TRUE;
}
static gboolean
parse_fill_rule (GtkCssParser *parser,
Context *context,
@@ -3247,6 +3385,33 @@ append_string_param (Printer *p,
g_string_append_c (p->str, '\n');
}
static const char *
enum_to_nick (GType type,
int value)
{
GEnumClass *class;
GEnumValue *v;
class = g_type_class_ref (type);
v = g_enum_get_value (class, value);
g_type_class_unref (class);
return v->value_nick;
}
static void
append_enum_param (Printer *p,
const char *param_name,
GType type,
int value)
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
g_string_append (p->str, enum_to_nick (type, value));
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
append_vec4_param (Printer *p,
const char *param_name,
@@ -3514,6 +3679,43 @@ gsk_text_node_serialize_font (GskRenderNode *node,
#endif
}
static void
gsk_text_node_serialize_font_options (GskRenderNode *node,
Printer *p)
{
PangoFont *font = gsk_text_node_get_font (node);
cairo_scaled_font_t *sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
cairo_font_options_t *options;
cairo_hint_metrics_t hint_metrics;
cairo_hint_style_t hint_style;
cairo_antialias_t antialias;
options = cairo_font_options_create ();
cairo_scaled_font_get_font_options (sf, options);
hint_metrics = cairo_font_options_get_hint_metrics (options);
hint_style = cairo_font_options_get_hint_style (options);
antialias = cairo_font_options_get_antialias (options);
cairo_font_options_destroy (options);
if (hint_metrics != CAIRO_HINT_METRICS_OFF && hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
append_enum_param (p, "hint-metrics", CAIRO_GOBJECT_TYPE_HINT_METRICS, hint_metrics);
if (hint_style != CAIRO_HINT_STYLE_SLIGHT && hint_style != CAIRO_HINT_STYLE_DEFAULT)
append_enum_param (p, "hint-style", CAIRO_GOBJECT_TYPE_HINT_STYLE, hint_style);
if (antialias != CAIRO_ANTIALIAS_GRAY && antialias != CAIRO_ANTIALIAS_DEFAULT)
append_enum_param (p, "antialias", CAIRO_GOBJECT_TYPE_ANTIALIAS, antialias);
}
static void
gsk_text_node_serialize_font_dpi (GskRenderNode *node,
Printer *p)
{
PangoFont *font = gsk_text_node_get_font (node);
append_float_param (p, "dpi", font_get_dpi (font), 96.f);
}
void
gsk_text_node_serialize_glyphs (GskRenderNode *node,
GString *p)
@@ -3595,33 +3797,6 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
pango_glyph_string_free (ascii);
}
static const char *
enum_to_nick (GType type,
int value)
{
GEnumClass *class;
GEnumValue *v;
class = g_type_class_ref (type);
v = g_enum_get_value (class, value);
g_type_class_unref (class);
return v->value_nick;
}
static void
append_enum_param (Printer *p,
const char *param_name,
GType type,
int value)
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
g_string_append (p->str, enum_to_nick (type, value));
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
append_path_param (Printer *p,
const char *param_name,
@@ -4086,6 +4261,9 @@ render_node_print (Printer *p,
if (!graphene_point_equal (offset, graphene_point_zero ()))
append_point_param (p, "offset", offset);
gsk_text_node_serialize_font_options (node, p);
gsk_text_node_serialize_font_dpi (node, p);
end_node (p);
}
break;

View File

@@ -1,22 +0,0 @@
/* GSK - The GTK Scene Kit
* 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
typedef struct _Scale Scale;
typedef struct _Point Point;
typedef struct _Box Box;

View File

@@ -1,252 +0,0 @@
#pragma once
#include "gsktypesprivate.h"
#include <graphene.h>
#include <math.h>
#include <smmintrin.h>
#include "scaleprivate.h"
#ifndef USE_SIMD
struct _Point
{
float x, y;
};
static inline float
point_x (const Point p)
{
return p.x;
}
static inline float
point_y (const Point p)
{
return p.y;
}
static inline Point
point (float x,
float y)
{
return (Point) { .x = x, .y = y };
}
static inline Point
point_from_graphene (const graphene_point_t *p)
{
return point (p->x, p->y);
}
static inline void
point_to_float (const Point p,
float v[2])
{
v[0] = p.x;
v[1] = p.y;
}
static inline Point
point_zero (void)
{
return point (0, 0);
}
static inline Point
point_neg (const Point p)
{
return (Point) { .x = -p.x, .y = -p.y };
}
static inline Point
point_mul (const Point p,
const Scale s)
{
return (Point) { .x = p.x * s.x, .y = p.y * s.y };
}
static inline Point
point_div (const Point p,
const Scale s)
{
return (Point) { .x = p.x / s.x, .y = p.y / s.y };
}
static inline Point
point_add (const Point p1,
const Point p2)
{
return (Point) { .x = p1.x + p2.x, .y = p1.y + p2.y };
}
static inline Point
point_sub (const Point p1,
const Point p2)
{
return (Point) { .x = p1.x - p2.x, .y = p1.y - p2.y };
}
static inline Point
point_floor (const Point p)
{
return (Point) { .x = floorf (p.x), .y = floorf (p.y) };
}
static inline Point
point_ceil (const Point p)
{
return (Point) { .x = ceilf (p.x), .y = ceilf (p.y) };
}
static inline Point
point_round (const Point p)
{
return (Point) { .x = roundf (p.x), .y = roundf (p.y) };
}
#else /* USE_SIMD */
#include <smmintrin.h>
struct _Point
{
GRAPHENE_ALIGNED_DECL (graphene_simd4f_t v, 16);
};
static inline float
point_x (const Point p)
{
return graphene_simd4f_get_x (p.v);
}
static inline float
point_y (const Point p)
{
return graphene_simd4f_get_y (p.v);
}
static inline Point
point (float x,
float y)
{
return (Point) { .v = graphene_simd4f_init (x, y, 0.f, 0.f) };
}
static inline Point
point_from_graphene (const graphene_point_t *p)
{
return point (p->x, p->y);
}
static inline void
point_to_float (const Point p,
float v[2])
{
graphene_simd4f_dup_2f (p.v, v);
}
static inline Point
point_zero (void)
{
return point (0, 0);
}
static inline Point
point_neg (const Point p)
{
return (Point) { .v = graphene_simd4f_neg (p.v) };
}
static inline Point
point_mul (const Point p,
const Scale s)
{
return (Point) { .v = graphene_simd4f_mul (p.v, s.v) };
}
static inline Point
point_div (const Point p,
const Scale s)
{
return (Point) { .v = graphene_simd4f_div (p.v, s.v) };
}
static inline Point
point_add (const Point p1,
const Point p2)
{
return (Point) { .v = graphene_simd4f_add (p1.v, p2.v) };
}
static inline Point
point_sub (const Point p1,
const Point p2)
{
return (Point) { .v = graphene_simd4f_sub (p1.v, p2.v) };
}
#ifdef __SSE4_1__
#ifndef graphene_simd4f_floor
# define graphene_simd4f_floor(v) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_floor_ps ((v)); \
}))
#endif
#ifndef graphene_simd4f_ceil
# define graphene_simd4f_ceil(v) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_ceil_ps ((v)); \
}))
#endif
#ifndef graphene_simd4f_round
# define graphene_simd4f_round(v) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_round_ps ((v)); \
}))
#endif
static inline Point
point_floor (const Point p)
{
return (Point) { .v = graphene_simd4f_floor (p.v) };
}
static inline Point
point_ceil (const Point p)
{
return (Point) { .v = graphene_simd4f_ceil (p.v) };
}
static inline Point
point_round (const Point p)
{
return (Point) { .v = graphene_simd4f_round (p.v) };
}
#else
static inline Point
point_floor (const Point p)
{
return point (floorf (point_x (p)), floorf (point_y (p)));
}
static inline Point
point_ceil (const Point p)
{
return point (ceilf (point_x (p)), ceilf (point_y (p)));
}
static inline Point
point_round (const Point p)
{
return point (roundf (point_x (p)), roundf (point_y (p)));
}
#endif
#endif

View File

@@ -1,183 +0,0 @@
#pragma once
#include "gsktypesprivate.h"
#include <graphene.h>
#include <math.h>
#ifndef USE_SIMD
struct _Scale
{
float x, y;
};
static inline float
scale_x (const Scale s)
{
return s.x;
}
static inline float
scale_y (const Scale s)
{
return s.y;
}
static inline Scale
scale (float x,
float y)
{
return (Scale) { .x = x, .y = y };
}
static inline Scale
scale_from_float (float s)
{
return scale (s, s);
}
static inline Scale
scale_from_graphene (const graphene_vec2_t *v)
{
return (Scale) { .x = graphene_vec2_get_x (v), .y = graphene_vec2_get_y (v) };
}
static inline void
scale_to_float (const Scale s,
float v[2])
{
v[0] = s.x;
v[1] = s.y;
}
static inline gboolean
scale_equal (const Scale s1,
const Scale s2)
{
return (gboolean) (s1.x == s2.x && s1.y == s2.y);
}
static inline Scale
scale_one (void)
{
return scale (1, 1);
}
static inline Scale
scale_inv (const Scale s)
{
return (Scale) { .x = 1 / s.x, .y = 1 / s.y };
}
static inline Scale
scale_mul (const Scale s1,
const Scale s2)
{
return (Scale) { .x = s1.x * s2.x, .y = s1.y * s2.y };
}
static inline Scale
scale_div (const Scale s1,
const Scale s2)
{
return (Scale) { .x = s1.x / s2.x, .y = s1.y / s2.y };
}
static inline Scale
scale_max (const Scale s)
{
return (Scale) { .x = MAX (s.x, s.y), .y = MAX (s.x, s.y) };
}
#else /* USE_SIMD */
struct _Scale
{
GRAPHENE_ALIGNED_DECL (graphene_simd4f_t v, 16);
};
static inline float
scale_x (const Scale s)
{
return graphene_simd4f_get_x (s.v);
}
static inline float
scale_y (const Scale s)
{
return graphene_simd4f_get_y (s.v);
}
static inline Scale
scale (float x,
float y)
{
return (Scale) { .v = graphene_simd4f_init (x, y, 0.f, 0.f) };
}
static inline Scale
scale_from_float (float s)
{
return scale (s, s);
}
static inline Scale
scale_from_graphene (const graphene_vec2_t *v)
{
return (Scale) { .v = v->__graphene_private_value };
}
static inline void
scale_to_float (const Scale s,
float v[2])
{
graphene_simd4f_dup_2f (s.v, v);
}
static inline gboolean
scale_equal (const Scale s1,
const Scale s2)
{
return (gboolean) graphene_simd4f_cmp_eq (s1.v, s2.v);
}
static inline Scale
scale_one (void)
{
return scale (1, 1);
}
static inline Scale
scale_inv (const Scale s)
{
return (Scale) { .v = graphene_simd4f_reciprocal (s.v) };
}
static inline Scale
scale_mul (const Scale s1,
const Scale s2)
{
return (Scale) { .v = graphene_simd4f_mul (s1.v, s2.v) };
}
static inline Scale
scale_div (const Scale s1,
const Scale s2)
{
return (Scale) { .v = graphene_simd4f_div (s1.v, s2.v) };
}
#ifndef graphene_simd4f_shuffle_yxzw
# define graphene_simd4f_shuffle_yxzw(v) \
(__extension__ ({ \
(graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (3, 2, 0, 1)); \
}))
#endif
static inline Scale
scale_max (const Scale s)
{
return (Scale) { .v = graphene_simd4f_max (graphene_simd4f_shuffle_yxzw (s.v), s.v) };
}
#endif

View File

@@ -1401,14 +1401,6 @@ gtk_at_spi_context_finalize (GObject *gobject)
G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->finalize (gobject);
}
static void
gtk_at_spi_context_constructed (GObject *gobject)
{
GtkAtSpiContext *self G_GNUC_UNUSED = GTK_AT_SPI_CONTEXT (gobject);
G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->constructed (gobject);
}
static const char *get_bus_address (GdkDisplay *display);
static void
@@ -1516,7 +1508,6 @@ gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkATContextClass *context_class = GTK_AT_CONTEXT_CLASS (klass);
gobject_class->constructed = gtk_at_spi_context_constructed;
gobject_class->finalize = gtk_at_spi_context_finalize;
context_class->realize = gtk_at_spi_context_realize;

View File

@@ -96,7 +96,7 @@ gtk_at_spi_root_finalize (GObject *gobject)
g_free (self->desktop_name);
g_free (self->desktop_path);
G_OBJECT_CLASS (gtk_at_spi_root_parent_class)->dispose (gobject);
G_OBJECT_CLASS (gtk_at_spi_root_parent_class)->finalize (gobject);
}
static void

View File

@@ -1149,6 +1149,96 @@ gtk_accessible_get_bounds (GtkAccessible *self,
return GTK_ACCESSIBLE_GET_IFACE (self)->get_bounds (self, x, y, width, height);
}
struct _GtkAccessibleList
{
GList *objects;
};
/**
* gtk_accessible_list_new_from_list:
* @list: (element-type GtkAccessible): a reference to a `GList` containing a list of accessible values
*
* Allocates a new `GtkAccessibleList`, doing a shallow copy of the
* passed list of `GtkAccessible` instances.
*
* Returns: (transfer full): the list of accessible instances
*
* Since: 4.14
*/
GtkAccessibleList *
gtk_accessible_list_new_from_list (GList *list)
{
GtkAccessibleList *accessible_list = g_new (GtkAccessibleList, 1);
accessible_list->objects = g_list_copy (list);
return accessible_list;
}
/**
* gtk_accessible_list_new_from_array:
* @accessibles: (array length=n_accessibles): array of GtkAccessible
* @n_accessibles: length of @accessibles array
*
* Allocates a new list of accessible instances.
*
* Returns: (transfer full): the newly created list of accessible instances
*
* Since: 4.14
*/
GtkAccessibleList *
gtk_accessible_list_new_from_array (GtkAccessible **accessibles,
gsize n_accessibles)
{
GtkAccessibleList *accessible_list;
GList *list = NULL;
g_return_val_if_fail (accessibles == NULL || n_accessibles == 0, NULL);
accessible_list = g_new (GtkAccessibleList, 1);
for (gsize i = 0; i < n_accessibles; i++)
{
list = g_list_prepend (list, accessibles[i]);
}
accessible_list->objects = g_list_reverse (list);
return accessible_list;
}
static void
gtk_accessible_list_free (GtkAccessibleList *accessible_list)
{
g_free (accessible_list->objects);
g_free (accessible_list);
}
static GtkAccessibleList *
gtk_accessible_list_copy (GtkAccessibleList *accessible_list)
{
return gtk_accessible_list_new_from_list (accessible_list->objects);
}
/**
* gtk_accessible_list_get_objects:
*
* Gets the list of objects this boxed type holds
*
* Returns: (transfer container) (element-type GtkAccessible): a shallow copy of the objects
*
* Since: 4.14
*/
GList *
gtk_accessible_list_get_objects (GtkAccessibleList *accessible_list)
{
return g_list_copy (accessible_list->objects);
}
G_DEFINE_BOXED_TYPE (GtkAccessibleList, gtk_accessible_list,
gtk_accessible_list_copy,
gtk_accessible_list_free)
/*< private >
* gtk_accessible_should_present:
* @self: a `GtkAccessible`

View File

@@ -154,6 +154,15 @@ struct _GtkAccessibleInterface
int *height);
};
/**
* GtkAccessibleList:
*
* A boxed type which wraps a list of references to GtkAccessible objects.
*
* Since: 4.14
*/
typedef struct _GtkAccessibleList GtkAccessibleList;
GDK_AVAILABLE_IN_ALL
GtkATContext * gtk_accessible_get_at_context (GtkAccessible *self);
@@ -236,4 +245,19 @@ GDK_AVAILABLE_IN_ALL
void gtk_accessible_relation_init_value (GtkAccessibleRelation relation,
GValue *value);
#define GTK_ACCESSIBLE_LIST (gtk_accessible_list_get_type())
GDK_AVAILABLE_IN_4_14
GType gtk_accessible_list_get_type (void);
GDK_AVAILABLE_IN_4_14
GList * gtk_accessible_list_get_objects (GtkAccessibleList *accessible_list);
GDK_AVAILABLE_IN_4_14
GtkAccessibleList * gtk_accessible_list_new_from_list (GList *list);
GDK_AVAILABLE_IN_4_14
GtkAccessibleList * gtk_accessible_list_new_from_array (GtkAccessible **accessibles,
gsize n_accessibles);
G_END_DECLS

View File

@@ -1332,7 +1332,18 @@ gtk_accessible_value_collect_value (const GtkAccessibleCollect *cstate,
GtkAccessibleValueRefListCtor ctor =
(GtkAccessibleValueRefListCtor) cstate->ctor;
GList *value = g_value_get_pointer (value_);
GList *value;
if (g_type_is_a (G_VALUE_TYPE(value_), GTK_ACCESSIBLE_LIST))
{
GtkAccessibleList *boxed = g_value_get_boxed (value_);
value = gtk_accessible_list_get_objects (boxed);
}
else
{
value = g_value_get_pointer (value_);
}
if (ctor == NULL)
{

View File

@@ -604,14 +604,10 @@ static const struct {
GtkAccessible *accessible,
GdkDisplay *display);
} a11y_backends[] = {
#if defined(GDK_WINDOWING_WAYLAND)
{ "AT-SPI (Wayland)", "atspi", gtk_at_spi_create_context },
#endif
#if defined(GDK_WINDOWING_X11)
{ "AT-SPI (X11)", "atspi", gtk_at_spi_create_context },
#if defined(GDK_WINDOWING_WAYLAND) || defined(GDK_WINDOWING_X11)
{ "AT-SPI", "atspi", gtk_at_spi_create_context },
#endif
{ "Test", "test", gtk_test_at_context_new },
{ NULL, NULL, NULL },
};
/**
@@ -634,6 +630,7 @@ gtk_at_context_create (GtkAccessibleRole accessible_role,
GdkDisplay *display)
{
static const char *gtk_a11y_env;
GtkATContext *res = NULL;
if (gtk_a11y_env == NULL)
{
@@ -661,12 +658,9 @@ gtk_at_context_create (GtkAccessibleRole accessible_role,
if (g_ascii_strcasecmp (gtk_a11y_env, "none") == 0)
return NULL;
GtkATContext *res = NULL;
for (guint i = 0; i < G_N_ELEMENTS (a11y_backends); i++)
for (size_t i = 0; i < G_N_ELEMENTS (a11y_backends); i++)
{
if (a11y_backends[i].name == NULL)
break;
g_assert (a11y_backends[i].name != NULL);
if (a11y_backends[i].create_context != NULL &&
(*gtk_a11y_env == '0' || g_ascii_strcasecmp (a11y_backends[i].env_name, gtk_a11y_env) == 0))

View File

@@ -117,7 +117,6 @@ gtk_list_item_change_release (GtkListItemChange *change,
if (!g_hash_table_replace (change->deleted_items, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (widget)), widget))
{
g_warning ("Duplicate item detected in list. Picking one randomly.");
gtk_list_item_change_recycle (change, widget);
}
}
@@ -968,10 +967,26 @@ gtk_list_item_manager_add_items (GtkListItemManager *self,
if (section != NULL && section->type == GTK_LIST_TILE_HEADER)
{
guint start, end;
GtkListTile *footer = gtk_list_tile_get_footer (self, section);
GtkListTile *previous_footer = gtk_list_tile_get_previous_skip (section);
gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position, &start, &end);
if (previous_footer != NULL && previous_footer->type == GTK_LIST_TILE_FOOTER &&
position > start && position < end)
{
gtk_list_item_change_clear_header (change, &section->widget);
gtk_list_tile_set_type (section, GTK_LIST_TILE_REMOVED);
gtk_list_tile_set_type (previous_footer, GTK_LIST_TILE_REMOVED);
section = gtk_list_tile_get_header (self, previous_footer);
}
gtk_list_item_change_clear_header (change, &section->widget);
gtk_list_tile_set_type (section,
GTK_LIST_TILE_UNMATCHED_HEADER);
gtk_list_tile_set_type (gtk_list_tile_get_footer (self, section),
gtk_list_tile_set_type (footer,
GTK_LIST_TILE_UNMATCHED_FOOTER);
}
}
@@ -1610,7 +1625,7 @@ gtk_list_item_manager_model_sections_changed_cb (GListModel *model,
gtk_list_item_change_clear_header (&change, &header->widget);
gtk_list_tile_set_type (header, GTK_LIST_TILE_UNMATCHED_HEADER);
n_items -= MIN (n_items, position - offset);
n_items += offset;
while (n_items > 0)
{
switch (tile->type)

View File

@@ -2949,6 +2949,17 @@ unset_titlebar (GtkWindow *window)
}
}
static gboolean
gtk_window_is_composited (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GdkDisplay *display;
display = priv->display;
return gdk_display_is_rgba (display) && gdk_display_is_composited (display);
}
static gboolean
gtk_window_supports_client_shadow (GtkWindow *window)
{
@@ -2957,22 +2968,7 @@ gtk_window_supports_client_shadow (GtkWindow *window)
display = priv->display;
if (!gdk_display_is_rgba (display))
return FALSE;
if (!gdk_display_is_composited (display))
return FALSE;
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (display))
{
if (!gdk_x11_screen_supports_net_wm_hint (gdk_x11_display_get_screen (display),
g_intern_static_string ("_GTK_FRAME_EXTENTS")))
return FALSE;
}
#endif
return TRUE;
return gdk_display_supports_shadow_width (display);
}
static void
@@ -2981,11 +2977,15 @@ gtk_window_enable_csd (GtkWindow *window)
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GtkWidget *widget = GTK_WIDGET (window);
/* We need a visual with alpha for client shadows */
if (priv->use_client_shadow)
gtk_widget_add_css_class (widget, "csd");
/* We need a visual with alpha for rounded corners */
if (gtk_window_is_composited (window))
{
gtk_widget_add_css_class (widget, "csd");
}
else
gtk_widget_add_css_class (widget, "solid-csd");
{
gtk_widget_add_css_class (widget, "solid-csd");
}
priv->client_decorated = TRUE;
}
@@ -3044,8 +3044,8 @@ gtk_window_set_titlebar (GtkWindow *window,
else
{
priv->use_client_shadow = gtk_window_supports_client_shadow (window);
gtk_window_enable_csd (window);
priv->titlebar = titlebar;
priv->title_box = titlebar;
gtk_widget_insert_before (priv->title_box, widget, NULL);
@@ -4298,9 +4298,9 @@ gtk_window_realize (GtkWidget *widget)
/* Create default title bar */
if (!priv->client_decorated && gtk_window_should_use_csd (window))
{
priv->use_client_shadow = gtk_window_supports_client_shadow (window);
if (priv->use_client_shadow)
if (gtk_window_is_composited (window))
{
priv->use_client_shadow = gtk_window_supports_client_shadow (window);
gtk_window_enable_csd (window);
if (priv->title_box == NULL)
@@ -4314,6 +4314,8 @@ gtk_window_realize (GtkWidget *widget)
update_window_actions (window);
}
else
priv->use_client_shadow = FALSE;
}
surface = gdk_surface_new_toplevel (gtk_widget_get_display (widget));
@@ -4453,6 +4455,8 @@ gtk_window_unrealize (GtkWidget *widget)
gdk_surface_set_widget (surface, NULL);
g_clear_pointer (&priv->surface, gdk_surface_destroy);
priv->use_client_shadow = FALSE;
}
static void

View File

@@ -447,6 +447,9 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
p.x += native_x;
p.y += native_y;
if (GTK_IS_WINDOW (native))
gtk_window_unfullscreen (GTK_WINDOW (native));
surface = gtk_native_get_surface (native);
if (GDK_IS_TOPLEVEL (surface))
gdk_toplevel_begin_move (GDK_TOPLEVEL (surface),

View File

@@ -1,5 +1,8 @@
#! /bin/sh
export LIBGL_ALWAYS_SOFTWARE=1
export GDK_VULKAN_DEVICE=1
version=$(head -5 meson.build | grep version | sed -e "s/[^']*'//" -e "s/'.*$//")
release_build_dir="release_build"
branch=$(git branch --show-current)

View File

@@ -1,5 +1,5 @@
project('gtk', 'c',
version: '4.13.6',
version: '4.13.7',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',

View File

@@ -115,12 +115,15 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend
GstPlayer *player)
{
GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer);
GdkDmabufFormats *dmabuf_formats;
GstElement *sink;
GdkGLContext *ctx;
dmabuf_formats = gdk_display_get_dmabuf_formats (gdk_display_get_default ());
sink = g_object_new (GTK_TYPE_GST_SINK,
"paintable", self,
"gl-context", self->context,
"dmabuf-formats", dmabuf_formats,
NULL);
if (self->context != NULL)

View File

@@ -52,10 +52,16 @@
#include <gst/gl/gstglfuncs.h>
#ifdef HAVE_GSTREAMER_DRM
#include <drm_fourcc.h>
#include <gst/allocators/gstdmabuf.h>
#endif
enum {
PROP_0,
PROP_PAINTABLE,
PROP_GL_CONTEXT,
PROP_DMABUF_FORMATS,
N_PROPS,
};
@@ -71,7 +77,11 @@ static GstStaticPadTemplate gtk_gst_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
GST_STATIC_CAPS (
#ifdef HAVE_GSTREAMER_DRM
GST_VIDEO_DMA_DRM_CAPS_MAKE "; "
#endif
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
"format = (string) RGBA, "
"width = " GST_VIDEO_SIZE_RANGE ", "
"height = " GST_VIDEO_SIZE_RANGE ", "
@@ -116,6 +126,42 @@ gtk_gst_sink_get_times (GstBaseSink *bsink,
}
}
#ifdef HAVE_GSTREAMER_DRM
static void
add_drm_formats_and_modifiers (GstCaps *caps,
GdkDmabufFormats *dmabuf_formats)
{
GValue dmabuf_list = G_VALUE_INIT;
size_t i;
g_value_init (&dmabuf_list, GST_TYPE_LIST);
for (i = 0; i < gdk_dmabuf_formats_get_n_formats (dmabuf_formats); i++)
{
GValue value = G_VALUE_INIT;
gchar *drm_format_string;
guint32 fmt;
guint64 mod;
gdk_dmabuf_formats_get_format (dmabuf_formats, i, &fmt, &mod);
if (mod == DRM_FORMAT_MOD_INVALID)
continue;
drm_format_string = gst_video_dma_drm_fourcc_to_string (fmt, mod);
if (!drm_format_string)
continue;
g_value_init (&value, G_TYPE_STRING);
g_value_take_string (&value, drm_format_string);
gst_value_list_append_and_take_value (&dmabuf_list, &value);
}
gst_structure_take_value (gst_caps_get_structure (caps, 0), "drm-format",
&dmabuf_list);
}
#endif
static GstCaps *
gtk_gst_sink_get_caps (GstBaseSink *bsink,
GstCaps *filter)
@@ -127,6 +173,13 @@ gtk_gst_sink_get_caps (GstBaseSink *bsink,
if (self->gst_context)
{
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
#ifdef HAVE_GSTREAMER_DRM
if (self->dmabuf_formats)
{
tmp = gst_caps_make_writable (tmp);
add_drm_formats_and_modifiers (tmp, self->dmabuf_formats);
}
#endif
}
else
{
@@ -159,8 +212,24 @@ gtk_gst_sink_set_caps (GstBaseSink *bsink,
GST_DEBUG_OBJECT (self, "set caps with %" GST_PTR_FORMAT, caps);
if (!gst_video_info_from_caps (&self->v_info, caps))
return FALSE;
#ifdef HAVE_GSTREAMER_DRM
if (gst_video_is_dma_drm_caps (caps)) {
if (!gst_video_info_dma_drm_from_caps (&self->drm_info, caps))
return FALSE;
if (!gst_video_info_dma_drm_to_video_info (&self->drm_info, &self->v_info))
return FALSE;
GST_INFO_OBJECT (self, "using DMABuf, passthrough possible");
} else {
gst_video_info_dma_drm_init (&self->drm_info);
#endif
if (!gst_video_info_from_caps (&self->v_info, caps))
return FALSE;
#ifdef HAVE_GSTREAMER_DRM
}
#endif
return TRUE;
}
@@ -202,6 +271,14 @@ gtk_gst_sink_propose_allocation (GstBaseSink *bsink,
return FALSE;
}
#ifdef HAVE_GSTREAMER_DRM
if (gst_caps_features_contains (gst_caps_get_features (caps, 0), GST_CAPS_FEATURE_MEMORY_DMABUF))
{
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
return TRUE;
}
#endif
if (!gst_caps_features_contains (gst_caps_get_features (caps, 0), GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
return FALSE;
@@ -287,6 +364,66 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
GstVideoFrame *frame = g_new (GstVideoFrame, 1);
GdkTexture *texture;
#ifdef HAVE_GSTREAMER_DRM
if (gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0)))
{
g_autoptr (GdkDmabufTextureBuilder) builder = NULL;
const GstVideoMeta *vmeta = gst_buffer_get_video_meta (buffer);
GError *error = NULL;
int i;
/* We don't map dmabufs */
g_clear_pointer (&frame, g_free);
g_return_val_if_fail (vmeta, NULL);
g_return_val_if_fail (self->gdk_context, NULL);
g_return_val_if_fail (self->drm_info.drm_fourcc != DRM_FORMAT_INVALID, NULL);
builder = gdk_dmabuf_texture_builder_new ();
gdk_dmabuf_texture_builder_set_display (builder, gdk_gl_context_get_display (self->gdk_context));
gdk_dmabuf_texture_builder_set_fourcc (builder, self->drm_info.drm_fourcc);
gdk_dmabuf_texture_builder_set_modifier (builder, self->drm_info.drm_modifier);
// Padded width/height is set into the vmeta, perhaps we should import using these ?
gdk_dmabuf_texture_builder_set_width (builder, GST_VIDEO_INFO_WIDTH (&self->v_info));
gdk_dmabuf_texture_builder_set_height (builder, GST_VIDEO_INFO_HEIGHT (&self->v_info));
gdk_dmabuf_texture_builder_set_n_planes (builder, vmeta->n_planes);
for (i = 0; i < vmeta->n_planes; i++)
{
GstMemory *mem;
guint mem_idx, length;
gsize skip;
if (!gst_buffer_find_memory (buffer,
vmeta->offset[i],
1,
&mem_idx,
&length,
&skip))
{
GST_ERROR_OBJECT (self, "Buffer data is bogus");
return NULL;
}
mem = gst_buffer_peek_memory (buffer, mem_idx);
gdk_dmabuf_texture_builder_set_fd (builder, i, gst_dmabuf_memory_get_fd (mem));
gdk_dmabuf_texture_builder_set_offset (builder, i, mem->offset + skip);
gdk_dmabuf_texture_builder_set_stride (builder, i, vmeta->stride[i]);
}
texture = gdk_dmabuf_texture_builder_build (builder,
(GDestroyNotify) gst_buffer_unref,
gst_buffer_ref (buffer),
&error);
if (!texture)
GST_ERROR_OBJECT (self, "Failed to create dmabuf texture: %s", error->message);
*pixel_aspect_ratio = ((double) GST_VIDEO_INFO_PAR_N (&self->v_info) /
(double) GST_VIDEO_INFO_PAR_D (&self->v_info));
}
else
#endif
if (self->gdk_context &&
gst_video_frame_map (frame, &self->v_info, buffer, GST_MAP_READ | GST_MAP_GL))
{
@@ -593,6 +730,10 @@ gtk_gst_sink_set_property (GObject *object,
g_clear_object (&self->gdk_context);
break;
case PROP_DMABUF_FORMATS:
self->dmabuf_formats = g_value_get_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -615,6 +756,9 @@ gtk_gst_sink_get_property (GObject *object,
case PROP_GL_CONTEXT:
g_value_set_object (value, self->gdk_context);
break;
case PROP_DMABUF_FORMATS:
g_value_set_boxed (value, self->dmabuf_formats);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -675,6 +819,19 @@ gtk_gst_sink_class_init (GtkGstSinkClass * klass)
GDK_TYPE_GL_CONTEXT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
/**
* GtkGstSink:dmabuf-formats:
*
* The #GdkDmabufFormats that are supported by the #GdkDisplay and can be used
* with #GdkDmabufTextureBuilder.
*
* Since: 4.14
*/
properties[PROP_DMABUF_FORMATS] =
g_param_spec_boxed ("dmabuf-formats", NULL, NULL,
GDK_TYPE_DMABUF_FORMATS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
gst_element_class_set_metadata (gstelement_class,

View File

@@ -47,11 +47,16 @@ struct _GtkGstSink
GstVideoSink parent;
GstVideoInfo v_info;
#ifdef HAVE_GSTREAMER_DRM
GstVideoInfoDmaDrm drm_info;
#endif
GtkGstPaintable * paintable;
GdkGLContext * gdk_context;
GstGLDisplay * gst_display;
GstGLContext * gst_gdk_context;
GstGLContext * gst_context;
GdkDmabufFormats * dmabuf_formats;
};
struct _GtkGstSinkClass

View File

@@ -43,6 +43,8 @@ gstplayer_dep = dependency('gstreamer-player-1.0', version: '>= 1.12.3',
required: get_option('media-gstreamer'))
gstgl_dep = dependency('gstreamer-gl-1.0', version: '>= 1.12.3',
required: get_option('media-gstreamer'))
gstdrm_dep = dependency('gstreamer-allocators-1.0', version: '>= 1.23',
required: false)
if gstplayer_dep.found() and gstgl_dep.found()
extra_win_cflags = []
@@ -54,6 +56,13 @@ if gstplayer_dep.found() and gstgl_dep.found()
media_backends += 'gstreamer'
cdata.set('HAVE_GSTREAMER', 1)
media_gst_deps = [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ]
if dmabuf_dep.found() and gstdrm_dep.found()
cdata.set('HAVE_GSTREAMER_DRM', 1)
media_gst_deps += [ gstdrm_dep ]
endif
shared_module('media-gstreamer',
sources: [
'gtkgstmediafile.c',
@@ -61,7 +70,7 @@ if gstplayer_dep.found() and gstgl_dep.found()
'gtkgstsink.c',
],
c_args: extra_c_args + extra_win_cflags,
dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ],
dependencies: media_gst_deps,
name_suffix: module_suffix,
install_dir: media_install_dir,
install: true,

View File

@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk+-master-po-gl-77922___.merged\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2024-01-22 13:47+0000\n"
"PO-Revision-Date: 2024-01-24 01:33+0100\n"
"POT-Creation-Date: 2024-01-25 11:35+0000\n"
"PO-Revision-Date: 2024-01-26 10:56+0100\n"
"Last-Translator: Fran Dieguez <fran.dieguez@gnome.org>\n"
"Language-Team: Galician <proxecto@trasno.gal>\n"
"Language: gl\n"
@@ -4424,6 +4424,7 @@ msgid ""
"Tints all the places where the current renderer uses Cairo instead of the "
"GPU."
msgstr ""
"Tinta todos os lugares onde o renderizador actual usa Cairo en lugar da GPU."
#: gtk/inspector/visual.ui:436
msgid "Show Cairo Rendering"
@@ -4463,7 +4464,7 @@ msgstr "Mostrar avisos de accesibilidade"
#: gtk/inspector/visual.ui:661
msgid "Show Graphics Offload"
msgstr ""
msgstr "Mostrar a descarga de gráficos"
#: gtk/inspector/visual.ui:693
msgid "Inspect Inspector"

165
po/he.po
View File

@@ -6,23 +6,23 @@
# Gil Osher <dolfin@rpg.org.il>, 2004.
# Yair Hershkovitz <yairhr@gmail.com>, 2006.
# Yaron Shahrabani <sh.yaron@gmail.com>, 2011, 2012.
# Yosef Or Boczko <yoseforb@gmail.com>, 2013-2023.
# Yosef Or Boczko <yoseforb@gmail.com>, 2013-2024.
#
msgid ""
msgstr ""
"Project-Id-Version: gtk+.HEAD.he\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2023-12-27 22:15+0000\n"
"PO-Revision-Date: 2023-12-28 13:40+0200\n"
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
"Language-Team: Hebrew <yoseforb@gmail.com>\n"
"POT-Creation-Date: 2024-01-22 13:47+0000\n"
"PO-Revision-Date: 2024-01-25 13:34+0200\n"
"Last-Translator: Yosef Or Boczko <yoseforb@gmail.com>\n"
"Language-Team: Hebrew\n"
"Language: he\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? "
"2 : 3);\n"
"X-Generator: Poedit 3.4.1\n"
"2 : 3)\n"
"X-Generator: Gtranslator 45.3\n"
"X-Project-Style: default\n"
#: gdk/broadway/gdkbroadway-server.c:135
@@ -34,11 +34,11 @@ msgstr "סוג תצוגת ה־broadway אינה נתמכת: %s"
msgid "This clipboard cannot store data."
msgstr "לוח גזירים זה לא יכול לאחסן נתונים."
#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:785 gdk/gdkclipboard.c:1085
#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:786 gdk/gdkclipboard.c:1086
msgid "Cannot read from empty clipboard."
msgstr "אי אפשר לקרוא מלוח גזירים ריק."
#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1135 gdk/gdkdrag.c:618
#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1136 gdk/gdkdrag.c:618
msgid "No compatible formats to transfer clipboard contents."
msgstr "אין תצורות תואמות להעברת תכני לוח גזירים."
@@ -57,31 +57,31 @@ msgstr "לא ניתן לספק תוכן בתור %s"
msgid "The current backend does not support OpenGL"
msgstr "המנשק הנוכחי אינו תומך ב־OpenGL"
#: gdk/gdkdisplay.c:1278 gdk/gdksurface.c:1268 gdk/gdkvulkancontext.c:1479
#: gdk/gdkdisplay.c:1296 gdk/gdkvulkancontext.c:1581
msgid "Vulkan support disabled via GDK_DEBUG"
msgstr "התמיכה ב־Vulkan מושבתת דרך GDK_DEBUG"
#: gdk/gdkdisplay.c:1310
#: gdk/gdkdisplay.c:1350
msgid "GL support disabled via GDK_DEBUG"
msgstr "התמיכה ב־GL הושבתה דרך GDK_DEBUG"
#: gdk/gdkdisplay.c:1606
#: gdk/gdkdisplay.c:1646
msgid "No EGL configuration available"
msgstr "אין תצורת EGL זמינה"
#: gdk/gdkdisplay.c:1614
#: gdk/gdkdisplay.c:1654
msgid "Failed to get EGL configurations"
msgstr "קבלת תצורות EGL נכשלה"
#: gdk/gdkdisplay.c:1644
#: gdk/gdkdisplay.c:1684
msgid "No EGL configuration with required features found"
msgstr "לא נמצאה תצורת EGL עם היכולות הנדרשות"
#: gdk/gdkdisplay.c:1651
#: gdk/gdkdisplay.c:1691
msgid "No perfect EGL configuration found"
msgstr "לא נמצאה תצורת EGL מושלמת"
#: gdk/gdkdisplay.c:1693
#: gdk/gdkdisplay.c:1733
#, c-format
msgid "EGL implementation is missing extension %s"
msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
@@ -90,23 +90,23 @@ msgstr[1] "למימוש ה־EGL חסרות שתי הרחבות: %1$s"
msgstr[2] "למימוש ה־EGL חסרות %2$d הרחבות: %1$s"
msgstr[3] "למימוש ה־EGL חסרות %2$d הרחבות: %1$s"
#: gdk/gdkdisplay.c:1743
#: gdk/gdkdisplay.c:1782
msgid "libEGL not available in this sandbox"
msgstr "libEGL אינו זמין בארגז חול זה"
#: gdk/gdkdisplay.c:1744
#: gdk/gdkdisplay.c:1783
msgid "libEGL not available"
msgstr "libEGL לא זמין"
#: gdk/gdkdisplay.c:1754
#: gdk/gdkdisplay.c:1793
msgid "Failed to create EGL display"
msgstr "יצירת תצוגת EGL נכשלה"
#: gdk/gdkdisplay.c:1764
#: gdk/gdkdisplay.c:1802
msgid "Could not initialize EGL display"
msgstr "לא ניתן להפעיל תצוגת EGL"
#: gdk/gdkdisplay.c:1775
#: gdk/gdkdisplay.c:1812
#, c-format
msgid "EGL version %d.%d is too old. GTK requires %d.%d"
msgstr "גרסת ה־EGL %d.%d ישנה מדי. GTK דורש %d.%d"
@@ -144,7 +144,7 @@ msgstr "היישום אינו תומך ב־API %s"
#. translators: This is about OpenGL backend names, like
#. * "Trying to use X11 GLX, but EGL is already in use"
#: gdk/gdkglcontext.c:2123
#: gdk/gdkglcontext.c:2115
#, c-format
msgid "Trying to use %s, but %s is already in use"
msgstr "מתבצע ניסיון להשתמש ב־%s אך %s כבר בשימוש"
@@ -542,7 +542,7 @@ msgstr "שגיאה בפענוח קובץ תמונת JPEG (%s)"
msgid "Unsupported JPEG colorspace (%d)"
msgstr "מרחב הצבעים של ה־JPEG אינו נתמך (%d)"
#: gdk/loaders/gdkjpeg.c:203 gdk/loaders/gdkpng.c:280 gdk/loaders/gdktiff.c:472
#: gdk/loaders/gdkjpeg.c:203 gdk/loaders/gdkpng.c:286 gdk/loaders/gdktiff.c:472
#, c-format
msgid "Not enough memory for image size %ux%u"
msgstr "אין מספיק זיכרון לתמונה בגודל %u×%u"
@@ -552,16 +552,22 @@ msgstr "אין מספיק זיכרון לתמונה בגודל %u×%u"
msgid "Error reading png (%s)"
msgstr "שגיאה בקריאת png (%s)"
#: gdk/loaders/gdkpng.c:211
#: gdk/loaders/gdkpng.c:212
#, c-format
msgid "Unsupported depth %u in png image"
msgstr "העומק %u אינו נתמך בתמונות png"
#: gdk/loaders/gdkpng.c:261
#: gdk/loaders/gdkpng.c:262
#, c-format
msgid "Unsupported color type %u in png image"
msgstr "סוג הצבע %u אינו נתמך בתמונות png"
#: gdk/loaders/gdkpng.c:272
#, fuzzy, c-format
#| msgid "Not enough memory for image size %ux%u"
msgid "Image stride too large for image size %ux%u"
msgstr "אין מספיק זיכרון לתמונה בגודל %u×%u"
#: gdk/loaders/gdktiff.c:358
msgid "Failed to load RGB data from TIFF file"
msgstr "טעינת נתוני RGB מקובץ TIFF נכשלה"
@@ -826,11 +832,16 @@ msgstr "תצורות שגויות בהמרת טקסט מרוכב."
msgid "Unsupported encoding “%s”"
msgstr "הקידוד „%s” אינו נתמך"
#: gsk/gl/gskglrenderer.c:210
#: gsk/gl/gskglrenderer.c:204
#, c-format
msgid "This GLES %d.%d implementation does not support half-float vertex data"
msgstr "מימוש זה של GLES %d.%d לא תומך בנתוני קודקודים עם נקודה חצי צפה"
#: gsk/gpu/gskgldevice.c:238
#, c-format
msgid "OpenGL ES 2.0 is not supported by this renderer."
msgstr ""
#: gtk/a11y/gtkatspiaction.c:239
msgctxt "accessibility"
msgid "Click"
@@ -1028,7 +1039,7 @@ msgid "Invalid"
msgstr "בלתי תקני"
#. This label is displayed in a treeview cell displaying an accelerator
#. * when the cell is clicked to change the acelerator.
#. * when the cell is clicked to change the accelerator.
#.
#: gtk/deprecated/gtkcellrendereraccel.c:436
#: gtk/deprecated/gtkcellrendereraccel.c:729
@@ -2374,7 +2385,7 @@ msgid "If you delete an item, it will be permanently lost."
msgstr "אם פריט ימחק, הוא יאבד לצמיתות."
#: gtk/gtkfilechooserwidget.c:1183 gtk/gtkfilechooserwidget.c:1781
#: gtk/gtklabel.c:5695 gtk/gtktext.c:6147 gtk/gtktextview.c:9018
#: gtk/gtklabel.c:5702 gtk/gtktext.c:6147 gtk/gtktextview.c:9018
msgid "_Delete"
msgstr "מ_חיקה"
@@ -2703,7 +2714,7 @@ msgstr "מאפייני סגנון"
msgid "Character Variations"
msgstr "הגווני תו"
#: gtk/gtkglarea.c:305
#: gtk/gtkglarea.c:309
msgid "OpenGL context creation failed"
msgstr "יצירת הקשר OpenGL נכשלה"
@@ -2716,32 +2727,32 @@ msgstr "סגירה"
msgid "Close the infobar"
msgstr "סגירת פס המידע"
#: gtk/gtklabel.c:5692 gtk/gtktext.c:6135 gtk/gtktextview.c:9006
#: gtk/gtklabel.c:5699 gtk/gtktext.c:6135 gtk/gtktextview.c:9006
msgid "Cu_t"
msgstr "_גזירה"
#: gtk/gtklabel.c:5693 gtk/gtktext.c:6139 gtk/gtktextview.c:9010
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6139 gtk/gtktextview.c:9010
msgid "_Copy"
msgstr "ה_עתקה"
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6143 gtk/gtktextview.c:9014
#: gtk/gtklabel.c:5701 gtk/gtktext.c:6143 gtk/gtktextview.c:9014
msgid "_Paste"
msgstr "ה_דבקה"
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6156 gtk/gtktextview.c:9039
#: gtk/gtklabel.c:5707 gtk/gtktext.c:6156 gtk/gtktextview.c:9039
msgid "Select _All"
msgstr "בחירה בה_כול"
#: gtk/gtklabel.c:5705
#: gtk/gtklabel.c:5712
msgid "_Open Link"
msgstr "_פתיחת קישור"
#: gtk/gtklabel.c:5709
#: gtk/gtklabel.c:5716
msgid "Copy _Link Address"
msgstr "העתקת כתובת ה_קישור"
# msgctxt "OpenType layout"
#: gtk/gtklabel.c:5753 gtk/gtktext.c:2716 gtk/gtktextview.c:9088
#: gtk/gtklabel.c:5760 gtk/gtktext.c:2716 gtk/gtktextview.c:9088
msgid "Context menu"
msgstr "תפריט הקשר"
@@ -3651,7 +3662,7 @@ msgstr "החלקה ימינה"
#. Translators: This is placeholder text for the search entry in the shortcuts window
#: gtk/gtkshortcutswindow.c:879 gtk/gtkshortcutswindow.c:946
#: gtk/gtkshortcutswindow.c:951
#: gtk/gtkshortcutswindow.c:952
msgid "Search Shortcuts"
msgstr "חיפוש קיצורי מקשים"
@@ -3665,12 +3676,12 @@ msgstr "צירופי מקשים"
msgid "Search Results"
msgstr "תוצאות חיפוש"
#: gtk/gtkshortcutswindow.c:1013 gtk/ui/gtkemojichooser.ui:349
#: gtk/gtkshortcutswindow.c:1014 gtk/ui/gtkemojichooser.ui:349
#: gtk/ui/gtkfilechooserwidget.ui:239
msgid "No Results Found"
msgstr "לא נמצאו תוצאות"
#: gtk/gtkshortcutswindow.c:1024 gtk/ui/gtkemojichooser.ui:362
#: gtk/gtkshortcutswindow.c:1025 gtk/ui/gtkemojichooser.ui:362
#: gtk/ui/gtkfilechooserwidget.ui:252 gtk/ui/gtkplacesview.ui:218
msgid "Try a different search"
msgstr "יש לנסות חיפוש שונה"
@@ -3884,37 +3895,37 @@ msgstr "מחלקות סגנון"
msgid "CSS Property"
msgstr "מאפיין CSS"
#: gtk/inspector/general.c:349
#: gtk/inspector/general.c:363
msgctxt "GL version"
msgid "None"
msgstr "ללא"
#: gtk/inspector/general.c:426
#: gtk/inspector/general.c:441
msgctxt "GL version"
msgid "Unknown"
msgstr "לא ידוע"
#: gtk/inspector/general.c:491
#: gtk/inspector/general.c:503
msgctxt "Vulkan device"
msgid "Disabled"
msgstr "מושבת"
#: gtk/inspector/general.c:492 gtk/inspector/general.c:493
#: gtk/inspector/general.c:504 gtk/inspector/general.c:505
msgctxt "Vulkan version"
msgid "Disabled"
msgstr "מושבת"
#: gtk/inspector/general.c:549
#: gtk/inspector/general.c:555
msgctxt "Vulkan device"
msgid "None"
msgstr "ללא"
#: gtk/inspector/general.c:550 gtk/inspector/general.c:551
#: gtk/inspector/general.c:556 gtk/inspector/general.c:557
msgctxt "Vulkan version"
msgid "None"
msgstr "ללא"
#: gtk/inspector/general.c:882
#: gtk/inspector/general.c:895
msgid "IM Context is hardcoded by GTK_IM_MODULE"
msgstr "IM Context קשיחה בקוד על ידי GTK_IM_MODULE"
@@ -3966,43 +3977,51 @@ msgstr "RGBA חזותי"
msgid "Composited"
msgstr "מורכב"
#: gtk/inspector/general.ui:559
#: gtk/inspector/general.ui:538
msgid "Protocols"
msgstr "פרוטוקולים"
#: gtk/inspector/general.ui:594
msgid "GL Version"
msgstr "גרסת GL"
#: gtk/inspector/general.ui:586
#: gtk/inspector/general.ui:621
msgid "GL Backend Version"
msgstr "גרסת מנגנון GL"
#: gtk/inspector/general.ui:636
#: gtk/inspector/general.ui:671
msgid "GL Backend Vendor"
msgstr "ספק מנגנון GL"
#: gtk/inspector/general.ui:663
#: gtk/inspector/general.ui:698
msgid "GL_VENDOR"
msgstr "GL_VENDOR"
#: gtk/inspector/general.ui:692
#: gtk/inspector/general.ui:727
msgid "GL_RENDERER"
msgstr "GL_RENDERER"
#: gtk/inspector/general.ui:721
#: gtk/inspector/general.ui:756
msgid "GL_VERSION"
msgstr "GL_VERSION"
#: gtk/inspector/general.ui:750
#: gtk/inspector/general.ui:785
msgid "GL_SHADING_LANGUAGE_VERSION"
msgstr "GL_SHADING_LANGUAGE_VERSION"
#: gtk/inspector/general.ui:789
#: gtk/inspector/general.ui:813 gtk/inspector/general.ui:929
msgid "Extensions"
msgstr "הרחבות"
#: gtk/inspector/general.ui:849
msgid "Vulkan Device"
msgstr "התקן Vulkan"
#: gtk/inspector/general.ui:816
#: gtk/inspector/general.ui:876
msgid "Vulkan API version"
msgstr "גרסת API של Vulkan"
#: gtk/inspector/general.ui:843
#: gtk/inspector/general.ui:903
msgid "Vulkan driver version"
msgstr "גרסת מנהל התקן של Vulkan"
@@ -7310,7 +7329,7 @@ msgid "Use style from CSS file"
msgstr "להשתמש בסגנון מקובץ CSS"
#: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-render.c:204
#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-render.c:203
#: tools/gtk-rendernode-tool-show.c:113
#, c-format
msgid "Could not initialize windowing system\n"
@@ -7356,13 +7375,13 @@ msgstr ""
"Use --force to overwrite.\n"
#: tools/gtk-builder-tool-screenshot.c:332
#: tools/gtk-rendernode-tool-render.c:172
#: tools/gtk-rendernode-tool-render.c:171
#, c-format
msgid "Output written to %s.\n"
msgstr "Output written to %s.\n"
#: tools/gtk-builder-tool-screenshot.c:336
#: tools/gtk-rendernode-tool-render.c:176
#: tools/gtk-rendernode-tool-render.c:175
#, c-format
msgid "Failed to save %s: %s\n"
msgstr "Failed to save %s: %s\n"
@@ -7380,7 +7399,7 @@ msgid "Overwrite existing file"
msgstr "שכתוב קובץ קיים"
#: tools/gtk-builder-tool-screenshot.c:363
#: tools/gtk-rendernode-tool-render.c:197
#: tools/gtk-rendernode-tool-render.c:196
msgid "FILE…"
msgstr "FILE…"
@@ -7857,6 +7876,7 @@ msgid ""
"Perform various tasks on GTK render nodes.\n"
"\n"
"Commands:\n"
" benchmark Benchmark rendering of a node\n"
" info Provide information about the node\n"
" show Show the node\n"
" render Take a screenshot of the node\n"
@@ -7868,6 +7888,7 @@ msgstr ""
"Perform various tasks on GTK render nodes.\n"
"\n"
"Commands:\n"
" benchmark Benchmark rendering of a node\n"
" info Provide information about the node\n"
" show Show the node\n"
" render Take a screenshot of the node\n"
@@ -7897,7 +7918,7 @@ msgstr "מקור: %g %g\n"
msgid "Provide information about the render node."
msgstr "אספקת מידע על נקודת העיבוד החזותי."
#: tools/gtk-rendernode-tool-info.c:236 tools/gtk-rendernode-tool-render.c:225
#: tools/gtk-rendernode-tool-info.c:236 tools/gtk-rendernode-tool-render.c:224
#: tools/gtk-rendernode-tool-show.c:134
#, c-format
msgid "No .node file specified\n"
@@ -7922,19 +7943,25 @@ msgstr ""
msgid "Failed to generate SVG: %s\n"
msgstr "יצירת SVG נכשלה: %s\n"
#: tools/gtk-rendernode-tool-render.c:196
#: tools/gtk-rendernode-tool-render.c:150
#, fuzzy, c-format
#| msgid "Failed to rewrite header\n"
msgid "Failed to create renderer: %s\n"
msgstr "Failed to rewrite header\n"
#: tools/gtk-rendernode-tool-render.c:195
msgid "Renderer to use"
msgstr "עיבוד לשימוש"
#: tools/gtk-rendernode-tool-render.c:196
#: tools/gtk-rendernode-tool-render.c:195
msgid "RENDERER"
msgstr "מעבד תצוגה"
#: tools/gtk-rendernode-tool-render.c:212
#: tools/gtk-rendernode-tool-render.c:211
msgid "Render a .node file to an image."
msgstr "עיבוד קובץ .node לתמונה."
#: tools/gtk-rendernode-tool-render.c:231
#: tools/gtk-rendernode-tool-render.c:230
#, c-format
msgid "Can only render a single .node file to a single output file\n"
msgstr "יכול לעבד קובץ ,node יחיד בלבד לקובץ פלט יחיד\n"
@@ -7952,12 +7979,12 @@ msgstr "הצגת צומת מעבד התצוגה."
msgid "Can only preview a single .node file\n"
msgstr "יכול להציג תצוגה מקדימה של קובץ .node יחיד בלבד\n"
#: tools/gtk-rendernode-tool-utils.c:51
#: tools/gtk-rendernode-tool-utils.c:54
#, c-format
msgid "Error at %s: %s\n"
msgstr "שגיאה ב־%s: %s\n"
#: tools/gtk-rendernode-tool-utils.c:69
#: tools/gtk-rendernode-tool-utils.c:72
#, c-format
msgid "Failed to load node file: %s\n"
msgstr "טעינת קובץ המצב נכשלה: %s\n"
@@ -8128,8 +8155,8 @@ msgstr ""
#~ msgid "Switch to list view"
#~ msgstr "החלפה לתצוגת רשימה"
msgid "default:LTR"
msgstr "default:RTL"
#~ msgid "default:LTR"
#~ msgstr "default:RTL"
#~ msgid "Other application…"
#~ msgstr "יישום אחר…"

101
po/ka.po
View File

@@ -11,8 +11,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2024-01-07 07:44+0000\n"
"PO-Revision-Date: 2024-01-08 05:11+0100\n"
"POT-Creation-Date: 2024-01-25 11:35+0000\n"
"PO-Revision-Date: 2024-01-27 18:13+0100\n"
"Last-Translator: Ekaterine Papava <papava.e@gtu.ge>\n"
"Language-Team: Georgian <http://mail.gnome.org/mailman/listinfo/gnome-ge-"
"list>\n"
@@ -55,53 +55,53 @@ msgstr "შემცველობის %s-ად გამოტანა შ
msgid "The current backend does not support OpenGL"
msgstr "მიმდინარე უკანაბოლოს OpenGL-ის მხარდაჭერა არ გააჩნია"
#: gdk/gdkdisplay.c:1292 gdk/gdksurface.c:1268 gdk/gdkvulkancontext.c:1581
#: gdk/gdkdisplay.c:1296 gdk/gdkvulkancontext.c:1581
msgid "Vulkan support disabled via GDK_DEBUG"
msgstr "Vulkan-ის მხარდაჭერა გამორთულია GDK_DEBUG-ით"
#: gdk/gdkdisplay.c:1335
#: gdk/gdkdisplay.c:1350
msgid "GL support disabled via GDK_DEBUG"
msgstr "GL-ის მხარდაჭერა გათიშულია GDK_DEBUG-ის მიერ"
#: gdk/gdkdisplay.c:1631
#: gdk/gdkdisplay.c:1646
msgid "No EGL configuration available"
msgstr "EGL-ის კონფიგურაცია მიუწვდომელია"
#: gdk/gdkdisplay.c:1639
#: gdk/gdkdisplay.c:1654
msgid "Failed to get EGL configurations"
msgstr "EGL-ის კონფიგურაციის მიღების შეცდოა"
#: gdk/gdkdisplay.c:1669
#: gdk/gdkdisplay.c:1684
msgid "No EGL configuration with required features found"
msgstr "მოთხოვნილი ფუნქციების მქონე EGL-ის კონფიგურაცია ნაპოვნი არაა"
#: gdk/gdkdisplay.c:1676
#: gdk/gdkdisplay.c:1691
msgid "No perfect EGL configuration found"
msgstr "EGL-ის მისაღები კონფიგურაცია ნაპოვნი არაა"
#: gdk/gdkdisplay.c:1718
#: gdk/gdkdisplay.c:1733
#, c-format
msgid "EGL implementation is missing extension %s"
msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
msgstr[0] "EGL-ის განხორციელებას %2$d გაფართოება აკლია: %1$s"
#: gdk/gdkdisplay.c:1768
#: gdk/gdkdisplay.c:1782
msgid "libEGL not available in this sandbox"
msgstr "ამ იზოლირებულ გარემოში libEGL მიუწვდომელია"
#: gdk/gdkdisplay.c:1769
#: gdk/gdkdisplay.c:1783
msgid "libEGL not available"
msgstr "libEGL მიუწვდომელია"
#: gdk/gdkdisplay.c:1779
#: gdk/gdkdisplay.c:1793
msgid "Failed to create EGL display"
msgstr "EGL ეკრანის შექმნის შეცდომა"
#: gdk/gdkdisplay.c:1789
#: gdk/gdkdisplay.c:1802
msgid "Could not initialize EGL display"
msgstr "EGL ეკრანის ინიციალიზაციის შეცდომა"
#: gdk/gdkdisplay.c:1800
#: gdk/gdkdisplay.c:1812
#, c-format
msgid "EGL version %d.%d is too old. GTK requires %d.%d"
msgstr "EGL-ის ვერსია %d.%d ძალიან ძველია. GTK-ს ესაჭიროება %d.%d"
@@ -139,7 +139,7 @@ msgstr "აპლიკაციას %s-ის API-ის მხარდა
#. translators: This is about OpenGL backend names, like
#. * "Trying to use X11 GLX, but EGL is already in use"
#: gdk/gdkglcontext.c:2124
#: gdk/gdkglcontext.c:2115
#, c-format
msgid "Trying to use %s, but %s is already in use"
msgstr "%s გამოყენების მცდელობა, მაგრამ %s უკვე გამოიყენება"
@@ -852,13 +852,18 @@ msgstr "არასწორი ფორმატები შედგენ
msgid "Unsupported encoding “%s”"
msgstr "კოდირება \"%s\" მხარდაუჭერელია"
#: gsk/gl/gskglrenderer.c:210
#: gsk/gl/gskglrenderer.c:204
#, c-format
msgid "This GLES %d.%d implementation does not support half-float vertex data"
msgstr ""
"GLES %d.%d-ის ამ განხორციელებას ნახევრად-მცურავმძიმიანი წვეროების "
"მონაცემების მხარდაჭერა არ გააჩნია"
#: gsk/gpu/gskgldevice.c:238
#, c-format
msgid "OpenGL ES 2.0 is not supported by this renderer."
msgstr "OpenGL ES 2.0 ამ რენდერერის მიერ მხარდაჭერილი არაა."
#: gtk/a11y/gtkatspiaction.c:239
msgctxt "accessibility"
msgid "Click"
@@ -1056,7 +1061,7 @@ msgid "Invalid"
msgstr "არასწორი"
#. This label is displayed in a treeview cell displaying an accelerator
#. * when the cell is clicked to change the acelerator.
#. * when the cell is clicked to change the accelerator.
#.
#: gtk/deprecated/gtkcellrendereraccel.c:436
#: gtk/deprecated/gtkcellrendereraccel.c:729
@@ -1235,7 +1240,6 @@ msgid "Mozilla Public License 2.0"
msgstr "Mozilla Public License 2.0"
#: gtk/gtkaboutdialog.c:137
#| msgid "BSD 2-Clause License"
msgid "BSD Zero-Clause License"
msgstr "BSD Zero-Clause License"
@@ -2349,7 +2353,7 @@ msgid "If you delete an item, it will be permanently lost."
msgstr "თუ წაშლით ელემენტს, ის სამუდამოდ დაიკარგება."
#: gtk/gtkfilechooserwidget.c:1183 gtk/gtkfilechooserwidget.c:1781
#: gtk/gtklabel.c:5697 gtk/gtktext.c:6147 gtk/gtktextview.c:9018
#: gtk/gtklabel.c:5702 gtk/gtktext.c:6147 gtk/gtktextview.c:9018
msgid "_Delete"
msgstr "წაშლა"
@@ -2675,7 +2679,7 @@ msgstr "სტილის ვარიაციები"
msgid "Character Variations"
msgstr "სიმბოლოების ვარიანტები"
#: gtk/gtkglarea.c:305
#: gtk/gtkglarea.c:309
msgid "OpenGL context creation failed"
msgstr "OpenGL-ის კონტექსტის შექმნის შეცდომა"
@@ -2688,31 +2692,31 @@ msgstr "დახურვა"
msgid "Close the infobar"
msgstr "საინფორმაციო ზოლის დახურვა"
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6135 gtk/gtktextview.c:9006
#: gtk/gtklabel.c:5699 gtk/gtktext.c:6135 gtk/gtktextview.c:9006
msgid "Cu_t"
msgstr "ამოჭრა"
#: gtk/gtklabel.c:5695 gtk/gtktext.c:6139 gtk/gtktextview.c:9010
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6139 gtk/gtktextview.c:9010
msgid "_Copy"
msgstr "ასლი"
#: gtk/gtklabel.c:5696 gtk/gtktext.c:6143 gtk/gtktextview.c:9014
#: gtk/gtklabel.c:5701 gtk/gtktext.c:6143 gtk/gtktextview.c:9014
msgid "_Paste"
msgstr "ჩასმა"
#: gtk/gtklabel.c:5702 gtk/gtktext.c:6156 gtk/gtktextview.c:9039
#: gtk/gtklabel.c:5707 gtk/gtktext.c:6156 gtk/gtktextview.c:9039
msgid "Select _All"
msgstr "ყველაფრის _მონიშვნა"
#: gtk/gtklabel.c:5707
#: gtk/gtklabel.c:5712
msgid "_Open Link"
msgstr "_ბმულის გახსნა"
#: gtk/gtklabel.c:5711
#: gtk/gtklabel.c:5716
msgid "Copy _Link Address"
msgstr "დაა_კოპირე ბმულის მისამართი"
#: gtk/gtklabel.c:5755 gtk/gtktext.c:2716 gtk/gtktextview.c:9088
#: gtk/gtklabel.c:5760 gtk/gtktext.c:2716 gtk/gtktextview.c:9088
msgid "Context menu"
msgstr "კონტექსტური მენიუ"
@@ -3853,37 +3857,37 @@ msgstr "სტილის კლასები"
msgid "CSS Property"
msgstr "CSS-ის თვისება"
#: gtk/inspector/general.c:352
#: gtk/inspector/general.c:363
msgctxt "GL version"
msgid "None"
msgstr "არცერთი"
#: gtk/inspector/general.c:430
#: gtk/inspector/general.c:441
msgctxt "GL version"
msgid "Unknown"
msgstr "უცნობი"
#: gtk/inspector/general.c:495
#: gtk/inspector/general.c:503
msgctxt "Vulkan device"
msgid "Disabled"
msgstr "გამორთულია"
#: gtk/inspector/general.c:496 gtk/inspector/general.c:497
#: gtk/inspector/general.c:504 gtk/inspector/general.c:505
msgctxt "Vulkan version"
msgid "Disabled"
msgstr "გამორთულია"
#: gtk/inspector/general.c:553
#: gtk/inspector/general.c:555
msgctxt "Vulkan device"
msgid "None"
msgstr "არცერთი"
#: gtk/inspector/general.c:554 gtk/inspector/general.c:555
#: gtk/inspector/general.c:556 gtk/inspector/general.c:557
msgctxt "Vulkan version"
msgid "None"
msgstr "არცერთი"
#: gtk/inspector/general.c:893
#: gtk/inspector/general.c:895
msgid "IM Context is hardcoded by GTK_IM_MODULE"
msgstr "IM-ის კონტექსტი GTK_IM_MODULE-ში ხელითაა ჩაწერილი"
@@ -7281,7 +7285,7 @@ msgid "Use style from CSS file"
msgstr "სტილის CSS ფაილიდან გამოყენება"
#: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-render.c:204
#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-render.c:203
#: tools/gtk-rendernode-tool-show.c:113
#, c-format
msgid "Could not initialize windowing system\n"
@@ -7327,13 +7331,13 @@ msgstr ""
"თავზე გადასაწერად გამოიყენეთ --force.\n"
#: tools/gtk-builder-tool-screenshot.c:332
#: tools/gtk-rendernode-tool-render.c:172
#: tools/gtk-rendernode-tool-render.c:171
#, c-format
msgid "Output written to %s.\n"
msgstr "გამოტანილი ინფორმაცია ჩაწერილია %s-ში.\n"
#: tools/gtk-builder-tool-screenshot.c:336
#: tools/gtk-rendernode-tool-render.c:176
#: tools/gtk-rendernode-tool-render.c:175
#, c-format
msgid "Failed to save %s: %s\n"
msgstr "\"%s'-ის შენახვის შეცდომა: %s\n"
@@ -7351,7 +7355,7 @@ msgid "Overwrite existing file"
msgstr "არსებულ ფაილზე გადაწერა"
#: tools/gtk-builder-tool-screenshot.c:363
#: tools/gtk-rendernode-tool-render.c:197
#: tools/gtk-rendernode-tool-render.c:196
msgid "FILE…"
msgstr "FILE…"
@@ -7821,6 +7825,7 @@ msgid ""
"Perform various tasks on GTK render nodes.\n"
"\n"
"Commands:\n"
" benchmark Benchmark rendering of a node\n"
" info Provide information about the node\n"
" show Show the node\n"
" render Take a screenshot of the node\n"
@@ -7832,6 +7837,7 @@ msgstr ""
"სხვადასხვა დავალებების შესრულება Gtk-ის რენდერის კვანძებზე.\n"
"\n"
"ბრძანებები:\n"
" benchmark კვანძის რენდერის წარმადობის გაზომვა\n"
" info ამ კვანძის შესახებ ინფორმაციის გამოტანა\n"
" show ამ კვანძის ჩვენება\n"
" render კვანძის ეკრანის ანაბეჭდის აღება\n"
@@ -7861,7 +7867,7 @@ msgstr "საწყისი: %g %g\n"
msgid "Provide information about the render node."
msgstr "შეიყვანეთ ინფორმაცია რენდერის კვანძის შესახებ."
#: tools/gtk-rendernode-tool-info.c:236 tools/gtk-rendernode-tool-render.c:225
#: tools/gtk-rendernode-tool-info.c:236 tools/gtk-rendernode-tool-render.c:224
#: tools/gtk-rendernode-tool-show.c:134
#, c-format
msgid "No .node file specified\n"
@@ -7887,19 +7893,24 @@ msgstr ""
msgid "Failed to generate SVG: %s\n"
msgstr "შეცდომა SVG-ის გენერაციისას: %s\n"
#: tools/gtk-rendernode-tool-render.c:196
#: tools/gtk-rendernode-tool-render.c:150
#, c-format
msgid "Failed to create renderer: %s\n"
msgstr "რენდერერის შექმნა ჩავარდა: %s\n"
#: tools/gtk-rendernode-tool-render.c:195
msgid "Renderer to use"
msgstr "გამოყენებული რენდერერი"
#: tools/gtk-rendernode-tool-render.c:196
#: tools/gtk-rendernode-tool-render.c:195
msgid "RENDERER"
msgstr "რენდერერი"
#: tools/gtk-rendernode-tool-render.c:212
#: tools/gtk-rendernode-tool-render.c:211
msgid "Render a .node file to an image."
msgstr ".ui ფაილის რენდერი გამოსახულებაში."
#: tools/gtk-rendernode-tool-render.c:231
#: tools/gtk-rendernode-tool-render.c:230
#, c-format
msgid "Can only render a single .node file to a single output file\n"
msgstr "ერთი .node ფაილის მხოლოდ ერთ გამოტანის ფაილში რენდერი შეგიძლიათ\n"
@@ -7917,12 +7928,12 @@ msgstr "რენდერის კვანძის ჩვენება."
msgid "Can only preview a single .node file\n"
msgstr "შეგიძლიათ მხოლოდ ერთი .node ფაილის გადახედვა\n"
#: tools/gtk-rendernode-tool-utils.c:51
#: tools/gtk-rendernode-tool-utils.c:54
#, c-format
msgid "Error at %s: %s\n"
msgstr "შეცდომა მისამართზე %s: %s\n"
#: tools/gtk-rendernode-tool-utils.c:69
#: tools/gtk-rendernode-tool-utils.c:72
#, c-format
msgid "Failed to load node file: %s\n"
msgstr "შეცდომა კვანძის ფაილის ჩატვირთვისას: %s\n"

View File

@@ -0,0 +1,8 @@
clip {
clip: 0 0 50 50;
child: border {
colors: rgb(255,0,0) rgb(0,255,0);
outline: -15 -15 80 80 / 40;
widths: 40 0;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

View File

@@ -0,0 +1,11 @@
blend {
mode: difference;
top: transform {
transform: scale(0);
child: text {
color: red;
font: "Cantarell 3";
glyphs: "o";
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

View File

@@ -0,0 +1,7 @@
text {
font: "Cantarell 12.9990234375";
glyphs: 1 0;
hint-metrics: on;
hint-style: full;
antialias: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

View File

@@ -0,0 +1,5 @@
text {
font: "Cantarell 12.9990234375";
glyphs: 27 0;
offset: 0.5 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

View File

@@ -27,6 +27,7 @@ compare_render_tests = [
'border-bottom-right',
'border-one-rounded',
'border-opacity',
'border-zero-width-color',
'borders-rotated',
'borders-scaled',
'clip-contained',
@@ -129,6 +130,7 @@ compare_render_tests = [
'scaled-cairo',
'scaled-texture',
'scaled-texture-scale',
'scale0-crash',
'shadow-behind',
'shadow-clip-contents',
'shadow-in-opacity',
@@ -143,6 +145,8 @@ compare_render_tests = [
'stroke-with-3d-contents-nogl-nocairo',
'subpixel-positioning',
'subpixel-positioning-hidpi-nogl-nocairo',
'text-A-no-aa',
'text-B-aa-nogl',
'text-color-mix',
'text-glyph-lsb',
'text-mixed-color-nocairo',
@@ -398,6 +402,8 @@ node_parser_tests = [
'text-font-errors.node',
'text-font-errors.ref.node',
'text-font-errors.errors',
'text-font-options.node',
'text-font-options.ref.node',
'text-no-color.node',
'texture-fail.node',
'texture-fail.ref.node',

View File

@@ -1,3 +1,3 @@
<data>:3:11-12: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:4:11-12: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:4:3-7: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:6:3-9: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:8:1-2: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE

View File

@@ -1,6 +1,4 @@
text {
color: rgb(50,50,50);
font: "Cantarell 11";
glyphs: "N";
offset: 0 32.0186;
color {
bounds: 0 0 50 50;
color: rgb(255,0,204);
}

View File

@@ -1,5 +1,4 @@
<data>:21:32-36: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:50:23-24: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:55:24-69:3: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:74:24-33: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:79:24-38: error: g-io-error-quark 15

View File

@@ -28,7 +28,7 @@ text {
glyphs: "Hello";
}
text {
font: "Cantarell 11";
font: "Noto Sans 11";
glyphs: "Hello";
}
text {

View File

@@ -0,0 +1,10 @@
text {
color: rgb(50,50,50);
font: "Cantarell 11";
glyphs: "N", 430 5, 406 8, 417 7, 772 4, 783 5, 783 5, 793 6 0 0 same-cluster;
offset: 0 32.0186;
hint-metrics: on;
hint-style: full;
antialias: none;
dpi: 111;
}

View File

@@ -0,0 +1,10 @@
text {
color: rgb(50,50,50);
font: "Cantarell 10.9990234375";
glyphs: "N", 430 5, 406 8, 417 7, 772 4, 783 5, 783 5, 793 6 0 0 same-cluster;
offset: 0 32.0186;
hint-metrics: on;
hint-style: full;
antialias: none;
dpi: 111;
}

View File

@@ -433,7 +433,7 @@ test_exhaustive (void)
gboolean add = FALSE, remove = FALSE;
guint position, n_items;
switch (g_test_rand_int_range (0, 6))
switch (g_test_rand_int_range (0, 7))
{
case 0:
if (g_test_verbose ())
@@ -483,6 +483,34 @@ test_exhaustive (void)
}
break;
case 6:
{
n_items = g_list_model_get_n_items (G_LIST_MODEL (store));
if (n_items > 0)
{
guint j = g_test_rand_int_range (0, n_items);
GListModel *source = g_list_model_get_item (G_LIST_MODEL (store), j);
guint source_size = g_list_model_get_n_items (G_LIST_MODEL (source));
GStrvBuilder *builder = g_strv_builder_new ();
guint inclusion_size = g_test_rand_int_range (1, 11);
char **inclusion;
for (j = 0; j < inclusion_size; j++)
g_strv_builder_add (builder, g_test_rand_bit () ? "A" : "B");
inclusion = g_strv_builder_end (builder);
g_strv_builder_unref (builder);
j = g_test_rand_int_range (0, source_size + 1);
gtk_string_list_splice (GTK_STRING_LIST (source), j, 0, (const char * const *) inclusion);
g_strfreev (inclusion);
if (g_test_verbose ())
g_test_message ("Adding %u items at position %u of a section which had %u items",
inclusion_size, j, source_size);
}
}
break;
default:
g_assert_not_reached ();
break;