Compare commits

..

117 Commits

Author SHA1 Message Date
Benjamin Otte
e390921500 vulkan: Make winding number computation more stable
Instead of just counting the roots, evaluate the y value between the
roots to ensure that the sign really did switch.

Gets rid of spurious winding number changes causing horizontal lines.

What is still causing horizontal lines is that the root solver misses
roots from time to time.
2023-07-31 16:51:04 +02:00
Benjamin Otte
78e3024924 vulkan: Split out color node special casing
It's done in multiple places, and because apps tend to use opacity +
color, we try to detect that, too.

Theoretically, other things, like color-matrix or crossfades, could be
added here, too.
2023-07-31 16:51:04 +02:00
Benjamin Otte
1382a2beaa vulkan: Make sure to create framebuffer-compatible images
When we want to render alpha, we need to create a
framebuffer-compatible format (ie, not do alpha-only).

Technically, we could create 2 different image views, one for rendering
and one for later usage, but I'm not going to go there today.
2023-07-31 16:51:04 +02:00
Benjamin Otte
f2c20b7ca9 contour: Compute stroke bounds correctly
We need to set the minimum miterwidth to sqrt(2) * line_width to catch
the square joins/butts of diagonal lines, because the rectangle spanned
by the square is rotated by 90 degrees.
2023-07-31 16:51:04 +02:00
Benjamin Otte
538ca8e0d4 vulkan: Add support for stroke nodes 2023-07-31 16:51:04 +02:00
Benjamin Otte
85a3931d41 vulkan: Use device for allocations
Big refactor - because suddenly everything cares about devices instead
of contexts.

But nothing really changed.
2023-07-31 16:51:04 +02:00
Benjamin Otte
560d42cf62 vulkan: Add GskVulkanDevice
This is the per-device global thing that is holding all the relevant
per-device stuff, like doing memory management, caching, and so on.

This is just the plumbing, and it's written so that it works without
GdkVulkanContext, which is one thing I want to get rid of.
2023-07-31 16:51:04 +02:00
Benjamin Otte
965b8c26bb vulkan: Add a cache allocation to buddy allocator
Instead of immediately freeing memory, keep one chunk around, because
surely somebody is gonna do another allocation soon.
2023-07-31 16:51:04 +02:00
Benjamin Otte
baf62c8923 vulkan: Add a simple buddy allocator 2023-07-31 16:51:04 +02:00
Benjamin Otte
d6c095a18b vulkan: Handle optimal tiling better
1. Request optimal tiling for offscreens
2. Don't use  host-mappable memory for optimal tiling.

Optimal tiling does not support memory mapping.
2023-07-31 16:51:04 +02:00
Benjamin Otte
9a6b1ff82b vulkan: Fix storage buffer handling
Instead of keeping a 256MB storage buffer around just to be safe, create
a 32kB one and handle enlarging the bfufer by 32kB when necessary.

The 32kB is quite arbitrarily chosen.
2023-07-31 16:51:04 +02:00
Benjamin Otte
5d30b347a9 vulkan: Get rid of GskVulkanMemory
Make buffers and images use GskVulkanAllocation instead and use the
allocator directly.

Also simplify the map/unmap into a simple get_data() call now that we
know we can keep everything mapped forever.

While doing this, pass alignment requirements to the allocator.

And copy/paste the memory type selection code from the Vulkan
documentation, so we do the same thing everybody else does.
2023-07-31 16:51:04 +02:00
Benjamin Otte
0ebcfc8bde vulkan: Add a dumb allocator that spams stout with stats 2023-07-31 16:51:04 +02:00
Benjamin Otte
dfb0d18290 vulkan: Introduce a memory allocator infrastructure
The only big difference (apart from lots more vfuncs) is that we map
mappable memory automatically and there is no longer a map/unmap step
involved.

According to various Vulkan docs, it is not necessary to do that
map/unmap shuffling, so we don't do it anymore.
2023-07-31 16:51:04 +02:00
Benjamin Otte
22590d24e1 vulkan: Implement support for all fill children
If the fill is not with a color, render the path to an alpha mask and
then mask the child with it.
2023-07-31 16:51:04 +02:00
Benjamin Otte
66e3082e2e vulkan: Rewrite fill shader a bit
- Split up distance in winding computation.
- Keep track of max interesting distance and exit early if stuff is
  further away
- don't compute winding for cubics entirely above/below the ray
2023-07-31 16:51:04 +02:00
Benjamin Otte
d2aa139e86 vulkan: Make fill node handle multiple contours
We still only handle standard contours, but now we can do multiple.
2023-07-31 16:51:04 +02:00
Benjamin Otte
9f12c5df07 XXX: hack node-editor to not die with paris-30k
Disable GL and Cairo renderer and turn off hilighting
2023-07-31 16:51:04 +02:00
Benjamin Otte
6fb33c775e node-editor: Don't reparse node when scaling
Makes scaling complex nodes bearable.
2023-07-31 16:51:04 +02:00
Benjamin Otte
ff9903d47f XXX: vulkan: Ignore stroke nodes
Useful for benchmarking.
2023-07-31 16:51:04 +02:00
Benjamin Otte
5eb0fa8b09 vulkan: Make the fill node use the contour output
For now, it only does a single standard contour.
And it can only do lines and cubics.
2023-07-31 16:51:04 +02:00
Benjamin Otte
7057f96c78 contour: Add gsk_contour_to_shader() function
This converts the contour into the format we pass to the GLSL shaders.

FIXME: Someone document that format maybe.
2023-07-31 16:51:04 +02:00
Benjamin Otte
8b6dffa5d2 vulkan: Add a naive fill node implementation 2023-07-31 16:51:04 +02:00
Benjamin Otte
19798883c4 xxx: stroke node bounds 2023-07-31 16:51:04 +02:00
Benjamin Otte
a7c842ee9d xxx debug-printf
Doesn't work yet, booo!
2023-07-31 16:51:04 +02:00
Matthias Clasen
802216e7c1 Add gsk vulkan tests
Add a testsuite called gsk-compare-vulkan to run
the gsk renderer tests with the Vulkan renderer.

The current stats:

Ok:                 184
Expected Fail:      0
Fail:               204
Unexpected Pass:    0
Skipped:            2
Timeout:            0

For now, we mark all the tests as failing to
avoid ci breakage. To run the tests locally,
you can do:

meson test -C_build --suite gsk-compare-vulkan
2023-07-31 16:51:04 +02:00
Benjamin Otte
30ed2603a9 node-editor: Add initial comparison UI
And yes, I'm aware of the icon I'm using.
2023-07-31 16:51:04 +02:00
Benjamin Otte
6631df684f node-editor: Add some form of undo stack
I have no idea about the UI for this yet, but there's a list of nodes
now that you can click on to get previous ones back.

Ultimately I want to have some way to compare nodes or do transitions,
but so far, this is an experiment.
2023-07-31 16:51:04 +02:00
Benjamin Otte
bc67bb3830 testsuite: Add a test for repeat node offscreen scaling
Ensure that the offscreens for repeat nodes pick the right xscale and
yscale so that they render pixel-aligned.
2023-07-31 16:51:04 +02:00
Benjamin Otte
1d02c78e1b testsuite: Add another test
This test ensures that offscreens for cross-fade children are properly
clipped and that the renderers can deal with the two not overlapping.
2023-07-31 16:51:04 +02:00
Benjamin Otte
29bd22025d testsuite: Add test for gradients
Test that it can do 64 color stops.

Should ensure that renderers either can do unlimited amounts or have
fallbacks in place.
2023-07-31 16:51:04 +02:00
Benjamin Otte
930ea4e019 testsuite: Test we don't crash with overly large nodes
... when these nodes are used as children of a complex transform nodes
and we lose the clip.
2023-07-31 16:51:04 +02:00
Benjamin Otte
7f5cca028a testsuite: Increase tolerances to make the path test work
I dislike the corner cases being so low (lower than 1% and off by a
whole point).
2023-07-31 16:51:04 +02:00
Benjamin Otte
e88d753f64 path: Handle segments of degenerate curves via lines
When curves have long straight parts that decompose into a single line,
don't try to split them. Instead, split at a well-known position and a
the part of that long straight line as a line.

This gives way more accurate numbers and is more accurate than 1% for
everything but contours with very small weight and
start_point == end_point, where the error is closer to 1.5%.
2023-07-31 16:51:04 +02:00
Benjamin Otte
34c52b4683 curve: Add a reason to decomposition
When decomposing curves that are too straight, we may emit lines for
long parts of the curve. These lines do not properly map
  t => distance
and it is better to treat them as a regular line than a curve.

This reason argument gives that information.

No users so far, that will happen in followup commits.
2023-07-31 16:51:04 +02:00
Benjamin Otte
ed737beda1 path: Move gsk_path_new_from_cairo() away
This is a regular path creation API, so treat it that way.

On top, it is rather awkward if the only constructor for a path that is
immediately visible to people reading the docs is the one that takes a
Cairo path - when we want to deprecate Cairo.
2023-07-31 16:51:04 +02:00
Matthias Clasen
5c7c452ea3 gtk-demo: Rewrite the text mask demo
Use GtkSnapshot and GskPath instead of cairo for this.
2023-07-31 16:51:04 +02:00
Benjamin Otte
25277d4d9e gtk-demo: Make path-text demo use gsk_builder_add_layout() 2023-07-31 16:51:04 +02:00
Matthias Clasen
a11d9cb942 path fill demo: Use gsk_path_builder_add_layout
We have an api now to hide the cairo use.
2023-07-31 16:51:04 +02:00
Matthias Clasen
49e3e8242a gsk: Add gsk_path_builder_add_layout
This api makes it easy to turn text into a path that
can be further manipulated. The implementation currently
goes via cairo.
2023-07-31 16:51:04 +02:00
Benjamin Otte
bae72fd737 path: Add gsk_path_builder_add_ellipse() 2023-07-31 16:51:04 +02:00
Benjamin Otte
4d4f4791e4 path: Change semantics of gtk_path_builder_add_segment()
Allow start >= end to mean that the path continues at the beginning
after reaching the end until it reaches the point at @end.
2023-07-31 16:51:04 +02:00
Benjamin Otte
ea3983b9ab path: Add gsk_path_measure_is_closed () 2023-07-31 16:51:04 +02:00
Benjamin Otte
c410e0510d path: Add gsk_path_measure_restrict_to_contour() 2023-07-31 16:51:04 +02:00
Matthias Clasen
67ee3ba0a3 Add gsk_path_measure_get_{path,tolerance}
These are just nice apis to have and avoid having to carry
these around as extra arguments in many places.

This was showing up as inconvenience in writing tests
for the measure apis.
2023-07-31 16:51:04 +02:00
Benjamin Otte
2f7ef4832e xxx path)_fill 2023-07-31 16:51:04 +02:00
Matthias Clasen
f728418d22 Add gsk_path_get_stroke_bounds
A relatively cheap way to get bounds for the area
that would be affected by stroking a path.
2023-07-31 16:51:04 +02:00
Benjamin Otte
5328e6d1ca testsuite: Add tests for the dasher 2023-07-31 16:51:04 +02:00
Benjamin Otte
70319b0316 path: Add a foreach function that dashes a path 2023-07-31 16:51:04 +02:00
Benjamin Otte
eb543bc58b path: Deal with non-uniformness of progress parameter
The progress is non-uniform, so simple translation of progress doesn't work.
So check if larger and smaller values inch closer towards minimal distance.
2023-07-31 16:51:04 +02:00
Benjamin Otte
e277bcdd12 path: Always decompose conics into at least 2 segments
Conics are evil in that their parameter skews towards the center, and if
it's a very flat conic (weight almost equal to 0), then we'd approximate
it with a single segment and not subdivide, which would cause the
parameter to be wildly off around 0.25 or 0.75.

And that would cause offset calculations to fail.
2023-07-31 16:51:04 +02:00
Matthias Clasen
e52d9d55a8 testsuite Add curve tangent tests 2023-07-31 16:51:04 +02:00
Benjamin Otte
b66935f168 testsuite: Add a test for the conic that got us segment() 2023-07-31 16:51:04 +02:00
Benjamin Otte
947e813d4b path: Add gsk_curve_segment()
Using split() twice with scaled t values does not work with conics.
2023-07-31 16:51:04 +02:00
Benjamin Otte
673d85ff16 testsuite: Add a test for gsk_curve_decompose() 2023-07-31 16:51:04 +02:00
Benjamin Otte
5a85046c09 testuite: Add tests for gsk_curve_get_tangent() 2023-07-31 16:51:04 +02:00
Matthias Clasen
887c1ff416 testuite: Add tests for gsk_curve_get_point()
Add a few tests for gsk_curve_get_point().

Since GskCurve is not public api, we add gskcurve.c
as source to the test binary.
2023-07-31 16:51:04 +02:00
Benjamin Otte
5877155c40 curve: Split eval() into get_point() and get_tangent()
That's more in line with the get_start/end_point/tangent() functions.

Plus, those calls are independent and we usually want one or the other.
2023-07-31 16:51:04 +02:00
Matthias Clasen
041b9170cc Add gsk_curve_get_{start,end}_tangent
Add a way to get the tangents at the start and end of the curve.
This will be used in stroking.
2023-07-31 16:51:04 +02:00
Benjamin Otte
968f5aea61 testsuite: Add conics to the random paths 2023-07-31 16:51:04 +02:00
Benjamin Otte
2badf27114 path: Add GskCurve
GskCurve is an abstraction for path operations. It's essentially a
collection of vfuncs per GskPathOperation.

GskStandardContour has been ported to use it where appropriate.
2023-07-31 16:51:04 +02:00
Benjamin Otte
0a05d864d1 path: Introduce gskpathop
A gskpathop is a pointer to a graphene_point_t* with the low bits used
to encode the GskPathOperation. It's an easy way to introduce API for
operations.

So far it's just used to replace GskStandardOperation.
2023-07-31 16:51:04 +02:00
Benjamin Otte
46fe43c5df WIP: css: Replace border rendering code with GskPath
The weight is wrong still, I need to compute the correct one to get real
45deg circle corners and not just roughly correct ones.
2023-07-31 16:51:04 +02:00
Benjamin Otte
74164440f6 WIP: pathbuilder: Add gsk_path_builder_add_rounded_rect()
It works, but does not use a custom contour yet.
2023-07-31 16:51:04 +02:00
Benjamin Otte
0cea93777a path: Add conic curves
So far this just adds the API, if you use it, you'll get lots of
g_warnings().

This will be fixed in future commits.
2023-07-31 16:51:04 +02:00
Benjamin Otte
70077d9a2a path: Rename to gtk_path_builder_add_segment()
It's about bulding paths, not about measuring them.
2023-07-31 16:51:04 +02:00
Benjamin Otte
df34aceee1 path: Split contours into their own file
I'm not sure I want to keep all contours in one file, but for now that's
how it is.
2023-07-31 16:51:04 +02:00
Benjamin Otte
70c6756639 path: Make all private contour APIs take a GskContour
... instead of a path, index tuple.
2023-07-31 16:51:04 +02:00
Benjamin Otte
63398ea869 stroke: Add support for dashes
... and hook it up in the node parser and for Cairo rendering.
2023-07-31 16:51:04 +02:00
Matthias Clasen
d315e0687e gsk: Implement parsing fill and stroke nodes
Make serialization and deserialization work for stroke and
fill nodes.
2023-07-31 16:51:04 +02:00
Benjamin Otte
89c63d1517 path: Add flags to gsk_path_foreach()
This way we can default to the siplest possible foreach() output - like
cairo_copy_path_flat() decomposing everything into lines - and add flags
to get more and more fancy.

This will be useful to have conics automatically decomposed for Cairo
drawing or if we want to add more line types in the future.
2023-07-31 16:51:04 +02:00
Benjamin Otte
3c5369a9ff testsuite: Add an in_fill() test 2023-07-31 16:51:04 +02:00
Matthias Clasen
e81e80e069 Implement gsk_path_measure_in_fill
Implement this in the obvious way, using the decomposed form
of standard contours. Since the decomposed form is part of the
measure object, this api moves from gsk_path_in_fill to
gsk_path_measure_in_fill.
2023-07-31 16:51:04 +02:00
Benjamin Otte
6dba706a9a testsuite: Add a parsing test
This test includes an implementation of a gsk_path_equal() func with
a tolerance that is necessary because parsing does not always work
100% exactly due to floating point rounding, so we can't just
compare the to_string() output.
2023-07-31 16:51:04 +02:00
Matthias Clasen
673e92645a path: Special-case rects and circles
Write out the commands for rects and circles in a special
way, and add code in the parser to recognize this, so we
can successfully round-trip these through the SVG path format.

The special way - for people who want to use it for debugging -
for now is that we use uppercase "Z" to close standard paths, but
lowercase "z" to close our special paths.

A test is included, but the random path serializations should take care
of it, too.
2023-07-31 16:51:04 +02:00
Matthias Clasen
8ef4b40e97 path: Fix serialization for circles
The svg A can not do a full circle, since it is a two point
parametrization - if the start and end point are the same,
it draws nothing. So, use two arcs.
2023-07-31 16:51:04 +02:00
Benjamin Otte
0ab25f0580 testsuite: Add librsvg path tests 2023-07-31 16:51:04 +02:00
Matthias Clasen
192bf4bbbe path: Implement gsk_path_parse
Implement the SVG path syntax to read back the strings
that we generate when serializing paths. The tests for
this code are taken from librsvg.

This includes an elliptical arc implementation according
to the SVG spec. The code is mostly taken from librsvg,
but pretty directly follows the SVG spec implementation
notes. We don't export this, since the parametrization
is inconvenient. We do want an arc_to API, but
these are not the arcs we are looking for.
2023-07-31 16:51:04 +02:00
Matthias Clasen
bddffb08cc path: Implement SVG arcs
This is elliptical arc implementation according to the SVG spec.
The code is mostly taken from librsvg, but pretty directly
follows the SVG spec implementation notes.

We don't export this, since the parametrization is inconvenient.
We do want an arc_to API, but these are not the arcs we are
looking for.

It will be used in parsing SVG path syntax.
2023-07-31 16:51:04 +02:00
Matthias Clasen
84dbd7c46f stroke: Add miter limit
Add a miter limit to GskStroke. This will be needed to
fully implement line joins.

Also introduce the GSK_LINE_JOIN_MITER_CLIP value,
following SVG 2.0. cairo does not have it, so translate
it to plain miter when using cairo.
2023-07-31 16:51:04 +02:00
Matthias Clasen
4487cafd40 Documentation typo fixes 2023-07-31 16:51:04 +02:00
Benjamin Otte
2f930f93cc testsuite: Add relative path functions
They're making the paths slightly weirder, but they test public API, so
woohoo!
2023-07-31 16:51:04 +02:00
Benjamin Otte
0a947d9a6a pathbuilder: Add relative path commands
And gsk_path_builder_get_current_point().

They will be needed by the string parser.
2023-07-31 16:51:04 +02:00
Benjamin Otte
46f405ac7d path: Add GSK_CIRCLE_POINT_INIT() to initialize points on the circle
This is just splitting out a commonly done operation into a macro.
2023-07-31 16:51:04 +02:00
Benjamin Otte
4f03537a28 pathbuilder: Redo semantics for starting curves
We now always have a "current point" which is either the last point an
operation was made to, or (0, 0) if no drawing operation has
been made yet.

Adding a contour of any kind to the builder will always update the
current point to that contour's end point.
2023-07-31 16:51:04 +02:00
Benjamin Otte
1621b53570 xxx: demo 2023-07-31 16:51:04 +02:00
Benjamin Otte
7e66dfe902 pathbuilder: Rename "builder" variables to "self"
This is a pure find/replace that is now possible after
the split in the previous commit.
2023-07-31 16:51:04 +02:00
Benjamin Otte
7bc6fabbf7 path: Split GskPathBuilder into its own file
... and add missing API docs.
2023-07-31 16:51:04 +02:00
Benjamin Otte
26c8702400 testsuite: Add a test using get_point() and get_closest_point() 2023-07-31 16:51:04 +02:00
Benjamin Otte
1b7c4420dc testsuite: Add a test for get_point() 2023-07-31 16:51:04 +02:00
Benjamin Otte
ece3153b1f testsuite: Update create_random_path()
1. Allow specifying the max number of contours
2. Be smarter about creating the paths:
   With 10% chance, create a "weird" path like the empty one or only
   points or things like that.
   Otherwise create a bunch of contours, with 2/3 a standard contour,
   with 1/3 a predetermined one.
2023-07-31 16:51:04 +02:00
Benjamin Otte
74dc039c7a gtk-demo: Add cute maze demo 2023-07-31 16:51:04 +02:00
Benjamin Otte
3e1c3aca2a testsuite: Add tests for gsk_path_measure_get_closest_point() 2023-07-31 16:51:04 +02:00
Benjamin Otte
51bc26b314 path: Add gsk_path_measure_get_closest_point()
... and gsk_path_measure_get_closest_point_full().

Those 2 functions allow finding the closest point on a path to a given
point.
2023-07-31 16:51:04 +02:00
Benjamin Otte
51a1adf312 spline: Use Skia's tolerance checks
This avoids measuring being too far off (it's still off, but it's less
than a percent now.
2023-07-31 16:51:04 +02:00
Benjamin Otte
d84132824f testsuite: Add tests for gsk_path_measure_add_segment() 2023-07-31 16:51:03 +02:00
Benjamin Otte
ffecc89352 gtk-demo: Add a text-on-path demo 2023-07-31 16:51:03 +02:00
Benjamin Otte
77518895ea demos: Add a simple demo filling a path 2023-07-31 16:51:03 +02:00
Benjamin Otte
9685a47693 path: Add gsk_path_measure_get_point()
Allows querying the coordinates and direction of any specific point on a
path.
2023-07-31 16:51:03 +02:00
Matthias Clasen
7f9825919c path: Add gsk_path_add_circle()
Adds a circle contour, too.
2023-07-31 16:51:03 +02:00
Benjamin Otte
2795fc53c1 pathmeasure: Implement support for beziers
Instead of treating bezier curves as lines, we properly decompose them
into line segments now so that we can treat those as lines.
2023-07-31 16:51:03 +02:00
Benjamin Otte
20ba4a225c path: Implement gsk_path_to_cairo() using foreach() 2023-07-31 16:51:03 +02:00
Benjamin Otte
eadbfc3433 path: Add gsk_path_foreach() 2023-07-31 16:51:03 +02:00
Benjamin Otte
b8ee48de63 path: Collect flags
We don't need them yet, but maybe later.
2023-07-31 16:51:03 +02:00
Benjamin Otte
25a5a8a85d testsuite: Add path tests 2023-07-31 16:51:03 +02:00
Benjamin Otte
5e1170bdb2 pathmeasure: Add gsk_path_measure_add_segment()
This allows chunking paths, weeee.
2023-07-31 16:51:03 +02:00
Benjamin Otte
f6bf74e2c9 path: Add gsk_path_builder_add_path() 2023-07-31 16:51:03 +02:00
Benjamin Otte
fa51c2eb0e gsk: Add GskPathMeasure
An object to do measuring operations on paths - determining their
length, cutting off subpaths, things like that.
2023-07-31 16:51:03 +02:00
Benjamin Otte
d34f1bbd6c path: Change data structure for standard path
Instead of the Cairo method and imitating cairo_path_data_t, use the
Skia method and keep points and operations separate.

That way we get a points array that includes the starting point -
because it's always the end point of the previous operation.
2023-07-31 16:51:03 +02:00
Benjamin Otte
8fd55e9f89 snapshot: Add gtk_snapshot_push_stroke() 2023-07-31 16:51:03 +02:00
Benjamin Otte
be4beeb8f2 gsk: Add GskStrokeNode 2023-07-31 16:51:03 +02:00
Benjamin Otte
09288f621a gsk: Add GskStroke
It's unused in this commit. This just prepares the new object.
2023-07-31 16:51:03 +02:00
Benjamin Otte
3ec3727575 snapshot: Add gtk_snapshot_push_fill() 2023-07-31 16:51:03 +02:00
Benjamin Otte
77e58d4463 rendernode: Implement fast-path for solid fills
They happen so often that it's worth avoiding the clip + paint path
there.
2023-07-31 16:51:03 +02:00
Benjamin Otte
bb58b504a6 gsk: Add GskFillNode
Take a rendernode as source and a GskPath and fill the region in the
path just like cairo_fill() would.
2023-07-31 16:51:03 +02:00
Benjamin Otte
f6bb568e91 gsk: Add GskPath 2023-07-31 16:51:03 +02:00
Benjamin Otte
efbb3ab535 xxx: benchmarking 2023-07-31 16:51:03 +02:00
506 changed files with 45535 additions and 68820 deletions

View File

@@ -30,16 +30,8 @@ variables:
workflow:
rules:
# run merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# do not run branch pipelines if corresponding merge requests exist...
# (this avoids duplicate pipelines)
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
# ...but otherwise run branch pipelines
- if: $CI_COMMIT_BRANCH
# run tag pipelines
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH
default:
retry:
@@ -205,30 +197,21 @@ msys2-mingw64:
paths:
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
macos-x86_64:
macos:
# Sadly, this fails regularly, and its failure is never enlightening
allow_failure: true
rules:
# Do not run in forks as the runner is not available there.
- if: $CI_PROJECT_NAMESPACE == "GNOME"
stage: build
tags:
- macosintel
- macos
needs: []
variables:
MESON_FORCE_BACKTRACKE: 1
TMPDIR: /Users/Shared/work/tmp
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
CCACHE_DIR: /Users/Shared/work/ccache
PIP_CACHE_DIR: /Users/Shared/build/cache
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
before_script:
- bash .gitlab-ci/show-info-osx.sh
- python3 -m venv .venv
- ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin
- ln -s /opt/ccache/ccache .venv/bin
- source .venv/bin/activate
- pip3 install meson==1.2.0
- pip3 install ninja==1.11.1
- pip3 install --user meson~=1.0
- pip3 install --user ninja
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
- export MESON_FORCE_BACKTRACE=1
script:
- meson setup ${COMMON_MESON_FLAGS}
-Dx11-backend=false
@@ -435,11 +418,10 @@ reference:
--buildtype=release
--force-fallback-for=gdk-pixbuf,pango
-Dintrospection=enabled
-Ddocumentation=true
-Dgtk_doc=true
-Dgdk-pixbuf:gtk_doc=true
-Dpango:gtk_doc=true
-Dbuild-demos=false
-Ddemos=false
-Dbuild-examples=false
-Dbuild-tests=false
-Dbuild-testsuite=false

View File

@@ -1,32 +0,0 @@
#!/usr/bin/sh
#
builddir=$1
suite=$2
unit=$3
echo "** builddir: ${builddir}"
echo "** suite: ${suite}"
echo "** unit: ${unit}"
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--print-errorlogs \
--setup=wayland \
--suite=${suite} \
--no-suite=failing \
--no-suite=flaky \
--no-suite=wayland_failing \
--no-suite=gsk-compare-broadway \
--verbose \
"${unit}"
exit_code=$?
kill ${compositor}
exit ${exit_code}

View File

@@ -23,7 +23,6 @@ case "${backend}" in
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=headless \
--no-suite=gsk-compare-broadway
# Store the exit code for the CI run, but always
@@ -46,7 +45,6 @@ case "${backend}" in
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=headless \
--no-suite=${backend}_failing \
--no-suite=gsk-compare-broadway
exit_code=$?
@@ -69,7 +67,6 @@ case "${backend}" in
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=headless \
--no-suite=gsk-compare-opengl
kill ${server}

View File

@@ -6,7 +6,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson~=0.64 || goto :error
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
ninja -C _build || goto :error
goto :EOF

45
AUTHORS
View File

@@ -7,7 +7,7 @@ Peter Mattis <petm@xcf.berkeley.edu>
Spencer Kimball <spencer@xcf.berkeley.edu>
Josh MacDonald <jmacd@xcf.berkeley.edu>
The team that build GTK 2 (in alphabetical order)
The Team that build GTK 2 (in alphabetical order)
-------------------------------------------------
Shawn T. Amundson <amundson@gtk.org>
Jerome Bolliet <bolliet@gtk.org>
@@ -28,8 +28,9 @@ Jay Painter <jpaint@gtk.org>
Manish Singh <manish@gtk.org>
Owen Taylor <otaylor@gtk.org>
The team that built GTK 3
-------------------------
The current team (GTK 3 and 4)
------------------------------
Jonas Ådahl <jadahl@gmail.com>
Tim Bäder <mail@baedert.org>
Emmanuele Bassi <ebassi@gnome.org>
@@ -39,16 +40,6 @@ Carlos Garnacho <mrgarnacho@gmail.com>
Alexander Larsson <alexl@redhat.com>
Benjamin Otte <otte@gnome.org>
The current team (GTK 4)
------------------------
Jonas Ådahl <jadahl@gmail.com>
Emmanuele Bassi <ebassi@gnome.org>
Christian Hergert <chergert@gnome.org>
Chun-wei Fan <fanchunwei@src.gnome.org>
Matthias Clasen <mclasen@redhat.com>
Carlos Garnacho <mrgarnacho@gmail.com>
Benjamin Otte <otte@gnome.org>
There are many others who have contributed patches; we thank them,
GTK is much better because of them.
@@ -58,15 +49,35 @@ Over time, GTK has incorporated some pieces of software which
started as independent projects. We list the original authors here:
MS-Windows theme engine
-----------------------
Raymond Penners
Dom Lachowicz
Pixbuf theme engine
-------------------
Owen Taylor
IME input method
----------------
Takuro Ashie
Kazuki IWAMOTO
MacOS backend
-------------
Mac OS X backend
----------------
Anders Carlsson
GtkInspector (originally gtkparasite)
-------------------------------------
DirectFB backend
----------------
Denis Oliver Kropp
Sven Neumann
Mike Emmel
gtkparasite
-----------
Christian Hammond

View File

@@ -35,7 +35,8 @@ The issue tracker is meant to be used for actionable issues only.
You should not open a new issue for security related questions.
When in doubt, follow [security](https://security.gnome.org/).
When in doubt, send an email to the [security](mailto:security@gnome.org)
mailing list.
### Bug reports
@@ -243,11 +244,13 @@ people committing to GTK to follow a few rules:
code, you should always ask. If your change is minor and you've been
working on GTK for a while it probably isn't necessary to ask. But when
in doubt, ask. Even if your change is correct, somebody may know a
better way to do things.
The `gtk` [room on matrix](https://matrix.to/#/#gtk:gnome.org) is also a
good place to find GTK developers to discuss changes, but if you live
outside of the EU/US time zones, the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
is the most certain and preferred method.
better way to do things. If you are making changes to GTK, you should
be subscribed to the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
mailing list; this is a good place to ask about intended changes.
The `#gtk` IRC channel on irc.gnome.org is also a good place to find GTK
developers to discuss changes, but if you live outside of the EU/US time
zones, an email to the gtk-devel mailing list is the most certain and
preferred method.
0. Ask _first_.

267
NEWS
View File

@@ -1,271 +1,6 @@
Overview of Changes in 4.13.1, xx-xx-xxxx
Overview of Changes in 4.11.5, xx-xx-xxxx
=========================================
* GtkTooltip:
- Don't cross native boundaries when looking for tooltips
* GtkCenterLayout, GtkEntry, GtkSearchEntry:
- Fix some issues with baseline handling
* GtkFileChooser:
- Make "Visit file" scroll to the file
* GtkSwitch:
- Respect text direction
* Paths:
- GskPathMeasure performance has been improved
- Add custom contours for circles, rounded rectangles and rectangles
- Simplify GskPathPoint handling
- gsk_path_point_get_closest_point now returns the distance as well
* Input:
- Handle (some) single-key compose sequences
* GSK:
- Make the repeated gradients match between GL and cairo
- Make rounded rect shrinking match between Vulkan, GL and cairo
- Fix parsing of text nodes with color glyphs
- Restrict an optimization to the cases where it is crrect
- Fix rendering of shadows with opacity
- The Vulkan renderer now requires Vulkan 1.2
* macOS:
- Clamp damage regions to the surface size
* Tools:
- gtk4-path-tool gained restrict and reverse commands
- gtk4-path-tool show and render can show control points
* Demos:
- Add a demo for hit testing with paths
* Build:
- Fix build problems with C++ compilers
* Translation updates
Brazilian Portuguese
British English
Catalan
Czech
Danish
Galician
Georgian
Italian
Korean
Lithuanian
Polish
Punjabi
Slovenian
Overview of Changes in 4.13.0, 25-08-2023
=========================================
* GskPath, GskPathBuilder, GskPathMeasure:
Data types and APIs for path rendering. These APIs are still
considered experimental, and may change until 4.14. Please try
them out and give us feedback. Documentation can be found
here: https://docs.gtk.org/gsk4/paths.html
* GtkGridView:
- Fix a crash when scrolling
* GtkColumnView:
- Fix a refcounting issue in the new scroll_to api
* GtkTreeView
- Fix style classes for sort arrows
* GtkEntry:
- Improve tracking of user changes (for undo)
* GtkNotebook:
- Fix a critical when switching pages
* GtkColor/FontDialogButton:
- Make these widgets activatable
* GtkMenuButton:
- Fix problems with focus handling
- Fix problems with DND
- Make flags a settable property
* GtkShortcutsWindow:
- Add API to build shortcuts windows programmatically
* Printing
- Fix the cpdb backend build
* MacOS:
- Make file filters work again
* GSK:
- Fix issues with color matrix nodes
* Wayland:
- Fix a crash with compositors other than gnome-shell
* Deprecations:
- Remaining GtkTreeModel-related types
* Demos:
- Add a few path demos to gtk4-demo
* Tools:
- gtk4-path-tool provides a commandline interface for paths
* Translation updates:
Basque
Catalan
Finnish
Galician
Georgian
German
Greek
Indonesian
Kazakh
Persian
Polish
Romanian
Spanish
Swedish
Turkish
Ukrainian
Overview of Changes in 4.12.0, 05-08-2023
=========================================
* List widgets:
- Add scroll_to APIs
* GtkFileLauncher:
- Add an always-ask property
* GtkTextView:
- Make backspace behavior match GtkEntry
* gsk:
- Fix handling of luminance in mask nodes
* Text rendering:
- Automate the setting of gtk-hint-font-metrics from the
scale factor. This improves font rendering in flatpaks
* Wayland:
- Fix behavior of stylus buttons
- Support suspended window state
* Vulkan:
- Many improvements
* Tools:
- Add gtk4-rendernode-tool
* Debugging:
- Drop the GTK_DEBUG_TOUCHSCREEN flag
* Build:
- Some build options have been renamed:
gtk_doc -> documentation
update_screenshots -> screenshots
The old names still work
* Translation updates:
Georgian
Greek
Hebrew
Persian
Vietnamese
* Contributors:
Aleksandr Melman
Alexander Mikhaylenko
Alexander Shopov
Alexandre Franke
Alice Mikhaylenko
António Fernandes
Arjan Molenaar
Asier Sarasua Garmendia
Balázs Meskó
Balázs Úr
Barnabás Pőcze
Bart Jacobs
Benjamin Otte
Bilal Elmoussaoui
Boyuan Yang
Bruce Cowan
Calvin Walton
Cam Cook
Chris Mayo
Christian Hergert
Christopher Davis
Chun-wei Fan
Corey Berla
Danial Behzadi
Daniel Boles
Daniel Rusek
Efstathios Iosifidis
Ekaterine Papava
Emin Tufan Çetin
Emmanuele Bassi
Erik Schilling
Fabio Tomat
FeRD (Frank Dana)
Fina Wilke
FineFindus
Fran Dieguez
G.Willems
Georges Basile Stavracas Neto
Guillaume Bernard
Hugo Carvalho
Ivan Molodetskikh
Jason Francis
Jonas Ådahl
Jordan Petridis
Jordi Mas
José Expósito
José Roberto de Souza
Khalid Abu Shawarib
Kévin Commaille
Leônidas Araújo
Luca Bacci
Ludovico de Nittis
Lukáš Tyrychtr
Marc-André Lureau
Marco Trevisan (Treviño)
Matt Turner
Matthias Clasen
Maximiliano Sandoval R
Michael Catanzaro
Michel Dänzer
Mohammed Sadiq
Nathan Follens
Nelson Benítez León
Ngọc Quân Trần
Niels De Graef
Olivier Crête
Patrick Griffis
Piotr Drąg
Sabri Ünal
Sebastian Keller
Sophie Herold
Sébastien Le Roux
Takao Fujiwara
Thomas Lange
Yiğit Burak
Yosef Or Boczko
Yuri Chornoivan
Zander Brown
al_SeveR
dgsasha
sumibi-yakitori
tszymanski
velsinki
Алексей Шилин
Арсений Засыпкин
Overview of Changes in 4.11.4, 03-07-2023
=========================================

View File

@@ -67,13 +67,6 @@ building for:
- [Graphene](https://github.com/ebassi/graphene)
- [Xkb-common](https://github.com/xkbcommon/libxkbcommon)
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
If you are building the X11 backend, you will also need:
- Xlib, and the following X extensions:
@@ -86,24 +79,32 @@ If you are building the X11 backend, you will also need:
- xdamage
- xcomposite
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
Once you have all the necessary dependencies, you can build GTK by using
Meson:
```sh
$ meson setup _build
$ meson compile -C_build
$ meson _build .
$ cd _build
$ ninja
```
You can run the test suite using:
```sh
$ meson test -C_build
$ meson test
```
And, finally, you can install GTK using:
```
$ sudo meson install -C_build
$ sudo ninja install
```
Complete information about installing GTK and related libraries

View File

@@ -483,8 +483,6 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->dispose = constraint_editor_window_dispose;
gtk_widget_class_set_template_from_resource (widget_class,

View File

@@ -20,7 +20,8 @@
#include "config.h"
#include "constraint-editor.h"
#include "constraint-view.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _ConstraintEditor
{
@@ -65,7 +66,7 @@ static const char *
get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "Super";
return "super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
@@ -79,29 +80,62 @@ constraint_target_combo (GListModel *model,
GtkWidget *combo,
gboolean is_source)
{
GtkStringList *targets;
int i;
targets = gtk_string_list_new (NULL);
gtk_string_list_append (targets, "Super");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "super", "Super");
if (model)
{
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
const char *name;
if (GTK_IS_CONSTRAINT (item))
continue;
gtk_string_list_append (targets, get_target_name (GTK_CONSTRAINT_TARGET (item)));
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
g_object_unref (item);
}
}
}
gtk_drop_down_set_model (GTK_DROP_DOWN (combo), G_LIST_MODEL (targets));
g_object_unref (targets);
static void
constraint_attribute_combo (GtkWidget *combo,
gboolean is_source)
{
if (is_source)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "none", "None");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "left", "Left");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "right", "Right");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "top", "Top");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "bottom", "Bottom");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "start", "Start");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "end", "End");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "width", "Width");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "height", "Height");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-x", "Center X");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-y", "Center Y");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "baseline", "Baseline");
}
static void
constraint_relation_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "le", "");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "eq", "=");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "ge", "");
}
static void
constraint_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static gpointer
@@ -113,7 +147,7 @@ get_target (GListModel *model,
if (id == NULL)
return NULL;
if (strcmp ("Super", id) == 0)
if (strcmp ("super", id) == 0)
return NULL;
for (i = 0; i < g_list_model_get_n_items (model); i++)
@@ -137,65 +171,16 @@ get_target (GListModel *model,
return NULL;
}
static void
select_target (GtkDropDown *combo,
const char *target_name)
{
GListModel *model = gtk_drop_down_get_model (combo);
for (unsigned int i = 0; i < g_list_model_get_n_items (model); i++)
{
GtkStringObject *s = g_list_model_get_item (model, i);
g_object_unref (s);
if (strcmp (target_name, gtk_string_object_get_string (s)) == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), i);
return;
}
}
}
static GtkConstraintAttribute
get_attr (unsigned int id)
get_target_attr (const char *id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_ATTRIBUTE_NONE;
case 1: return GTK_CONSTRAINT_ATTRIBUTE_LEFT;
case 2: return GTK_CONSTRAINT_ATTRIBUTE_RIGHT;
case 3: return GTK_CONSTRAINT_ATTRIBUTE_TOP;
case 4: return GTK_CONSTRAINT_ATTRIBUTE_BOTTOM;
case 5: return GTK_CONSTRAINT_ATTRIBUTE_START;
case 6: return GTK_CONSTRAINT_ATTRIBUTE_END;
case 7: return GTK_CONSTRAINT_ATTRIBUTE_WIDTH;
case 8: return GTK_CONSTRAINT_ATTRIBUTE_HEIGHT;
case 9: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_X;
case 10: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y;
case 11: return GTK_CONSTRAINT_ATTRIBUTE_BASELINE;
default: g_assert_not_reached ();
}
}
GtkConstraintAttribute attr;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
attr = value->value;
g_type_class_unref (class);
static unsigned int
get_attr_id (GtkConstraintAttribute attr)
{
switch (attr)
{
case GTK_CONSTRAINT_ATTRIBUTE_NONE: return 0;
case GTK_CONSTRAINT_ATTRIBUTE_LEFT: return 1;
case GTK_CONSTRAINT_ATTRIBUTE_RIGHT: return 2;
case GTK_CONSTRAINT_ATTRIBUTE_TOP: return 3;
case GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: return 4;
case GTK_CONSTRAINT_ATTRIBUTE_START: return 5;
case GTK_CONSTRAINT_ATTRIBUTE_END: return 6;
case GTK_CONSTRAINT_ATTRIBUTE_WIDTH: return 7;
case GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: return 8;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: return 9;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: return 10;
case GTK_CONSTRAINT_ATTRIBUTE_BASELINE: return 11;
default: g_assert_not_reached ();
}
return attr;
}
static const char *
@@ -210,27 +195,15 @@ get_attr_nick (GtkConstraintAttribute attr)
}
static GtkConstraintRelation
get_relation (unsigned int id)
get_relation (const char *id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_RELATION_LE;
case 1: return GTK_CONSTRAINT_RELATION_EQ;
case 2: return GTK_CONSTRAINT_RELATION_GE;
default: g_assert_not_reached ();
}
}
GtkConstraintRelation relation;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
relation = value->value;
g_type_class_unref (class);
static unsigned int
get_relation_id (GtkConstraintRelation relation)
{
switch (relation)
{
case GTK_CONSTRAINT_RELATION_LE: return 0;
case GTK_CONSTRAINT_RELATION_EQ: return 1;
case GTK_CONSTRAINT_RELATION_GE: return 2;
default: g_assert_not_reached ();
}
return relation;
}
static const char *
@@ -261,29 +234,15 @@ get_relation_display_name (GtkConstraintRelation relation)
}
static GtkConstraintStrength
get_strength (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
get_strength (const char *id)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
@@ -335,7 +294,7 @@ static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
{
gpointer obj;
const char *id;
gpointer target;
GtkConstraintAttribute target_attr;
gpointer source;
@@ -346,27 +305,25 @@ create_constraint (GtkButton *button,
int strength;
GtkConstraint *constraint;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
if (obj)
target = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
target = NULL;
target_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->target_attr)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
target = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
target_attr = get_target_attr (id);
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
if (obj)
source = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
source = NULL;
source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN(editor->source_attr)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
relation = get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation));
relation = get_relation (id);
multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL);
constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL);
strength = get_strength (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength)));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
constraint = gtk_constraint_new (target, target_attr,
relation,
@@ -381,9 +338,12 @@ create_constraint (GtkButton *button,
static void
source_attr_changed (ConstraintEditor *editor)
{
if (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))) == GTK_CONSTRAINT_ATTRIBUTE_NONE)
const char *id;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (id, "none") == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source), GTK_INVALID_LIST_POSITION);
gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), -1);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "");
gtk_widget_set_sensitive (editor->source, FALSE);
gtk_widget_set_sensitive (editor->multiplier, FALSE);
@@ -449,7 +409,7 @@ update_preview (ConstraintEditor *editor)
GString *str;
const char *name;
const char *attr;
const char *relation;
char *relation;
const char *multiplier;
const char *constant;
double c, m;
@@ -459,22 +419,23 @@ update_preview (ConstraintEditor *editor)
str = g_string_new ("");
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target))));
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected ((GTK_DROP_DOWN (editor->target_attr)))));
relation = get_relation_nick (get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation))));
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
g_free (relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (attr, "none") != 0)
{
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source))));
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
@@ -502,18 +463,12 @@ update_preview (ConstraintEditor *editor)
static void
update_button (ConstraintEditor *editor)
{
gpointer obj;
const char *target;
const char *source;
GtkConstraintAttribute source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr)));
const char *target = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
const char *source = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
const char *source_attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
target = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
source = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
if (target && (source || (source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
if (target &&
(source || (source_attr && get_target_attr (source_attr) == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
@@ -531,7 +486,12 @@ constraint_editor_constructed (GObject *object)
ConstraintEditor *editor = CONSTRAINT_EDITOR (object);
constraint_target_combo (editor->model, editor->target, FALSE);
constraint_attribute_combo (editor->target_attr, FALSE);
constraint_relation_combo (editor->relation);
constraint_target_combo (editor->model, editor->source, TRUE);
constraint_attribute_combo (editor->source_attr, TRUE);
constraint_strength_combo (editor->strength);
if (editor->constraint)
{
@@ -539,24 +499,30 @@ constraint_editor_constructed (GObject *object)
GtkConstraintAttribute attr;
GtkConstraintRelation relation;
GtkConstraintStrength strength;
const char *nick;
char *val;
double multiplier;
double constant;
target = gtk_constraint_get_target (editor->constraint);
select_target (GTK_DROP_DOWN (editor->target), get_target_name (target));
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick);
attr = gtk_constraint_get_target_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (attr));
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), nick);
target = gtk_constraint_get_source (editor->constraint);
select_target (GTK_DROP_DOWN (editor->source), get_target_name (target));
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), nick);
attr = gtk_constraint_get_source_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (attr));
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), nick);
relation = gtk_constraint_get_relation (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (relation));
nick = get_relation_nick (relation);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), nick);
multiplier = gtk_constraint_get_multiplier (editor->constraint);
val = g_strdup_printf ("%g", multiplier);
@@ -569,16 +535,17 @@ constraint_editor_constructed (GObject *object)
g_free (val);
strength = gtk_constraint_get_strength (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (GTK_CONSTRAINT_RELATION_EQ));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "required");
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0");
gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0");

View File

@@ -1,21 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkStringList" id="targets">
<items>
<item>None</item>
<item>Left</item>
<item>Right</item>
<item>Top</item>
<item>Bottom</item>
<item>Start</item>
<item>End</item>
<item>Width</item>
<item>Height</item>
<item>Center X</item>
<item>Center Y</item>
<item>Baseline</item>
</items>
</object>
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
@@ -35,9 +19,9 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="target">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="target">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">1</property>
@@ -45,9 +29,8 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="target_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<object class="GtkComboBoxText" id="target_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">1</property>
@@ -64,17 +47,8 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="relation">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<property name="model">
<object class="GtkStringList">
<items>
<item>≤</item>
<item>=</item>
<item>≥</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="relation">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">2</property>
@@ -91,9 +65,9 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="source">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="source">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
@@ -101,11 +75,10 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="source_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="source_attr_changed" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<object class="GtkComboBoxText" id="source_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="source_attr_changed" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
@@ -158,17 +131,7 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="column">1</property>
<property name="row">6</property>

View File

@@ -21,6 +21,8 @@
#include "guide-editor.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _GuideEditor
{
GtkWidget parent_instance;
@@ -57,30 +59,25 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
static GtkConstraintStrength
get_strength (unsigned int id)
static void
guide_strength_combo (GtkWidget *combo)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
static GtkConstraintStrength
get_strength (const char *id)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
@@ -121,11 +118,11 @@ static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
const char *id;
int strength;
const char *name;
int w, h;
GtkConstraintGuide *guide;
unsigned int id;
if (editor->guide)
guide = g_object_ref (editor->guide);
@@ -147,7 +144,7 @@ create_guide (GtkButton *button,
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
id = gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
@@ -194,9 +191,14 @@ guide_editor_constructed (GObject *object)
{
GuideEditor *editor = GUIDE_EDITOR (object);
guide_strength_combo (editor->strength);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
if (editor->guide)
@@ -222,7 +224,8 @@ guide_editor_constructed (GObject *object)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_constraint_guide_get_strength (editor->guide);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
@@ -242,7 +245,7 @@ guide_editor_constructed (GObject *object)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_MEDIUM));
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}

View File

@@ -167,17 +167,7 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="column">1</property>
<property name="row">4</property>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -2,6 +2,8 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef GtkApplication DemoApplication;
typedef GtkApplicationClass DemoApplicationClass;
@@ -214,41 +216,6 @@ activate_quit (GSimpleAction *action,
}
}
static void
delete_messages (gpointer data)
{
g_list_free_full ((GList *)data, g_free);
}
static void
pop_message (GtkWidget *status)
{
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
if (messages)
{
char *message = messages->data;
messages = g_list_remove (messages, message);
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
gtk_label_set_label (GTK_LABEL (status), message);
}
}
static void
push_message (GtkWidget *status,
const char *message)
{
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
gtk_label_set_label (GTK_LABEL (status), message);
messages = g_list_prepend (messages, g_strdup (message));
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
}
static void
update_statusbar (GtkTextBuffer *buffer,
DemoApplicationWindow *window)
@@ -259,7 +226,7 @@ update_statusbar (GtkTextBuffer *buffer,
GtkTextIter iter;
/* clear any previous message, underflow is allowed */
pop_message (window->status);
gtk_statusbar_pop (GTK_STATUSBAR (window->status), 0);
count = gtk_text_buffer_get_char_count (buffer);
@@ -273,7 +240,7 @@ update_statusbar (GtkTextBuffer *buffer,
msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
row, col, count);
push_message (window->status, msg);
gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, msg);
g_free (msg);
}

View File

@@ -76,13 +76,8 @@
</object>
</child>
<child>
<object class="GtkLabel" id="status">
<object class="GtkStatusbar" id="status">
<property name="hexpand">1</property>
<property name="xalign">0</property>
<property name="margin-start">2</property>
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>

View File

@@ -1,5 +1,5 @@
/* Builder
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkShortcutController, toolbar
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkStatusBar, GtkShortcutController, toolbar
*
* Demonstrates a traditional interface, loaded from a XML description,
* and shows how to connect actions to the menu items and toolbar buttons.
@@ -37,34 +37,30 @@ remove_timeout (gpointer data)
g_source_remove (id);
}
static int
pop_message (gpointer data)
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static gboolean
pop_status (gpointer data)
{
GtkWidget *status = data;
gtk_label_set_label (GTK_LABEL (status), "");
g_object_set_data (G_OBJECT (status), "timeout", GUINT_TO_POINTER (0));
gtk_statusbar_pop (GTK_STATUSBAR (data), 0);
g_object_set_data (G_OBJECT (data), "timeout", NULL);
return G_SOURCE_REMOVE;
}
static void
status_message (GtkWidget *status,
const char *text)
status_message (GtkStatusbar *status,
const char *text)
{
guint id;
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (status), "timeout"));
if (id)
g_source_remove (id);
gtk_label_set_text (GTK_LABEL (status), text);
id = g_timeout_add (5000, pop_message, status);
gtk_statusbar_push (GTK_STATUSBAR (status), 0, text);
id = g_timeout_add (5000, pop_status, status);
g_object_set_data_full (G_OBJECT (status), "timeout", GUINT_TO_POINTER (id), remove_timeout);
}
G_GNUC_END_IGNORE_DEPRECATIONS
static void
help_activate (GSimpleAction *action,
GVariant *parameter,
@@ -73,7 +69,7 @@ help_activate (GSimpleAction *action,
GtkWidget *status;
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, "Help not available");
status_message (GTK_STATUSBAR (status), "Help not available");
}
static void
@@ -86,7 +82,7 @@ not_implemented (GSimpleAction *action,
text = g_strdup_printf ("Action “%s” not implemented", g_action_get_name (G_ACTION (action)));
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, text);
status_message (GTK_STATUSBAR (status), text);
g_free (text);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

After

Width:  |  Height:  |  Size: 985 B

View File

@@ -6,6 +6,8 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,
@@ -47,23 +49,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -82,7 +81,6 @@ do_css_basics (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "CSS Basics");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
text = gtk_text_buffer_new (NULL);

View File

@@ -4,24 +4,23 @@
* anymore. :)
*/
/* This resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
@import url("resource://css_shadows/reset.css");
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use */
@import url("resource://css_basics/reset.css");
/* Set a very futuristic style by default */
.demo * {
* {
color: green;
font-family: Monospace;
border: 1px solid;
}
window.demo {
window {
background-color: white;
}
/* Make sure selections are visible */
.demo selection {
selection {
background-color: darkGreen;
color: black;
}

View File

@@ -6,6 +6,8 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,
@@ -48,23 +50,33 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
drawing_area_draw (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
GtkStyleProvider *provider = data;
GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (da));
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -83,17 +95,16 @@ do_css_multiplebgs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Multiple Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
child = gtk_drawing_area_new ();
/* Don't set a draw_func, since we are only interested in CSS drawing,
* which happens automatically.
*/
gtk_widget_set_name (child, "canvas");
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
drawing_area_draw,
NULL, NULL);
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
child = gtk_button_new ();

View File

@@ -7,6 +7,8 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,
@@ -49,23 +51,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -84,7 +83,6 @@ do_css_pixbufs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Animated Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);

View File

@@ -50,7 +50,7 @@
100% { background-size: 12px, 96px, 12px, 96px, 12px, 96px, 12px, 96px, auto; }
}
window.demo {
window {
background-image: url("resource://css_pixbufs/images/apple-red.png"),
url("resource://css_pixbufs/images/gnome-applets.png"),
url("resource://css_pixbufs/images/gnome-calendar.png"),
@@ -66,11 +66,11 @@ window.demo {
}
/* Make the text editor has a nice style */
window.demo .view, scrollbar, separator {
.view, scrollbar, separator {
color: black;
background-color: rgba(255,255,255,0.5);
}
window.demo .view:selected {
.view:selected {
background-color: rgba(127,127,255,0.5);
}

View File

@@ -5,6 +5,8 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,
@@ -46,23 +48,20 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
static GtkWidget *
@@ -102,7 +101,6 @@ do_css_shadows (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Shadows");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
@@ -144,7 +142,7 @@ do_css_shadows (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -5,13 +5,12 @@
*/
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
* and overrides all user settings and the theme in use */
@import url("resource://css_shadows/reset.css");
@import url("resource://css_shadows/cssview.css");
/* Get a nice background for the window */
window.demo.background {
.background {
background-color: #4870bc;
background-image: linear-gradient(to left, transparent, rgba(255,255,255,.07) 50%, transparent 50%),
linear-gradient(to left, transparent, rgba(255,255,255,.13) 50%, transparent 50%),
@@ -20,7 +19,7 @@ window.demo.background {
background-size: 29px, 59px, 73px, 109px;
}
window.demo button {
button {
color: black;
padding: 10px;
border-radius: 5px;
@@ -28,15 +27,18 @@ window.demo button {
border: 1px transparent solid;
}
window.demo button:hover {
button:hover {
text-shadow: 3px 3px 5px alpha(black, 0.75);
-gtk-icon-shadow: 3px 3px 5px alpha(black, 0.75);
box-shadow: 3px 3px 5px alpha(black, 0.5) inset;
border: solid 1px alpha(black, 0.75);
}
window.demo button:active {
button:active {
padding: 11px 9px 9px 11px;
text-shadow: 1px 1px 2.5px alpha(black, 0.6);
-gtk-icon-shadow: 1px 1px 2.5px alpha(black, 0.6);
}

View File

@@ -1,21 +1,21 @@
/* Make the text editor has a nice style */
window.demo .view {
.view {
color: #2e3436;
font-family: Monospace;
background-color: alpha(white, 0.30);
}
window.demo .view:selected {
.view:selected {
color: white;
background-color: #4a90d9;
}
window.demo scrollbar trough,
scrollbar trough,
.scrollbars-junction {
background-color: alpha(white, 0.80);
}
window.demo scrollbar slider {
scrollbar slider {
border-width: 3px;
border-style: solid;
border-radius: 10px;
@@ -24,11 +24,11 @@ window.demo scrollbar slider {
background-color: #999;
}
window.demo scrollbar slider:hover {
scrollbar slider:hover {
background-color: #555;
}
window.demo paned separator {
paned separator {
background-color: alpha(white, 0.80);
background-image: linear-gradient(transparent, transparent 1px, #999 1px, #999 4px, transparent 4px);
background-size: 40px auto;
@@ -36,6 +36,6 @@ window.demo paned separator {
background-position: center;
}
window.demo paned separator:hover {
paned separator:hover {
background-image: linear-gradient(transparent, transparent 1px, #555 1px, #555 4px, transparent 4px);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -127,7 +127,6 @@
<file>fishbowl.ui</file>
<file>gtkfishbowl.c</file>
<file>gtkfishbowl.h</file>
<file>tiger.node</file>
</gresource>
<gresource prefix="/frames">
<file>frames.ui</file>
@@ -338,9 +337,6 @@
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_maze.c</file>
<file>path_spinner.c</file>
<file>path_sweep.c</file>
<file>path_walk.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
@@ -427,14 +423,6 @@
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/path_sweep">
<file>path_sweep.ui</file>
<file compressed="true">path_world.txt</file>
</gresource>
<gresource prefix="/path_walk">
<file>path_walk.ui</file>
<file compressed="true">path_world.txt</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>

View File

@@ -208,13 +208,7 @@
</object>
</child>
<child>
<object class="GtkLabel" id="statusbar1">
<property name="xalign">0</property>
<property name="margin-start">2</property>
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
</object>
<object class="GtkStatusbar" id="statusbar1"/>
</child>
</object>
</child>

View File

@@ -760,7 +760,9 @@ do_dnd (GtkWidget *do_widget)
GtkCssProvider *provider;
GString *css;
button = gtk_color_dialog_button_new (gtk_color_dialog_new ());
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
button = gtk_color_button_new ();
G_GNUC_END_IGNORE_DEPRECATIONS
g_object_unref (g_object_ref_sink (button));
provider = gtk_css_provider_new ();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -10,6 +10,8 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *window = NULL;
static void
@@ -43,22 +45,21 @@ do_expander (GtkWidget *do_widget)
if (!window)
{
toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget));
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Expander");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (toplevel));
area = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_start (area, 10);
gtk_widget_set_margin_end (area, 10);
gtk_widget_set_margin_top (area, 10);
gtk_widget_set_margin_bottom (area, 10);
gtk_window_set_child (GTK_WINDOW (window), area);
label = gtk_label_new ("<big><b>Something went wrong</b></big>");
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_box_append (GTK_BOX (area), label);
label = gtk_label_new ("Here are some more details but not the full story");
window = gtk_message_dialog_new_with_markup (GTK_WINDOW (toplevel),
0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"<big><b>%s</b></big>",
"Something went wrong");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (window),
"Here are some more details "
"but not the full story.");
area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (window));
label = gtk_widget_get_last_child (area);
gtk_label_set_wrap (GTK_LABEL (label), FALSE);
gtk_widget_set_vexpand (label, FALSE);
gtk_box_append (GTK_BOX (area), label);
expander = gtk_expander_new ("Details:");
gtk_widget_set_vexpand (expander, TRUE);
@@ -121,7 +122,7 @@ do_expander (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));

View File

@@ -11,9 +11,6 @@
#include "gtkgears.h"
#include "gskshaderpaintable.h"
#include "nodewidget.h"
#include "graphwidget.h"
const char *const css =
".blurred-button {"
" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
@@ -71,11 +68,13 @@ create_blurred_button (void)
return w;
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *
create_font_button (void)
{
return gtk_font_dialog_button_new (gtk_font_dialog_new ());
return gtk_font_button_new ();
}
G_GNUC_END_IGNORE_DEPRECATIONS
static GtkWidget *
create_level_bar (void)
@@ -204,18 +203,6 @@ create_menu_button (void)
return w;
}
static GtkWidget *
create_tiger (void)
{
return node_widget_new ("/fishbowl/tiger.node");
}
static GtkWidget *
create_graph (void)
{
return graph_widget_new ();
}
static const struct {
const char *name;
GtkWidget * (*create_func) (void);
@@ -233,8 +220,6 @@ static const struct {
{ "Switch", create_switch },
{ "Menubutton", create_menu_button },
{ "Shader", create_cogs },
{ "Tiger", create_tiger },
{ "Graph", create_graph },
};
static int selected_widget_type = -1;
@@ -325,20 +310,11 @@ do_fishbowl (GtkWidget *do_widget)
if (!window)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkWidget *bowl;
g_type_ensure (GTK_TYPE_FISHBOWL);
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), fishbowl_prev_button_clicked_cb);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), fishbowl_next_button_clicked_cb);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), fishbowl_changes_toggled_cb);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), format_header_cb);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/fishbowl/fishbowl.ui", NULL);
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
@@ -350,7 +326,6 @@ do_fishbowl (GtkWidget *do_widget)
gtk_widget_realize (window);
g_object_unref (builder);
g_object_unref (scope);
}
if (!gtk_widget_get_visible (window))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,153 +0,0 @@
#include "graphwidget.h"
struct _GraphWidget
{
GtkWidget parent_instance;
GskPath *path;
GskStroke *stroke;
GdkRGBA color;
guint tick_cb;
guint64 start_time;
double period;
double amplitude;
};
struct _GraphWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GraphWidget, graph_widget, GTK_TYPE_WIDGET)
static void
update_path (GraphWidget *self,
float amplitude)
{
graphene_point_t p[20];
GskPathBuilder *builder;
g_clear_pointer (&self->path, gsk_path_unref);
for (int i = 0; i < 20; i++)
{
p[i].x = 10 * i;
p[i].y = 50;
if (i % 4 == 1 || i % 4 == 2)
{
if (i % 8 < 4)
p[i].y += amplitude;
else
p[i].y -= amplitude;
}
}
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, p[0].x, p[0].y);
for (int i = 0; i < 20; i += 4)
gsk_path_builder_cubic_to (builder,
p[i+1].x, p[i+1].y,
p[i+2].x, p[i+2].y,
p[i+3].x, p[i+3].y);
self->path = gsk_path_builder_free_to_path (builder);
}
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GraphWidget *self = GRAPH_WIDGET (widget);
guint64 now;
double angle;
now = gdk_frame_clock_get_frame_time (frame_clock);
if (self->start_time == 0)
self->start_time = now;
angle = 360 * (now - self->start_time) / (double)(self->period * G_TIME_SPAN_MINUTE);
update_path (self, sin (angle) * self->amplitude);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
graph_widget_init (GraphWidget *self)
{
self->color.red = g_random_double_range (0, 1);
self->color.green = g_random_double_range (0, 1);
self->color.blue = g_random_double_range (0, 1);
self->color.alpha = 1;
self->period = g_random_double_range (0.5, 1);
self->amplitude = g_random_double_range (10, 25);
self->stroke = gsk_stroke_new (2);
update_path (self, 0);
self->start_time = 0;
self->tick_cb = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
}
static void
graph_widget_dispose (GObject *object)
{
GraphWidget *self = GRAPH_WIDGET (object);
g_clear_pointer (&self->path, gsk_path_unref);
gsk_stroke_free (self->stroke);
G_OBJECT_CLASS (graph_widget_parent_class)->dispose (object);
}
static void
graph_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GraphWidget *self = GRAPH_WIDGET (widget);
gtk_snapshot_append_stroke (snapshot, self->path, self->stroke, &self->color);
}
static void
graph_widget_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = 200;
else
*minimum = *natural = 100;
}
static void
graph_widget_class_init (GraphWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = graph_widget_dispose;
widget_class->snapshot = graph_widget_snapshot;
widget_class->measure = graph_widget_measure;
}
GtkWidget *
graph_widget_new (void)
{
return g_object_new (GRAPH_TYPE_WIDGET, NULL);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GRAPH_TYPE_WIDGET (graph_widget_get_type ())
G_DECLARE_FINAL_TYPE (GraphWidget, graph_widget, GRAPH, WIDGET, GtkWidget)
GtkWidget * graph_widget_new (void);

View File

@@ -840,24 +840,24 @@ gtk_gears_unrealize (GtkWidget *widget)
GtkGearsPrivate *priv = gtk_gears_get_instance_private ((GtkGears *) widget);
gtk_gl_area_make_current (glarea);
if (gtk_gl_area_get_error (glarea) == NULL)
{
/* Release the resources associated with OpenGL */
if (priv->gear_vbo[0] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[0]));
if (gtk_gl_area_get_error (glarea) != NULL)
return;
if (priv->gear_vbo[1] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[1]));
/* Release the resources associated with OpenGL */
if (priv->gear_vbo[0] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[0]));
if (priv->gear_vbo[2] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[2]));
if (priv->gear_vbo[1] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[1]));
if (priv->vao != 0)
glDeleteVertexArrays (1, &priv->vao);
if (priv->gear_vbo[2] != 0)
glDeleteBuffers (1, &(priv->gear_vbo[2]));
if (priv->program != 0)
glDeleteProgram (priv->program);
}
if (priv->vao != 0)
glDeleteVertexArrays (1, &priv->vao);
if (priv->program != 0)
glDeleteProgram (priv->program);
priv->ModelViewProjectionMatrix_location = 0;
priv->NormalMatrix_location = 0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -354,18 +354,10 @@ do_iconscroll (GtkWidget *do_widget)
if (!window)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkWidget *label;
guint id;
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), iconscroll_prev_clicked_cb);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), iconscroll_next_clicked_cb);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/iconscroll/iconscroll.ui", NULL);
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_display (GTK_WINDOW (window),
@@ -383,7 +375,6 @@ do_iconscroll (GtkWidget *do_widget)
GUINT_TO_POINTER (id), remove_timeout);
g_object_unref (builder);
g_object_unref (scope);
}
if (!gtk_widget_get_visible (window))

View File

@@ -74,9 +74,6 @@ demos = files([
'password_entry.c',
'path_fill.c',
'path_maze.c',
'path_spinner.c',
'path_sweep.c',
'path_walk.c',
'path_text.c',
'peg_solitaire.c',
'pickers.c',
@@ -142,8 +139,6 @@ extra_demo_sources = files([
'unicode-names.c',
'suggestionentry.c',
'language-names.c',
'nodewidget.c',
'graphwidget.c',
])
if os_unix
@@ -158,6 +153,8 @@ if librsvg_dep.found()
gtkdemo_deps += [ librsvg_dep ]
endif
gtkdemo_args = [ '-DGDK_DISABLE_DEPRECATED', '-DGTK_DISABLE_DEPRECATED', ]
demos_h = custom_target('gtk4 demo header',
output: 'demos.h',
input: demos,
@@ -241,7 +238,7 @@ gtkdemo_deps += [ demo_conf_h ]
executable('gtk4-demo',
sources: [demos, demos_h, extra_demo_sources, gtkdemo_resources],
c_args: demo_cflags,
c_args: gtkdemo_args + demo_cflags,
dependencies: gtkdemo_deps,
include_directories: confinc,
win_subsystem: 'windows',
@@ -251,7 +248,7 @@ executable('gtk4-demo',
executable('gtk4-demo-application',
sources: ['application.c', gtkdemo_resources],
c_args: common_cflags,
c_args: gtkdemo_args + common_cflags,
dependencies: gtkdemo_deps,
include_directories: confinc,
win_subsystem: 'windows',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,76 +0,0 @@
#include "nodewidget.h"
struct _NodeWidget
{
GtkWidget parent_instance;
GskRenderNode *node;
};
struct _NodeWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (NodeWidget, node_widget, GTK_TYPE_WIDGET)
static void
node_widget_init (NodeWidget *self)
{
}
static void
node_widget_dispose (GObject *object)
{
NodeWidget *self = NODE_WIDGET (object);
gsk_render_node_unref (self->node);
G_OBJECT_CLASS (node_widget_parent_class)->dispose (object);
}
static void
node_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
NodeWidget *self = NODE_WIDGET (widget);
gtk_snapshot_append_node (snapshot, self->node);
}
static void
node_widget_class_init (NodeWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = node_widget_dispose;
widget_class->snapshot = node_widget_snapshot;
}
GtkWidget *
node_widget_new (const char *resource)
{
NodeWidget *self;
GBytes *bytes;
GskRenderNode *node;
graphene_rect_t bounds;
float scale;
GskTransform *transform;
self = g_object_new (NODE_TYPE_WIDGET, NULL);
bytes = g_resources_lookup_data (resource, 0, NULL);
node = gsk_render_node_deserialize (bytes, NULL, NULL);
g_bytes_unref (bytes);
gsk_render_node_get_bounds (node, &bounds);
scale = MIN (100.0/bounds.size.width, 100.0/bounds.size.height);
transform = gsk_transform_scale (NULL, scale, scale);
self->node = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
gsk_render_node_unref (node);
return GTK_WIDGET (self);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define NODE_TYPE_WIDGET (node_widget_get_type ())
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
GtkWidget * node_widget_new (const char *file);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -7,6 +7,8 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum {
COLOR_SET,
N_SIGNALS
@@ -122,16 +124,19 @@ drawing_area_unmap (GtkWidget *widget)
static void
drawing_area_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
GtkSnapshot *snapshot)
{
DrawingArea *area = (DrawingArea *) widget;
int width, height;
GtkAllocation allocation;
cairo_t *cr;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_widget_get_allocation (widget, &allocation);
cr = gtk_snapshot_append_cairo (snapshot,
&GRAPHENE_RECT_INIT (
0, 0,
allocation.width,
allocation.height
));
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@@ -140,7 +145,7 @@ drawing_area_snapshot (GtkWidget *widget,
cairo_paint (cr);
cairo_set_source_rgb (cr, 0.6, 0.6, 0.6);
cairo_rectangle (cr, 0, 0, width, height);
cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
cairo_stroke (cr);
cairo_destroy (cr);

View File

@@ -1,170 +1,317 @@
/* Path/Fill and Stroke
/* Path/Fill
*
* This demo shows how to use GskPath to draw shapes that are (a bit)
* more complex than a rounded rectangle.
* This demo shows how to use PangoCairo to draw text with more than
* just a single color.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#include "gsk/gskpathdashprivate.h"
#define GTK_TYPE_LOGO_PAINTABLE (gtk_logo_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkLogoPaintable, gtk_logo_paintable, GTK, LOGO_PAINTABLE, GObject)
#define GTK_TYPE_PATH_PAINTABLE (gtk_path_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathPaintable, gtk_path_paintable, GTK, PATH_PAINTABLE, GObject)
struct _GtkLogoPaintable
struct _GtkPathPaintable
{
GObject parent_instance;
int width;
int height;
GskPath *path[3];
GdkRGBA color[3];
GskPath *stroke_path;
GskStroke *stroke1;
GskStroke *stroke2;
GdkRGBA stroke_color;
GskPath *path;
GdkPaintable *background;
};
struct _GtkLogoPaintableClass
struct _GtkPathPaintableClass
{
GObjectClass parent_class;
};
static int
gtk_logo_paintable_get_intrinsic_width (GdkPaintable *paintable)
gtk_path_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
return self->width;
if (self->background)
return MAX (gdk_paintable_get_intrinsic_width (self->background), self->width);
else
return self->width;
}
static int
gtk_logo_paintable_get_intrinsic_height (GdkPaintable *paintable)
gtk_path_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
return self->height;
if (self->background)
return MAX (gdk_paintable_get_intrinsic_height (self->background), self->height);
else
return self->height;
}
static void
gtk_logo_paintable_snapshot (GdkPaintable *paintable,
gtk_path_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (paintable);
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
for (unsigned int i = 0; i < 3; i++)
#if 0
gtk_snapshot_push_fill (snapshot, self->path, GSK_FILL_RULE_WINDING);
#else
GskStroke *stroke = gsk_stroke_new (2.0);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gsk_stroke_free (stroke);
#endif
if (self->background)
{
gtk_snapshot_push_fill (snapshot, self->path[i], GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot,
&self->color[i],
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gdk_paintable_snapshot (self->background, snapshot, width, height);
}
for (unsigned int i = 0; i < 3; i++)
else
{
gtk_snapshot_push_stroke (snapshot, self->stroke_path, self->stroke1);
gtk_snapshot_append_color (snapshot,
&self->stroke_color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
(GskColorStop[8]) {
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
},
8);
}
gtk_snapshot_push_stroke (snapshot, self->stroke_path, self->stroke2);
gtk_snapshot_append_color (snapshot,
&self->stroke_color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
static GdkPaintableFlags
gtk_logo_paintable_get_flags (GdkPaintable *paintable)
gtk_path_paintable_get_flags (GdkPaintable *paintable)
{
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return gdk_paintable_get_flags (self->background);
else
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_logo_paintable_paintable_init (GdkPaintableInterface *iface)
gtk_path_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->get_intrinsic_width = gtk_logo_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_logo_paintable_get_intrinsic_height;
iface->snapshot = gtk_logo_paintable_snapshot;
iface->get_flags = gtk_logo_paintable_get_flags;
iface->get_intrinsic_width = gtk_path_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_path_paintable_get_intrinsic_height;
iface->snapshot = gtk_path_paintable_snapshot;
iface->get_flags = gtk_path_paintable_get_flags;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkLogoPaintable, gtk_logo_paintable, G_TYPE_OBJECT,
G_DEFINE_TYPE_WITH_CODE (GtkPathPaintable, gtk_path_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_logo_paintable_paintable_init))
gtk_path_paintable_paintable_init))
static void
gtk_logo_paintable_dispose (GObject *object)
/* Here's the boilerplate for the GObject declaration.
* We need to disconnect the signals here that we set up elsewhere
*/
static void
gtk_path_paintable_dispose (GObject *object)
{
GtkLogoPaintable *self = GTK_LOGO_PAINTABLE (object);
GtkPathPaintable *self = GTK_PATH_PAINTABLE (object);
for (unsigned int i = 0; i < 3; i++)
gsk_path_unref (self->path[i]);
if (self->background)
{
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_contents, self);
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_size, self);
g_clear_object (&self->background);
}
gsk_path_unref (self->stroke_path);
gsk_stroke_free (self->stroke1);
gsk_stroke_free (self->stroke2);
G_OBJECT_CLASS (gtk_logo_paintable_parent_class)->dispose (object);
G_OBJECT_CLASS (gtk_path_paintable_parent_class)->dispose (object);
}
static void
gtk_logo_paintable_class_init (GtkLogoPaintableClass *klass)
gtk_path_paintable_class_init (GtkPathPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_logo_paintable_dispose;
object_class->dispose = gtk_path_paintable_dispose;
}
static void
gtk_logo_paintable_init (GtkLogoPaintable *self)
gtk_path_paintable_init (GtkPathPaintable *self)
{
}
static GdkPaintable *
gtk_logo_paintable_new (void)
/* And finally, we add a simple constructor.
* It is declared in the header so that the other examples
* can use it.
*/
GdkPaintable *
gtk_path_paintable_new (GskPath *path,
GdkPaintable *background,
int width,
int height)
{
GtkLogoPaintable *self;
graphene_rect_t bounds, bounds2;
GtkPathPaintable *self;
self = g_object_new (GTK_TYPE_LOGO_PAINTABLE, NULL);
/* Paths and colors extracted from gtk-logo.svg */
self->path[0] = gsk_path_parse ("m3.12,66.17 -2.06,-51.46 32.93,24.7 v55.58 l-30.87,-28.82 z");
self->path[1] = gsk_path_parse ("m34,95 49.4,-20.58 4.12,-51.46 -53.52,16.47 v55.58 z");
self->path[2] = gsk_path_parse ("m1.06,14.71 32.93,24.7 53.52,-16.47 -36.75,-21.88 -49.7,13.65 z");
gdk_rgba_parse (&self->color[0], "#e40000");
gdk_rgba_parse (&self->color[1], "#7fe719");
gdk_rgba_parse (&self->color[2], "#729fcf");
self->stroke_path = gsk_path_parse ("m50.6,51.3 -47.3,14 z l33,23 z v-50");
self->stroke1 = gsk_stroke_new (2.12);
self->stroke2 = gsk_stroke_new (1.25);
gdk_rgba_parse (&self->stroke_color, "#ffffff");
gsk_path_get_stroke_bounds (self->path[0], self->stroke1, &bounds);
gsk_path_get_stroke_bounds (self->path[1], self->stroke1, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
gsk_path_get_stroke_bounds (self->path[2], self->stroke1, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
gsk_path_get_stroke_bounds (self->stroke_path, self->stroke2, &bounds2);
graphene_rect_union (&bounds, &bounds2, &bounds);
self->width = bounds.origin.x + bounds.size.width;
self->height = bounds.origin.y + bounds.size.height;
self = g_object_new (GTK_TYPE_PATH_PAINTABLE, NULL);
self->path = path;
self->background = background;
if (self->background)
{
g_object_ref (self->background);
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
}
self->width = width;
self->height = height;
return GDK_PAINTABLE (self);
}
void
gtk_path_paintable_set_path (GtkPathPaintable *self,
GskPath *path)
{
g_clear_pointer (&self->path, gsk_path_unref);
self->path = gsk_path_ref (path);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
static GskPath *
create_hexagon (GtkWidget *widget)
{
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, 120, 0);
gsk_path_builder_line_to (builder, 360, 0);
gsk_path_builder_line_to (builder, 480, 208);
gsk_path_builder_line_to (builder, 360, 416);
gsk_path_builder_line_to (builder, 120, 416);
gsk_path_builder_line_to (builder, 0, 208);
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static GskPath *
create_path_from_text (GtkWidget *widget)
{
PangoLayout *layout;
PangoFontDescription *desc;
GskPathBuilder *builder;
layout = gtk_widget_create_pango_layout (widget, "Pango power!\nPango power!\nPango power!");
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
builder = gsk_path_builder_new ();
gsk_path_builder_add_layout (builder, layout);
return gsk_path_builder_free_to_path (builder);
}
static gboolean
build_path (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer user_data)
{
GskPathBuilder *builder = user_data;
switch (op)
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (builder);
break;
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
break;
case GSK_PATH_CURVE:
gsk_path_builder_curve_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, weight);
break;
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
static gboolean
update_path (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer measure)
{
float progress = gdk_frame_clock_get_frame_time (frame_clock) % (60 * G_USEC_PER_SEC) / (float) (30 * G_USEC_PER_SEC);
GskPathBuilder *builder;
GskPath *path;
graphene_point_t pos;
graphene_vec2_t tangent;
GskStroke *stroke;
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder,
measure,
#if 1
0.0, gsk_path_measure_get_length (measure));
#else
progress > 1 ? (progress - 1) * gsk_path_measure_get_length (measure) : 0.0,
(progress < 1 ? progress : 1.0) * gsk_path_measure_get_length (measure));
#endif
path = gsk_path_builder_free_to_path (builder);
stroke = gsk_stroke_new (1);
gsk_stroke_set_dash (stroke, (float[2]) { 10, 5 }, 2);
gsk_stroke_set_dash_offset (stroke, - (gdk_frame_clock_get_frame_time (frame_clock) % G_USEC_PER_SEC) * 15. / G_USEC_PER_SEC);
builder = gsk_path_builder_new ();
gsk_path_dash (path, stroke, 0.2, build_path, builder);
gsk_path_unref (path);
gsk_path_measure_get_point (measure,
(progress > 1 ? (progress - 1) : progress) * gsk_path_measure_get_length (measure),
&pos,
&tangent);
gsk_path_builder_move_to (builder, pos.x + 5 * graphene_vec2_get_x (&tangent), pos.y + 5 * graphene_vec2_get_y (&tangent));
gsk_path_builder_line_to (builder, pos.x + 3 * graphene_vec2_get_y (&tangent), pos.y + 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_line_to (builder, pos.x - 3 * graphene_vec2_get_y (&tangent), pos.y - 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_close (builder);
path = gsk_path_builder_free_to_path (builder);
gtk_path_paintable_set_path (GTK_PATH_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget))),
path);
gsk_path_unref (path);
return G_SOURCE_CONTINUE;
}
GtkWidget *
do_path_fill (GtkWidget *do_widget)
{
@@ -174,14 +321,35 @@ do_path_fill (GtkWidget *do_widget)
{
GtkWidget *picture;
GdkPaintable *paintable;
GtkMediaStream *stream;
GskPath *path;
graphene_rect_t bounds;
GskPathMeasure *measure;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Fill and Stroke");
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paintable = gtk_logo_paintable_new ();
#if 0
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
#else
stream = gtk_nuclear_media_stream_new ();
#endif
gtk_media_stream_play (stream);
gtk_media_stream_set_loop (stream, TRUE);
path = create_hexagon (window);
path = create_path_from_text (window);
gsk_path_get_bounds (path, &bounds);
paintable = gtk_path_paintable_new (path,
GDK_PAINTABLE (stream),
bounds.origin.x + bounds.size.width,
bounds.origin.y + bounds.size.height);
picture = gtk_picture_new_for_paintable (paintable);
measure = gsk_path_measure_new (path);
gtk_widget_add_tick_callback (picture, update_path, measure, (GDestroyNotify) gsk_path_measure_unref);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_CONTAIN);
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_unref (paintable);

View File

@@ -1,14 +1,13 @@
/* Path/Maze
*
* This demo shows how to use a GskPath to create a maze and use
* gsk_path_get_closest_point() to check the mouse stays
* gsk_path_measure_get_closest_point() to check the mouse stays
* on the path.
*
* It also shows off the performance of GskPath (or not) as this
* is a rather complex path.
*/
#include "config.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
@@ -132,47 +131,17 @@ gtk_maze_class_init (GtkMazeClass *klass)
widget_class->snapshot = gtk_maze_snapshot;
}
static void
celebrate (gboolean win)
{
char *path;
GtkMediaStream *stream;
if (win)
path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "complete.oga", NULL);
else
path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "suspend-error.oga", NULL);
stream = gtk_media_file_new_for_filename (path);
gtk_media_stream_set_volume (stream, 1.0);
gtk_media_stream_play (stream);
g_signal_connect (stream, "notify::ended", G_CALLBACK (g_object_unref), NULL);
g_free (path);
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkMaze *self)
{
GskPathPoint point;
float distance;
if (!self->active)
return;
if (gsk_path_get_closest_point (self->path,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point,
&distance))
{
if (distance < MAZE_STROKE_SIZE_ACTIVE / 2.f)
return;
}
celebrate (FALSE);
if (gsk_path_measure_get_closest_point (self->measure, &GRAPHENE_POINT_INIT (x, y), NULL) <= MAZE_STROKE_SIZE_ACTIVE / 2.0f)
return;
self->active = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (self));

View File

@@ -1,323 +0,0 @@
/* Path/Spinner
*
* This demo shows how to use GskPath to draw a simple animation
* that could be used as a spinner.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#undef SHOW_CONTROLS
#define GTK_TYPE_SPINNER_PAINTABLE (gtk_spinner_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkSpinnerPaintable, gtk_spinner_paintable, GTK, SPINNER_PAINTABLE, GObject)
struct _GtkSpinnerPaintable
{
GObject parent_instance;
gint64 start_time;
int width;
double angle;
double completion;
GskPath *circle;
GskPath *path;
GskStroke *stroke;
GdkRGBA color;
GdkRGBA circle_color;
#ifdef SHOW_CONTROLS
GskPath *controls;
GdkRGBA control_color;
#endif
};
struct _GtkSpinnerPaintableClass
{
GObjectClass parent_class;
};
static int
gtk_spinner_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
return self->width;
}
static int
gtk_spinner_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
return self->width;
}
static void
gtk_spinner_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
gtk_snapshot_append_stroke (snapshot, self->circle, self->stroke, &self->circle_color);
gtk_snapshot_append_stroke (snapshot, self->path, self->stroke, &self->color);
#ifdef SHOW_CONTROLS
GskStroke *stroke = gsk_stroke_new (1);
gtk_snapshot_append_stroke (snapshot, self->controls, stroke, &self->control_color);
gsk_stroke_free (stroke);
#endif
}
static GdkPaintableFlags
gtk_spinner_paintable_get_flags (GdkPaintable *paintable)
{
return GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_spinner_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->get_intrinsic_width = gtk_spinner_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_spinner_paintable_get_intrinsic_height;
iface->snapshot = gtk_spinner_paintable_snapshot;
iface->get_flags = gtk_spinner_paintable_get_flags;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkSpinnerPaintable, gtk_spinner_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_spinner_paintable_paintable_init))
static void
gtk_spinner_paintable_dispose (GObject *object)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (object);
gsk_path_unref (self->circle);
gsk_path_unref (self->path);
#ifdef SHOW_CONTROLS
gsk_path_unref (self->controls);
#endif
gsk_stroke_free (self->stroke);
G_OBJECT_CLASS (gtk_spinner_paintable_parent_class)->dispose (object);
}
static void
gtk_spinner_paintable_class_init (GtkSpinnerPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_spinner_paintable_dispose;
}
static void
gtk_spinner_paintable_init (GtkSpinnerPaintable *self)
{
}
static GdkPaintable *
gtk_spinner_paintable_new (void)
{
GtkSpinnerPaintable *self;
GskPathBuilder *builder;
self = g_object_new (GTK_TYPE_SPINNER_PAINTABLE, NULL);
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (50, 50), 40);
self->circle = gsk_path_builder_free_to_path (builder);
self->width = 100;
self->angle = 0;
self->completion = 1;
gdk_rgba_parse (&self->color, "green");
gdk_rgba_parse (&self->circle_color, "lightgray");
#ifdef SHOW_CONTROLS
gdk_rgba_parse (&self->control_color, "black");
#endif
self->stroke = gsk_stroke_new (5);
return GDK_PAINTABLE (self);
}
#ifdef SHOW_CONTROLS
static gboolean
add_controls (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer data)
{
GskPathBuilder *builder = data;
switch (op)
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_CLOSE:
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
break;
case GSK_PATH_QUAD:
case GSK_PATH_CONIC:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
gsk_path_builder_line_to (builder, pts[2].x, pts[2].y);
break;
case GSK_PATH_CUBIC:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
gsk_path_builder_line_to (builder, pts[2].x, pts[2].y);
gsk_path_builder_line_to (builder, pts[3].x, pts[3].y);
break;
default:
g_assert_not_reached ();
}
return TRUE;
}
#endif
static void
update_path (GtkSpinnerPaintable *self)
{
GskPathBuilder *builder;
GskPathPoint start, end;
graphene_point_t p0, p1;
float start_angle, end_angle;
start_angle = self->angle;
end_angle = fmod (self->angle + 360 * self->completion / 100, 360);
p0 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * start_angle / 180),
50 + 40 * sin (M_PI * start_angle / 180));
p1 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * end_angle / 180),
50 + 40 * sin (M_PI * end_angle / 180));
g_clear_pointer (&self->path, gsk_path_unref);
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start, NULL);
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end, NULL);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, self->circle, &start, &end);
self->path = gsk_path_builder_free_to_path (builder);
#ifdef SHOW_CONTROLS
g_clear_pointer (&self->controls, gsk_path_unref);
builder = gsk_path_builder_new ();
gsk_path_foreach (self->path, -1, add_controls, builder);
self->controls = gsk_path_builder_free_to_path (builder);
#endif
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
static void
gtk_spinner_paintable_set_completion (GtkSpinnerPaintable *self,
float completion)
{
self->completion = CLAMP (completion, 0, 100);
update_path (self);
}
static float
gtk_spinner_paintable_get_completion (GtkSpinnerPaintable *self)
{
return self->completion;
}
static void
gtk_spinner_paintable_set_frame_time (GtkSpinnerPaintable *self,
gint64 time)
{
double delta;
if (self->start_time == 0)
self->start_time = time;
delta = (time - self->start_time) / (double) G_TIME_SPAN_SECOND;
self->angle = fmod (60 * delta, 360);
update_path (self);
}
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *clock,
gpointer data)
{
GtkSpinnerPaintable *self = data;
gtk_spinner_paintable_set_frame_time (self, gdk_frame_clock_get_frame_time (clock));
return G_SOURCE_CONTINUE;
}
static gboolean
progress_timeout (gpointer data)
{
GtkSpinnerPaintable *self = data;
static float progress_delta = 0.5;
float progress;
progress = gtk_spinner_paintable_get_completion (self);
if (progress >= 100 || progress <= 0)
progress_delta = -progress_delta;
gtk_spinner_paintable_set_completion (self, progress + progress_delta);
return G_SOURCE_CONTINUE;
}
static void
unset_timeout (gpointer data)
{
g_source_remove (GPOINTER_TO_UINT (data));
}
GtkWidget *
do_path_spinner (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *picture;
GdkPaintable *paintable;
guint timeout_id;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Spinner");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
paintable = gtk_spinner_paintable_new ();
picture = gtk_picture_new_for_paintable (paintable);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_CONTAIN);
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_unref (paintable);
gtk_widget_add_tick_callback (picture, tick_cb, paintable, NULL);
timeout_id = g_timeout_add (100, progress_timeout, paintable);
g_object_set_data_full (G_OBJECT (picture), "timeout", GUINT_TO_POINTER (timeout_id), unset_timeout);
gtk_window_set_child (GTK_WINDOW (window), picture);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,319 +0,0 @@
/* Path/Sweep
*
* This demo shows how path intersections can be used.
*
* The world map that is used here is a path with 211 lines and 1569 cubic
* Bėzier segments in 121 contours.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define GTK_TYPE_PATH_SWEEP (gtk_path_sweep_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathSweep, gtk_path_sweep, GTK, PATH_SWEEP, GtkWidget)
#define POINT_SIZE 8
enum {
PROP_0,
PROP_PATH,
N_PROPS
};
struct _GtkPathSweep
{
GtkWidget parent_instance;
GskPath *path;
graphene_rect_t bounds;
float y_pos;
gboolean in;
};
struct _GtkPathSweepClass
{
GtkWidgetClass parent_class;
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathSweep, gtk_path_sweep, GTK_TYPE_WIDGET)
static gboolean
intersection_cb (GskPath *path1,
const GskPathPoint *point1,
GskPath *path2,
const GskPathPoint *point2,
GskPathIntersection kind,
gpointer data)
{
GskPathBuilder *builder = data;
graphene_point_t p;
gsk_path_point_get_position (point1, path1, &p);
gsk_path_builder_add_circle (builder, &p, 4);
return TRUE;
}
static GskPath *
get_intersection_path (GskPath *path1,
GskPath *path2)
{
GskPathBuilder *builder = gsk_path_builder_new ();
gsk_path_foreach_intersection (path1, path2, intersection_cb, builder);
return gsk_path_builder_to_path (builder);
}
static void
gtk_path_sweep_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkPathSweep *self = GTK_PATH_SWEEP (widget);
GskStroke *stroke;
if (self->path == NULL)
return;
gtk_snapshot_save (snapshot);
stroke = gsk_stroke_new (2.0);
gtk_snapshot_append_stroke (snapshot, self->path, stroke, &(GdkRGBA) { 0, 0, 0, 1 });
if (self->in)
{
graphene_rect_t bounds;
GskPathBuilder *builder;
GskPath *line, *isecs;
gsk_path_get_stroke_bounds (self->path, stroke, &bounds);
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, bounds.origin.x, bounds.origin.y + self->y_pos);
gsk_path_builder_line_to (builder, bounds.origin.x + bounds.size.width, bounds.origin.y + self->y_pos);
line = gsk_path_builder_free_to_path (builder);
gtk_snapshot_append_stroke (snapshot, line, stroke, &(GdkRGBA) { 0, 0, 0, 1 });
isecs = get_intersection_path (self->path, line);
gtk_snapshot_append_fill (snapshot, isecs, GSK_FILL_RULE_WINDING, &(GdkRGBA) { 1, 0, 0, 1 });
gtk_snapshot_append_stroke (snapshot, isecs, stroke, &(GdkRGBA) { 0, 0, 0, 1 });
gsk_path_unref (isecs);
gsk_path_unref (line);
}
gsk_stroke_free (stroke);
gtk_snapshot_restore (snapshot);
}
static void
gtk_path_sweep_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkPathSweep *self = GTK_PATH_SWEEP (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = (int) ceilf (self->bounds.size.width);
else
*minimum = *natural = (int) ceilf (self->bounds.size.height);
}
static void
gtk_path_sweep_set_path (GtkPathSweep *self,
GskPath *path)
{
if (self->path == path)
return;
g_clear_pointer (&self->path, gsk_path_unref);
graphene_rect_init (&self->bounds, 0, 0, 0, 0);
if (path)
{
GskStroke *stroke;
self->path = gsk_path_ref (path);
stroke = gsk_stroke_new (2.0);
gsk_path_get_stroke_bounds (path, stroke, &self->bounds);
gsk_stroke_free (stroke);
}
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PATH]);
}
static void
gtk_path_sweep_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPathSweep *self = GTK_PATH_SWEEP (object);
switch (prop_id)
{
case PROP_PATH:
gtk_path_sweep_set_path (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_sweep_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPathSweep *self = GTK_PATH_SWEEP (object);
switch (prop_id)
{
case PROP_PATH:
g_value_set_boxed (value, self->path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_sweep_dispose (GObject *object)
{
GtkPathSweep *self = GTK_PATH_SWEEP (object);
g_clear_pointer (&self->path, gsk_path_unref);
G_OBJECT_CLASS (gtk_path_sweep_parent_class)->dispose (object);
}
static void
gtk_path_sweep_class_init (GtkPathSweepClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_sweep_dispose;
object_class->set_property = gtk_path_sweep_set_property;
object_class->get_property = gtk_path_sweep_get_property;
widget_class->snapshot = gtk_path_sweep_snapshot;
widget_class->measure = gtk_path_sweep_measure;
properties[PROP_PATH] =
g_param_spec_boxed ("path", NULL, NULL,
GSK_TYPE_PATH,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
motion_cb (GtkEventControllerMotion *controller,
double x,
double y,
gpointer data)
{
GtkPathSweep *self = data;
self->y_pos = y;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
enter_cb (GtkEventControllerMotion *controller,
double x,
double y,
gpointer data)
{
GtkPathSweep *self = data;
self->in = TRUE;
self->y_pos = y;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
leave_cb (GtkEventControllerMotion *controller,
gpointer data)
{
GtkPathSweep *self = data;
self->in = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
gtk_path_sweep_init (GtkPathSweep *self)
{
GtkEventController *controller;
/* Data taken from
* https://commons.wikimedia.org/wiki/Maps_of_the_world#/media/File:Simplified_blank_world_map_without_Antartica_(no_borders).svg
*/
GBytes *data = g_resources_lookup_data ("/path_sweep/path_world.txt", 0, NULL);
GskPath *path = gsk_path_parse (g_bytes_get_data (data, NULL));
g_bytes_unref (data);
gtk_path_sweep_set_path (self, path);
gsk_path_unref (path);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "motion", G_CALLBACK (motion_cb), self);
g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), self);
g_signal_connect (controller, "leave", G_CALLBACK (leave_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
GtkWidget *
gtk_path_sweep_new (void)
{
GtkPathSweep *self;
self = g_object_new (GTK_TYPE_PATH_SWEEP, NULL);
return GTK_WIDGET (self);
}
GtkWidget *
do_path_sweep (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_PATH_SWEEP);
builder = gtk_builder_new_from_resource ("/path_sweep/path_sweep.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">World Map</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkPathSweep" id="view">
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</property>
</object>
</interface>

View File

@@ -1,9 +1,6 @@
/* Path/Text
*
* This demo shows how to use GskPath to transform a path along another path.
*
* It also demonstrates that paths can be filled with more interesting
* content than just plain colors.
* This demo shows how to use GskPath to animate a path along another path.
*/
#include <glib/gi18n.h>
@@ -31,8 +28,10 @@ struct _GtkPathWidget
graphene_point_t points[4];
guint active_point;
float line_closest;
GskPath *line_path;
GskPathMeasure *line_measure;
GskPath *text_path;
GdkPaintable *background;
@@ -89,18 +88,11 @@ gtk_path_transform_point (GskPathMeasure *measure,
graphene_point_t *res)
{
graphene_vec2_t tangent;
GskPathPoint point;
if (gsk_path_measure_get_point (measure, (pt->x + offset->x) * scale, &point))
{
GskPath *path = gsk_path_measure_get_path (measure);
gsk_path_measure_get_point (measure, (pt->x + offset->x) * scale, res, &tangent);
gsk_path_point_get_position (&point, path, res);
gsk_path_point_get_tangent (&point, path, GSK_PATH_TO_END, &tangent);
res->x -= (pt->y + offset->y) * scale * graphene_vec2_get_y (&tangent);
res->y += (pt->y + offset->y) * scale * graphene_vec2_get_x (&tangent);
}
res->x -= (pt->y + offset->y) * scale * graphene_vec2_get_y (&tangent);
res->y += (pt->y + offset->y) * scale * graphene_vec2_get_x (&tangent);
}
static gboolean
@@ -130,22 +122,13 @@ gtk_path_transform_op (GskPathOperation op,
}
break;
case GSK_PATH_QUAD:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_quad_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y);
}
break;
case GSK_PATH_CUBIC:
case GSK_PATH_CURVE:
{
graphene_point_t res[3];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[2]);
gsk_path_builder_cubic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
gsk_path_builder_curve_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
}
break;
@@ -153,7 +136,7 @@ gtk_path_transform_op (GskPathOperation op,
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, weight);
}
break;
@@ -171,11 +154,10 @@ gtk_path_transform_op (GskPathOperation op,
}
static GskPath *
gtk_path_transform (GskPath *line_path,
gtk_path_transform (GskPathMeasure *measure,
GskPath *path,
const graphene_point_t *offset)
{
GskPathMeasure *measure = gsk_path_measure_new (line_path);
GtkPathTransform transform = { measure, gsk_path_builder_new (), *offset };
graphene_rect_t bounds;
@@ -185,9 +167,7 @@ gtk_path_transform (GskPath *line_path,
else
transform.scale = 1.0f;
gsk_path_foreach (path, -1, gtk_path_transform_op, &transform);
gsk_path_measure_unref (measure);
gsk_path_foreach (path, GSK_PATH_FOREACH_ALLOW_CURVE, gtk_path_transform_op, &transform);
return gsk_path_builder_free_to_path (transform.builder);
}
@@ -204,6 +184,7 @@ gtk_path_widget_clear_paths (GtkPathWidget *self)
gtk_path_widget_clear_text_path (self);
g_clear_pointer (&self->line_path, gsk_path_unref);
g_clear_pointer (&self->line_measure, gsk_path_measure_unref);
}
static void
@@ -214,8 +195,11 @@ gtk_path_widget_create_text_path (GtkPathWidget *self)
gtk_path_widget_clear_text_path (self);
if (self->line_measure == NULL)
return;
path = create_path_from_text (GTK_WIDGET (self), self->text, &offset);
self->text_path = gtk_path_transform (self->line_path, path, &offset);
self->text_path = gtk_path_transform (self->line_measure, path, &offset);
gsk_path_unref (path);
}
@@ -235,12 +219,14 @@ gtk_path_widget_create_paths (GtkPathWidget *self)
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder,
self->points[0].x * width, self->points[0].y * height);
gsk_path_builder_cubic_to (builder,
gsk_path_builder_curve_to (builder,
self->points[1].x * width, self->points[1].y * height,
self->points[2].x * width, self->points[2].y * height,
self->points[3].x * width, self->points[3].y * height);
self->line_path = gsk_path_builder_free_to_path (builder);
self->line_measure = gsk_path_measure_new (self->line_path);
gtk_path_widget_create_text_path (self);
}
@@ -320,6 +306,23 @@ gtk_path_widget_snapshot (GtkWidget *widget,
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
if (self->line_closest >= 0)
{
GskPathBuilder *builder;
graphene_point_t closest;
builder = gsk_path_builder_new ();
gsk_path_measure_get_point (self->line_measure, self->line_closest, &closest, NULL);
gsk_path_builder_add_circle (builder, &closest, POINT_SIZE);
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
}
@@ -500,22 +503,21 @@ pointer_motion (GtkEventControllerMotion *controller,
double y,
GtkPathWidget *self)
{
GskPathPoint point;
gsk_path_measure_get_closest_point_full (self->line_measure,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&self->line_closest,
NULL, NULL, NULL);
if (gsk_path_get_closest_point (self->line_path,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point,
NULL))
{
gtk_widget_queue_draw (GTK_WIDGET (self));
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkPathWidget *self)
{
self->line_closest = -1;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -536,6 +538,8 @@ gtk_path_widget_init (GtkPathWidget *self)
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->line_closest = -1;
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);

View File

@@ -1,373 +0,0 @@
/* Path/Walk
*
* This demo draws a world map and shows how to animate objects along a GskPath.
*
* The world map that is used here is a path with 211 lines and 1569 cubic
* Bėzier segments in 121 contours.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define GTK_TYPE_PATH_WALK (gtk_path_walk_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathWalk, gtk_path_walk, GTK, PATH_WALK, GtkWidget)
#define POINT_SIZE 8
enum {
PROP_0,
PROP_N_POINTS,
PROP_PATH,
N_PROPS
};
struct _GtkPathWalk
{
GtkWidget parent_instance;
GskPath *path;
GskPathMeasure *measure;
graphene_rect_t bounds;
GskPath *arrow_path;
guint n_points;
};
struct _GtkPathWalkClass
{
GtkWidgetClass parent_class;
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathWalk, gtk_path_walk, GTK_TYPE_WIDGET)
static void
rgba_init_from_hsla (GdkRGBA *rgba,
float hue,
float saturation,
float lightness,
float alpha)
{
float m1, m2;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness + saturation - lightness * saturation;
m1 = 2 * lightness - m2;
rgba->alpha = alpha;
if (saturation == 0)
{
rgba->red = lightness;
rgba->green = lightness;
rgba->blue = lightness;
}
else
{
hue = hue + 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->red = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->red = m2;
else if (hue < 240)
rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->red = m1;
hue -= 120;
if (hue < 0)
hue += 360;
if (hue < 60)
rgba->green = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->green = m2;
else if (hue < 240)
rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->green = m1;
hue -= 120;
if (hue < 0)
hue += 360;
if (hue < 60)
rgba->blue = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->blue = m2;
else if (hue < 240)
rgba->blue = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->blue = m1;
}
}
static void
gtk_path_walk_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkPathWalk *self = GTK_PATH_WALK (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
float length, progress;
GskStroke *stroke;
guint i;
if (self->path == NULL)
return;
gtk_snapshot_save (snapshot);
stroke = gsk_stroke_new (2.0);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_stroke_free (stroke);
length = gsk_path_measure_get_length (self->measure);
progress = 25.f * gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)) / G_USEC_PER_SEC;
stroke = gsk_stroke_new (1.0);
for (i = 0; i < self->n_points; i++)
{
GskPathPoint point;
graphene_point_t position;
float angle;
GdkRGBA color;
float distance;
distance = i * length / self->n_points;
distance = fmod (distance + progress, length);
gsk_path_measure_get_point (self->measure, distance, &point);
gsk_path_point_get_position (&point, self->path, &position);
angle = gsk_path_point_get_rotation (&point, self->path, GSK_PATH_FROM_START);
rgba_init_from_hsla (&color, 360.f * i / self->n_points, 1, 0.5, 1);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &position);
gtk_snapshot_rotate (snapshot, angle);
gtk_snapshot_append_fill (snapshot, self->arrow_path, GSK_FILL_RULE_EVEN_ODD, &color);
gtk_snapshot_append_stroke (snapshot, self->arrow_path, stroke, &(GdkRGBA) { 0, 0, 0, 1 });
gtk_snapshot_restore (snapshot);
}
gsk_stroke_free (stroke);
gtk_snapshot_restore (snapshot);
}
static void
gtk_path_walk_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkPathWalk *self = GTK_PATH_WALK (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = (int) ceilf (self->bounds.size.width);
else
*minimum = *natural = (int) ceilf (self->bounds.size.height);
}
static void
gtk_path_walk_set_n_points (GtkPathWalk *self,
gsize n_points)
{
if (self->n_points == n_points)
return;
self->n_points = n_points;
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_POINTS]);
}
static void
gtk_path_walk_set_path (GtkPathWalk *self,
GskPath *path)
{
if (self->path == path)
return;
g_clear_pointer (&self->path, gsk_path_unref);
graphene_rect_init (&self->bounds, 0, 0, 0, 0);
if (path)
{
GskStroke *stroke;
self->path = gsk_path_ref (path);
stroke = gsk_stroke_new (2.0);
gsk_path_get_stroke_bounds (path, stroke, &self->bounds);
gsk_stroke_free (stroke);
self->measure = gsk_path_measure_new (self->path);
}
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PATH]);
}
static void
gtk_path_walk_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPathWalk *self = GTK_PATH_WALK (object);
switch (prop_id)
{
case PROP_N_POINTS:
gtk_path_walk_set_n_points (self, g_value_get_uint (value));
break;
case PROP_PATH:
gtk_path_walk_set_path (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_walk_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPathWalk *self = GTK_PATH_WALK (object);
switch (prop_id)
{
case PROP_N_POINTS:
g_value_set_uint (value, self->n_points);
break;
case PROP_PATH:
g_value_set_boxed (value, self->path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_walk_dispose (GObject *object)
{
GtkPathWalk *self = GTK_PATH_WALK (object);
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
g_clear_pointer (&self->arrow_path, gsk_path_unref);
G_OBJECT_CLASS (gtk_path_walk_parent_class)->dispose (object);
}
static void
gtk_path_walk_class_init (GtkPathWalkClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_walk_dispose;
object_class->set_property = gtk_path_walk_set_property;
object_class->get_property = gtk_path_walk_get_property;
widget_class->snapshot = gtk_path_walk_snapshot;
widget_class->measure = gtk_path_walk_measure;
properties[PROP_N_POINTS] =
g_param_spec_uint ("n-points",
NULL, NULL,
1, G_MAXUINT,
500,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_PATH] =
g_param_spec_boxed ("path",
NULL, NULL,
GSK_TYPE_PATH,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static gboolean
tick_tick_tick (GtkWidget *self,
GdkFrameClock *frame_clock,
gpointer unused)
{
gtk_widget_queue_draw (GTK_WIDGET (self));
return G_SOURCE_CONTINUE;
}
static void
gtk_path_walk_init (GtkPathWalk *self)
{
/* Data taken from
* https://commons.wikimedia.org/wiki/Maps_of_the_world#/media/File:Simplified_blank_world_map_without_Antartica_(no_borders).svg
*/
GBytes *data = g_resources_lookup_data ("/path_walk/path_world.txt", 0, NULL);
GskPath *path = gsk_path_parse (g_bytes_get_data (data, NULL));
g_bytes_unref (data);
gtk_path_walk_set_path (self, path);
gsk_path_unref (path);
self->arrow_path = gsk_path_parse ("M 5 0 L 0 -5. 0 -2, -5 -2, -5 2, 0 2, 0 5 Z");
self->n_points = 500;
gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_tick_tick, NULL, NULL);
}
GtkWidget *
gtk_path_walk_new (void)
{
GtkPathWalk *self;
self = g_object_new (GTK_TYPE_PATH_WALK, NULL);
return GTK_WIDGET (self);
}
GtkWidget *
do_path_walk (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_PATH_WALK);
builder = gtk_builder_new_from_resource ("/path_walk/path_walk.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">World Map</property>
<property name="titlebar">
<object class="GtkHeaderBar">
<child type="end">
<object class="GtkSpinButton">
<property name="adjustment">
<object class="GtkAdjustment" id="adjustment">
<property name="lower">0</property>
<property name="upper">5000</property>
<property name="value">500</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
</property>
</object>
</child>
</object>
</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkPathWalk" id="view">
<property name="n-points" bind-source="adjustment" bind-property="value"/>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</property>
</object>
</interface>

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -6,6 +6,6 @@
* Also, when adding new style properties, please add them here.
*/
window.demo * {
* {
all: unset;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -188,20 +188,10 @@ do_spinbutton (GtkWidget *do_widget)
if (!window)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkAdjustment *adj;
GtkWidget *label;
scope = gtk_builder_cscope_new ();
builder = gtk_builder_new ();
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_hex_spin_input);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_hex_spin_output);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_time_spin_input);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_time_spin_output);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_month_spin_input);
gtk_builder_cscope_add_callback (GTK_BUILDER_CSCOPE (scope), spinbutton_month_spin_output);
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/spinbutton/spinbutton.ui", NULL);
builder = gtk_builder_new_from_resource ("/spinbutton/spinbutton.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
@@ -243,7 +233,6 @@ do_spinbutton (GtkWidget *do_widget)
NULL, NULL);
g_object_unref (builder);
g_object_unref (scope);
}
if (!gtk_widget_get_visible (window))

View File

@@ -27,6 +27,7 @@ GtkWidget *
do_spinner (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *content_area;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *button;
@@ -34,19 +35,28 @@ do_spinner (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Spinner");
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
window = gtk_dialog_new_with_buttons ("Spinner",
GTK_WINDOW (do_widget),
0,
_("_Close"),
GTK_RESPONSE_NONE,
NULL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "response",
G_CALLBACK (gtk_window_destroy), NULL);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_top (vbox, 5);
gtk_widget_set_margin_bottom (vbox, 5);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (window));
G_GNUC_END_IGNORE_DEPRECATIONS
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_widget_set_margin_start (vbox, 5);
gtk_widget_set_margin_end (vbox, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
gtk_widget_set_margin_top (vbox, 5);
gtk_widget_set_margin_bottom (vbox, 5);
gtk_box_append (GTK_BOX (content_area), vbox);
/* Sensitive */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);

View File

@@ -801,7 +801,7 @@ suggestion_entry_key_pressed (GtkEventControllerKey *controller,
selected = matches - 1;
}
gtk_list_view_scroll_to (GTK_LIST_VIEW (self->list), selected, GTK_LIST_SCROLL_SELECT, NULL);
gtk_single_selection_set_selected (self->selection, selected);
return TRUE;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 844 B

View File

@@ -7,68 +7,186 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static void
draw_text (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
#define TEXT_TYPE_MASK_DEMO (text_mask_demo_get_type ())
G_DECLARE_FINAL_TYPE (TextMaskDemo, text_mask_demo, TEXT, MASK_DEMO, GtkWidget)
struct _TextMaskDemo
{
cairo_pattern_t *pattern;
PangoLayout *layout;
GtkWidget parent_instance;
char *text;
PangoFontDescription *desc;
GskPath *path;
};
cairo_save (cr);
struct _TextMaskDemoClass
{
GtkWidgetClass parent_class;
};
layout = gtk_widget_create_pango_layout (GTK_WIDGET (da), "Pango power!\nPango power!\nPango power!");
desc = pango_font_description_from_string ("sans bold 34");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
G_DEFINE_TYPE (TextMaskDemo, text_mask_demo, GTK_TYPE_WIDGET)
cairo_move_to (cr, 30, 20);
pango_cairo_layout_path (cr, layout);
g_object_unref (layout);
static void
update_path (TextMaskDemo *demo)
{
PangoLayout *layout;
GskPathBuilder *builder;
pattern = cairo_pattern_create_linear (0.0, 0.0, width, height);
cairo_pattern_add_color_stop_rgb (pattern, 0.0, 1.0, 0.0, 0.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.2, 1.0, 0.0, 0.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.3, 1.0, 1.0, 0.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.4, 0.0, 1.0, 0.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.6, 0.0, 1.0, 1.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.7, 0.0, 0.0, 1.0);
cairo_pattern_add_color_stop_rgb (pattern, 0.8, 1.0, 0.0, 1.0);
cairo_pattern_add_color_stop_rgb (pattern, 1.0, 1.0, 0.0, 1.0);
g_clear_pointer (&demo->path, gsk_path_unref);
cairo_set_source (cr, pattern);
cairo_fill_preserve (cr);
layout = gtk_widget_create_pango_layout (GTK_WIDGET (demo), demo->text);
pango_layout_set_font_description (layout, demo->desc);
cairo_pattern_destroy (pattern);
builder = gsk_path_builder_new ();
gsk_path_builder_add_layout (builder, layout);
demo->path = gsk_path_builder_free_to_path (builder);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_set_line_width (cr, 0.5);
cairo_stroke (cr);
gtk_widget_queue_draw (GTK_WIDGET (demo));
}
cairo_restore (cr);
static void
text_mask_demo_init (TextMaskDemo *demo)
{
demo->text = g_strdup ("No text. No fun");
demo->desc = pango_font_description_from_string ("Cantarell 20");
update_path (demo);
}
static void
text_mask_demo_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
TextMaskDemo *demo = TEXT_MASK_DEMO (widget);
float width, height;
GskColorStop stops[4];
GskStroke *stroke;
gdk_rgba_parse (&stops[0].color, "red");
gdk_rgba_parse (&stops[1].color, "green");
gdk_rgba_parse (&stops[2].color, "yellow");
gdk_rgba_parse (&stops[3].color, "blue");
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
stops[0].offset = 0;
stops[1].offset = 0.25;
stops[2].offset = 0.50;
stops[3].offset = 0.75;
gtk_snapshot_push_fill (snapshot, demo->path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
stops, 4);
gtk_snapshot_pop (snapshot);
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, demo->path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot,
&(GdkRGBA){ 0, 0, 0, 1 },
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
void
text_mask_demo_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum_size,
int *natural_size,
int *minimum_baseline,
int *natural_baseline)
{
TextMaskDemo *demo = TEXT_MASK_DEMO (widget);
graphene_rect_t rect;
gsk_path_get_bounds (demo->path, &rect);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum_size = *natural_size = rect.size.width;
else
*minimum_size = *natural_size = rect.size.height;
}
static void
text_mask_demo_finalize (GObject *object)
{
TextMaskDemo *demo = TEXT_MASK_DEMO (object);
g_free (demo->text);
pango_font_description_free (demo->desc);
gsk_path_unref (demo->path);
G_OBJECT_CLASS (text_mask_demo_parent_class)->finalize (object);
}
static void
text_mask_demo_class_init (TextMaskDemoClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->finalize = text_mask_demo_finalize;
widget_class->snapshot = text_mask_demo_snapshot;
widget_class->measure = text_mask_demo_measure;
}
static GtkWidget *
text_mask_demo_new (void)
{
return g_object_new (text_mask_demo_get_type (), NULL);
}
static void
text_mask_demo_set_text (TextMaskDemo *demo,
const char *text)
{
g_free (demo->text);
demo->text = g_strdup (text);
update_path (demo);
}
static void
text_mask_demo_set_font (TextMaskDemo *demo,
PangoFontDescription *desc)
{
pango_font_description_free (demo->desc);
demo->desc = pango_font_description_copy (desc);
update_path (demo);
}
GtkWidget *
do_textmask (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
static GtkWidget *da;
static GtkWidget *demo;
if (!window)
{
PangoFontDescription *desc;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_widget_set_size_request (window, 400, 240);
gtk_window_set_title (GTK_WINDOW (window), "Text Mask");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
da = gtk_drawing_area_new ();
demo = text_mask_demo_new ();
text_mask_demo_set_text (TEXT_MASK_DEMO (demo), "Pango power!\nPango power!\nPango power!");
desc = pango_font_description_from_string ("Sans Bold 34");
text_mask_demo_set_font (TEXT_MASK_DEMO (demo), desc);
pango_font_description_free (desc);
gtk_window_set_child (GTK_WINDOW (window), da);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_text, NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), demo);
}
if (!gtk_widget_get_visible (window))

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -3,6 +3,7 @@ node_editor_sources = [
'main.c',
'node-editor-application.c',
'node-editor-window.c',
'rendernodeutils.c'
]
node_editor_resources = gnome.compile_resources('node_editor_resources',

View File

@@ -22,6 +22,7 @@
#include "node-editor-window.h"
#include "gtkrendererpaintableprivate.h"
#include "rendernodeutilsprivate.h"
#include "gsk/gskrendernodeparserprivate.h"
#include "gsk/gl/gskglrenderer.h"
@@ -61,8 +62,10 @@ struct _NodeEditorWindow
GtkWidget *scale_scale;
GtkWidget *renderer_listbox;
GListStore *saved_nodes;
GListStore *renderers;
GskRenderNode *node;
GtkAdjustment *compare_progress;
GFile *file;
GFileMonitor *file_monitor;
@@ -130,6 +133,7 @@ deserialize_error_func (const GskParseLocation *start_location,
g_array_append_val (self->errors, text_view_error);
}
#if 0
static void
text_iter_skip_alpha_backward (GtkTextIter *iter)
{
@@ -165,33 +169,22 @@ text_iter_skip_whitespace_backward (GtkTextIter *iter)
gtk_text_iter_backward_char (iter);
}
}
#endif
static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
node_changed (NodeEditorWindow *self)
{
char *text;
GBytes *bytes;
GtkTextIter iter;
GtkTextIter start, end;
float scale;
GskRenderNode *big_node;
g_array_remove_range (self->errors, 0, self->errors->len);
text = get_current_text (self->text_buffer);
text_buffer_remove_all_tags (self->text_buffer);
bytes = g_bytes_new_take (text, strlen (text));
g_clear_pointer (&self->node, gsk_render_node_unref);
/* If this is too slow, go fix the parser performance */
self->node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
scale = gtk_scale_button_get_value (GTK_SCALE_BUTTON (self->scale_scale));
if (self->node && scale != 0.)
{
GskTransform *transform;
scale = pow (2., scale);
big_node = gsk_transform_node_new (self->node, gsk_transform_scale (NULL, scale, scale));
transform = gsk_transform_scale (NULL, scale, scale);
big_node = gsk_transform_node_new (self->node, transform);
gsk_transform_unref (transform);
}
else if (self->node)
{
@@ -202,14 +195,13 @@ text_changed (GtkTextBuffer *buffer,
big_node = NULL;
}
g_bytes_unref (bytes);
if (self->node)
{
/* XXX: Is this code necessary or can we have API to turn nodes into paintables? */
GtkSnapshot *snapshot;
GdkPaintable *paintable;
graphene_rect_t bounds;
guint i;
guint i, n;
snapshot = gtk_snapshot_new ();
gsk_render_node_get_bounds (big_node, &bounds);
@@ -225,6 +217,8 @@ text_changed (GtkTextBuffer *buffer,
gtk_snapshot_append_node (snapshot, self->node);
paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size);
n = g_list_model_get_n_items (G_LIST_MODEL (self->saved_nodes));
g_list_store_splice (self->saved_nodes, MAX (n, 1) - 1, MIN (n, 1), (gpointer[1]) { paintable }, 1);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i++)
{
gpointer item = g_list_model_get_item (G_LIST_MODEL (self->renderers), i);
@@ -240,7 +234,30 @@ text_changed (GtkTextBuffer *buffer,
}
g_clear_pointer (&big_node, gsk_render_node_unref);
}
static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
{
char *text;
GBytes *bytes;
g_array_remove_range (self->errors, 0, self->errors->len);
text = get_current_text (self->text_buffer);
text_buffer_remove_all_tags (self->text_buffer);
bytes = g_bytes_new_take (text, strlen (text));
g_clear_pointer (&self->node, gsk_render_node_unref);
/* If this is too slow, go fix the parser performance */
self->node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
node_changed (self);
g_bytes_unref (bytes);
#if 0
gtk_text_buffer_get_start_iter (self->text_buffer, &iter);
while (!gtk_text_iter_is_end (&iter))
@@ -307,6 +324,18 @@ text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_get_bounds (self->text_buffer, &start, &end);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "no-hyphens",
&start, &end);
#endif
}
static void
stash_current_node (NodeEditorWindow *self)
{
GdkPaintable *last;
last = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes),
g_list_model_get_n_items (G_LIST_MODEL (self->saved_nodes)) - 1);
g_list_store_append (self->saved_nodes, last);
g_object_unref (last);
}
static void
@@ -314,7 +343,7 @@ scale_changed (GObject *object,
GParamSpec *pspec,
NodeEditorWindow *self)
{
text_changed (self->text_buffer, self);
node_changed (self);
}
static gboolean
@@ -378,7 +407,8 @@ text_view_query_tooltip_cb (GtkWidget *widget,
static gboolean
load_bytes (NodeEditorWindow *self,
GBytes *bytes);
GBytes *bytes,
gboolean stash);
static void
load_error (NodeEditorWindow *self,
@@ -396,7 +426,7 @@ load_error (NodeEditorWindow *self,
node = gtk_snapshot_free_to_node (snapshot);
bytes = gsk_render_node_serialize (node);
load_bytes (self, bytes);
load_bytes (self, bytes, TRUE);
gsk_render_node_unref (node);
g_object_unref (layout);
@@ -404,7 +434,8 @@ load_error (NodeEditorWindow *self,
static gboolean
load_bytes (NodeEditorWindow *self,
GBytes *bytes)
GBytes *bytes,
gboolean stash)
{
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
{
@@ -412,6 +443,9 @@ load_bytes (NodeEditorWindow *self,
g_bytes_unref (bytes);
return FALSE;
}
if (stash)
stash_current_node (self);
gtk_text_buffer_set_text (self->text_buffer,
g_bytes_get_data (bytes, NULL),
@@ -437,7 +471,29 @@ load_file_contents (NodeEditorWindow *self,
return FALSE;
}
return load_bytes (self, bytes);
return load_bytes (self, bytes, TRUE);
}
static void
saved_node_activate_cb (GtkListView *listview,
guint pos,
NodeEditorWindow *self)
{
GdkPaintable *paintable;
GtkSnapshot *snapshot;
GskRenderNode *node;
GBytes *bytes;
paintable = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes), pos);
snapshot = gtk_snapshot_new ();
gdk_paintable_snapshot (paintable, snapshot, gdk_paintable_get_intrinsic_width (paintable), gdk_paintable_get_intrinsic_height (paintable));
node = gtk_snapshot_free_to_node (snapshot);
bytes = gsk_render_node_serialize (node);
load_bytes (self, bytes, TRUE);
g_object_unref (paintable);
}
static GdkContentProvider *
@@ -466,7 +522,7 @@ on_picture_drop_read_done_cb (GObject *source,
if (g_output_stream_splice_finish (stream, res, NULL) >= 0)
{
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
if (load_bytes (self, bytes))
if (load_bytes (self, bytes, TRUE))
action = GDK_ACTION_COPY;
}
@@ -650,6 +706,10 @@ save_response_cb (GObject *source,
g_object_unref (alert);
g_error_free (error);
}
else
{
stash_current_node (self);
}
g_free (text);
g_object_unref (file);
@@ -1075,6 +1135,8 @@ testcase_save_clicked_cb (GtkWidget *button,
gtk_editable_set_text (GTK_EDITABLE (self->testcase_name_entry), "");
gtk_popover_popdown (GTK_POPOVER (self->testcase_popover));
stash_current_node (self);
out:
g_free (text);
g_free (png_file);
@@ -1083,8 +1145,54 @@ out:
}
static void
dark_mode_cb (GtkToggleButton *button,
GParamSpec *pspec,
update_compare (NodeEditorWindow *self)
{
GdkPaintable *from, *to;
GtkSnapshot *snapshot;
GskRenderNode *node, *node_from, *node_to;
GBytes *bytes;
guint n;
n = g_list_model_get_n_items (G_LIST_MODEL (self->saved_nodes));
from = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes), n - 3);
snapshot = gtk_snapshot_new ();
gdk_paintable_snapshot (from, snapshot, gdk_paintable_get_intrinsic_width (from), gdk_paintable_get_intrinsic_height (from));
node_from = gtk_snapshot_free_to_node (snapshot);
g_object_unref (from);
to = g_list_model_get_item (G_LIST_MODEL (self->saved_nodes), n - 2);
snapshot = gtk_snapshot_new ();
gdk_paintable_snapshot (to, snapshot, gdk_paintable_get_intrinsic_width (to), gdk_paintable_get_intrinsic_height (to));
node_to = gtk_snapshot_free_to_node (snapshot);
g_object_unref (to);
node = render_node_interpolate (node_from, node_to, gtk_adjustment_get_value (self->compare_progress));
bytes = gsk_render_node_serialize (node);
load_bytes (self, bytes, FALSE);
gsk_render_node_unref (node);
gsk_render_node_unref (node_to);
gsk_render_node_unref (node_from);
}
static void
compare_toggled_cb (GtkToggleButton *button,
GParamSpec *pspec,
NodeEditorWindow *self)
{
if (!gtk_toggle_button_get_active (button))
return;
stash_current_node (self);
update_compare (self);
}
static void
dark_mode_cb (GtkToggleButton *button,
GParamSpec *pspec,
NodeEditorWindow *self)
{
g_object_set (gtk_widget_get_settings (GTK_WIDGET (self)),
@@ -1115,6 +1223,7 @@ node_editor_window_finalize (GObject *object)
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
}
#if 0
static void
node_editor_window_add_renderer (NodeEditorWindow *self,
GskRenderer *renderer,
@@ -1149,11 +1258,9 @@ node_editor_window_realize (GtkWidget *widget)
GTK_WIDGET_CLASS (node_editor_window_parent_class)->realize (widget);
#if 0
node_editor_window_add_renderer (self,
NULL,
"Default");
#endif
node_editor_window_add_renderer (self,
gsk_gl_renderer_new (),
"OpenGL");
@@ -1171,6 +1278,7 @@ node_editor_window_realize (GtkWidget *widget)
gsk_cairo_renderer_new (),
"Cairo");
}
#endif
static void
node_editor_window_unrealize (GtkWidget *widget)
@@ -1553,11 +1661,12 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/node-editor/node-editor-window.ui");
widget_class->realize = node_editor_window_realize;
//widget_class->realize = node_editor_window_realize;
widget_class->unrealize = node_editor_window_unrealize;
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_view);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, picture);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, compare_progress);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, renderer_listbox);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_popover);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_error_label);
@@ -1565,18 +1674,22 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_name_entry);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_save_button);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, scale_scale);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, saved_nodes);
gtk_widget_class_bind_template_callback (widget_class, text_view_query_tooltip_cb);
gtk_widget_class_bind_template_callback (widget_class, saved_node_activate_cb);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, export_image_cb);
gtk_widget_class_bind_template_callback (widget_class, clip_image_cb);
gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, compare_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb);
gtk_widget_class_bind_template_callback (widget_class, on_picture_drag_prepare_cb);
gtk_widget_class_bind_template_callback (widget_class, on_picture_drop_cb);
gtk_widget_class_bind_template_callback (widget_class, click_gesture_pressed);
gtk_widget_class_bind_template_callback (widget_class, update_compare);
gtk_widget_class_install_action (widget_class, "smart-edit", NULL, edit_action_cb);

View File

@@ -147,6 +147,11 @@
<property name="popover">testcase_popover</property>
</object>
</child>
<child type="start">
<object class="GtkSpinner">
<property name="spinning">1</property>
</object>
</child>
<child type="end">
<object class="GtkMenuButton" id="gear_menu_button">
<property name="focus-on-click">0</property>
@@ -165,6 +170,16 @@
<signal name="notify::active" handler="dark_mode_cb" swapped="0"/>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="compare_button">
<property name="focus-on-click">0</property>
<property name="valign">center</property>
<property name="has-frame">0</property>
<property name="icon-name">emblem-synchronizing-symbolic</property>
<property name="tooltip-text" translatable="yes">Compare the last 2 items</property>
<signal name="notify::active" handler="compare_toggled_cb" swapped="0"/>
</object>
</child>
<child type="end">
<object class="GtkScaleButton" id="scale_scale">
<property name="focus-on-click">0</property>
@@ -185,85 +200,157 @@
</object>
</child>
<child>
<object class="GtkPaned">
<property name="shrink-start-child">false</property>
<property name="shrink-end-child">false</property>
<property name="position">400</property>
<property name="start-child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="wrap-mode">word</property>
<property name="monospace">1</property>
<property name="top-margin">6</property>
<property name="left-margin">6</property>
<property name="right-margin">6</property>
<property name="bottom-margin">6</property>
<property name="has-tooltip">1</property>
<property name="extra-menu">extra_menu</property>
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
<style>
<class name="editor" />
</style>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkListView">
<property name="orientation">horizontal</property>
<property name="single-click-activate">1</property>
<property name="model">
<object class="GtkNoSelection">
<property name="model">
<object class="GListStore" id="saved_nodes" />
</property>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="paintable">
<lookup name="item">GtkListItem</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<signal name="activate" handler="saved_node_activate_cb"/>
</object>
</child>
<child>
<object class="GtkPaned">
<property name="shrink-start-child">false</property>
<property name="shrink-end-child">false</property>
<property name="position">400</property>
<property name="start-child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkGestureClick">
<property name="button">1</property>
<signal name="pressed" handler="click_gesture_pressed"/>
<object class="GtkTextView" id="text_view">
<property name="wrap-mode">word</property>
<property name="monospace">1</property>
<property name="top-margin">6</property>
<property name="left-margin">6</property>
<property name="right-margin">6</property>
<property name="bottom-margin">6</property>
<property name="has-tooltip">1</property>
<property name="extra-menu">extra_menu</property>
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
<style>
<class name="editor" />
</style>
<child>
<object class="GtkGestureClick">
<property name="button">1</property>
<signal name="pressed" handler="click_gesture_pressed"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
<property name="end-child">
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="min-content-height">100</property>
<property name="min-content-width">100</property>
</property>
<property name="end-child">
<object class="GtkBox">
<child>
<object class="GtkViewport">
<object class="GtkOverlay">
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="halign">center</property>
<property name="valign">center</property>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="min-content-height">100</property>
<property name="min-content-width">100</property>
<child>
<object class="GtkDragSource">
<property name="actions">copy</property>
<signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
<object class="GtkViewport">
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
<object class="GtkDragSource">
<property name="actions">copy</property>
<signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkDropTargetAsync">
<property name="actions">copy</property>
<property name="formats">application/x-gtk-render-node</property>
<signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="overlay">
<object class="GtkBox">
<property name="margin-top">16</property>
<property name="margin-start">16</property>
<property name="margin-end">16</property>
<property name="margin-bottom">16</property>
<property name="halign">fill</property>
<property name="valign">end</property>
<property name="visible" bind-source="compare_button" bind-property="active">0</property>
<style>
<class name="osd" />
</style>
<child>
<object class="GtkScale">
<property name="width-request">200</property>
<property name="draw-value">0</property>
<property name="adjustment">
<object class="GtkAdjustment" id="compare_progress">
<property name="upper">1</property>
<property name="value">0.5</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.1</property>
<signal name="notify::value" handler="update_compare" swapped="yes"/>
</object>
</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkDropTargetAsync">
<property name="actions">copy</property>
<property name="formats">application/x-gtk-render-node</property>
<signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
<object class="GtkListBox" id="renderer_listbox">
<property name="selection-mode">none</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkListBox" id="renderer_listbox">
<property name="selection-mode">none</property>
</object>
</child>
</object>
</child>
</property>
</object>
</property>
</child>
</object>
</child>
</template>

View File

@@ -147,19 +147,6 @@ Creates a node like `gsk_cross_fade_node_new()` with the given properties.
Creates a node like `gsk_debug_node_new()` with the given properties.
### fill
| property | syntax | default | printed |
| --------- | --------------- | ---------------------- | ----------- |
| child | `<node>` | *see below* | always |
| path | `<string>` | "" | always |
| fill-rule | `<fill-rule>` | winding | always |
Creates a node like `gsk_fill_node_new()` with the given properties.
The default child node is the default color node, but created with the
bounds of the path.
### glshader
| property | syntax | default | printed |
@@ -302,24 +289,6 @@ Creates a node like `gsk_rounded_clip_node_new()` with the given properties.
Creates a node like `gsk_shadow_node_new()` with the given properties.
### stroke
| property | syntax | default | printed |
| ----------- | ------------------ | ----------------- | ----------- |
| child | `<node>` | *see below* | always |
| path | `<string>` | "" | always |
| line-width | `<number>` | 0 | non-default |
| line-cap | `<line-cap>` | butt | always |
| line-join | `<line-join>` | miter | always |
| miter-limit | `<number>` | 4 | non-default |
| dash | `<number>{+}|none` | none | non-default |
| dash-offset | `<number>` | 0 | non-default |
Creates a node like `gsk_stroke_node_new()` with the given properties.
The default child node is the default color node, but created with the
stroke bounds of the path.
### text
| property | syntax | default | printed |

View File

@@ -0,0 +1,435 @@
/*
* Copyright © 2023 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "rendernodeutilsprivate.h"
static inline double
double_interpolate (double start,
double end,
double progress)
{
return start + (end - start) * progress;
}
static inline float
float_interpolate (float start,
float end,
double progress)
{
return start + (end - start) * progress;
}
static void
rgba_interpolate (GdkRGBA *result,
const GdkRGBA *start,
const GdkRGBA *end,
double progress)
{
result->alpha = CLAMP (double_interpolate (start->alpha, end->alpha, progress), 0, 1);
if (result->alpha <= 0.0)
{
result->red = result->green = result->blue = 0.0;
}
else
{
result->red = CLAMP (double_interpolate (start->red * start->alpha, end->red * end->alpha, progress), 0, 1) / result->alpha;
result->green = CLAMP (double_interpolate (start->green * start->alpha, end->green * end->alpha, progress), 0, 1) / result->alpha;
result->blue = CLAMP (double_interpolate (start->blue * start->alpha, end->blue * end->alpha, progress), 0, 1) / result->alpha;
}
}
static void
rounded_rect_interpolate (GskRoundedRect *dest,
const GskRoundedRect *start,
const GskRoundedRect *end,
double progress)
{
guint i;
graphene_rect_interpolate (&start->bounds, &end->bounds, progress, &dest->bounds);
for (i = 0; i < 4; i++)
graphene_size_interpolate (&start->corner[i], &end->corner[i], progress, &dest->corner[i]);
}
static GskTransform *
transform_interpolate (GskTransform *start,
GskTransform *end,
double progress)
{
switch (MIN (gsk_transform_get_category (start), gsk_transform_get_category (end)))
{
case GSK_TRANSFORM_CATEGORY_IDENTITY:
return NULL;
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
{
float startx, starty, endx, endy;
gsk_transform_to_translate (start, &startx, &starty);
gsk_transform_to_translate (end, &endx, &endy);
return gsk_transform_translate (NULL,
&GRAPHENE_POINT_INIT (float_interpolate (startx, endx, progress),
float_interpolate (starty, endy, progress)));
}
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
case GSK_TRANSFORM_CATEGORY_2D:
{
float start_skew_x, start_skew_y, start_scale_x, start_scale_y, start_angle, start_dx, start_dy;
float end_skew_x, end_skew_y, end_scale_x, end_scale_y, end_angle, end_dx, end_dy;
GskTransform *transform;
gsk_transform_to_2d_components (start,
&start_skew_x, &start_skew_y,
&start_scale_x, &start_scale_y,
&start_angle,
&start_dx, &start_dy);
gsk_transform_to_2d_components (end,
&end_skew_x, &end_skew_y,
&end_scale_x, &end_scale_y,
&end_angle,
&end_dx, &end_dy);
transform = gsk_transform_translate (NULL,
&GRAPHENE_POINT_INIT (float_interpolate (start_dx, end_dx, progress),
float_interpolate (start_dy, end_dy, progress)));
transform = gsk_transform_rotate (transform,
float_interpolate (start_angle, end_angle, progress));
transform = gsk_transform_scale (transform,
float_interpolate (start_scale_x, end_scale_x, progress),
float_interpolate (start_scale_y, end_scale_y, progress));
transform = gsk_transform_skew (transform,
float_interpolate (start_skew_x, end_skew_x, progress),
float_interpolate (start_skew_y, end_skew_y, progress));
return transform;
}
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
{
graphene_matrix_t start_matrix, end_matrix, matrix;
gsk_transform_to_matrix (start, &start_matrix);
gsk_transform_to_matrix (end, &end_matrix);
graphene_matrix_interpolate (&start_matrix, &end_matrix, progress, &matrix);
return gsk_transform_matrix (NULL, &matrix);
}
default:
g_return_val_if_reached (NULL);
}
}
static void
color_stops_interpolate (GskColorStop *stops,
const GskColorStop *start_stops,
const GskColorStop *end_stops,
gsize n_stops,
double progress)
{
guint i;
for (i = 0; i < n_stops; i++)
{
stops[i].offset = float_interpolate (start_stops[i].offset, end_stops[i].offset, progress);
rgba_interpolate (&stops[i].color, &start_stops[i].color, &end_stops[i].color, progress);
}
}
GskRenderNode *
render_node_interpolate (GskRenderNode *start,
GskRenderNode *end,
double progress)
{
GskRenderNodeType start_type, end_type;
if (progress <= 0)
return gsk_render_node_ref (start);
else if (progress >= 1)
return gsk_render_node_ref (end);
start_type = gsk_render_node_get_node_type (start);
end_type = gsk_render_node_get_node_type (end);
if (start_type == end_type)
{
switch (start_type)
{
case GSK_COLOR_NODE:
{
GdkRGBA rgba;
graphene_rect_t start_bounds, end_bounds, bounds;
rgba_interpolate (&rgba, gsk_color_node_get_color (start), gsk_color_node_get_color (end), progress);
gsk_render_node_get_bounds (start, &start_bounds);
gsk_render_node_get_bounds (end, &end_bounds);
graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
return gsk_color_node_new (&rgba, &bounds);
}
case GSK_DEBUG_NODE:
{
GskRenderNode *result, *child;
/* xxx: do we need to interpolate the message somehow? */
child = render_node_interpolate (gsk_debug_node_get_child (start),
gsk_debug_node_get_child (end),
progress);
result = gsk_debug_node_new (child, g_strdup_printf ("progress %g", progress));
gsk_render_node_unref (child);
return result;
}
case GSK_CONTAINER_NODE:
{
GskRenderNode **nodes;
GskRenderNode *result;
gsize i, n_nodes;
if (gsk_container_node_get_n_children (start) != gsk_container_node_get_n_children (end))
break;
n_nodes = gsk_container_node_get_n_children (start);
nodes = g_new (GskRenderNode *, n_nodes);
for (i = 0; i < n_nodes; i++)
{
nodes[i] = render_node_interpolate (gsk_container_node_get_child (start, i),
gsk_container_node_get_child (end, i),
progress);
}
result = gsk_container_node_new (nodes, n_nodes);
for (i = 0; i < n_nodes; i++)
gsk_render_node_unref (nodes[i]);
g_free (nodes);
return result;
}
case GSK_TEXTURE_NODE:
{
graphene_rect_t start_bounds, end_bounds, bounds;
gsk_render_node_get_bounds (start, &start_bounds);
gsk_render_node_get_bounds (end, &end_bounds);
graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
return gsk_texture_node_new (gsk_texture_node_get_texture (progress > 0.5 ? end : start),
&bounds);
}
case GSK_TEXTURE_SCALE_NODE:
{
graphene_rect_t start_bounds, end_bounds, bounds;
gsk_render_node_get_bounds (start, &start_bounds);
gsk_render_node_get_bounds (end, &end_bounds);
graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
return gsk_texture_scale_node_new (gsk_texture_scale_node_get_texture (progress > 0.5 ? end : start),
&bounds,
gsk_texture_scale_node_get_filter (progress > 0.5 ? end : start));
}
case GSK_TRANSFORM_NODE:
{
GskRenderNode *result, *child;
GskTransform *transform;
child = render_node_interpolate (gsk_transform_node_get_child (start),
gsk_transform_node_get_child (end),
progress);
transform = transform_interpolate (gsk_transform_node_get_transform (start),
gsk_transform_node_get_transform (end),
progress);
result = gsk_transform_node_new (child, transform);
gsk_transform_unref (transform);
gsk_render_node_unref (child);
return result;
}
case GSK_CLIP_NODE:
{
GskRenderNode *result, *child;
graphene_rect_t clip;
graphene_rect_interpolate (gsk_clip_node_get_clip (start),
gsk_clip_node_get_clip (end),
progress,
&clip);
child = render_node_interpolate (gsk_clip_node_get_child (start),
gsk_clip_node_get_child (end),
progress);
result = gsk_clip_node_new (child, &clip);
gsk_render_node_unref (child);
return result;
}
case GSK_ROUNDED_CLIP_NODE:
{
GskRenderNode *result, *child;
GskRoundedRect clip;
rounded_rect_interpolate (&clip,
gsk_rounded_clip_node_get_clip (start),
gsk_rounded_clip_node_get_clip (end),
progress);
child = render_node_interpolate (gsk_rounded_clip_node_get_child (start),
gsk_rounded_clip_node_get_child (end),
progress);
result = gsk_rounded_clip_node_new (child, &clip);
gsk_render_node_unref (child);
return result;
}
case GSK_BORDER_NODE:
{
GdkRGBA color[4];
const GdkRGBA *start_color, *end_color;
float width[4];
const float *start_width, *end_width;
GskRoundedRect outline;
guint i;
rounded_rect_interpolate (&outline,
gsk_border_node_get_outline (start),
gsk_border_node_get_outline (end),
progress);
start_color = gsk_border_node_get_colors (start);
end_color = gsk_border_node_get_colors (end);
start_width = gsk_border_node_get_widths (start);
end_width = gsk_border_node_get_widths (end);
for (i = 0; i < 4; i++)
{
rgba_interpolate (&color[i], &start_color[i], &end_color[i], progress);
width[i] = float_interpolate (start_width[i], end_width[i], progress);
}
return gsk_border_node_new (&outline, width, color);
}
case GSK_MASK_NODE:
{
GskRenderNode *source, *mask, *result;
source = render_node_interpolate (gsk_mask_node_get_source (start),
gsk_mask_node_get_source (end),
progress);
mask = render_node_interpolate (gsk_mask_node_get_mask (start),
gsk_mask_node_get_mask (end),
progress);
result = gsk_mask_node_new (source,
mask,
gsk_mask_node_get_mask_mode (progress > 0.5 ? end : start));
gsk_render_node_unref (source);
gsk_render_node_unref (mask);
return result;
}
case GSK_CONIC_GRADIENT_NODE:
{
graphene_rect_t start_bounds, end_bounds, bounds;
graphene_point_t center;
float rotation;
GskColorStop *color_stops;
gsize n_color_stops;
GskRenderNode *result;
if (gsk_conic_gradient_node_get_n_color_stops (start) != gsk_conic_gradient_node_get_n_color_stops (end))
break;
n_color_stops = gsk_conic_gradient_node_get_n_color_stops (start);
color_stops = g_new (GskColorStop, n_color_stops);
gsk_render_node_get_bounds (start, &start_bounds);
gsk_render_node_get_bounds (end, &end_bounds);
graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
graphene_point_interpolate (gsk_conic_gradient_node_get_center (start),
gsk_conic_gradient_node_get_center (end),
progress,
&center);
rotation = float_interpolate (gsk_conic_gradient_node_get_rotation (start),
gsk_conic_gradient_node_get_rotation (end),
progress);
color_stops_interpolate (color_stops,
gsk_conic_gradient_node_get_color_stops (start, NULL),
gsk_conic_gradient_node_get_color_stops (end, NULL),
n_color_stops,
progress);
result = gsk_conic_gradient_node_new (&bounds,
&center,
rotation,
color_stops,
n_color_stops);
g_free (color_stops);
return result;
}
case GSK_REPEAT_NODE:
{
graphene_rect_t start_bounds, end_bounds, bounds, child_bounds;
GskRenderNode *child, *result;
gsk_render_node_get_bounds (start, &start_bounds);
gsk_render_node_get_bounds (end, &end_bounds);
graphene_rect_interpolate (&start_bounds, &end_bounds, progress, &bounds);
graphene_rect_interpolate (gsk_repeat_node_get_child_bounds (start),
gsk_repeat_node_get_child_bounds (end),
progress,
&child_bounds);
child = render_node_interpolate (gsk_repeat_node_get_child (start),
gsk_repeat_node_get_child (end),
progress);
result = gsk_repeat_node_new (&bounds, child, &child_bounds);
gsk_render_node_unref (child);
return result;
}
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_OPACITY_NODE:
case GSK_COLOR_MATRIX_NODE:
case GSK_BLUR_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
g_warning ("FIXME: not implemented");
break;
case GSK_GL_SHADER_NODE:
case GSK_CAIRO_NODE:
case GSK_TEXT_NODE:
break;
case GSK_NOT_A_RENDER_NODE:
default:
g_assert_not_reached ();
break;
}
}
return gsk_cross_fade_node_new (start, end, progress);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2020 Benjamin Otte
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,15 +19,12 @@
#pragma once
void assert_path_equal_func (const char *domain,
const char *file,
int line,
const char *func,
GskPath *path1,
GskPath *path2,
float epsilon);
#include <gsk/gsk.h>
#define assert_path_equal(p1,p2) assert_path_equal_func(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, (p1),(p2), FLOAT_EPSILON)
#define assert_path_equal_with_epsilon(p1,p2, epsilon) \
assert_path_equal_func(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, (p1),(p2), (epsilon))
G_BEGIN_DECLS
GskRenderNode * render_node_interpolate (GskRenderNode *start,
GskRenderNode *end,
double progress);
G_END_DECLS

View File

@@ -6,6 +6,8 @@
#include "demo_conf.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *main_window;
static GFile *filename = NULL;
static GtkPageSetup *page_setup = NULL;
@@ -41,7 +43,7 @@ update_statusbar (void)
GtkTextIter iter;
const char *print_str;
gtk_label_set_label (GTK_LABEL (statusbar), "");
gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 0);
gtk_text_buffer_get_iter_at_mark (buffer,
&iter,
@@ -59,10 +61,10 @@ update_statusbar (void)
msg = g_strdup_printf ("%d, %d%s %s",
row, col,
file_changed?" - Modified":"",
print_str);
file_changed?" - Modified":"",
print_str);
gtk_label_set_label (GTK_LABEL (statusbar), msg);
gtk_statusbar_push (GTK_STATUSBAR (statusbar), 0, msg);
g_free (msg);
}
@@ -825,12 +827,7 @@ activate (GApplication *app)
contents);
/* Create statusbar */
statusbar = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (statusbar), 0);
gtk_widget_set_margin_start (statusbar, 2);
gtk_widget_set_margin_end (statusbar, 2);
gtk_widget_set_margin_top (statusbar, 2);
gtk_widget_set_margin_bottom (statusbar, 2);
statusbar = gtk_statusbar_new ();
gtk_box_append (GTK_BOX (box), statusbar);
/* Show text widget info in the statusbar */

View File

@@ -5,6 +5,16 @@ How to do a GTK release?
Make sure you have suitable versions of Meson and Ninja.
Also make sure you have the following packages installed with all their
dependencies:
* gtk-doc
* docbook-utils
Without those packages make distcheck will *not* pass.
Make sure that gtk-doc is the latest released version.
## Release check list
0. Save all your work, then move to the branch from which you want
@@ -18,8 +28,8 @@ $ git clean -dfx
1. Build using the common sequence:
```sh
$ meson setup _build
$ meson compile -C _build
$ meson _build .
$ ninja -C _build
```
2. Update NEWS based on the content of git log; follow the format of prior
@@ -30,10 +40,11 @@ $ meson compile -C _build
writers, committers, etc. Anybody who is mentioned in the commit log
gets a credit, but only real names, not email addresses or nicknames.
3. Update the pot file and commit the changes:
3. Update the pot files and commit the changes:
```sh
$ ninja -C _build gtk40-pot
$ ninja -C _build gtk40-properties-pot
```
4. If this is a major, stable, release, verify that the release notes
@@ -61,7 +72,7 @@ $ ninja -C _build gtk40-pot
Make sure that all new symbols have proper Since: tags, and that there
is an index in the main `-docs.xml` for the next stable version.
8. Run `meson dist -C_build` to generate the tarball.
8. Run `ninja dist` to generate the tarball.
9. Fix broken stuff found by 8), commit changes, repeat.
@@ -83,8 +94,7 @@ $ ninja -C _build gtk40-pot
$ git tag -m "GTK 4.2.0" 4.2.0
```
13. Bump the version number in `meson.build`, and add a section for the next
release in NEWS and commit the change.
13. Bump the version number in `meson.build` and commit the change.
14. Push the changes upstream, and push the tag as well. The git command for
doing that is:
@@ -101,8 +111,7 @@ $ git push origin 4.2.0
```sh
$ scp gtk-4.2.0.tar.xz matthiasc@master.gnome.org:
$ ssh matthiasc@master.gnome.org
$ ftpadmin install gtk-4.2.0.tar.xz
$ ssh matthiasc@master.gnome.org ftpadmin install gtk-4.2.0.tar.xz
```
16. Go to the gnome-announce list archives, find the last announce message,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

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