Compare commits

..

364 Commits

Author SHA1 Message Date
Matthias Clasen
218b905a88 3.99.2 2020-09-29 14:44:31 -04:00
Matthias Clasen
00c6340777 gsk: Add some more shader docs
Do a pass over the docs and address minor inconsistencies,
cosmetics and formatting differences.

Mention GSK_DEBUG=shaders.
2020-09-29 14:44:31 -04:00
Matthias Clasen
687ed74d46 Merge branch 'snapshot-stack-optimize' into 'master'
Minor optimizations to GtkSnapshot state stack

See merge request GNOME/gtk!2641
2020-09-29 18:44:07 +00:00
Alexander Larsson
796e6ee306 snapshot: Preallocate and don't memset the state stack
Most of the time the snapshot is less than 16 levels deep (did some testing
in gtk-demo), so lets pre-allocate 16 levels of state stack to avoid the
extra allocation most of the time.
2020-09-29 16:03:06 +02:00
Alexander Larsson
18b8b499de gdkarray: Add support for GDK_ARRAY_NO_MEMSET
If all your callers already initialize the array element as needed,
then we don't need to memset it to zero first.

This is pretty useful for the snapshot state stack, because due
to the per-node-type data area the elements on the stack are
quite large, but often a lot of it is not used.
2020-09-29 16:02:59 +02:00
Alexander Larsson
8a0dd452d2 gdkarray: Inline splice and reserve
This inlines the splice and reserver GdkArray calls. These are
typically only called from the gdk_array_(append/set_size) functions
anyway, and inlining the caller means we can constant propagate the
constant arguments in those calls. Its hard to get exact numbers, but
in fishbowl i noticed a significant decrease in the time spent in
the array code when pushing and poping states.
2020-09-29 15:57:33 +02:00
Matthias Clasen
4cfa9ee19f Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2639
2020-09-29 12:57:36 +00:00
Matthias Clasen
719c44a610 Merge branch 'glshader-track-uniform-state' into 'master'
gl: Track the current uniform state for custom programs

See merge request GNOME/gtk!2638
2020-09-29 12:49:22 +00:00
Matthias Clasen
4a2c817690 docs: Document various entry ::activate signals 2020-09-29 07:04:07 -04:00
Matthias Clasen
aac9414117 statusbar: Remove a misleading doc comment 2020-09-29 07:04:07 -04:00
Matthias Clasen
c897daf797 snapshot: Document radial gradient apis 2020-09-29 07:04:07 -04:00
Matthias Clasen
f1299410bf docs: Fix a typo 2020-09-29 07:04:07 -04:00
Matthias Clasen
165768b6ad wayland: Match header and doc arguments
gtk-doc doesn't take this lightly.
2020-09-29 07:04:07 -04:00
Matthias Clasen
07c338b487 gsk: Document radial gradient api 2020-09-29 07:04:07 -04:00
Matthias Clasen
3af249c046 Silence a compiler warning
These variables are not used anymore since
commit 11e4a46967.
2020-09-29 07:04:07 -04:00
Matthias Clasen
91c3edba35 NEWS: Updates 2020-09-29 07:04:07 -04:00
Alexander Larsson
51ab56d33a gl: Track the current uniform state for custom programs
This allows us to avoid updating uniforms if that is not necessary. This
in turn allows us to sometimes reuse the same draw op by just extending the
vertex array size we draw rather than doing a separate glDraw call.

For example, in the fishbowl demo, all the icons added at the same
time will have the same time and size, so we emit single draw calls
with 100s of triangles instead of 100s of draw calls with 2 triangles.
2020-09-29 11:52:39 +02:00
Alexander Larsson
2e5caa68bc Merge branch 'glshader-node' into 'master'
Add support for GLShader nodes

See merge request GNOME/gtk!2594
2020-09-29 08:30:48 +00:00
Matthias Clasen
4e55220d76 Add some shader tests
These are just basic api usage tests, no rendering.
They found the issues fixed in the preceding commits.
2020-09-29 09:51:16 +02:00
Alexander Larsson
e76cb3e1e4 gtk-demo: Add a shader paintable to the fishbowl
This gets around 500 instances at 60fps on my system.
2020-09-29 09:51:16 +02:00
Alexander Larsson
8bcb031418 gtk-demo: Add GskGLShaderNode demo
Add adds a demo showing off GskGLShaderNode in various ways.

It has a transistion widget, using some examples from
gl-transitions.com, with child widgets being both images, a GL area
and real widgets (that let you edit the transition shaders
themselves.

It also has a fancy fire effect on hove on the buttons.
2020-09-29 09:51:16 +02:00
Alexander Larsson
4d697283ae Support GLShaderNode in backends
For vulkan/broadway this just means to ignore it, but for the gl
backend we support (with up to 4 texture inputs, which is similar to
what shadertoy does, so should be widely supported).
2020-09-29 09:51:16 +02:00
Alexander Larsson
950cc41e15 GtkSnapshot: Add gtk_snapshot_push_glshader() 2020-09-29 09:51:16 +02:00
Alexander Larsson
7ea755e206 Add GskGLShaderNode and GskGLShader
A GskGLShader is an abstraction of a GLSL fragment shader that
can produce pixel values given inputs:
 * N (currently max 4) textures
 * Current arguments for the shader uniform
Uniform types are: float,(u)int,bool,vec234)
There is also a builder for the uniform arguments which are
passed around as immutable GBytes in the built form.

A GskGLShaderNode is a render node that renders a GskGLShader inside a
specified rectangular bounds. It renders its child nodes as textures
and passes those as texture arguments to the shader. You also pass it
a uniform arguments object.
2020-09-29 09:51:16 +02:00
Matthias Clasen
6e9b58b6f0 gsk: Add more shader debug spew
Print out the full assembled shader sources when
GSK_DEBUG=shaders is given. This is very verbose,
but may be useful to see what we actually pass
to the compiler.
2020-09-29 09:51:16 +02:00
Alexander Larsson
645fc6a9a5 GtkWindow: Create renderer before realizing child widgets
This way the child widgets can rely on the renderer (for example what
type it is) to decide details about how they render (such as if they
should use OpenGL shaders).
2020-09-29 09:51:16 +02:00
Matthias Clasen
a91b6b4786 css: Move the last parser api to the new header
This lets us use it from the render node parser
in gsk.
2020-09-29 09:51:16 +02:00
Alexander Larsson
16cdb33c6c shadertoy demo: Fix GLSL on GLES
I was getting "assignment to varying fragColor" errors
2020-09-29 09:51:16 +02:00
Alexander Larsson
bacb3affb3 gl: Add some namespacing to the preamble symbols
This adds a gsk prefix to the stuff in the preamble, as we want to
avoid it conflicting with things in the main shader. Especially once
we start allow some customization of shaders.
2020-09-29 09:51:16 +02:00
Alexander Larsson
9460d0131f gl backend: Add line numbers to source in glsl compilation errors
Almost always the source is created by combining various sources, which
means the line numbers in the error messages are hard to use. Adding
the line numbers to the source in the error message helps with this.
2020-09-29 09:51:16 +02:00
Alexander Larsson
7edcd1748c gl: Properly report error if shader linking fails
In gsk_gl_shader_builder_create_program(), if linking fails we
need to return -1 to indicate error, rather than the old deleted
program id.
2020-09-29 09:51:16 +02:00
Alexander Larsson
6887d0ce24 glrenderer: Move ProgramState into Program
There is no real reason to have this on the side indexed via the
index, as it is stored next to each other anyway. Plus, storing them
together lets use use `Program` structures not in the array.
2020-09-29 09:51:10 +02:00
Matthias Clasen
e29c586b7c Merge branch 'arnaudb/menubutton-direction' into 'master'
Make GtkMenuButton::direction more useful.

Closes #2811

See merge request GNOME/gtk!2636
2020-09-29 01:55:24 +00:00
Matthias Clasen
4f8a211c51 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

Closes #3202

See merge request GNOME/gtk!2637
2020-09-29 01:53:02 +00:00
Matthias Clasen
30b7545fb5 Add a reftest for flipping transforms
Verify that a scale of -1 does in fact cause a
gradient to go the other direction.
2020-09-28 21:07:51 -04:00
Matthias Clasen
a799c86edb textbuffer: Elaborate docs
Explain a bit more what gtk_text_buffer_get_content_provider()
is for.

Fixes: #3202
2020-09-28 20:51:13 -04:00
Matthias Clasen
68bb532290 window: Don't get surfaces needlessly
There is a 1-1 correspondence between natives and
surfaces, so we can just compare the natives, no
need to get the surface for every single one.
2020-09-28 20:51:13 -04:00
Matthias Clasen
d2f0e3fa6b doc: Document some apis as widget implementor only
A better solution for this would be nice. For the
time being, just add a sentence to the docs.
2020-09-28 20:51:13 -04:00
Arnaud Bonatti
4684082232 Make GtkMenuButton::direction more useful.
This property was only used until now when
there was neither an icon nor a label set,
for arrow direction and popover placement.

Starting with Gtk4, a GtkMenuButton with a
label shows an arrow at the right (in LTR)
of the label. Allow disabling the arrow or
changing its direction using the direction
property, to have a way to restore a Gtk3-
like look or to improve popover placement.

Fixes #2811.
2020-09-29 02:26:13 +02:00
Matthias Clasen
5536a2ffe6 Merge branch 'wip/carlosg/for-master' into 'master'
gtkeventcontrollerscroll: Drop device type checks

Closes #3210

See merge request GNOME/gtk!2635
2020-09-28 22:03:36 +00:00
Carlos Garnacho
11e4a46967 gtkeventcontrollerscroll: Drop device type checks
Kinetic scrolling (and begin/end tracking) broke with commit cab1dcb696
since the pointing device used on X11 does not get as much GdkInputSource
granularity as the source device used to have in GTK3.

Actually this is kinda pointless, devices incapable of smooth scroll
should send discrete events, without those devices in the picture, we
want kinetic scroll to apply on every other device capable of smooth
scroll, so just do that.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3210
2020-09-28 23:35:36 +02:00
Yosef Or Boczko
01ddc181f9 Update Hebrew translation
(cherry picked from commit f6e3dfd73e)
2020-09-28 19:00:52 +00:00
Yosef Or Boczko
2b3c2962ab Update Hebrew translation
(cherry picked from commit 02d1d9714e)
2020-09-28 18:59:32 +00:00
Matthias Clasen
27b3bb59eb Merge branch 'another-attempt-to-fix-shadertoy' into 'master'
Flip GLArea textures

See merge request GNOME/gtk!2634
2020-09-28 16:16:51 +00:00
Matthias Clasen
ff61f35b77 Merge branch 'cloudproviders-ci' into 'master'
Cloudproviders ci

Closes #2480

See merge request GNOME/gtk!2632
2020-09-28 15:45:08 +00:00
Matthias Clasen
5206cfa837 Merge branch 'wip/otte/for-master' into 'master'
snapshot: Don't flip textures

See merge request GNOME/gtk!2633
2020-09-28 15:43:02 +00:00
Matthias Clasen
b711c12bbe glarea: Flip our texture
The texture that produce is upside-down, compared to what
GSK expects, so flip things around with a transform.

This fixes the shadertoy demo being upside-down after a
recent fix to avoid downloading and reuploading the texture.
2020-09-28 11:34:23 -04:00
Matthias Clasen
431f144f37 gsk: Normalize when transforming bounds
Bounds are assumed to be normalized, and transforms
with negative scales or 3d rotations can make us get
negative sizes.

Fix by Benjamin Otte.
2020-09-28 11:34:16 -04:00
Benjamin Otte
651c92c0ed snapshot: Don't flip textures
... or gradients or borders or shadows. Instead, ensure that affines
have non-negative scale factors. Otherwise add a transform node.

The only place where this check is not necessary is color nodes, but
special casing them seems not worth it.
2020-09-28 16:14:28 +02:00
Milo Casagrande
8487e82133 Update Italian translation 2020-09-28 07:41:47 +00:00
Aurimas Černius
15b635d7bd Updated Lithuanian translation 2020-09-27 22:06:30 +03:00
Matthias Clasen
3aa2519c2b ci: Use v23 images
I added libcloudproviders to the base image, but
now I see that we already enabled libcloudproviders
in the build anyway, so I'm a bit confused.

Fixes: #2480
2020-09-27 11:48:19 -04:00
Matthias Clasen
55bd6d08d4 ci: Add libcloudproviders to the image
Add libcloudproviders to fedora-base:v23 and fedora:v23.
This is so we can enable the cloud-providers feature in
our ci builds.
2020-09-27 11:41:04 -04:00
Matthias Clasen
536e1a1954 Merge branch 'patch-1' into 'master'
treestore: Document the fact that iter is modified by the function, in a machine-readable fashion.

See merge request GNOME/gtk!2613
2020-09-27 15:03:04 +00:00
Danny Milosavljevic
32baa0a549 Update gtktreestore.c: gtk_tree_store_remove didn't have the proper comment annotation
"inout" for the parameter ITER passed.  This means that bindings would misjudge what
the function does.  In the case of guile-gi, it would be misjudged for a predicate,
see gulie-gi bug 87.
2020-09-27 15:03:03 +00:00
Matthias Clasen
6f823cd0bd Merge branch 'issue2627-gtk4' into 'master'
gdk/wayland: Replace gtk-primary-selection with primary-selection-unstable-v1

See merge request GNOME/gtk!2630
2020-09-27 14:51:23 +00:00
Matthias Clasen
97d052ef1b Merge branch 'avoid-gl-texture-download' into 'master'
gsk: Avoid downloading GL textures when possible

See merge request GNOME/gtk!2628
2020-09-27 14:47:52 +00:00
Robert Mader
9ea0469ab0 gdk/wayland: Replace gtk-primary-selection with primary-selection-unstable-v1
The later is the public upstream version, while identical implementation wise.

https://gitlab.gnome.org/GNOME/gtk/-/issues/2591
2020-09-27 16:23:42 +02:00
Matthias Clasen
895c1681f0 Merge branch 'fontchooser-no-lang' into 'master'
fontchooser: Fix builds without PangoFT2

See merge request GNOME/gtk!2629
2020-09-27 12:42:42 +00:00
Matthias Clasen
9ca9f42452 gsk: Avoid downloading GL textures when possible
I found that the gears demo was spending 40% cpu
downloading a GL texture every frame, only to
upload it again to another context.

While the GSK rendering and the GtkGLArea use different
GL contexts, they are (usually) connected by sharing data
with the same global context, so we can just use the
texture without the download/upload dance. This brings
gears down to < 10% cpu.
2020-09-26 21:55:28 -04:00
Matthias Clasen
752270253f fontchooser: Fix builds without PangoFT2
Currently, only if PangoFT2 is present and used it is supported
to retrieve the languages that are supported by a particular font.

If we don't have PangoFT2, remove the language filtering and the
sample text selection.

Based on earlier work by Chun-wei Fan, see
https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2614
2020-09-26 19:15:45 -04:00
Matthias Clasen
92e551f895 Merge branch 'BUG_gtktreeview_headers_focus_on_click_GTK4' into 'master'
GtkTreeviewColumn: don't focus-on-click header buttons

See merge request GNOME/gtk!1806
2020-09-26 22:50:23 +00:00
Matthias Clasen
593907f7b0 testupload: Test more formats
Copy the format conversion code from GdkMemoryTexture
so we can produce all formats, and test them all.

The upload fast paths assume that the stride is a
multiple of four, so some of the padding values cause
it to fail. Apart from that, things seem to work for
all combinations.
2020-09-26 17:26:12 -04:00
Matthias Clasen
34ec226852 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2626
2020-09-26 14:00:32 +00:00
Matthias Clasen
d56ad7c40c Add a test for various texture uploads
Create textures with various characteristics (alpha, premultiplication,
stride) that trigger different code paths in the gl texture upload
function, and show the resulting images. If all goes well, they all
should look the same.

On my system, this tests texture upload for memory formats
GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8, and
GDK_MEMORY_R8G8B8, and it works with both gl and gles.
2020-09-26 09:20:00 -04:00
Matthias Clasen
ae09e20e8a NEWS: Updates 2020-09-26 09:04:42 -04:00
Matthias Clasen
54944c9cea Merge branch 'fix-texture-upload-more' into 'master'
More texture upload fixes

Closes #3198

See merge request GNOME/gtk!2624
2020-09-26 12:52:25 +00:00
Matthias Clasen
fe8986f2d5 Merge branch 'matthiasc/for-master' into 'master'
gl: Make debug spew more complete

Closes #3197

See merge request GNOME/gtk!2623
2020-09-26 02:02:13 +00:00
Matthias Clasen
d6912a6791 More texture upload fixes
In some cases, with bpp == 3 and a rowstride
that is divisible by 4, we were passing invalid
parameters to GL.

Fixes: #3198
2020-09-25 21:59:33 -04:00
Matthias Clasen
db4b7e3d11 Merge branch 'add-child-clash' into 'master'
Make GtkBuildable vfunc accessor functions private

Closes #3191

See merge request GNOME/gtk!2619
2020-09-26 01:17:08 +00:00
Matthias Clasen
6cdbf1a352 popup: Fix up a doc blurb
The GdkPopup:autohide property was mis-documented.

Fixes: #3197
2020-09-25 20:43:01 -04:00
Matthias Clasen
3d881752bf gl: Make debug spew more complete
List GL_EXT_unpack_subimage among the extensions
we check for.
2020-09-25 20:42:01 -04:00
Matthias Clasen
1b93108d10 Merge branch 'fix-rgb-upload' into 'master'
gl: Fix RGB uploads

Closes #3194

See merge request GNOME/gtk!2620
2020-09-26 00:30:31 +00:00
Florian Müllner
e4d4b50d6d docs: Document GtkBuildable changes in migration guide
https://gitlab.gnome.org/GNOME/gtk/-/issues/3191
2020-09-26 02:16:57 +02:00
Florian Müllner
2715b3ec31 buildable: Make vfunc accessor functions private
With the exception of gtk_buildable_get_id(), those are only used
to construct objects from XML descriptions, which is functionality
internal to GTK.

The API is therefore unlikely to be missed, and keeping it internal
means they can no longer unintentionally shadow object methods in
bindings with less namespacing; for example it's currently ambiguous
whether `infoBar.add_child()` refers to gtk_info_bar_add_child() or
gtk_buildable_add_child().

https://gitlab.gnome.org/GNOME/gtk/-/issues/3191
2020-09-26 02:16:57 +02:00
Florian Müllner
12189bc10f buildable: Rename set_name() to set_buildable_id()
GtkBuildable's get_name()/set_name() methods may shadow
GtkWidget's methods. Avoid that by renaming the API to
get_buildable_id()/set_buildable_id(), which also reflects
the name of the XML attribute the API refers to.

https://gitlab.gnome.org/GNOME/gtk/-/issues/3191
2020-09-26 02:16:05 +02:00
Matthias Clasen
3db217ab7a gl: Reset GL_UNPACK_ALIGNMENT
Reset GL_UNPACK_ALIGNMENT to its initial value of 4 after
changing it for a glTexImage2D call.
2020-09-25 16:17:45 -04:00
Matthias Clasen
a9de1d702e Merge branch 'matthiasc/for-master' into 'master'
columnview: Simplify column constructors

See merge request GNOME/gtk!2622
2020-09-25 18:25:09 +00:00
Matthias Clasen
0c3f42e06e columnview: Simplify column constructors
Drop gtk_column_view_column_new_with_factory and
just make gtk_column_view_column_new accept a
nullable factory. This follows what we've been
doing elsewhere.

Update all callers.
2020-09-25 13:57:10 -04:00
Matthias Clasen
d4b740ce62 Merge branch 'wip/carlosg/for-master' into 'master'
Wip/carlosg/for master

Closes #3125 and #3121

See merge request GNOME/gtk!2621
2020-09-25 17:49:59 +00:00
Carlos Garnacho
d9d494826f gtkbutton: Clean up priv->in_button
This is now only toggled around, may be cleaned up.
2020-09-25 19:20:27 +02:00
Carlos Garnacho
ea6e575901 gtkbutton: Check release coordinates on all release event types
The priv->in_button state that used to be relied upon for pointer
events has been reduced over time to a broken state, since the button
does not track crossing events anymore.

Make the coordinate-based checks apply for pointer events too, besides
touch events. This fixes GtkButton mistakenly emitting ::clicked with
pointer button releases outside the widget.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3121
2020-09-25 19:20:04 +02:00
Matthias Clasen
12f05e80aa gl: Fix RGB uploads
I don't really know what to say, other than:
OpenGL is terrible

Fixes: #3194
2020-09-25 13:16:47 -04:00
Carlos Garnacho
0ccdbfd802 gtktextview: Avoid GtkGestureClick claiming on touch press
We still want the drag gesture (and text selection) to work. Avoid claiming
the gesture early, like it's done in the pointer case.
2020-09-25 19:02:26 +02:00
Carlos Garnacho
7d5accc69f gtkscrolledwindow: Do not eagerly claim touch press event
Claiming early makes the contents unable to react to the touch press
event. Do this on GtkGestureDrag::update past a threshold, so the
child widget(s) can claim before the scrolledwindow does.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3125
2020-09-25 18:58:44 +02:00
Carlos Garnacho
b1606db839 gtkscrolledwindow: Drop gtk_scrolled_window_set_capture_button_press()
This API is kinda stuck in the GdkEvent days, we now negotiate ownership
of the input sequence via GtkGestures. Remove it as it reflects a way to
work that was not exactly accurate and it will turn plainly wrong soon.
2020-09-25 18:57:40 +02:00
Matthias Clasen
c9f6a9f7c5 Merge branch 'gles-texture-colors' into 'master'
Fix uploads of textures in GLES (and make texture uploads better)

See merge request GNOME/gtk!2616
2020-09-25 14:53:19 +00:00
Timm Bäder
09564a5798 Merge branch 'wip/baedert/for-master' into 'master'
Wip/baedert/for master

See merge request GNOME/gtk!2617
2020-09-25 13:35:20 +00:00
Alexander Larsson
a299bbfc58 Drop gdk_cairo_surface_upload_to_gl() helper
There is nothing really special about this code, its just a helper for
uploading pixel data to opengl, and we're not really in the business
of doing opengl-specific helper functions.
2020-09-25 15:00:07 +02:00
Alexander Larsson
90fc671ef8 gl backend: Avoid roundtripping via surface when updloading
Do custom uploads rather than using gdk_cairo_surface_upload_to_gl(),
because this way we avoids a roundtrip (memcpy and possibly conversion)
to the cairo image surface format.
2020-09-25 10:04:48 +02:00
Alexander Larsson
c71921a6be gdk_gl_context_upload_texture() avoid conversion for pixbuf format
The gdk-pixbuf non-rgba format can be directly uploaded without
conversion.

The rgba format needs alpha premultiplication though, which is not
supported by GL during upload.
2020-09-25 09:31:43 +02:00
Alexander Larsson
1001995d49 Correctly upload textures for GLES
GLES doesn't support the GL_BGRA +  GL_UNSIGNED_INT_24_8 hack that
we use on desktop OpenGL to upload textures directly in the cairo
pixel format. This adds the required conversions to all the places
that currently need it.

We also add a data_format to the internal gdk_gl_context_upload_texture()
function to make it clearer what the format are. Currently it is always
the cairo image surface format, but eventually we want to support other
formats so that we can avoid some of the unnecessary conversions we do.

Also, the current gdk_gl_context_upload_texture() code always converts
to a cairo format and uploads that like we did before. Later commits
will allow this to use other upload formats that gl supports to avoid
conversions.
2020-09-25 09:31:43 +02:00
Alexander Larsson
8e59cdabac Add GDK_MEMORY_R8G8B8A8_PREMULTIPLIED
This is the default OpenGL format, and in fact the only pixel format
that GLES supports uploading as. Actually, the premultiplied part is
really just about how we use the textures, but all textures in GTK
are premultiplied.
2020-09-25 09:31:43 +02:00
Alexander Larsson
88b709d5ec texture: Unvirtualize download_surface
We only have one implementation, so why do all this vfunc work?
2020-09-25 09:31:43 +02:00
Matthias Clasen
e6d5a3c4e8 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

Closes #3180, #3178, and #3179

See merge request GNOME/gtk!2618
2020-09-24 18:50:26 +00:00
Matthias Clasen
e70ed905d1 columview: Don't overdraw
Just always tell the title and cell widgets to
clip their children to the right size. Otherwise
we risk things getting out of sync and unintended
overdraw.

Fixes: #3179
2020-09-24 14:30:40 -04:00
Matthias Clasen
7eb0ae39c5 columview: Fix column resizing
We were not handling the fixed_width quite right,
and that was causing screaming from the GTK size
allocation machinery.

Fixes: #3178
2020-09-24 14:18:38 -04:00
Timm Bäder
2f93287473 cssimagefallback: Whitespace 2020-09-24 19:08:22 +02:00
Timm Bäder
484dcc043b cssimagefallback: Avoid allocating GPtrArray for colors
If we just parse a color, like image(#FFF), avoid allocating the
GPtrArray to store images. This happens in Adwaita for background images
of backdrop buttons. We save around 70 GPtrArrays this way.
2020-09-24 19:08:22 +02:00
Timm Bäder
716b5afe6a Adwaita: Fix calendar header button backdrop bg color 2020-09-24 19:08:22 +02:00
Timm Bäder
fd728ea8bc gl renderer: Lower maximum gradient stop count
6 is still plenty according to my market research.

Should help with #2624
2020-09-24 19:08:22 +02:00
Timm Bäder
8d7b3bade3 gl renderer: Fall back to cairo if gradients use too many stops 2020-09-24 19:08:22 +02:00
Timm Bäder
12cc178756 textbuffer: Don't try to inset NULL text from clipboard
That used to generate a critical error message.

Also free() the data.
2020-09-24 19:08:22 +02:00
Timm Bäder
9eaa8bd1e7 gl renderer: Only return error if creating programs failed 2020-09-24 19:08:22 +02:00
Timm Bäder
15994db74d gl renderer: Use scale_x/y when rendering clipped nodes 2020-09-24 19:08:22 +02:00
Timm Bäder
467be0b7dc gl renderer: Don't use ops_get_scale() when rendering clip nodes
Differentiate between scale_x and scale_y. This works better for e.g.
transform nodes using scaleX().
2020-09-24 19:08:22 +02:00
Timm Bäder
84d2a33c10 gl renderer: Support scaleX/Y better when rendering radial gradients
We should do this everywhere, but this is a start.
2020-09-24 19:08:22 +02:00
Matthias Clasen
9fde0137a0 listview: Avoid a critical when reordering
When sorting a cell into the place its already at,
we were triggering criticals. Avoid that.

Fixes: #3180
2020-09-23 22:53:21 -04:00
Matthias Clasen
9dab51e7be Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

Closes #3188

See merge request GNOME/gtk!2612
2020-09-23 22:44:22 +00:00
Matthias Clasen
810218b2f5 fontchooser: Don't center the list
The centered layout of the font previews don't look appealing
and make it harder to judge the relative width and weight of
the individual styles.

Fixes: #3188
2020-09-23 16:32:48 -04:00
Balázs Úr
7acbbd6bdd Update Hungarian translation 2020-09-23 15:25:12 +00:00
Balázs Úr
a364ab1efb Update Hungarian translation 2020-09-23 14:39:40 +00:00
Thomas Holder
4325c20013 gtktreeview: Fix child access after TEST_EXPAND_ROW
In gtk_tree_view_build_tree with recurse=TRUE, the TEST_EXPAND_ROW
signal might invalidate the child iterator. Getting the iterator after
the signal (instead of before) fixes the issue.

Fixes https://gitlab.com/inkscape/inkscape/-/issues/1879
2020-09-23 07:53:33 -04:00
Matthias Clasen
7bae48335f Merge branch 'wip/jimmac/osd-spinbutton' into 'master'
Adwaita: osd spinbutton specificity bump

Closes #2769

See merge request GNOME/gtk!2610
2020-09-23 11:47:01 +00:00
Matthias Clasen
571f15cac6 Merge branch 'make-claiming-button-release-work' into 'master'
gestures: Make claiming button release work

See merge request GNOME/gtk!2576
2020-09-23 11:35:59 +00:00
Jakub Steiner
78236bfdbe Adwaita: osd spinbutton specificity bump
- mimic the peculiar selector from the normal style onto osd to
  override.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/2769
2020-09-23 10:16:55 +02:00
Matthias Clasen
5e4180b5f0 Merge branch 'improve-columnview-styling' into 'master'
Adwaita: Improve columnview styling

See merge request GNOME/gtk!2608
2020-09-22 03:01:38 +00:00
nana-4
2d6a9990b7 Adwaita: Don't restrict columnview editablelabel style to .data-table
This should be available without .data-table.
2020-09-22 10:40:15 +09:00
nana-4
42be26f1b1 Adwaita: Improve columnview styling
- Move padding from parent row to child cell.
- Align horizontal sizing of cell with header button.
- Properly support GtkColumnView:show-column-separators.
- Change cell height with and without .data-table.
2020-09-22 10:37:04 +09:00
nana-4
f98055b075 Adwaita: Fix separator color for lists 2020-09-22 10:35:15 +09:00
Matthias Clasen
3252d4cab2 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2607
2020-09-21 18:11:41 +00:00
Matthias Clasen
2c527ec87e inspector: Make switches go back to normal size 2020-09-21 11:53:48 -04:00
Matthias Clasen
d5e315c470 gtk-demo: Improve the pickers demo
"Two of every kind..." Add some customized pickers
here. This found a number of issues that have been
fixed in the preceding commits.
2020-09-21 11:53:48 -04:00
Matthias Clasen
256f845d89 colorbutton: Fix handling of transient parents
When we create the dialog before the button has
been rooted, we need to update its transient
parent when that happens.
2020-09-21 11:53:48 -04:00
Timm Bäder
b3c21bc89a Merge branch 'fix-hover-tracking' into 'master'
main: Update pointer focus state for button releases

Closes #3172

See merge request GNOME/gtk!2601
2020-09-21 12:20:00 +00:00
Marek Černocký
6bc46a9a69 Updated Czech translation 2020-09-21 08:30:59 +02:00
Matthias Clasen
1d34f955a2 filechooser: Fix gtk_file_chooser_set_choice
This broke when it was ported to GtkDropDown.
2020-09-20 12:04:49 -04:00
Matthias Clasen
ee75bae8f8 fontchooser: Make sure the tweak button is updated
This was showing up as tweak buttons being visible
when they should not. The code probably relied on
widgets being hidden by default (as they were in
GTK3).
2020-09-20 10:59:37 -04:00
Matthias Clasen
3c62cd90d4 fontchooser: Handle families without faces
This might seem useless, but I've met fonts
where pango_font_family_get_face (family, NULL)
return NULL. Handle it without criticals.
2020-09-20 10:59:37 -04:00
Matthias Clasen
81793b62d8 docs: Improve gtk_widget_set_font_map docs 2020-09-20 10:59:37 -04:00
Matthias Clasen
9ee7bdf4cb Merge branch 'fix-wayland-popups' into 'master'
wayland: Fix grabbing popup

See merge request GNOME/gtk!2604
2020-09-20 14:19:50 +00:00
Matthias Clasen
bb402a1f1d wayland: Fix grabbing popup
A typo snuck into commit 3023a61e1d that
caused us to fail all grabbing popups with
"grab failed: not viewable". Fix that.
2020-09-20 10:02:53 -04:00
Emin Tufan Çetin
02614713da Update Turkish translation 2020-09-20 06:38:03 +00:00
Matthias Clasen
18a5ca257a Merge branch 'kill-widget-new' into 'master'
Drop gtk_widget_new

See merge request GNOME/gtk!2603
2020-09-19 21:25:32 +00:00
Matthias Clasen
874b9ef8b0 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2602
2020-09-19 21:22:30 +00:00
Matthias Clasen
d89f7fd046 Drop gtk_widget_new
An abstract type should not have a constructor.
If you want to be generic, just use g_object_new.
2020-09-19 16:58:42 -04:00
Matthias Clasen
aeeffe27c2 NEWS: Updates 2020-09-19 16:49:46 -04:00
Matthias Clasen
cdc5e83ef2 Merge branch 'matthiasc/for-master' into 'master'
textbuffer: Redo insert markup a little bit

See merge request GNOME/gtk!2600
2020-09-19 20:48:49 +00:00
Matthias Clasen
661da6baec main: Update pointer focus state for button releases
Failure to do so makes the old pointer focus target
'sticky', because we end up ignoring the result of
picking the pointer focus until a motion event comes
in.

Fixes: #3172
2020-09-19 16:48:15 -04:00
Matthias Clasen
e927866ed4 shortcutswindow: Drop the Private struct 2020-09-19 16:22:04 -04:00
Matthias Clasen
4b9e7ac355 revealer: Drop the Private struct 2020-09-19 14:41:41 -04:00
Matthias Clasen
bebe0b5c1b magnifier: Drop the Private struct 2020-09-19 14:36:44 -04:00
Matthias Clasen
2ad9864cdc Cosmetic 2020-09-19 14:31:02 -04:00
Matthias Clasen
ec46900f06 colorscale: Drop the Private struct 2020-09-19 14:29:35 -04:00
Matthias Clasen
93cfa3855c Merge branch 'wayland-backend-api-cleanup' into 'master'
wayland: Change backend api to use GdkToplevel

See merge request GNOME/gtk!2598
2020-09-19 18:19:18 +00:00
Matthias Clasen
6b708e9b60 textbuffer: Redo insert markup a little bit
Redo the tag insertion function to avoid quadratic
behavior, and at the same time, fix handling of
alpha for color attributes.

Update the copy of this function in gtk4-demo
as well.
2020-09-19 14:17:28 -04:00
Matthias Clasen
6e81573776 Merge branch 'password-entry-activate' into 'master'
Add GtkPasswordEntry::activate

Closes #3174

See merge request GNOME/gtk!2599
2020-09-19 18:12:35 +00:00
Matthias Clasen
dd0da0f3cc passwordentry: Add an ::activate signal
GtkSearchEntry has one, no reason why GtkPasswordEntry
should not as well.

Fixes: #3174
2020-09-19 13:25:03 -04:00
Matthias Clasen
48594a2d7a passwordentry: Drop the Private struct 2020-09-19 13:23:40 -04:00
Matthias Clasen
31042bd761 docs: Add missing Wayland backend api
Since Wayland is now our flagship backend,
we should put some effort into the docs.
2020-09-19 13:13:31 -04:00
Matthias Clasen
3023a61e1d wayland: Change backend api to use GdkToplevel
Most of the surface api we have in the Wayland backend
only makes sense for toplevels, so reshuffle things to
take a GdkToplevel instead of a GdkSurface.

Update all callers and the docs.
2020-09-19 13:07:11 -04:00
Matthias Clasen
c1e33056fb NEWS: Updates 2020-09-19 12:09:24 -04:00
Matthias Clasen
57253b0039 Merge branch 'wip/baedert/radial-gradient' into 'master'
Radial gradients

Closes #2262, #3170, and #3173

See merge request GNOME/gtk!2597
2020-09-19 15:49:14 +00:00
Matthias Clasen
84d82dcda9 Merge branch 'wip/fontchooser-language-filtering' into 'master'
fontchooser: add language filtering

See merge request GNOME/gtk!2551
2020-09-19 15:06:56 +00:00
Matthias Clasen
4e35d56263 fontchooser: Remove signal handlers in dispose
Avoid ordering issues in dispose by disconnecting
the rows_changed_cb handler first thing.
2020-09-19 10:44:50 -04:00
Matthias Clasen
a9bf129286 fontchooser: Don't show "No fonts" prematurely
Don't switch to the empty page while we are still busy
filtering. Fonts might yet appear.
2020-09-19 10:25:45 -04:00
Matthias Clasen
76b7f0ca1c fontchooser: Use filter language for sample text
When you are asking to only see fonts that support
a given language, you probably want to see the
sample text for that language too.
2020-09-19 10:13:36 -04:00
Matthias Clasen
09604eb3eb fontchooser: Add user filtering
Add a popover that has filtering options. As a start,
allow filtering by monospace and by language coverage.
2020-09-19 10:13:36 -04:00
Matthias Clasen
0485a6c008 Improve language names
Shorten a few of the names we pick up by removing
parentheses that make them excessively long.
2020-09-19 09:47:15 -04:00
Matthias Clasen
169c208b7a Merge branch 'matthiasc/for-master' into 'master'
win32: Fix compiler warnings

See merge request GNOME/gtk!2596
2020-09-19 13:26:34 +00:00
Matthias Clasen
7b2c4fdb6a Merge branch 'font-chooser-sample-text' into 'master'
fontchooser: Determine sample text intelligently

See merge request GNOME/gtk!2546
2020-09-19 13:19:28 +00:00
Matthias Clasen
e0b1c3e8b0 win32: Fix compiler warnings
The compiler informs me that GetLastError() return a DWORD,
so use %lx to print it.
2020-09-19 08:29:29 -04:00
Matthias Clasen
6b9622f0da Try one more time to fix win32 ci 2020-09-19 08:13:35 -04:00
Zander Brown
cfd1520a9f Update British English translation 2020-09-19 11:42:18 +00:00
Timm Bäder
79dc25e0b1 cssimageradial: Avoid creating color stops with an offset > 1 2020-09-19 08:55:18 +02:00
Timm Bäder
1d371db8d8 scrolledwindow: Ignore captured motion events if no child is set
Fixes #3173
2020-09-19 08:44:58 +02:00
Matthias Clasen
69d5dc7c9a fontchooser: Determine sample text intelligently
Look at the languages supported by a font, and pick
a suitable sample text from the pango list of sample
texts. We can only implement this on platforms using
fontconfig, since it relies on pangofc apis.

This bumps the pango dependency to 1.47.1.
2020-09-18 23:04:39 -04:00
Timm Bäder
f938377464 rendernodes: Clarify color_stops arguments 2020-09-18 19:01:10 +02:00
Timm Bäder
6e14b26622 gsk: Add docs for radial gradient nodes 2020-09-18 18:41:01 +02:00
Timm Bäder
5d5fbc69a4 rendernodes: Enfore end > start for radial gradient nodes 2020-09-18 18:29:08 +02:00
Timm Bäder
a770ab34c4 gl renderer: Consolidate color pre-multiplication
Add a common function that tells us what it does and replace all the
manual stuff with it.

Fixes #3170
2020-09-18 15:45:08 +02:00
Timm Bäder
b8e4240751 gl renderer: Add radial gradient shader 2020-09-18 15:39:07 +02:00
Timm Bäder
2c5a4a799a rendernode: Pull local variable into closest scope 2020-09-18 15:39:07 +02:00
Timm Bäder
07b6431afe Inspector: Show radial gradient node info 2020-09-18 15:39:07 +02:00
Timm Bäder
0c2d00835b gl renderer: Set an error if we don't have one already
We can't fail and not set the error, since caller don't expect that.
2020-09-18 15:39:07 +02:00
Timm Bäder
dbfc172f6a radial gradients: Allow 0 start/end values 2020-09-18 15:39:07 +02:00
Timm Bäder
6a089816fc gsk: Parse radial gradient nodes 2020-09-18 15:39:07 +02:00
Matthias Clasen
2886e19772 css: switch to h/vradius 2020-09-18 15:39:07 +02:00
Matthias Clasen
c08df82d54 snapshot: switch to h/vradius 2020-09-18 15:39:07 +02:00
Matthias Clasen
ebfb3e771d rendernode: switch to h/vradius 2020-09-18 15:39:04 +02:00
Matthias Clasen
2881d347d3 css: Use snapshot api for radial gradients 2020-09-18 15:39:04 +02:00
Matthias Clasen
66d16049c3 snapshot: Add api for radial gradients
These are the equivalents of the linear gradient apis.
2020-09-18 15:39:04 +02:00
Matthias Clasen
0c6226c20b gsk: Add a radial gradient node
Only a fallback implementation for now.

Fixes #2262
2020-09-18 15:38:55 +02:00
Matthias Clasen
9267f705ef Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Cosmetic changes

See merge request GNOME/gtk!2590
2020-09-18 02:00:46 +00:00
Matthias Clasen
a8adbfbc9f gtk-demo: Cosmetic changes
Polish the text view demos a little bit.
2020-09-17 21:38:10 -04:00
Matthias Clasen
f00f6e9641 Merge branch 'language-names-GError-fixes' into 'master'
Language names g error fixes

See merge request GNOME/gtk!2589
2020-09-17 23:34:03 +00:00
Peter Bloomfield
50f373fbc2 language-names: Do not g_free() a GError
It's NULL anyway, so freeing GError with g_free() when it's allocated with
GSlice never actually happens, but it just looks bad.
2020-09-17 23:34:03 +00:00
Matthias Clasen
f2f0a9ee0e Merge branch 'wip/wayland-respond-to-configure' into 'master'
Make sure to respond to configure events in time

Closes #2910

See merge request GNOME/gtk!2588
2020-09-17 18:49:31 +00:00
Jonas Ådahl
4200936f21 wayland/surface: Make sure to commit ack_configure
We must wl_surface.commit after xdg_surface.ack_configure to make it
have an effect. We failed to do so when a configure event didn't result
in new updates, so make sure we fall back on an simple
wl_surface.commit if there was no new actual frame painted.

Closes: #2910
2020-09-17 18:20:08 +02:00
Goran Vidović
90991a341d Update Croatian translation
(cherry picked from commit 1c07a20ca4)
2020-09-17 15:39:02 +00:00
Jonas Ådahl
1abcd6f304 wayland: Commit surface from cairo context
In order to make the cairo renderer/context behave more similar to how
the OpenGL and Vulkan renderer/context behaves, request a frame callback
and commit in the end frame vfunc.

This means the end frame vfunc in cairo does

 * attach buffer
 * request frame callback
 * sync surface state
 * commit

Where as e.g. the OpenGL version of the same flow does

 * attach buffer
 * request frame callback
 * sync surface state
 * eglSwapBuffers()

where eglSwapBuffers() indirectly calls wl_surface_commit().
2020-09-17 17:35:35 +02:00
Jonas Ådahl
f87de393b5 wayland/surface: Remove 'committed' signal
It wasn't used by anything anymore, lets remove it.
2020-09-17 16:01:08 +02:00
Matthias Clasen
35c3a60c08 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2587
2020-09-17 03:41:32 +00:00
Matthias Clasen
cf1ed3a72a gtk-demo: Fix toggle- vs checkbutton confusion 2020-09-16 23:07:21 -04:00
Matthias Clasen
18e46bd6f8 gtk-demo: Beef up the hypertext demo
Its almost a dictionary.
2020-09-16 23:01:49 -04:00
Matthias Clasen
7082624fd7 textview: Properly delete anchored children
When we remove anchors with widgets from the text
buffer, we used to call gtk_widget_destroy(), which
indirectly called gtk_container_remove() which cleared
the child properly. When gtk_widget_destroy() was
removed, we replaced the calls with gtk_widget_unparent(),
but that is not enough. Explicitly call
gtk_text_view_remove() instead - we know the parent
is a text view.
2020-09-16 23:01:49 -04:00
Matthias Clasen
25d30011a0 textview: Make clickable tags work again
We were claiming the clicks too eagerly, preventing
clickable links, e.g. in GtkAboutDialog, from working.
2020-09-16 22:30:58 -04:00
Matthias Clasen
cd60ed4391 Plug a memory leak in an error case
gtk_show_uri() not freeing the error after showing
it to the user.

Pointed out by Peter Bloomfield in #3166
2020-09-16 19:13:18 -04:00
Matthias Clasen
a1e21c1acb Merge branch 'wip/sadiq/headerbar-demo' into 'master'
gtk-demo: Add a switch to headerbar demo

See merge request GNOME/gtk!2571
2020-09-16 23:12:26 +00:00
Milo Casagrande
ba6c14ad34 Update Italian translation 2020-09-16 07:43:11 +00:00
Matthias Clasen
c6aff910ed Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Add another demo

See merge request GNOME/gtk!2584
2020-09-16 02:56:08 +00:00
Matthias Clasen
d71337513f gtk-demo: Add another demo
Show how to add a context menu to a custom widget,
and how to make a GtkPicture lookalike.
2020-09-15 22:40:13 -04:00
Matthias Clasen
2741431d6e Merge branch 'stack-add-child' into 'master'
stack: Add gtk_stack_add_child

Closes #3165

See merge request GNOME/gtk!2583
2020-09-16 02:22:36 +00:00
Matthias Clasen
cc9fe4b354 stack: Add gtk_stack_add_child
The name of children is not essential, so add
a way to add children without providing one.

Fixes: #3165
2020-09-15 18:39:09 -04:00
Matthias Clasen
e4d29ba9fd Merge branch 'master.win32' into 'master'
Some more fixes for Windows

Closes #3157

See merge request GNOME/gtk!2580
2020-09-15 11:12:27 +00:00
Matthias Clasen
6f56d8df28 Merge branch 'wip/jimmac/dnd-green' into 'master'
Adwaita: update tango color for DND

Closes #3158

See merge request GNOME/gtk!2581
2020-09-15 11:04:59 +00:00
Matthias Clasen
9eb4eef48b Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2582
2020-09-15 11:04:54 +00:00
Matthias Clasen
e69b623a27 Merge branch 'wip/baedert/for-master' into 'master'
Wip/baedert/for master

See merge request GNOME/gtk!2579
2020-09-15 10:54:31 +00:00
Jakub Steiner
d1a68ac7ba Adwaita: update tango color for DND
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3158
2020-09-15 12:18:55 +02:00
Chun-wei Fan
52ba70d549 gdksurface-win32.c: Fix display of CSD windows
Since the changes to GDK to use surface subtypes, CSD windows were
broken because we did not set the window styles properly.  Fix this by
first acquiring whether decorations are used by the GtkWindow, and based
on that result we set the decorations that we want to use accordingly
and so apply them.

Thanks to Matt Jakeman for investigating into the issue and providing
pointers to a proposed fix.

Fixes issue #3157, besides the part where window sizes are not correct
since that is likely caused a separate issue.
2020-09-15 15:56:36 +08:00
Chun-wei Fan
02aec7f5f4 gdkevents-win32.c: Clean up WM_ACTIVATE handling a bit
We can group some things together, to make things a little bit more clear
2020-09-15 15:53:34 +08:00
Chun-wei Fan
c766e31e8f demos: Fix minesweeper demos on Windows
Make sure the callback functions in the .ui files are exported, so that
those functions can be recognized at runtime so that things run
properly.
2020-09-15 15:53:20 +08:00
Timm Bäder
a545fa15e4 inspector: Remove unsued function 2020-09-15 05:28:31 +02:00
Timm Bäder
e669433cde listbox: Activate single-click rows if n_press >= 1
Quickly clicking rows should always activate the row if
single-click-activation is enabled. Before, only the first click
(n_press == 1) would activate the row.
2020-09-15 05:21:54 +02:00
Timm Bäder
a6f86d9c26 popover: Only destroy arrow render node if position changed 2020-09-15 05:21:54 +02:00
Timm Bäder
d0f182757a sizegroup demo: Fix a checkbutton/togglebutton mixup 2020-09-15 05:21:54 +02:00
Timm Bäder
c8f4c8c4f0 filechooserwidget: Plug a memory leak
g_list_store_append refs the file
2020-09-15 05:21:54 +02:00
Timm Bäder
87f589f738 emojichooser: Fix typo in css class 2020-09-15 05:21:54 +02:00
Timm Bäder
27f3600419 listbox: Add preconditions to remove() 2020-09-15 05:21:53 +02:00
Timm Bäder
40ee7186bf build: Unify two if statements
They both check glib_minor_req.is_odd()
2020-09-15 05:21:53 +02:00
Timm Bäder
a0422bfe25 inspector: Fix huge listbox rows
This is handled by .rich-list
2020-09-15 05:21:53 +02:00
Matthias Clasen
67c1600ac2 Document some API as widget-implementation only
Using gtk_widget_insert_before on a complex container
is a *bad* idea; it will mess up the containers bookkeeping
of its children and can easily lead to failure and crashes.
2020-09-14 20:28:44 -04:00
Matthias Clasen
50400879e0 gtk-demo: Add more detail to the dnd demo text 2020-09-14 17:49:16 -04:00
Matthias Clasen
b20e67dc83 gtk-demo: Add some keywords
Make the builder demo show up in searches for toolbar and
menubar.
2020-09-14 17:33:12 -04:00
Matthias Clasen
a3dcfafba6 gtk-demo: Improve the builder demo
Make the keyboard shortcuts work.
2020-09-14 17:06:34 -04:00
Matthias Clasen
82ce1a9d6b gtk-demo: Improve the builder demo
Make the toolbar look right.
2020-09-14 16:51:05 -04:00
Matthias Clasen
cc6faeab50 gtk-demo: More space
Increase the inter-paragraph spacing in the info
text, to make paragraphs more clearly separated.
2020-09-14 16:21:13 -04:00
Matthias Clasen
aa32613beb gtk-demo: Cosmetic change 2020-09-14 16:20:52 -04:00
Matthias Clasen
6a3e12cfae gtk-demo: Add some details 2020-09-14 16:11:11 -04:00
Rūdolfs Mazurs
fc6d621146 Update Latvian translation 2020-09-14 19:45:03 +00:00
Matthias Clasen
37a24711a4 Merge branch 'issue-2923' into 'master'
Annotate the expression array as "nullable"

Closes #2923

See merge request GNOME/gtk!2578
2020-09-14 17:01:54 +00:00
Emmanuele Bassi
595cc929e6 Annotate the expression array as "nullable"
While it's a bit dubious whether array+length annotations should be
marked as "nullable", we do this elsewhere in the API, so might as well
be consistent.

In practice, the array argument is only ever allowed to be NULL iff the
length argument is 0; annotations are static, so if somebody decides to
pass a NULL argument with a non-zero value, they will get a run time
critical error, instead of a compile time one, which is somewhat counter
to the point of annotating the API in the first place.

Fixes: #2923
2020-09-14 17:00:23 +01:00
Matthias Clasen
27e6826860 Merge branch 'matthiasc/for-master' into 'master'
widget-factory: Fix the toggle buttons on page 3

See merge request GNOME/gtk!2577
2020-09-14 15:44:51 +00:00
Matthias Clasen
7a2400c8a1 widget-factory: Fix the toggle buttons on page 3
They should not both be active initially.
2020-09-14 11:19:39 -04:00
Piotr Drąg
3c4259393c Update POTFILES.skip 2020-09-14 16:55:31 +02:00
Matthias Clasen
a201bfd9a5 Merge branch 'wip/jimmac/navlist-expander-whitespace' into 'master'
Adwaita: navigation list expander whitespace

See merge request GNOME/gtk!2575
2020-09-14 12:59:05 +00:00
Matthias Clasen
921f3a6e16 Merge branch 'wip/jimmac/gridview-whitespace' into 'master'
Wip/jimmac/gridview whitespace

Closes #3164

See merge request GNOME/gtk!2574
2020-09-14 12:49:52 +00:00
Matthias Clasen
53dddf163d gestures: Make claiming button release work
When claiming a sequence in a gesture signal handler,
the expected result is that GtkGesture::handle-event
returns TRUE, causing the event to not be propagated
further.

This doesn't work for button release events, since
gtk_gesture_handle_event does the following:
  add point
  emit ::update
  remove point
  check claimed status
The ::update signal is where the application code
claims the sequence. But removing the point purges
the sequence from the gestures memory, so checking
the claimed status returns FALSE.

This patch fixes things to behave as expected, by
checking the claimed status before removing the point.
2020-09-14 08:35:44 -04:00
Jakub Steiner
e7c75f04dd Adwaita: navigation list expander whitespace
- Address https://gitlab.gnome.org/GNOME/gtk/-/issues/3138#note_910476
2020-09-14 14:31:23 +02:00
Jakub Steiner
7dd819dffc icon-browser: use content-view
- make content prominent by using content-view style for the main grid.
2020-09-14 14:18:52 +02:00
Jakub Steiner
8eab10dabf Adwaita: whitespace for the grid
- separate labels
- 12px margins around cells

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3164
2020-09-14 14:18:52 +02:00
Mohammed Sadiq
bd900fe8c9 gtk-demo: Add a switch to headerbar demo
We don't have any demos with a switch in headerbar.
2020-09-14 17:11:13 +05:30
Matthias Clasen
6a676d527c Merge branch 'wip/jimmac/natigation-sidebar-whitespace' into 'master'
Wip/jimmac/natigation sidebar whitespace

Closes #3138

See merge request GNOME/gtk!2572
2020-09-14 11:13:52 +00:00
Jakub Steiner
f125e6234b Merge branch 'wip/jimmac/cut-finger' into 'master'
assets: adjust gesture graphic

Closes #3074

See merge request GNOME/gtk!2573
2020-09-14 10:34:52 +00:00
Jakub Steiner
bcb2861447 assets: adjust gesture graphic
- quick, somebody on the internet is offended!

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3074
2020-09-14 12:14:40 +02:00
Jakub Steiner
962f76ddc9 Adwaita: navigation-sidebar spacing
- split from placessidebar as it's more generic

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3138
2020-09-14 11:51:54 +02:00
Matthias Clasen
d45aabb4ec Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2570
2020-09-14 04:45:07 +00:00
Matthias Clasen
9f03462ffb gtk-demo: Improve the scrolling demo
Add an fps label to the scrolling demo.
2020-09-13 23:43:45 -04:00
Matthias Clasen
3b11896581 gtk-demo: Impove the fishbowl demo
Use tnum for the fps label to avoid jiggling.
2020-09-13 23:43:45 -04:00
Matthias Clasen
c66a8cb941 gtk-demo: Use gdk_frame_clock_get_fps
Remove another copy of this code in the theme
switching benchmark.
2020-09-13 23:43:45 -04:00
Matthias Clasen
c462f35a5e inspector: Use gdk_frame_clock_get_fps 2020-09-13 23:35:01 -04:00
Matthias Clasen
b166999683 Add gdk_frame_clock_get_fps
We already have more than one copy of this code
in GTK, so just export this function.
2020-09-13 23:35:01 -04:00
Matthias Clasen
4b589b6afb main: Reshuffle debug code
Mode all the debug flags related code together,
to make gtkmain.c a bit less messy.
2020-09-13 22:48:29 -04:00
Matthias Clasen
fedeb51f31 Drop support for GTK_TEST_TOUCHSCREEN
This environment variable is undocumented, and you can
just use GTK_DEBUG=touchscreen insead.
2020-09-13 22:44:32 -04:00
Matthias Clasen
d2faa38eed Move version-related functions to gtkversion.c
This is just an internal cleanup, to make gtkmain.c
a bit less messy.
2020-09-13 22:23:06 -04:00
Matthias Clasen
ff9ca2b68d Clean up debug flags code a bit
Use the GtkDebugFlags enum, since we have it.
2020-09-13 22:10:25 -04:00
Matthias Clasen
aa5207b349 iconview: Small doc additions 2020-09-13 21:51:42 -04:00
Matthias Clasen
2b5b6e0885 Drop gtk_render_slider from headers
The function does not exist.
2020-09-13 21:51:42 -04:00
Matthias Clasen
93d9a2ceda colorchooser: Bring back gtk_color_chooser_widget_new
This was removed by accident in commit f392fbfb6d6f1116728b.
2020-09-13 21:51:42 -04:00
Matthias Clasen
5ab77e72e2 docs: Misc updates
Pick up a number of symbols that have been missed,
and drop GtkAccelLabel.
2020-09-13 21:51:42 -04:00
Matthias Clasen
5a7faa6512 docs: Add new check button apis 2020-09-13 21:51:42 -04:00
Matthias Clasen
b7d42502ce docs: Some touchups to the migration guide 2020-09-13 21:51:42 -04:00
Matthias Clasen
2d766dff96 NEWS: Updates 2020-09-13 21:51:42 -04:00
Matthias Clasen
e3bab0b766 Merge branch 'gtk-demo-demo' into 'master'
Gtk demo demo

See merge request GNOME/gtk!2569
2020-09-13 23:37:22 +00:00
Matthias Clasen
d3c5c7f4ef Merge branch 'update-default-palette' into 'master'
colorchooserwidget: Update default palette

See merge request GNOME/gtk!2568
2020-09-13 23:28:57 +00:00
nana-4
f6e4486338 colorchooserwidget: Update default palette
This makes it completely in line with the new GNOME HIG color palette.

See https://gitlab.gnome.org/GNOME/gtk/-/issues/3146
2020-09-14 07:05:04 +09:00
Matthias Clasen
9d6990fdb9 gtk-demo: Don't offer to run titles
When a group is selected (such as 'Benchmark'),
make the run button insensitive - there is nothing
to run.
2020-09-13 17:55:10 -04:00
Matthias Clasen
3f1fa66479 Demo thyself
Make gtk-demo show itself as a useful example.
2020-09-13 17:54:58 -04:00
Matthias Clasen
8094f757eb Merge branch 'demo-keywords' into 'master'
gtk-demo: add keywords to filtering

See merge request GNOME/gtk!2567
2020-09-13 21:13:21 +00:00
Matthias Clasen
d732c869c2 gtk-demo: Add keywords to demos
Add the names of the main widgets as keywords to
our demos, but also things like "game". This helps
finding relevant demos in our growing list. You
can now for example type "label", and find the
"error states" and "links" demos showing GtkLabel
features.
2020-09-13 15:00:14 -04:00
Matthias Clasen
691261c71a gtk-demo: Support keywords for search
Filter the sidebar on keywords that can be provided
by the demos. We extract keywords from the doc comment
at the top of each demo source by looking for words that
look like class names. We also allow to specify keywords
explicitly.
2020-09-13 15:00:14 -04:00
Matthias Clasen
fe6f70efe1 gtk-demo: Ignore some lines in info
Ignore lines starting with # in the info comment at
the top of source files. This will be used to add
keywords for search in following commits.
2020-09-13 14:42:03 -04:00
Matthias Clasen
cddbc8f1cc Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2566
2020-09-13 18:39:12 +00:00
Matthias Clasen
a90801e696 gtk-demo: Add another demo
This one is a more or less direct copy of the
settings dialog from widget-factory, demonstrating
error states and builder scopes.
2020-09-13 12:36:30 -04:00
Rūdolfs Mazurs
f445cc0d70 Update Latvian translation 2020-09-13 12:30:52 +00:00
Claude Paroz
6cf7b95bec Updated French translation 2020-09-13 10:46:33 +02:00
Matthias Clasen
7518fd0d70 gtk-demo: Make F11 toggle fullscreen
In the video player demo, we have a button to make
the window fullscreen, but no easy way back. Add
the usual F11 keybinding, to make things at least
somewhat recoverable.
2020-09-13 02:31:41 -04:00
Matthias Clasen
30c3a533f4 video: Make autoplay work
We were setting things up in the wrong order, so
autoplay had no effect when you using gtk_video_set_file().
2020-09-13 01:56:56 -04:00
Matthias Clasen
52304fe7da gtk-demo: Add some example videos
Add buttons to show the gtk-logo animation and
the Big Buck Bunny trailer.
2020-09-13 01:51:55 -04:00
Matthias Clasen
22257b124a placessidebar: Remove a pointless restriction
The sidebar was refusing to show shortcuts for
things that don't have a local path, for no
good reason.
2020-09-13 01:14:00 -04:00
Matthias Clasen
4629182246 filechooser: Fix setting unlisted filters
This is documented to work, but it was broken
when we ported things to list models.
2020-09-13 01:12:51 -04:00
Matthias Clasen
c8a9e7fa82 Fix a compiler warning 2020-09-13 01:12:39 -04:00
Matthias Clasen
8f593827cf widget-factory: Fix error states demo
Fix a corner case of input validation in the settings
dialog.
2020-09-13 00:17:19 -04:00
Matthias Clasen
8984fe3c35 Cosmetics 2020-09-13 00:17:19 -04:00
Matthias Clasen
fc720b57e2 gtk-demo: Don't refer to removed demos
The animated background demos was referring to the
pixbuf demo that was removed a while ago. Reword
the text accordingly.
2020-09-13 00:17:19 -04:00
Emin Tufan Çetin
4cb367a6e2 Update Turkish translation 2020-09-12 17:11:40 +00:00
Matthias Clasen
b534752d5c Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

Closes #3110 and #2994

See merge request GNOME/gtk!2565
2020-09-12 16:25:17 +00:00
Matthias Clasen
929a56e53c Clean up lots of GTK+ -> GTK
Replace most remaining uses of GTK+ in the docs and
user-visible strings by GTK. Also remove some leftover
"Was added in 3.x" sentences from the docs.
2020-09-12 12:01:04 -04:00
Matthias Clasen
6ed1c181ee AUTHORS: some updates 2020-09-12 11:52:14 -04:00
Matthias Clasen
0011a1032d text: Claim the sequence when we start selecting
Without this, drag-select will only work sporadically
in entries in headerbars.

Fixes: #2994
2020-09-12 11:18:36 -04:00
Matthias Clasen
38b71ba292 Cosmetics
Add a missing comma.
2020-09-12 11:11:28 -04:00
Matthias Clasen
b5f3ac9718 Add a testcase for controls in headerbars
This is meant to help with figuring out entry
selection drag issues.
2020-09-12 10:58:07 -04:00
Matthias Clasen
756c52ef08 filechooser: Prevent a crash
With csd, we are handling external widgets when
there is an entry in the headerbar. Use a weak ref
to prevent that pointer from going stale. This fixes
a crash when cancelling a save dialog.

Fixes: #3110
2020-09-12 10:40:13 -04:00
Emmanuele Bassi
9afdb41b6b Merge branch 'ebassi/for-master' into 'master'
Properly annotate GtkLayoutManagerClass.create_layout_child()

Closes #3156

See merge request GNOME/gtk!2564
2020-09-12 14:24:13 +00:00
Emmanuele Bassi
25bcec5cbb Properly annotate GtkLayoutManagerClass.create_layout_child()
We're missing the ownership transfer rule for the created GtkLayoutChild
instance; this makes the virtual function not introspectable.

Fixes: #3156
2020-09-12 14:33:24 +01:00
Emin Tufan Çetin
eba5232e35 Update Turkish translation 2020-09-12 06:14:30 +00:00
Matthias Clasen
7ee3439522 Merge branch 'emblem-demo' into 'master'
Emblem demo

See merge request GNOME/gtk!2563
2020-09-12 01:33:51 +00:00
Matthias Clasen
71ea619274 gtk-demo: Add an emblem demo
Add a simple demo for adding emblems to icons
using GdkPaintable.
2020-09-11 21:09:41 -04:00
Matthias Clasen
f679ba566e gtk-demo: Tweak the animated paintable
Make it possible to have no background in
the animated paintable. This will be used
in a future demo.

Update all users.
2020-09-11 21:08:36 -04:00
Matthias Clasen
2679e29375 gtk-demo: Fix a few crash
The paintable demos were forgetting to clear
their window variable.
2020-09-11 21:07:10 -04:00
Matthias Clasen
e55bdf87b5 Merge branch 'text-layout-speedup' into 'master'
textlayout: Avoid some iter comparisons

See merge request GNOME/gtk!2561
2020-09-11 21:20:38 +00:00
Matthias Clasen
c09575d9cb textlayout: Avoid some iter comparisons
We were doing more iter comparisons than necessary in the
inner loop of gtk_text_layout_snapshot(), in the presence
of a selection. Rewrite the code to compare line numbers
instead, which is faster than full iter comparisons.
2020-09-11 16:41:42 -04:00
Matthias Clasen
c3b925d696 Merge branch 'wip/otte/for-master' into 'master'
contentserializer: Don't send the terminating \0 byte for strings

Closes #3150

See merge request GNOME/gtk!2560
2020-09-11 15:50:23 +00:00
Benjamin Otte
640856edec contentserializer: Don't send the terminating \0 byte for strings
Fixes #3150
2020-09-11 17:25:02 +02:00
Matthias Clasen
1e7fccf46f Merge branch 'wip/jimmac/new-colors' into 'master'
Wip/jimmac/new colors

Closes #3146

See merge request GNOME/gtk!2558
2020-09-11 13:56:48 +00:00
Matthias Clasen
ff392fbfb6 colorchooser: Don't parse color names needlessly
We have a fancy macro to initialize GdkRGBAs without
any runtime work, lets use them.
2020-09-11 09:31:17 -04:00
Matthias Clasen
498cbae95c colorchooser: Drop color names
These were not used anymore, after a11y stopped using them.
2020-09-11 09:12:34 -04:00
Matthias Clasen
fa9608fd02 color chooser: Don't show too many custom colors
The code was hardcoding a fixed number of custom
colors, but we really want to match the number
of columns in the palette(s). Make it so.
2020-09-11 08:42:03 -04:00
Jakub Steiner
8700e136da colorChooser: updte color palette
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3146
2020-09-11 10:47:24 +02:00
Ask Hjorth Larsen
2e54810937 Updated Danish translation of gtk-properties 2020-09-11 02:31:50 +02:00
Ask Hjorth Larsen
93a09a4a6a Updated Danish translation of gtk 2020-09-11 02:31:41 +02:00
Matthias Clasen
299b1bd848 Merge branch 'matthiasc/for-master' into 'master'
x11: Print all tested glx extensions

See merge request GNOME/gtk!2556
2020-09-10 21:56:46 +00:00
Matthias Clasen
1e9a9876d5 x11: Print all tested glx extensions
When initializing a glx context, print all the extensions
we look for.
2020-09-10 17:30:28 -04:00
Matthias Clasen
1de7440c8c Merge branch 'gdk-cleanups' into 'master'
Gdk cleanups

Closes #2790

See merge request GNOME/gtk!2553
2020-09-10 20:21:12 +00:00
Matej Urbančič
5c87432a0c Update Slovenian translation 2020-09-10 20:12:10 +00:00
Matej Urbančič
80e53e704c Update Slovenian translation 2020-09-10 20:09:27 +00:00
Matthias Clasen
24bf01dd42 Merge branch 'fix-vulkan-context-creation' into 'master'
Fix vulkan context creation

Closes #3147

See merge request GNOME/gtk!2555
2020-09-10 18:18:55 +00:00
Matthias Clasen
2113f98c5c gdk: Don't create surfaces of size 0x0
Don't pass 0x0 as size when calling gdk_surface_new().
The Wayland backend takes us literally, and we end
up with a surface that (temporarily) has these
dimensions, confusing other APIs that we pass the
size to, such as Vulkan.
2020-09-10 13:56:44 -04:00
Matthias Clasen
b9d4654fca vulkan: Fix swapchain creation
We end up with a surface that has size 0x0 at the
time we create the Vulkan context, and that is a
size that Vulkan doesn't like, so ensure we request
at least 1x1.

Fixes: #3147
2020-09-10 13:55:16 -04:00
Matthias Clasen
7151b1fc31 Merge branch 'ebassi/for-master' into 'master'
docs: Add note on command line arguments

See merge request GNOME/gtk!2554
2020-09-10 17:39:25 +00:00
Emmanuele Bassi
790733673f docs: Add note on command line arguments
We don't parse them any more, and developers should stop using them when
migrating from GTK3 to GTK4.
2020-09-10 17:53:50 +01:00
Milo Casagrande
aff788e583 Update Italian translation 2020-09-10 08:03:38 +00:00
Matthias Clasen
d5d4af585d gdk: Move GdkSurfaceEdge to the right header
This is only used in gdktoplevel.h, so move it there.
2020-09-10 00:44:05 -04:00
Matthias Clasen
93078e52c0 gdk: Rename GdkSurfaceState to GdkToplevelState
That is what it is.

Fixes: #2790
2020-09-10 00:39:03 -04:00
Matthias Clasen
cee275980a gdk: Move GdkSurfaceState to the right header
This is really a toplevel state, so move it
to that header.
2020-09-10 00:25:51 -04:00
Matthias Clasen
b3aa5ad4f9 Move GdkFullscreenMode to the right header
This enum is just used for a GdkToplevel property now,
so move the declaration to the gdktoplevel.h header.
2020-09-10 00:22:26 -04:00
Matthias Clasen
9b0b19d335 NEWS: Updates 2020-09-09 23:49:58 -04:00
Matthias Clasen
d47d036663 search entry: Don't propagate handled events
When the text says it has handled the event,
trust it. We don't want to emit ::search-started
if the content hasn't changed, but we still
should not propagate e.g. an Insert key press
if it has already toggled overwrite mode in
the text.

Fixes: #2874
2020-09-09 22:26:27 -04:00
Matthias Clasen
5c67fe0bc2 Merge branch 'fix-gl-texture-cache' into 'master'
gsk: Fix the gl texture cache

See merge request GNOME/gtk!2552
2020-09-09 19:27:24 +00:00
Matthias Clasen
1057588a8f gsk: Fix the gl texture cache
We need to include both the scale and the filtering
in the key for the texture cache, since those affect
the texture.

This fixes misrendering in the recorder in the inspector
whenever transforms are involved. An example where this
was showing up is testrevealer's swing transition.
2020-09-09 13:55:09 -04:00
Tim Sabsch
75f0b7acaa Update German translation 2020-09-09 17:23:14 +00:00
Benjamin Otte
9a927176df Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

Closes #3137

See merge request GNOME/gtk!2550
2020-09-09 16:44:29 +00:00
Benjamin Otte
cb5b375f43 revealer: Remove arbitrary 100x scale limit
This is no longer necessary because the bug it was rying to solve is now
solved via the preference for min and nat size.
2020-09-09 17:38:37 +02:00
Benjamin Otte
dfccaa8831 revealer: Prefer min and nat size
Assume that the fully expanded revealer will likely get an allocation
that matches the child's minimum or natural allocation, so we
special-case these two values.

So when - due to the precision loss - multiple sizes would match the
current allocation, we don't pick one at random, we prefer the min and
nat size.

The preference of nat size over min sie was decided after an IRC vote,
we don't actually have an idea what's more likely to happen in the real
world.
Should we ever get better data, we might want to switch.
2020-09-09 17:38:37 +02:00
Benjamin Otte
cc58956dbb revealer: Use floor(), not ceil()
We use ceil() in measure(), so using it again will increase the
child's size whenever there is even a tiny rounding error.

This should also not make the size too small, because:
min = ceil(child_min * scale)
min / scale >= child_min
floor (min / scale) >= floor (child_min) = child_min
The last equality is because child_min is an integer.

Fixes #3137
2020-09-09 17:38:37 +02:00
Benjamin Otte
0ad10ccf39 revealer: Refactor code
Assign the values in the same place.
2020-09-09 17:38:37 +02:00
Benjamin Otte
8cb03a8cc0 widget: Add a critical when allocation is too small. 2020-09-09 17:38:37 +02:00
Emmanuele Bassi
df7cbdfff4 Merge branch 'issue-3140' into 'master'
Make sure we don't call back into GtkEntryBuffer

Closes #3140

See merge request GNOME/gtk!2549
2020-09-09 10:54:07 +00:00
Emmanuele Bassi
f4b410daa7 Make sure we don't call back into GtkEntryBuffer
After commit 7e77afe94c moved the deletion
of text into the signal handler, in order to make undo work, we need to
override the GtkEntryBuffer::deleted-text class closure when subclassing
GtkEntryBuffer, as well as overriding GtkEntryBufferClass.delete_text,
otherwise the default class closure will be invoked, and will try to
delete an empty buffer.

Fixes: #3140
2020-09-09 11:29:16 +01:00
Emmanuele Bassi
b3d3d81c82 Merge branch 'gtksecurememory-win32' into 'master'
Port gtksecurememory.c to Windows

See merge request GNOME/gtk!2548
2020-09-09 10:12:44 +00:00
Chun-wei Fan
3095bccd2e gtksecurememory.c: Port secure memory allocation to Windows
Use the Windows API CryptProtectMemory() to encrypt the data that we want to
secure, and use CryptUnprotectMemory() to de-crypt the secured data that we
want to access, since mmap() and mlock() are not available on Windows.
2020-09-09 13:50:15 +08:00
Chun-wei Fan
c72b2f6167 gtksecurememory.c: Don't include unistd.h unconditionally
It is not universally available on non-POSIX systems.
2020-09-09 13:48:33 +08:00
Matthias Clasen
3d10b28df4 Merge branch 'matthiasc/for-master' into 'master'
shadertoy demo: Cosmetic fixes

See merge request GNOME/gtk!2547
2020-09-09 00:40:54 +00:00
Matthias Clasen
d6807b966c shadertoy demo: Cosmetic fixes 2020-09-08 20:08:23 -04:00
Matthias Clasen
887d0b7411 Merge branch 'ebassi/secure-buffer' into 'master'
Add secure entry buffer

Closes #3119 and #2403

See merge request GNOME/gtk!2545
2020-09-08 23:48:25 +00:00
Matthias Clasen
3921476504 Merge branch 'shadertoy-demo' into 'master'
gtk-demo: Add shadertoy demo

See merge request GNOME/gtk!2540
2020-09-08 23:47:54 +00:00
Emmanuele Bassi
ae97284409 docs: Add a note on GtkPasswordEntry's secure storage 2020-09-08 23:50:12 +01:00
Emmanuele Bassi
7cda32d49e Use GtkPasswordEntryBuffer in GtkPasswordEntry
Now that we have a secure buffer, we should start using it.

Fixed: #3119
2020-09-08 23:50:12 +01:00
Emmanuele Bassi
fb99bde840 Add a secure GtkEntryBuffer
We have a widget for password and passphrase entries, but we have no way
to handle the data securely. This is usually performed by a separate
GtkEntryBuffer—for instance, the one in GCR. While we have API for
setting a new entry buffer on GtkText, we don't have API for
GtkPasswordEntry, though, so the options are:

 - expose additional API for GtkPasswordEntry to allow setting a secure
   text buffer on the internal GtkText widget
 - provide a secure text buffer out of the box

Given that an insecure-by-default GtkPasswordEntry is basically
pointless, might as well have a secure buffer built in.

We don't really need to make the password entry buffer public out of the
box, but we can re-evaluate at a later date.

Fixes: #2403
2020-09-08 23:50:12 +01:00
Emmanuele Bassi
9dc5c6a0f3 Move g_autoptr macro for GtkEntryBuffer
We need it into its own header, so we can derive from GtkEntryBuffer
with G_DECLARE_* macros without including gtk.h.
2020-09-08 23:50:12 +01:00
Emmanuele Bassi
107e49002d Check for mlock()
We use it in the secure memory allocator, if it's available.
2020-09-08 23:50:12 +01:00
Emmanuele Bassi
31a7574544 Import egg-secure-memory allocator from gcr
We can re-use the code inside gcr, as we know that it's working, tested,
and license compatible.
2020-09-08 23:50:12 +01:00
Emmanuele Bassi
859df747ac Merge branch 'sorter-constructor-fix-warning' into 'master'
Fix warning in listview_settings demo

See merge request GNOME/gtk!2544
2020-09-08 17:54:25 +00:00
Andreas Persson
81c835c418 Fix warning in listview_settings demo
Fix a warning introduced when sorter constructors were changed to return
exact types.
2020-09-08 18:48:54 +02:00
Ask Hjorth Larsen
33e633cc5c Updated Danish translation of gtk-properties 2020-09-08 16:23:16 +02:00
Ask Hjorth Larsen
73b46eafe1 Updated Danish translation of gtk 2020-09-08 16:23:05 +02:00
Marek Černocký
710ef690ec Updated Czech translation 2020-09-08 15:33:40 +02:00
Matthias Clasen
cb2b0688ca Merge branch 'filter-constructors' into 'master'
Filter constructors

See merge request GNOME/gtk!2360
2020-09-08 12:58:27 +00:00
Danial Behzadi
45c61fdbe3 Update Persian translation 2020-09-08 12:50:36 +00:00
Alexandre Franke
ec49b68257 Update French translation 2020-09-08 09:15:19 +00:00
Alexander Larsson
0092a08dfc gtk-demo: Add shadertoy demo
This adds a small demo of using OpenGL shaders, it renders a quad
over the entire widget with a custom fragment shader. The coordinates
and the uniform names are compatible with the ones on shadertoy.com
(although some features, like texture inputs are missing currently).

The default shader in the demo is
https://www.shadertoy.com/view/wsjBD3 which is CC0, so it is
redistributable by Gtk+ (most other shaders are CC-BY-NC-SA which
isn't obviously compatible). I also added a set of buttons loading
a few other CC0 shaders I found.
2020-09-08 09:56:25 +02:00
Matthias Clasen
24389a0ef5 Make sorter constructors return exact types
Make functions like gtk_custom_sorter_new() return
the actual type they construct.

Update all callers.
2020-09-05 21:50:15 -04:00
Matthias Clasen
dfabe74c59 Make filter constructors return exact types
Make functions like gtk_custom_filter_new() return
the actual type they construct.

Update all callers.
2020-09-05 21:43:42 -04:00
Nelson Benítez León
ba9b4f418d GtkTreeviewColumn: don't focus-on-click header buttons
currently when mouse clicking on a column header
to sort it it is grabbing keyboard focus, this
should not happen, keyboard focus should remain
where it was before. This can be seen on the
GtkFileChooser widget, when having the keyboard
focus on the file list items and clicking on a
column header to sort it the keyboard focus is
now on the header.
2020-04-30 22:59:08 -04:00
469 changed files with 59774 additions and 50015 deletions

View File

@@ -20,7 +20,7 @@ variables:
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v22"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v23"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
DOCS_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora-docs:v19"

View File

@@ -44,6 +44,7 @@ RUN dnf -y install \
lcov \
libasan \
libattr-devel \
libcloudproviders-devel \
libepoxy-devel \
libffi-devel \
libmount-devel \

View File

@@ -1,4 +1,4 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v21
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v23
# Enable sudo for wheel users
RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers

View File

@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.65.0 glib-2.0; then
fi
pkg-config --modversion glib-2.0
if ! pkg-config --atleast-version=1.45.4 pango; then
if ! pkg-config --atleast-version=1.47.0 pango; then
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
meson setup _pango_build _pango
meson compile -C _pango_build

30
AUTHORS
View File

@@ -1,5 +1,5 @@
Please do not mail any of the authors listed here
asking questions about this version of GTK+.
Please do not mail any of the authors listed here
asking questions about this version of GTK.
Original Authors
----------------
@@ -7,8 +7,8 @@ Peter Mattis <petm@xcf.berkeley.edu>
Spencer Kimball <spencer@xcf.berkeley.edu>
Josh MacDonald <jmacd@xcf.berkeley.edu>
The GTK+ Team (in alphabetical order)
-------------------------------------
The Team that build GTK 2 (in alphabetical order)
-------------------------------------------------
Shawn T. Amundson <amundson@gtk.org>
Jerome Bolliet <bolliet@gtk.org>
Damon Chaplin <damon@gtk.org>
@@ -28,11 +28,24 @@ Jay Painter <jpaint@gtk.org>
Manish Singh <manish@gtk.org>
Owen Taylor <otaylor@gtk.org>
The current team (GTK 3 and 4)
------------------------------
Jonas Ådahl <jadahl@gmail.com>
Tim Bäder <mail@baedert.org>
Emmanuele Bassi <ebassi@gnome.org>
Chun-wei Fan <fanchunwei@src.gnome.org>
Matthias Clasen <mclasen@redhat.com>
Carlos Garnacho <mrgarnacho@gmail.com>
Alexander Larsson <alexl@redhat.com>
Benjamin Otte <otte@gnome.org>
There are many others who have contributed patches; we thank them,
GTK+ is much better because of them.
GTK is much better because of them.
Over time, GTK+ has incorporated some pieces of software which
Over time, GTK has incorporated some pieces of software which
started as independent projects. We list the original authors here:
@@ -63,3 +76,8 @@ DirectFB backend
Denis Oliver Kropp
Sven Neumann
Mike Emmel
gtkparasite
-----------
Christian Hammond

141
NEWS
View File

@@ -1,3 +1,144 @@
Overview of Changes in GTK 3.99.2
=================================
* GtkButton:
- Check coordinates for button releases
* GtkColorChooser:
- Update the default palette
* GtkEntry:
- Fix issues with Emoji insertion
- Fix issues with dnd
- Set correct hotspot for dnd icon
* GtkFileChooser:
- Fix a crash
- Fix setting unlisted filters
* GtkFontChooser:
- Determine sample text based on font coverage (requires fontconfig)
- Allow filtering by language (requires fontconfig)
- Don't center the list
* GtkMenuButton:
- Always use the direction property for the arrow
* GtkPasswordEntry:
- Use non-pageable memory
- Add an ::activate signal
* GtkRevealer:
- Fix clipping issues in the swing transitions
* GtkScrolledWindow:
- Fix kinetic scrolling in X11
* GtkSearchEntry:
- Don't handle forwarded events twice
* GtkStack:
- Add gtk_stack_add_child
* GtkTextView:
- Fix dnd
- Improve undo state tracking
- Speed rendering in the presence of selections
- Make clickable links work again
- Fix handling of anchored children
* GtkVideo:
- Make autoplay work
* CSS:
- Allow more than 64 selectors per rule
- Avoid some allocation overhead
* Adwaita:
- Improve gesture graphics
- Tweak DND highlight color
- Add spacing to .navigation-sidebar
* GDK:
- Add gdk_frame_clock_get_fps
- GLES: Fix color channel mixup in textures
- GL: Reduce image copying for texture uploads
* GSK:
- Add radial gradient nodes
- Add GskGLShader and shader nodes
* GL renderer:
- Fix clipping with projective transforms
- Use linear interpolation for offscreen rendering
with non-axis-aligned transforms
- Fix texture caching to avoid size mismatches
- Avoid downloading GL textures when possible,
improving GtkGLArea performance
* Vulkan renderer:
- Fix swapchain creation
* Windows:
- Fix display of CSD windows
* Wayland
- Always ack configure to avoid jumping windows
- Use the primary-selection-unstable-v1 protocol
* API cleanups:
- Make filter and sorter constructors return exact types
- Rename GdkSurfaceState to GdkToplevelState
- Remove GdkWaylandSurface::committed
- Make Wayland backend api take GdkToplevel
- Drop gtk_widget_new
- Drop cairo_surface_upload_to_gl
- Drop gtk_scrolled_window_set_capture_button_press
- Drop gtk_column_view_column_new_with_factory
- Rename gtk_buildable_set_name to gtk_buildable_set_buildable_id
- Drop other GtkBuildable api
* Demos:
- Bug and crash fixes
- Cosmetic improvements for several demos
- Improve search in the sidebar
- Add a Shadertoy demo
- Add a OpenGL transitions demo
- Add an Emblem demo
- Add a demo for input validation and error states
- Add a demo for context menus
- Make gtk-demo demo itself
* Build:
- Fix Vulkan dependency checking
- Make sysprof truly optional
* Translation updates:
Basque
British English
Catalan
Croatian
Czech
Danish
French
Galician
German
Hebrew
Hungarian
Indonesian
Italian
Kazakh
Latvian
Lithuanian
Persian
Polish
Slovak
Slovenian
Spanish
Turkish
Ukrainian
Overview of Changes in GTK 3.99.1
=================================

View File

@@ -69,6 +69,9 @@
/* Define to 1 if you have the `mkstemp' function. */
#mesondefine HAVE_MKSTEMP
/* Define to 1 if you have the `mlock` function. */
#mesondefine HAVE_MLOCK
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP

View File

@@ -177,11 +177,11 @@ constraint_view_init (ConstraintView *self)
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
list = g_list_store_new (G_TYPE_LIST_MODEL);

View File

@@ -0,0 +1,345 @@
// Originally from: https://www.shadertoy.com/view/wsjBD3
// License CC0: A battered alien planet
// Been experimenting with space inspired shaders
#define PI 3.141592654
#define TAU (2.0*PI)
#define TOLERANCE 0.00001
#define MAX_ITER 65
#define MIN_DISTANCE 0.01
#define MAX_DISTANCE 9.0
const vec3 skyCol1 = vec3(0.35, 0.45, 0.6);
const vec3 skyCol2 = vec3(0.4, 0.7, 1.0);
const vec3 skyCol3 = pow(skyCol1, vec3(0.25));
const vec3 sunCol1 = vec3(1.0,0.6,0.4);
const vec3 sunCol2 = vec3(1.0,0.9,0.7);
const vec3 smallSunCol1 = vec3(1.0,0.5,0.25)*0.5;
const vec3 smallSunCol2 = vec3(1.0,0.5,0.25)*0.5;
const vec3 mountainColor = 1.0*sqrt(vec3(0.95, 0.65, 0.45));
const float cellWidth = 1.0;
const vec4 planet = vec4(80.0, -20.0, 100.0, 50.0)*1000.0;
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(p.x*c + p.y*s, -p.x*s + p.y*c);
}
vec2 mod2(inout vec2 p, vec2 size) {
vec2 c = floor((p + size*0.5)/size);
p = mod(p + size*0.5,size) - size*0.5;
return c;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float egg(vec2 p, float ra, float rb) {
const float k = sqrt(3.0);
p.x = abs(p.x);
float r = ra - rb;
return ((p.y<0.0) ? length(vec2(p.x, p.y )) - r :
(k*(p.x+r)<p.y) ? length(vec2(p.x, p.y-k*r)) :
length(vec2(p.x+r,p.y )) - 2.0*r) - rb;
}
vec2 hash(vec2 p) {
p = vec2(dot (p, vec2 (127.1, 311.7)), dot (p, vec2 (269.5, 183.3)));
return -1. + 2.*fract (sin (p)*43758.5453123);
}
vec2 raySphere(vec3 ro, vec3 rd, vec4 sphere) {
vec3 center = sphere.xyz;
float radius = sphere.w;
vec3 m = ro - center.xyz;
float b = dot(m, rd);
float c = dot(m, m) - radius*radius;
if(c > 0.0 && b > 0.0) return vec2(-1.0, -1.0);
float discr = b * b - c;
if(discr < 0.0) return vec2(-1.0);
float normalMultiplier = 1.0;
float s = sqrt(discr);
float t0 = -b - s;
float t1 = -b + s;;
return vec2(t0, t1);
}
float noise1(vec2 p) {
vec2 n = mod2(p, vec2(cellWidth));
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
hh.x *= hh.y;
float r = 0.225*cellWidth;
float d = circle(p, 2.0*r);
float h = hh.x*smoothstep(0.0, r, -d);
return h*0.25;
}
float noise2(vec2 p) {
vec2 n = mod2(p, vec2(cellWidth));
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
hh.x *= hh.y;
rot(p, TAU*hh.y);
float r = 0.45*cellWidth;
// float d = circle(p, 1.0*r);
float d = egg(p, 0.75*r, 0.5*r*abs(hh.y));
float h = (hh.x)*smoothstep(0.0, r, -2.0*d);
return h*0.275;
}
float height(vec2 p, float dd, int mx) {
const float aa = 0.45;
const float ff = 2.03;
const float tt = 1.2;
const float oo = 3.93;
const float near = 0.25;
const float far = 0.65;
float a = 1.0;
float o = 0.2;
float s = 0.0;
float d = 0.0;
int i = 0;
for (; i < 4;++i) {
float nn = a*noise2(p);
s += nn;
d += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
float lod = s/d;
float rdd = dd/MAX_DISTANCE;
mx = int(mix(float(4), float(mx), step(rdd, far)));
for (; i < mx; ++i) {
float nn = a*noise1(p);
s += nn;
d += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
float hid = (s/d);
return mix(hid, lod, smoothstep(near, far, rdd));
}
float loheight(vec2 p, float d) {
return height(p, d, 0);
}
float height(vec2 p, float d) {
return height(p, d, 6);
}
float hiheight(vec2 p, float d) {
return height(p, d, 8);
}
vec3 normal(vec2 p, float d) {
vec2 eps = vec2(0.00125, 0.0);
vec3 n;
n.x = (hiheight(p - eps.xy, d) - hiheight(p + eps.xy, d));
n.y = 2.0*eps.x;
n.z = (hiheight(p - eps.yx, d) - hiheight(p + eps.yx, d));
return normalize(n);
}
const float stepLength[] = float[](0.9, 0.25);
float march(vec3 ro, vec3 rd, out int max_iter) {
float dt = 0.1;
float d = MIN_DISTANCE;
int currentStep = 0;
float lastd = d;
for (int i = 0; i < MAX_ITER; ++i)
{
vec3 p = ro + d*rd;
float h = height(p.xz, d);
if (d > MAX_DISTANCE) {
max_iter = i;
return MAX_DISTANCE;
}
float hd = p.y - h;
if (hd < TOLERANCE) {
++currentStep;
if (currentStep >= stepLength.length()) {
max_iter = i;
return d;
}
d = lastd;
continue;
}
float sl = stepLength[currentStep];
dt = max(hd, TOLERANCE)*sl + 0.0025*d;
lastd = d;
d += dt;
}
max_iter = MAX_ITER;
return MAX_DISTANCE;
}
vec3 sunDirection() {
return normalize(vec3(-0.5, 0.085, 1.0));
}
vec3 smallSunDirection() {
return normalize(vec3(-0.2, -0.05, 1.0));
}
float psin(float f) {
return 0.5 + 0.5*sin(f);
}
vec3 skyColor(vec3 ro, vec3 rd) {
vec3 sunDir = sunDirection();
vec3 smallSunDir = smallSunDirection();
float sunDot = max(dot(rd, sunDir), 0.0);
float smallSunDot = max(dot(rd, smallSunDir), 0.0);
float angle = atan(rd.y, length(rd.xz))*2.0/PI;
vec3 skyCol = mix(mix(skyCol1, skyCol2, max(0.0, angle)), skyCol3, clamp(-angle*2.0, 0.0, 1.0));
vec3 sunCol = 0.5*sunCol1*pow(sunDot, 20.0) + 8.0*sunCol2*pow(sunDot, 2000.0);
vec3 smallSunCol = 0.5*smallSunCol1*pow(smallSunDot, 200.0) + 8.0*smallSunCol2*pow(smallSunDot, 20000.0);
vec3 dust = pow(sunCol2*mountainColor, vec3(1.75))*smoothstep(0.05, -0.1, rd.y)*0.5;
vec2 si = raySphere(ro, rd, planet);
vec3 planetSurface = ro + si.x*rd;
vec3 planetNormal = normalize(planetSurface - planet.xyz);
float planetDiff = max(dot(planetNormal, sunDir), 0.0);
float planetBorder = max(dot(planetNormal, -rd), 0.0);
float planetLat = (planetSurface.x+planetSurface.y)*0.0005;
vec3 planetCol = mix(1.3*vec3(0.9, 0.8, 0.7), 0.3*vec3(0.9, 0.8, 0.7), pow(psin(planetLat+1.0)*psin(sqrt(2.0)*planetLat+2.0)*psin(sqrt(3.5)*planetLat+3.0), 0.5));
vec3 final = vec3(0.0);
final += step(0.0, si.x)*pow(planetDiff, 0.75)*planetCol*smoothstep(-0.075, 0.0, rd.y)*smoothstep(0.0, 0.1, planetBorder);
final += skyCol + sunCol + smallSunCol + dust;
return final;
}
vec3 getColor(vec3 ro, vec3 rd) {
int max_iter = 0;
vec3 skyCol = skyColor(ro, rd);
vec3 col = vec3(0);
float d = march(ro, rd, max_iter);
if (d < MAX_DISTANCE) {
vec3 sunDir = sunDirection();
vec3 osunDir = sunDir*vec3(-1.0, .0, -1.0);
vec3 p = ro + d*rd;
vec3 normal = normal(p.xz, d);
float amb = 0.2;
float dif1 = max(0.0, dot(sunDir, normal));
vec3 shd1 = sunCol2*mix(amb, 1.0, pow(dif1, 0.75));
float dif2 = max(0.0, dot(osunDir, normal));
vec3 shd2 = sunCol1*mix(amb, 1.0, pow(dif2, 0.75));
vec3 ref = reflect(rd, normal);
vec3 rcol = skyColor(p, ref);
col = mountainColor*amb*skyCol3;
col += mix(shd1, shd2, -0.5)*mountainColor;
float fre = max(dot(normal, -rd), 0.0);
fre = pow(1.0 - fre, 5.0);
col += rcol*fre*0.5;
col += (1.0*p.y);
col = tanh(col);
col = mix(col, skyCol, smoothstep(0.5*MAX_DISTANCE, 1.0*MAX_DISTANCE, d));
} else {
col = skyCol;
}
// col += vec3(1.1, 0.0, 0.0)* smoothstep(0.25, 1.0,(float(max_iter)/float(MAX_ITER)));
return col;
}
vec3 getSample1(vec2 p, float time) {
float off = 0.5*iTime;
vec3 ro = vec3(0.5, 1.0-0.25, -2.0 + off);
vec3 la = ro + vec3(0.0, -0.30, 2.0);
vec3 ww = normalize(la - ro);
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0), ww));
vec3 vv = normalize(cross(ww, uu));
vec3 rd = normalize(p.x*uu + p.y*vv + 2.0*ww);
vec3 col = getColor(ro, rd) ;
return col;
}
vec3 getSample2(vec2 p, float time) {
p.y-=time*0.25;
float h = height(p, 0.0);
vec3 n = normal(p, 0.0);
vec3 lp = vec3(10.0, -1.2, 0.0);
vec3 ld = normalize(vec3(p.x, h, p.y)- lp);
float d = max(dot(ld, n), 0.0);
vec3 col = vec3(0.0);
col = vec3(1.0)*(h+0.1);
col += vec3(1.5)*pow(d, 0.75);
return col;
}
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 q = fragCoord.xy/iResolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= iResolution.x/iResolution.y;
vec3 col = getSample1(p, iTime);
fragColor = vec4(col, 1.0);
}

View File

@@ -472,11 +472,11 @@ static void
surface_state_changed (GtkWidget *widget)
{
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
GdkSurfaceState new_state;
GdkToplevelState new_state;
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
window->maximized = (new_state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
window->fullscreen = (new_state & GDK_SURFACE_STATE_FULLSCREEN) != 0;
window->maximized = (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
window->fullscreen = (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
}
static void

View File

@@ -1,8 +1,8 @@
/* Assistant
*
* Demonstrates a sample multi-step assistant. Assistants are used to divide
* an operation into several simpler sequential steps, and to guide the user
* through these steps.
* Demonstrates a sample multi-step assistant with GtkAssistant. Assistants
* are used to divide an operation into several simpler sequential steps,
* and to guide the user through these steps.
*/
#include <gtk/gtk.h>

BIN
demos/gtk-demo/bbb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,6 +1,8 @@
/* Builder
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkStatusBar, toolbar
*
* Demonstrates an interface loaded from a XML description.
* Demonstrates a traditional interface, loaded from a XML description,
* and shows how to connect actions to the menu items and toolbar buttons.
*/
#include <gtk/gtk.h>
@@ -104,6 +106,7 @@ do_builder (GtkWidget *do_widget)
GtkBuilder *builder;
GtkWidget *about;
GtkWidget *status;
GtkEventController *controller;
builder = gtk_builder_new_from_resource ("/builder/demo.ui");
@@ -117,6 +120,41 @@ do_builder (GtkWidget *do_widget)
window);
gtk_widget_insert_action_group (window, "win", actions);
controller = gtk_shortcut_controller_new ();
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
GTK_SHORTCUT_SCOPE_GLOBAL);
gtk_widget_add_controller (window, controller);
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_n, GDK_CONTROL_MASK),
gtk_named_action_new ("win.new")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_o, GDK_CONTROL_MASK),
gtk_named_action_new ("win.open")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_s, GDK_CONTROL_MASK),
gtk_named_action_new ("win.save")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_s, GDK_CONTROL_MASK|GDK_SHIFT_MASK),
gtk_named_action_new ("win.save-as")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_q, GDK_CONTROL_MASK),
gtk_named_action_new ("win.quit")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_c, GDK_CONTROL_MASK),
gtk_named_action_new ("win.copy")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_x, GDK_CONTROL_MASK),
gtk_named_action_new ("win.cut")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_v, GDK_CONTROL_MASK),
gtk_named_action_new ("win.paste")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_F1, 0),
gtk_named_action_new ("win.help")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_F7, 0),
gtk_named_action_new ("win.about")));
about = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (window));
gtk_window_set_hide_on_close (GTK_WINDOW (about), TRUE);

224
demos/gtk-demo/cogs.glsl Normal file
View File

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

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

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

View File

@@ -1,4 +1,5 @@
/* Combo Boxes
* #Keywords: GtkCellRenderer
*
* The GtkComboBox widget allows to select one option out of a list.
* The GtkComboBoxEntry additionally allows the user to enter a value

View File

@@ -1,4 +1,5 @@
/* Constraints/Simple
* #Keywords: GtkLayoutManager
*
* GtkConstraintLayout provides a layout manager that uses relations
* between widgets (also known as "constraints") to compute the position

View File

@@ -1,4 +1,5 @@
/* Constraints/Interactive
* #Keywords: GtkConstraintLayout
*
* Demonstrate how constraints can be updates during user interaction.
* The vertical edge between the buttons can be dragged with the mouse.

View File

@@ -1,7 +1,6 @@
/* Theming/CSS Accordion
*
* A simple accordion demo written using CSS transitions and multiple backgrounds
*
*/
#include <gtk/gtk.h>

View File

@@ -1,8 +1,7 @@
/* Theming/CSS Basics
*
* Gtk themes are written using CSS. Every widget is build of multiple items
* GTK themes are written using CSS. Every widget is build of multiple items
* that you can style very similarly to a regular website.
*
*/
#include <gtk/gtk.h>

View File

@@ -1,8 +1,7 @@
/* Theming/Multiple Backgrounds
*
* Gtk themes are written using CSS. Every widget is build of multiple items
* GTK themes are written using CSS. Every widget is build of multiple items
* that you can style very similarly to a regular website.
*
*/
#include <gtk/gtk.h>

View File

@@ -1,6 +1,7 @@
/* Theming/Animated Backgrounds
*
* This demo is done in honour of the Pixbufs demo further down.
* This demo is in honour of a classic Pixbufs demo.
*
* It is done exclusively with CSS as the background of the window.
*/

View File

@@ -112,6 +112,9 @@
<gresource prefix="/dnd">
<file>dnd.css</file>
</gresource>
<gresource prefix="/errorstates">
<file>errorstates.ui</file>
</gresource>
<gresource prefix="/fishbowl">
<file>fishbowl.ui</file>
<file>gtkfishbowl.c</file>
@@ -121,6 +124,27 @@
<file>gtkgears.c</file>
<file>gtkgears.h</file>
</gresource>
<gresource prefix="/shadertoy">
<file>gtkshadertoy.c</file>
<file>gtkshadertoy.h</file>
<file>alienplanet.glsl</file>
<file>mandelbrot.glsl</file>
<file>neon.glsl</file>
<file>cogs.glsl</file>
<file>glowingstars.glsl</file>
</gresource>
<gresource prefix="/gltransition">
<file>gtkshaderstack.c</file>
<file>gtkshaderstack.h</file>
<file>gtkshaderbin.h</file>
<file>gtkshaderbin.c</file>
<file>fire.glsl</file>
<file>transition1.glsl</file>
<file>transition2.glsl</file>
<file>transition3.glsl</file>
<file>transition4.glsl</file>
<file>cogs2.glsl</file>
</gresource>
<gresource prefix="/iconscroll">
<file>iconscroll.ui</file>
</gresource>
@@ -164,6 +188,16 @@
<file compressed="true">color.names.txt</file>
<file>listview_colors.css</file>
</gresource>
<gresource prefix="/main">
<file>fontify.c</file>
<file>fontify.h</file>
<file>main.ui</file>
</gresource>
<gresource prefix="/menu">
<file>demo3widget.c</file>
<file>demo3widget.h</file>
<file>demo3widget.ui</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
@@ -187,6 +221,9 @@
<file>floppybuddy.gif</file>
<file>gtk-logo.webm</file>
</gresource>
<gresource prefix="/video-player">
<file>bbb.png</file>
</gresource>
<gresource prefix="/sources">
<file>application_demo.c</file>
<file>assistant.c</file>
@@ -210,6 +247,7 @@
<file>editable_cells.c</file>
<file>entry_completion.c</file>
<file>entry_undo.c</file>
<file>errorstates.c</file>
<file>expander.c</file>
<file>filtermodel.c</file>
<file>fishbowl.c</file>
@@ -221,6 +259,7 @@
<file>gears.c</file>
<file>gestures.c</file>
<file>glarea.c</file>
<file>gltransition.c</file>
<file>headerbar.c</file>
<file>hypertext.c</file>
<file>iconscroll.c</file>
@@ -242,13 +281,16 @@
<file>listview_weather.c</file>
<file>listview_words.c</file>
<file>list_store.c</file>
<file>main.c</file>
<file>markup.c</file>
<file>menu.c</file>
<file>overlay.c</file>
<file>overlay2.c</file>
<file>paint.c</file>
<file>pagesetup.c</file>
<file>paintable.c</file>
<file>paintable_animated.c</file>
<file>paintable_emblem.c</file>
<file>paintable_mediastream.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
@@ -260,6 +302,7 @@
<file>scale.c</file>
<file>search_entry.c</file>
<file>search_entry2.c</file>
<file>shadertoy.c</file>
<file>shortcuts.c</file>
<file>shortcut_triggers.c</file>
<file>sizegroup.c</file>

View File

@@ -29,29 +29,24 @@
<item>
<attribute name="label" translatable="yes">_New</attribute>
<attribute name="action">win.new</attribute>
<attribute name="accel">&lt;Control&gt;n</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open</attribute>
<attribute name="action">win.open</attribute>
<attribute name="accel">&lt;Control&gt;o</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="action">win.save</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save _As</attribute>
<attribute name="action">win.save-as</attribute>
<attribute name="accel">&lt;Control&gt;q</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">win.quit</attribute>
<attribute name="accel">&lt;Control&gt;&lt;Shift&gt;s</attribute>
</item>
</section>
</submenu>
@@ -61,17 +56,14 @@
<item>
<attribute name="label" translatable="yes">_Copy</attribute>
<attribute name="action">win.copy</attribute>
<attribute name="accel">&lt;Control&gt;c</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Cut</attribute>
<attribute name="action">win.cut</attribute>
<attribute name="accel">&lt;Control&gt;x</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Paste</attribute>
<attribute name="action">win.paste</attribute>
<attribute name="accel">&lt;Control&gt;v</attribute>
</item>
</section>
</submenu>
@@ -81,12 +73,10 @@
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">win.help</attribute>
<attribute name="accel">F1</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About</attribute>
<attribute name="action">win.about</attribute>
<attribute name="accel">F7</attribute>
</item>
</section>
</submenu>
@@ -110,11 +100,15 @@
</child>
<child>
<object class="GtkBox" id="toolbar1">
<style>
<class name="toolbar"/>
</style>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">New</property>
<property name="tooltip-text" translatable="yes">Create a new file</property>
<property name="icon-name">document-new</property>
<property name="action-name">win.new</property>
</object>
</child>
<child>
@@ -122,6 +116,7 @@
<property name="label" translatable="yes">Open</property>
<property name="tooltip-text" translatable="yes">Open a file</property>
<property name="icon-name">document-open</property>
<property name="action-name">win.open</property>
</object>
</child>
<child>
@@ -129,6 +124,7 @@
<property name="label" translatable="yes">Save</property>
<property name="tooltip-text" translatable="yes">Save a file</property>
<property name="icon-name">document-save</property>
<property name="action-name">win.save</property>
</object>
</child>
<child>
@@ -139,6 +135,7 @@
<property name="label" translatable="yes">Copy</property>
<property name="tooltip-text" translatable="yes">Copy selected object into the clipboard</property>
<property name="icon-name">edit-copy</property>
<property name="action-name">win.copy</property>
</object>
</child>
<child>
@@ -146,6 +143,7 @@
<property name="label" translatable="yes">Cut</property>
<property name="tooltip-text" translatable="yes">Cut selected object into the clipboard</property>
<property name="icon-name">edit-cut</property>
<property name="action-name">win.cut</property>
</object>
</child>
<child>
@@ -153,6 +151,7 @@
<property name="label" translatable="yes">Paste</property>
<property name="tooltip-text" translatable="yes">Paste object from the clipboard</property>
<property name="icon-name">edit-paste</property>
<property name="action-name">win.paste</property>
</object>
</child>
</object>

View File

@@ -0,0 +1,243 @@
#include <math.h>
#include "demo3widget.h"
enum
{
PROP_PAINTABLE = 1,
PROP_SCALE
};
struct _Demo3Widget
{
GtkWidget parent_instance;
GdkPaintable *paintable;
float scale;
GtkWidget *menu;
};
struct _Demo3WidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (Demo3Widget, demo3_widget, GTK_TYPE_WIDGET)
static void
demo3_widget_init (Demo3Widget *self)
{
self->scale = 1.f;
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
demo3_widget_dispose (GObject *object)
{
Demo3Widget *self = DEMO3_WIDGET (object);
g_clear_object (&self->paintable);
g_clear_pointer (&self->menu, gtk_widget_unparent);
G_OBJECT_CLASS (demo3_widget_parent_class)->dispose (object);
}
static void
demo3_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
int x, y, width, height;
double w, h;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
w = self->scale * gdk_paintable_get_intrinsic_width (self->paintable);
h = self->scale * gdk_paintable_get_intrinsic_height (self->paintable);
x = MAX (0, (width - ceil (w)) / 2);
y = MAX (0, (height - ceil (h)) / 2);
gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gdk_paintable_snapshot (self->paintable, snapshot, w, h);
gtk_snapshot_restore (snapshot);
gtk_snapshot_pop (snapshot);
}
static void
demo3_widget_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
int size;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
size = gdk_paintable_get_intrinsic_width (self->paintable);
else
size = gdk_paintable_get_intrinsic_height (self->paintable);
*minimum = *natural = self->scale * size;
}
static void
demo3_widget_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
/* Since we are not using a layout manager (who would do this
* for us), we need to allocate a size for our menu by calling
* gtk_native_check_resize().
*/
gtk_native_check_resize (GTK_NATIVE (self->menu));
}
static void
demo3_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
Demo3Widget *self = DEMO3_WIDGET (object);
switch (prop_id)
{
case PROP_PAINTABLE:
g_clear_object (&self->paintable);
self->paintable = g_value_dup_object (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
case PROP_SCALE:
self->scale = g_value_get_float (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo3_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
Demo3Widget *self = DEMO3_WIDGET (object);
switch (prop_id)
{
case PROP_PAINTABLE:
g_value_set_object (value, self->paintable);
break;
case PROP_SCALE:
g_value_set_float (value, self->scale);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
pressed_cb (GtkGestureClick *gesture,
guint n_press,
double x,
double y,
Demo3Widget *self)
{
/* We are placing our menu at the point where
* the click happened, before popping it up.
*/
gtk_popover_set_pointing_to (GTK_POPOVER (self->menu),
&(const GdkRectangle){ x, y, 1, 1 });
gtk_popover_popup (GTK_POPOVER (self->menu));
}
static void
zoom_cb (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
Demo3Widget *self = DEMO3_WIDGET (widget);
float scale;
if (g_str_equal (action_name, "zoom.in"))
scale = MIN (10, self->scale * M_SQRT2);
else if (g_str_equal (action_name, "zoom.out"))
scale = MAX (0.01, self->scale / M_SQRT2);
else
scale = 1.0;
gtk_widget_action_set_enabled (widget, "zoom.in", scale < 10);
gtk_widget_action_set_enabled (widget, "zoom.out", scale > 0.01);
gtk_widget_action_set_enabled (widget, "zoom.reset", scale != 1);
g_object_set (widget, "scale", scale, NULL);
}
static void
demo3_widget_class_init (Demo3WidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo3_widget_dispose;
object_class->set_property = demo3_widget_set_property;
object_class->get_property = demo3_widget_get_property;
widget_class->snapshot = demo3_widget_snapshot;
widget_class->measure = demo3_widget_measure;
widget_class->size_allocate = demo3_widget_size_allocate;
g_object_class_install_property (object_class, PROP_PAINTABLE,
g_param_spec_object ("paintable", "Paintable", "Paintable",
GDK_TYPE_PAINTABLE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_SCALE,
g_param_spec_float ("scale", "Scale", "Scale",
0.0, 10.0, 1.0,
G_PARAM_READWRITE));
/* These are the actions that we are using in the menu */
gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "zoom.reset", NULL, zoom_cb);
gtk_widget_class_set_template_from_resource (widget_class, "/menu/demo3widget.ui");
gtk_widget_class_bind_template_child (widget_class, Demo3Widget, menu);
gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
}
GtkWidget *
demo3_widget_new (const char *resource)
{
Demo3Widget *self;
GdkPixbuf *pixbuf;
GdkPaintable *paintable;
pixbuf = gdk_pixbuf_new_from_resource (resource, NULL);
paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
self = g_object_new (DEMO3_TYPE_WIDGET, "paintable", paintable, NULL);
g_object_unref (pixbuf);
g_object_unref (paintable);
return GTK_WIDGET (self);
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include <gtk/gtk.h>
#define DEMO3_TYPE_WIDGET (demo3_widget_get_type ())
G_DECLARE_FINAL_TYPE (Demo3Widget, demo3_widget, DEMO3, WIDGET, GtkWidget)
GtkWidget * demo3_widget_new (const char *resource);

View File

@@ -0,0 +1,30 @@
<interface>
<menu id="model">
<item>
<attribute name="label">Zoom Out</attribute>
<attribute name="action">zoom.out</attribute>
</item>
<item>
<attribute name="label">Zoom In</attribute>
<attribute name="action">zoom.in</attribute>
</item>
<item>
<attribute name="label">11</attribute>
<attribute name="action">zoom.reset</attribute>
</item>
</menu>
<template class="Demo3Widget">
<child>
<object class="GtkPopoverMenu" id="menu">
<property name="has-arrow">0</property>
<property name="menu-model">model</property>
</object>
</child>
<child>
<object class="GtkGestureClick">
<property name="button">3</property>
<signal name="pressed" handler="pressed_cb"/>
</object>
</child>
</template>
</interface>

View File

@@ -1,4 +1,5 @@
/* Dialogs
* #Keywords: GtkMessageDialog
*
* Dialogs are used to pop up transient windows for information
* and user feedback.

View File

@@ -1,8 +1,12 @@
/* Drag-and-Drop
* #Keywords: dnd, menu, popover, gesture
*
* This demo shows dragging colors and widgets.
* The items in this demo can be moved, recolored
* and rotated.
*
* The demo also has an example for creating a
* menu-like popover without using a menu model.
*/
#include <gtk/gtk.h>

View File

@@ -1,4 +1,5 @@
/* Drawing Area
* #Keywords: GtkDrawingArea
*
* GtkDrawingArea is a blank area where you can draw custom displays
* of various kinds.

View File

@@ -0,0 +1,124 @@
/* Error states
*
* GtkLabel and GtkEntry can indicate errors if you set the .error
* style class on them.
*
* This examples shows how this can be used in a dialog for input validation.
*
* It also shows how pass callbacks and objects to GtkBuilder with
* GtkBuilderScope and gtk_builder_expose_object().
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static void
validate_more_details (GtkEntry *entry,
GParamSpec *pspec,
GtkEntry *details)
{
if (strlen (gtk_editable_get_text (GTK_EDITABLE (entry))) > 0 &&
strlen (gtk_editable_get_text (GTK_EDITABLE (details))) == 0)
{
gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "Must have details first");
gtk_widget_add_css_class (GTK_WIDGET (entry), "error");
}
else
{
gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "");
gtk_widget_remove_css_class (GTK_WIDGET (entry), "error");
}
}
static gboolean
mode_switch_state_set (GtkSwitch *sw,
gboolean state,
GtkWidget *scale)
{
GtkWidget *label;
label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label"));
if (!state ||
(gtk_range_get_value (GTK_RANGE (scale)) > 50))
{
gtk_widget_hide (label);
gtk_switch_set_state (sw, state);
}
else
{
gtk_widget_show (label);
}
return TRUE;
}
static void
level_scale_value_changed (GtkRange *range,
GtkWidget *sw)
{
GtkWidget *label;
label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label"));
if (gtk_switch_get_active (GTK_SWITCH (sw)) &&
!gtk_switch_get_state (GTK_SWITCH (sw)) &&
(gtk_range_get_value (range) > 50))
{
gtk_widget_hide (label);
gtk_switch_set_state (GTK_SWITCH (sw), TRUE);
}
else if (gtk_switch_get_state (GTK_SWITCH (sw)) &&
(gtk_range_get_value (range) <= 50))
{
gtk_switch_set_state (GTK_SWITCH (sw), FALSE);
}
}
GtkWidget *
do_errorstates (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *toplevel;
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkWidget *sw, *label;
toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget));
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
"validate_more_details", G_CALLBACK (validate_more_details),
"mode_switch_state_set", G_CALLBACK (mode_switch_state_set),
"level_scale_value_changed", G_CALLBACK (level_scale_value_changed),
NULL);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_expose_object (builder, "toplevel", G_OBJECT (toplevel));
gtk_builder_add_from_resource (builder, "/errorstates/errorstates.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "dialog"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
sw = GTK_WIDGET (gtk_builder_get_object (builder, "mode_switch"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
g_object_set_data (G_OBJECT (sw), "error_label", label);
g_object_unref (builder);
g_object_unref (scope);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkDialog" id="dialog">
<property name="transient-for">toplevel</property>
<property name="modal">1</property>
<property name="resizable">0</property>
<property name="use-header-bar">1</property>
<property name="title" translatable="yes">Settings</property>
<property name="hide-on-close">1</property>
<child internal-child="content_area">
<object class="GtkBox">
<child>
<object class="GtkGrid">
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<child>
<object class="GtkLabel">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="label">_Details</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">details_entry</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="details_entry">
<property name="valign">baseline</property>
<signal name="notify::text" handler="validate_more_details" object="more_details_entry" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="label">More D_etails</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">more_details_entry</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="more_details_entry">
<property name="valign">baseline</property>
<signal name="notify::text" handler="validate_more_details" object="details_entry" swapped="no"/>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="label">_Level</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">level_scale</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkScale" id="level_scale">
<property name="valign">baseline</property>
<property name="draw-value">0</property>
<property name="adjustment">
<object class="GtkAdjustment">
<property name="upper">100</property>
<property name="lower">0</property>
<property name="value">50</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
</property>
<signal name="value-changed" handler="level_scale_value_changed" object="mode_switch" swapped="no"/>
<layout>
<property name="column">1</property>
<property name="row">2</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="label">_Mode</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">mode_switch</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSwitch" id="mode_switch">
<property name="halign">start</property>
<property name="valign">baseline</property>
<signal name="state-set" handler="mode_switch_state_set" object="level_scale" swapped="no"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="error_label">
<property name="visible">0</property>
<property name="halign">start</property>
<property name="valign">baseline</property>
<property name="label">Level too low</property>
<style>
<class name="error"/>
</style>
<layout>
<property name="column">2</property>
<property name="row">3</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,4 +1,5 @@
/* Tree View/Filter Model
* #Keywords: GtkTreeView
*
* This example demonstrates how GtkTreeModelFilter can be used not
* just to show a subset of the rows, but also to compute columns

72
demos/gtk-demo/fire.glsl Normal file
View File

@@ -0,0 +1,72 @@
uniform float u_time;
uniform sampler2D u_texture1;
/* 2D -> [0..1] random number generator */
float random(vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233))) *
43758.5453123);
}
/* Generate a smoothed 2d noise based on random() */
float noise(vec2 v) {
/* Round point v to integer grid grid */
vec2 grid_point = floor(v);
/* Randomize in grid corners */
float corner1 = random(grid_point);
float corner2 = random(grid_point + vec2(1, 0));
float corner3 = random(grid_point + vec2(0, 1));
float corner4 = random(grid_point + vec2(1, 1));
/* Interpolate smoothly between grid points */
vec2 fraction = smoothstep(vec2(0.0), vec2(1.0), fract(v));
return mix(mix(corner1, corner2, fraction.x),
mix(corner3, corner4, fraction.x),
fraction.y);
}
/* fractal brownian motion noice, see https://www.iquilezles.org/www/articles/fbm/fbm.htm */
float fbm(in vec2 x)
{
const float octaveScale = 1.9;
const float G = 0.5;
float f = 1.0;
float a = 1.0;
float t = 0.0;
int numOctaves = 5;
for (int i = 0; i < numOctaves; i++) {
t += a*noise(f*x);
f *= octaveScale;
a *= G;
}
return t;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
vec2 xy = fragCoord / resolution;
float zoom = 3.0 - sin(u_time*0.5)*0.3;
// Normalize coord to height of widget
vec2 p = (vec2 (-resolution.x/2.0 + fragCoord.x, resolution.y - fragCoord.y) / resolution.yy)* zoom;
// Use recursive incantations of fbm
float q1 = fbm(p - vec2(0.8, 0.3) * u_time);
float q2 = fbm(p - vec2(0.5, 1.3) * u_time);
float r = fbm(2.0*p + vec2(q1,q2) - vec2(0.0, 1.0)*u_time*10.0 *0.4);
// Compute intensity, mostly on the bottom
float w = 2.0 * r * p.y;
// Smooth out left/right side and fade in at start
w /= smoothstep(0.0,0.1, xy.x)* smoothstep(0.0,0.1, 1.0-xy.x) * smoothstep(0.0,0.4, u_time);
// Compute colors
vec3 c = vec3(1.0,.2,.05);
vec3 color = 1.0 / (w*w/c + 1.0);
// Mix in widget
vec4 widget = GskTexture(u_texture1,uv);
fragColor = gsk_premultiply(mix(vec4(color,1), widget, 1.0-color.x));
}

View File

@@ -9,6 +9,7 @@
#include "gtkfishbowl.h"
#include "gtkgears.h"
#include "gskshaderpaintable.h"
const char *const css =
".blurred-button {"
@@ -149,6 +150,38 @@ create_switch (void)
return w;
}
static gboolean
update_paintable (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GskShaderPaintable *paintable;
gint64 frame_time;
paintable = GSK_SHADER_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget)));
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
gsk_shader_paintable_update_time (paintable, 0, frame_time);
return G_SOURCE_CONTINUE;
}
static GtkWidget *
create_cogs (void)
{
GtkWidget *picture;
static GskGLShader *cog_shader = NULL;
GdkPaintable *paintable;
if (cog_shader == NULL)
cog_shader = gsk_gl_shader_new_from_resource ("/gltransition/cogs2.glsl");
paintable = gsk_shader_paintable_new (g_object_ref (cog_shader), NULL);
picture = gtk_picture_new_for_paintable (paintable);
gtk_widget_set_size_request (picture, 150, 75);
gtk_widget_add_tick_callback (picture, update_paintable, NULL, NULL);
return picture;
}
static void
mapped (GtkWidget *w)
{
@@ -185,6 +218,7 @@ static const struct {
{ "Gears", create_gears },
{ "Switch", create_switch },
{ "Menubutton", create_menu_button },
{ "Shader", create_cogs },
};
static int selected_widget_type = -1;

View File

@@ -33,6 +33,9 @@
<lookup name="framerate">bowl</lookup>
</closure>
</binding>
<attributes>
<attribute name="font-features" value="tnum=1"/>
</attributes>
</object>
</child>
<child type="end">

View File

@@ -1,4 +1,5 @@
/* Fixed Layout
* #Keywords: GtkLayoutManager
*
* GtkFixed is a container that allows placing and transforming
* widgets manually.

View File

@@ -24,15 +24,29 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
GtkTextIter *end)
{
GtkTextTagTable *table;
PangoAttribute *attr;
GSList *attrs, *l;
GtkTextTag *tag;
char name[256];
float fg_alpha, bg_alpha;
table = gtk_text_buffer_get_tag_table (buffer);
#define STRING_ATTR(pango_attr_name, attr_name) \
attr = pango_attr_iterator_get (iter, pango_attr_name); \
if (attr) \
#define LANGUAGE_ATTR(attr_name) \
{ \
const char *language = pango_language_to_string (((PangoAttrLanguage*)attr)->value); \
g_snprintf (name, 256, "language=%s", language); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
{ \
tag = gtk_text_tag_new (name); \
g_object_set (tag, #attr_name, language, NULL); \
gtk_text_tag_table_add (table, tag); \
g_object_unref (tag); \
} \
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define STRING_ATTR(attr_name) \
{ \
const char *string = ((PangoAttrString*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%s", string); \
@@ -47,9 +61,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define INT_ATTR(pango_attr_name, attr_name) \
attr = pango_attr_iterator_get (iter, pango_attr_name); \
if (attr) \
#define INT_ATTR(attr_name) \
{ \
int value = ((PangoAttrInt*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%d", value); \
@@ -64,9 +76,24 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define FLOAT_ATTR(pango_attr_name, attr_name) \
attr = pango_attr_iterator_get (iter, pango_attr_name); \
if (attr) \
#define FONT_ATTR(attr_name) \
{ \
PangoFontDescription *desc = ((PangoAttrFontDesc*)attr)->desc; \
char *str = pango_font_description_to_string (desc); \
g_snprintf (name, 256, "font-desc=%s", str); \
g_free (str); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
{ \
tag = gtk_text_tag_new (name); \
g_object_set (tag, #attr_name, desc, NULL); \
gtk_text_tag_table_add (table, tag); \
g_object_unref (tag); \
} \
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define FLOAT_ATTR(attr_name) \
{ \
float value = ((PangoAttrFloat*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%g", value); \
@@ -81,9 +108,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define RGBA_ATTR(pango_attr_name, attr_name) \
attr = pango_attr_iterator_get (iter, pango_attr_name); \
if (attr) \
#define RGBA_ATTR(attr_name, alpha_value) \
{ \
PangoColor *color; \
GdkRGBA rgba; \
@@ -91,7 +116,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
rgba.red = color->red / 65535.; \
rgba.green = color->green / 65535.; \
rgba.blue = color->blue / 65535.; \
rgba.alpha = 1.; \
rgba.alpha = alpha_value; \
char *str = gdk_rgba_to_string (&rgba); \
g_snprintf (name, 256, #attr_name "=%s", str); \
g_free (str); \
@@ -106,63 +131,153 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
attr = pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE);
if (attr)
fg_alpha = bg_alpha = 1.;
attrs = pango_attr_iterator_get_attrs (iter);
for (l = attrs; l; l = l->next)
{
const char *language = pango_language_to_string (((PangoAttrLanguage*)attr)->value);
g_snprintf (name, 256, "language=%s", language);
tag = gtk_text_tag_table_lookup (table, name);
if (!tag)
PangoAttribute *attr = l->data;
switch ((int)attr->klass->type)
{
tag = gtk_text_tag_new (name);
g_object_set (tag, "language", language, NULL);
gtk_text_tag_table_add (table, tag);
g_object_unref (tag);
case PANGO_ATTR_FOREGROUND_ALPHA:
fg_alpha = ((PangoAttrInt*)attr)->value / 65535.;
break;
case PANGO_ATTR_BACKGROUND_ALPHA:
bg_alpha = ((PangoAttrInt*)attr)->value / 65535.;
break;
default:
break;
}
gtk_text_buffer_apply_tag (buffer, tag, start, end);
}
STRING_ATTR (PANGO_ATTR_FAMILY, family)
INT_ATTR (PANGO_ATTR_STYLE, style)
INT_ATTR (PANGO_ATTR_WEIGHT, weight)
INT_ATTR (PANGO_ATTR_VARIANT, variant)
INT_ATTR (PANGO_ATTR_STRETCH, stretch)
INT_ATTR (PANGO_ATTR_SIZE, size)
attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_DESC);
if (attr)
for (l = attrs; l; l = l->next)
{
PangoFontDescription *desc = ((PangoAttrFontDesc*)attr)->desc;
char *str = pango_font_description_to_string (desc);
g_snprintf (name, 256, "font-desc=%s", str);
g_free (str);
tag = gtk_text_tag_table_lookup (table, name);
if (!tag)
PangoAttribute *attr = l->data;
switch (attr->klass->type)
{
tag = gtk_text_tag_new (name);
g_object_set (tag, "font-desc", desc, NULL);
gtk_text_tag_table_add (table, tag);
g_object_unref (tag);
case PANGO_ATTR_LANGUAGE:
LANGUAGE_ATTR (language);
break;
case PANGO_ATTR_FAMILY:
STRING_ATTR (family);
break;
case PANGO_ATTR_STYLE:
INT_ATTR (style);
break;
case PANGO_ATTR_WEIGHT:
INT_ATTR (weight);
break;
case PANGO_ATTR_VARIANT:
INT_ATTR (variant);
break;
case PANGO_ATTR_STRETCH:
INT_ATTR (stretch);
break;
case PANGO_ATTR_SIZE:
INT_ATTR (size);
break;
case PANGO_ATTR_FONT_DESC:
FONT_ATTR (font-desc);
break;
case PANGO_ATTR_FOREGROUND:
RGBA_ATTR (foreground_rgba, fg_alpha);
break;
case PANGO_ATTR_BACKGROUND:
RGBA_ATTR (background_rgba, bg_alpha);
break;
case PANGO_ATTR_UNDERLINE:
INT_ATTR (underline);
break;
case PANGO_ATTR_UNDERLINE_COLOR:
RGBA_ATTR (underline_rgba, fg_alpha);
break;
case PANGO_ATTR_OVERLINE:
INT_ATTR (overline);
break;
case PANGO_ATTR_OVERLINE_COLOR:
RGBA_ATTR (overline_rgba, fg_alpha);
break;
case PANGO_ATTR_STRIKETHROUGH:
INT_ATTR (strikethrough);
break;
case PANGO_ATTR_STRIKETHROUGH_COLOR:
RGBA_ATTR (strikethrough_rgba, fg_alpha);
break;
case PANGO_ATTR_RISE:
INT_ATTR (rise);
break;
case PANGO_ATTR_SCALE:
FLOAT_ATTR (scale);
break;
case PANGO_ATTR_FALLBACK:
INT_ATTR (fallback);
break;
case PANGO_ATTR_LETTER_SPACING:
INT_ATTR (letter_spacing);
break;
case PANGO_ATTR_FONT_FEATURES:
STRING_ATTR (font_features);
break;
case PANGO_ATTR_ALLOW_BREAKS:
INT_ATTR (allow_breaks);
break;
case PANGO_ATTR_SHOW:
INT_ATTR (show_spaces);
break;
case PANGO_ATTR_INSERT_HYPHENS:
INT_ATTR (insert_hyphens);
break;
case PANGO_ATTR_SHAPE:
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
case PANGO_ATTR_GRAVITY_HINT:
case PANGO_ATTR_FOREGROUND_ALPHA:
case PANGO_ATTR_BACKGROUND_ALPHA:
break;
case PANGO_ATTR_INVALID:
default:
g_assert_not_reached ();
break;
}
gtk_text_buffer_apply_tag (buffer, tag, start, end);
}
RGBA_ATTR (PANGO_ATTR_FOREGROUND, foreground_rgba)
RGBA_ATTR (PANGO_ATTR_BACKGROUND, background_rgba)
INT_ATTR (PANGO_ATTR_UNDERLINE, underline)
RGBA_ATTR (PANGO_ATTR_UNDERLINE_COLOR, underline_rgba)
INT_ATTR (PANGO_ATTR_OVERLINE, overline)
RGBA_ATTR (PANGO_ATTR_OVERLINE_COLOR, overline_rgba)
INT_ATTR (PANGO_ATTR_STRIKETHROUGH, strikethrough)
RGBA_ATTR (PANGO_ATTR_STRIKETHROUGH_COLOR, strikethrough_rgba)
INT_ATTR (PANGO_ATTR_RISE, rise)
FLOAT_ATTR (PANGO_ATTR_SCALE, scale)
INT_ATTR (PANGO_ATTR_FALLBACK, fallback)
INT_ATTR (PANGO_ATTR_LETTER_SPACING, letter_spacing)
STRING_ATTR (PANGO_ATTR_FONT_FEATURES, font_features)
INT_ATTR (PANGO_ATTR_ALLOW_BREAKS, allow_breaks)
INT_ATTR (PANGO_ATTR_SHOW, show_spaces)
INT_ATTR (PANGO_ATTR_INSERT_HYPHENS, insert_hyphens)
g_slist_free_full (attrs, (GDestroyNotify)pango_attribute_destroy);
#undef LANGUAGE_ATTR
#undef STRING_ATTR
#undef INT_ATTR
#undef FONT_ATTR
#undef FLOAT_ATTR
#undef RGBA_ATTR
}
typedef struct

View File

@@ -6,6 +6,22 @@ import re
import os
from collections import *
def add_quotes(s):
return "\"" + s.lower() + "\""
def wordify(s):
return s.strip().rstrip(".,;:")
def is_keyword(s):
if s == "GTK":
return False
elif s.startswith(("Gtk", "Gdk", "Pango")):
return True
elif s.startswith("G") and s[1].isupper():
return True
else:
return False
out_file = sys.argv[1]
in_files = sys.argv[2:]
@@ -19,13 +35,14 @@ struct _DemoData
{
const char *name;
const char *title;
const char **keywords;
const char *filename;
GDoDemoFunc func;
DemoData *children;
};
"""
# Demo = namedtuple('Demo', ['name', 'title', 'file', 'func'])
# Demo = namedtuple('Demo', ['name', 'title', 'keywords', 'file', 'func'])
demos = []
@@ -34,14 +51,17 @@ for demo_file in in_files:
demo_name = filename.replace(".c", "")
with open(demo_file, 'r', encoding='utf-8') as f:
title = f.readline().replace("/*", "").strip()
keywords = set()
line = f.readline().strip();
while not line.endswith('*/'):
if line.startswith("* #Keywords:"):
keywords = keywords.union(set(map(wordify, line.replace ("* #Keywords:", "").strip().split(","))))
else:
keywords = keywords.union(set(filter(is_keyword, map(wordify, line.replace ("* ", "").split()))))
line = f.readline().strip()
file_output += "GtkWidget *do_" + demo_name + " (GtkWidget *do_widget);\n"
# demos += Demo(name = demo_name,
# title = title,
# file = demo_file,
# func = "do_" + title)
demos.append((demo_name, title, filename, "do_" + demo_name, -1))
demos.append((demo_name, title, keywords, filename, "do_" + demo_name, -1))
# Generate a List of "Parent names"
parents = []
@@ -57,7 +77,7 @@ for demo in demos:
if not parent_name in parents:
parents.append(parent_name)
parent_ids.append(parent_index)
demos.append(("NULL", parent_name, "NULL", "NULL", parent_index))
demos.append(("NULL", parent_name, set(), "NULL", "NULL", parent_index))
parent_index = parent_index + 1
@@ -71,8 +91,7 @@ for parent in parents:
for child in demos:
if child[1].startswith(parent + "/"):
title = child[1][child[1].rfind('/') + 1:]
file_output += " { \"" + child[0] + "\", \"" + title + "\", \"" + child[2] + "\", " + child[3] + ", NULL },\n"
file_output += " { \"" + child[0] + "\", \"" + title + "\", " + "(const char*[]) {" + ", ".join(list(map(add_quotes, child[2])) + ["NULL"]) + " }, \"" + child[3] + "\", " + child[4] + ", NULL },\n"
file_output += " { NULL }\n};\n"
i = i + 1
@@ -86,9 +105,10 @@ for demo in demos:
# Do not generate one of these for demos with a parent demo
if "/" not in demo[1]:
child_array = "NULL"
name = demo[0];
title = demo[1];
file = demo[2]
name = demo[0]
title = demo[1]
keywords = demo[2]
file = demo[3]
if name != "NULL":
name = "\"" + name + "\""
if title != "NULL":
@@ -96,9 +116,9 @@ for demo in demos:
if file != "NULL":
file = "\"" + file + "\""
if demo[4] != -1:
child_array = "child" + str(demo[4])
file_output += " { " + name + ", " + title + ", " + file + ", " + demo[3] + ", " + child_array + " },\n"
if demo[5] != -1:
child_array = "child" + str(demo[5])
file_output += " { " + name + ", " + title + ", " + "(const char*[]) {" + ", ".join(list(map(add_quotes, keywords)) + ["NULL"]) + " }, " + file + ", " + demo[4] + ", " + child_array + " },\n"
file_output += " { NULL }\n};\n"

View File

@@ -1,4 +1,5 @@
/* Gestures
* #Keywords: GtkGesture
*
* Perform gestures on touchscreens and other input devices. This
* demo reacts to long presses and swipes from all devices, plus

View File

@@ -0,0 +1,174 @@
// Originally from: https://www.shadertoy.com/view/ttBcRV
// License CC0: Flying through glowing stars
// The result of playing around trying to improve an old shader
#define PI 3.141592654
#define TAU (2.0*PI)
#define TIME iTime
#define RESOLUTION iResolution
#define LESS(a,b,c) mix(a,b,step(0.,c))
#define SABS(x,k) LESS((.5/(k))*(x)*(x)+(k)*.5,abs(x),abs(x)-(k))
#define MROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
vec3 hsv2rgb(vec3 c) {
const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
float hash(in vec3 co) {
return fract(sin(dot(co, vec3(12.9898,58.233, 12.9898+58.233))) * 13758.5453);
}
float starn(vec2 p, float r, int n, float m) {
// From IQ: https://www.shadertoy.com/view/3tSGDy
// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
// Minor tweak to use SABS over abs to smooth inner corners
// SABS: https://www.shadertoy.com/view/Ws2SDK
// next 4 lines can be precomputed for a given shape
float an = 3.141593/float(n);
float en = 3.141593/m; // m is between 2 and n
vec2 acs = vec2(cos(an),sin(an));
vec2 ecs = vec2(cos(en),sin(en)); // ecs=vec2(0,1) for regular polygon,
float bn = mod(atan(p.x,p.y),2.0*an) - an;
p = length(p)*vec2(cos(bn),SABS(sin(bn), 0.15));
p -= r*acs;
p += ecs*clamp( -dot(p,ecs), 0.0, r*acs.y/ecs.y);
return length(p)*sign(p.x);
}
vec4 alphaBlend(vec4 back, vec4 front) {
vec3 xyz = mix(back.xyz*back.w, front.xyz, front.w);
float w = mix(back.w, 1.0, front.w);
return vec4(xyz, w);
}
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(c*p.x + s*p.y, -s*p.x + c*p.y);
}
vec3 offset(float z) {
float a = z;
vec2 p = -0.075*(vec2(cos(a), sin(a*sqrt(2.0))) + vec2(cos(a*sqrt(0.75)), sin(a*sqrt(0.5))));
return vec3(p, z);
}
vec3 doffset(float z) {
float eps = 0.05;
return 0.5*(offset(z + eps) - offset(z - eps))/eps;
}
vec3 ddoffset(float z) {
float eps = 0.05;
return 0.5*(doffset(z + eps) - doffset(z - eps))/eps;
}
vec4 planeCol(vec3 ro, vec3 rd, float n, vec3 pp) {
const float s = 0.5;
vec2 p = pp.xy;
float z = pp.z;
vec2 dpy = dFdy(p);
float aa = length(dpy);
p -= (1.0+5.0*(pp.z - ro.z))*offset(z).xy;
p *= s;
float r = hash(vec3(floor(p+0.5), n));
p = fract(p+0.5)-0.5;
rot(p, ((TAU*r+n)*0.25));
float d = starn(p, 0.20, 3 + 2*int(3.0*r), 3.0);
d -= 0.06;
d/=s;
float ds = -d+0.03;
vec3 cols = hsv2rgb(vec3(337.0/360.0+0.1*sin(n*0.3), 0.8, 0.54+0.2*sin(n*0.3)));
float ts = 1.0 - smoothstep(-aa, 0.0, ds);
vec4 cs = vec4(cols, ts*0.93);
float db = abs(d) - (0.06);
db = abs(db) - 0.03;
db = abs(db) - 0.00;
db = max(db, -d+0.03);
vec3 colb = vec3(1.0, 0.7, 0.5);
float tb = exp(-(db)*30.0*(1.0 - 10.0*aa));
vec4 cb = vec4(1.5*colb, tb);
vec4 ct = alphaBlend(cs, cb);
return ct;
}
vec3 color(vec3 ww, vec3 uu, vec3 vv, vec3 ro, vec2 p) {
vec3 rd = normalize(p.x*uu + p.y*vv + (2.0-tanh(length(p)))*ww);
vec4 col = vec4(vec3(0.0), 1.0);
const float planeDist = 1.0;
const int furthest = 6;
const int fadeFrom = furthest-3;
float nz = floor(ro.z / planeDist);
for (int i = furthest; i >= 1; --i) {
float pz = planeDist*nz + planeDist*float(i);
float pd = (pz - ro.z)/rd.z;
if (pd > 0.0) {
vec3 pp = ro + rd*pd;
vec4 pcol = planeCol(ro, rd, nz+float(i), pp);
float fadeIn = 1.0-smoothstep(planeDist*float(fadeFrom), planeDist*float(furthest), pp.z-ro.z);
pcol.xyz *= sqrt(fadeIn);
col = alphaBlend(col, pcol);
}
}
return col.xyz*col.w;
}
vec3 postProcess(vec3 col, vec2 q) {
col=pow(clamp(col,0.0,1.0),vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col);
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4);
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7);
return col;
}
vec3 effect(vec2 p, vec2 q) {
float tm = TIME*0.65;
vec3 ro = offset(tm);
vec3 dro = doffset(tm);
vec3 ddro = ddoffset(tm);
vec3 ww = normalize(dro);
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0)+1.5*ddro, ww));
vec3 vv = normalize(cross(ww, uu));
vec3 col = color(ww, uu, vv, ro, p);
col = postProcess(col, q);
const float fadeIn = 2.0;
return col*smoothstep(0.0, fadeIn, TIME);
}
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 q = fragCoord/RESOLUTION.xy;
vec2 p = -1. + 2. * q;
p.x *= RESOLUTION.x/RESOLUTION.y;
vec3 col = effect(p, q);
fragColor = vec4(col, 1.0);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,526 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <epoxy/gl.h>
#include "gtkshadertoy.h"
const char *default_image_shader =
"void mainImage(out vec4 fragColor, in vec2 fragCoord) {\n"
" // Normalized pixel coordinates (from 0 to 1)\n"
" vec2 uv = fragCoord/iResolution.xy;\n"
"\n"
" // Time varying pixel color\n"
" vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));\n"
"\n"
" if (distance(iMouse.xy, fragCoord.xy) <= 10.0) {\n"
" col = vec3(0.0);\n"
" }\n"
"\n"
" // Output to screen\n"
" fragColor = vec4(col,1.0);\n"
"}\n";
const char *shadertoy_vertex_shader =
"#version 150 core\n"
"\n"
"uniform vec3 iResolution;\n"
"\n"
"in vec2 position;\n"
"out vec2 fragCoord;\n"
"\n"
"void main() {\n"
" gl_Position = vec4(position, 0.0, 1.0);\n"
"\n"
" // Convert from OpenGL coordinate system (with origin in center\n"
" // of screen) to Shadertoy/texture coordinate system (with origin\n"
" // in lower left corner)\n"
" fragCoord = (gl_Position.xy + vec2(1.0)) / vec2(2.0) * iResolution.xy;\n"
"}\n";
const char *fragment_prefix =
"#version 150 core\n"
"\n"
"uniform vec3 iResolution; // viewport resolution (in pixels)\n"
"uniform float iTime; // shader playback time (in seconds)\n"
"uniform float iTimeDelta; // render time (in seconds)\n"
"uniform int iFrame; // shader playback frame\n"
"uniform float iChannelTime[4]; // channel playback time (in seconds)\n"
"uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)\n"
"uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click\n"
"uniform sampler2D iChannel0;\n"
"uniform sampler2D iChannel1;\n"
"uniform sampler2D iChannel2;\n"
"uniform sampler2D iChannel3;\n"
"uniform vec4 iDate; // (year, month, day, time in seconds)\n"
"uniform float iSampleRate; // sound sample rate (i.e., 44100)\n"
"\n"
"in vec2 fragCoord;\n"
"out vec4 vFragColor;\n";
// Fragment shader suffix
const char *fragment_suffix =
" void main() {\n"
" vec4 c;\n"
" mainImage(c, fragCoord);\n"
" vFragColor = c;\n"
" }\n";
typedef struct {
char *image_shader;
gboolean image_shader_dirty;
gboolean error_set;
/* Vertex buffers */
GLuint vao;
GLuint buffer;
/* Active program */
GLuint program;
/* Location of uniforms for program */
GLuint resolution_location;
GLuint time_location;
GLuint timedelta_location;
GLuint frame_location;
GLuint mouse_location;
/* Current uniform values */
float resolution[3];
float time;
float timedelta;
float mouse[4];
int frame;
/* Animation data */
gint64 first_frame_time;
gint64 first_frame;
guint tick;
} GtkShadertoyPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GtkShadertoy, gtk_shadertoy, GTK_TYPE_GL_AREA)
static gboolean gtk_shadertoy_render (GtkGLArea *area,
GdkGLContext *context);
static void gtk_shadertoy_reshape (GtkGLArea *area,
int width,
int height);
static void gtk_shadertoy_realize (GtkWidget *widget);
static void gtk_shadertoy_unrealize (GtkWidget *widget);
static gboolean gtk_shadertoy_tick (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data);
GtkWidget *
gtk_shadertoy_new (void)
{
return g_object_new (gtk_shadertoy_get_type (), NULL);
}
static void
drag_begin_cb (GtkGestureDrag *drag,
double x,
double y,
gpointer user_data)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (user_data);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
int height = gtk_widget_get_height (GTK_WIDGET (shadertoy));
int scale = gtk_widget_get_scale_factor (GTK_WIDGET (shadertoy));
priv->mouse[0] = x * scale;
priv->mouse[1] = (height - y) * scale;
priv->mouse[2] = priv->mouse[0];
priv->mouse[3] = priv->mouse[1];
}
static void
drag_update_cb (GtkGestureDrag *drag,
double dx,
double dy,
gpointer user_data)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (user_data);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
int width = gtk_widget_get_width (GTK_WIDGET (shadertoy));
int height = gtk_widget_get_height (GTK_WIDGET (shadertoy));
int scale = gtk_widget_get_scale_factor (GTK_WIDGET (shadertoy));
double x, y;
gtk_gesture_drag_get_start_point (drag, &x, &y);
x += dx;
y += dy;
if (x >= 0 && x < width &&
y >= 0 && y < height)
{
priv->mouse[0] = x * scale;
priv->mouse[1] = (height - y) * scale;
}
}
static void
drag_end_cb (GtkGestureDrag *drag,
gdouble dx,
gdouble dy,
gpointer user_data)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (user_data);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
priv->mouse[2] = -priv->mouse[2];
priv->mouse[3] = -priv->mouse[3];
}
static void
gtk_shadertoy_init (GtkShadertoy *shadertoy)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
GtkGesture *drag;
priv->image_shader = g_strdup (default_image_shader);
priv->tick = gtk_widget_add_tick_callback (GTK_WIDGET (shadertoy), gtk_shadertoy_tick, shadertoy, NULL);
drag = gtk_gesture_drag_new ();
gtk_widget_add_controller (GTK_WIDGET (shadertoy), GTK_EVENT_CONTROLLER (drag));
g_signal_connect (drag, "drag-begin", (GCallback)drag_begin_cb, shadertoy);
g_signal_connect (drag, "drag-update", (GCallback)drag_update_cb, shadertoy);
g_signal_connect (drag, "drag-end", (GCallback)drag_end_cb, shadertoy);
}
static void
gtk_shadertoy_finalize (GObject *obj)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (obj);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
gtk_widget_remove_tick_callback (GTK_WIDGET (shadertoy), priv->tick);
g_free (priv->image_shader);
G_OBJECT_CLASS (gtk_shadertoy_parent_class)->finalize (obj);
}
static void
gtk_shadertoy_class_init (GtkShadertoyClass *klass)
{
GTK_GL_AREA_CLASS (klass)->render = gtk_shadertoy_render;
GTK_GL_AREA_CLASS (klass)->resize = gtk_shadertoy_reshape;
GTK_WIDGET_CLASS (klass)->realize = gtk_shadertoy_realize;
GTK_WIDGET_CLASS (klass)->unrealize = gtk_shadertoy_unrealize;
G_OBJECT_CLASS (klass)->finalize = gtk_shadertoy_finalize;
}
/* new window size or exposure */
static void
gtk_shadertoy_reshape (GtkGLArea *area, int width, int height)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private ((GtkShadertoy *) area);
priv->resolution[0] = width;
priv->resolution[1] = height;
priv->resolution[2] = 1.0; /* screen aspect ratio */
/* Set the viewport */
glViewport (0, 0, (GLint) width, (GLint) height);
}
static GLuint
create_shader (int type,
const char *src,
GError **error)
{
GLuint shader;
int status;
shader = glCreateShader (type);
glShaderSource (shader, 1, &src, NULL);
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetShaderInfoLog (shader, log_len, NULL, buffer);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
"Compile failure in %s shader:\n%s",
type == GL_VERTEX_SHADER ? "vertex" : "fragment",
buffer);
g_free (buffer);
glDeleteShader (shader);
return 0;
}
return shader;
}
static gboolean
init_shaders (GtkShadertoy *shadertoy,
const char *vertex_source,
const char *fragment_source,
GError **error)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
GLuint vertex, fragment;
GLuint program = 0;
int status;
gboolean res = TRUE;
vertex = create_shader (GL_VERTEX_SHADER, vertex_source, error);
if (vertex == 0)
return FALSE;
fragment = create_shader (GL_FRAGMENT_SHADER, fragment_source, error);
if (fragment == 0)
{
glDeleteShader (vertex);
return FALSE;
}
program = glCreateProgram ();
glAttachShader (program, vertex);
glAttachShader (program, fragment);
glLinkProgram (program);
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc (log_len + 1);
glGetProgramInfoLog (program, log_len, NULL, buffer);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
"Linking failure:\n%s", buffer);
res = FALSE;
g_free (buffer);
glDeleteProgram (program);
goto out;
}
if (priv->program != 0)
glDeleteProgram (priv->program);
priv->program = program;
priv->resolution_location = glGetUniformLocation (program, "iResolution");
priv->time_location = glGetUniformLocation (program, "iTime");
priv->timedelta_location = glGetUniformLocation (program, "iTimeDelta");
priv->frame_location = glGetUniformLocation (program, "iFrame");
priv->mouse_location = glGetUniformLocation (program, "iMouse");
glDetachShader (program, vertex);
glDetachShader (program, fragment);
out:
/* These are now owned by the program and can be deleted */
glDeleteShader (vertex);
glDeleteShader (fragment);
return res;
}
static void
gtk_shadertoy_realize_shader (GtkShadertoy *shadertoy)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
char *fragment_shader;
GError *error = NULL;
fragment_shader = g_strconcat (fragment_prefix, priv->image_shader, fragment_suffix, NULL);
if (!init_shaders (shadertoy, shadertoy_vertex_shader, fragment_shader, &error))
{
priv->error_set = TRUE;
gtk_gl_area_set_error (GTK_GL_AREA (shadertoy), error);
g_error_free (error);
}
g_free (fragment_shader);
/* Start new shader at time zero */
priv->first_frame_time = 0;
priv->first_frame = 0;
priv->image_shader_dirty = FALSE;
}
static gboolean
gtk_shadertoy_render (GtkGLArea *area,
GdkGLContext *context)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (area);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
if (gtk_gl_area_get_error (area) != NULL)
return FALSE;
if (priv->image_shader_dirty)
gtk_shadertoy_realize_shader (shadertoy);
/* Clear the viewport */
glClearColor (0.0, 0.0, 0.0, 1.0);
glClear (GL_COLOR_BUFFER_BIT);
glUseProgram (priv->program);
/* Update uniforms */
if (priv->resolution_location != -1)
glUniform3fv (priv->resolution_location, 1, priv->resolution);
if (priv->time_location != -1)
glUniform1f (priv->time_location, priv->time);
if (priv->timedelta_location != -1)
glUniform1f (priv->timedelta_location, priv->timedelta);
if (priv->frame_location != -1)
glUniform1i (priv->frame_location, priv->frame);
if (priv->mouse_location != -1)
glUniform4fv (priv->mouse_location, 1, priv->mouse);
/* Use the vertices in our buffer */
glBindBuffer (GL_ARRAY_BUFFER, priv->buffer);
glEnableVertexAttribArray (0);
glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays (GL_TRIANGLES, 0, 6);
/* We finished using the buffers and program */
glDisableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, 0);
glUseProgram (0);
/* Flush the contents of the pipeline */
glFlush ();
return TRUE;
}
const char *
gtk_shadertoy_get_image_shader (GtkShadertoy *shadertoy)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
return priv->image_shader;
}
void
gtk_shadertoy_set_image_shader (GtkShadertoy *shadertoy,
const char *shader)
{
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
g_free (priv->image_shader);
priv->image_shader = g_strdup (shader);
/* Don't override error we didn't set it ourselves */
if (priv->error_set)
{
gtk_gl_area_set_error (GTK_GL_AREA (shadertoy), NULL);
priv->error_set = FALSE;
}
priv->image_shader_dirty = TRUE;
}
static void
gtk_shadertoy_realize (GtkWidget *widget)
{
GtkGLArea *glarea = GTK_GL_AREA (widget);
GtkShadertoy *shadertoy = GTK_SHADERTOY (widget);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
/* Draw two triangles across whole screen */
const GLfloat vertex_data[] = {
-1.0f, -1.0f, 0.f, 1.f,
-1.0f, 1.0f, 0.f, 1.f,
1.0f, 1.0f, 0.f, 1.f,
-1.0f, -1.0f, 0.f, 1.f,
1.0f, 1.0f, 0.f, 1.f,
1.0f, -1.0f, 0.f, 1.f,
};
GTK_WIDGET_CLASS (gtk_shadertoy_parent_class)->realize (widget);
gtk_gl_area_make_current (glarea);
if (gtk_gl_area_get_error (glarea) != NULL)
return;
glGenVertexArrays (1, &priv->vao);
glBindVertexArray (priv->vao);
glGenBuffers (1, &priv->buffer);
glBindBuffer (GL_ARRAY_BUFFER, priv->buffer);
glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
glBindBuffer (GL_ARRAY_BUFFER, 0);
gtk_shadertoy_realize_shader (shadertoy);
}
static void
gtk_shadertoy_unrealize (GtkWidget *widget)
{
GtkGLArea *glarea = GTK_GL_AREA (widget);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private ((GtkShadertoy *) widget);
gtk_gl_area_make_current (glarea);
if (gtk_gl_area_get_error (glarea) == NULL)
{
if (priv->buffer != 0)
glDeleteBuffers (1, &priv->buffer);
if (priv->vao != 0)
glDeleteVertexArrays (1, &priv->vao);
if (priv->program != 0)
glDeleteProgram (priv->program);
}
GTK_WIDGET_CLASS (gtk_shadertoy_parent_class)->unrealize (widget);
}
static gboolean
gtk_shadertoy_tick (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GtkShadertoy *shadertoy = GTK_SHADERTOY (widget);
GtkShadertoyPrivate *priv = gtk_shadertoy_get_instance_private (shadertoy);
gint64 frame_time;
gint64 frame;
float previous_time;
frame = gdk_frame_clock_get_frame_counter (frame_clock);
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
if (priv->first_frame_time == 0)
{
priv->first_frame_time = frame_time;
priv->first_frame = frame;
previous_time = 0;
}
else
previous_time = priv->time;
priv->time = (frame_time - priv->first_frame_time) / 1000000.0f;
priv->frame = frame - priv->first_frame;
priv->timedelta = priv->time - previous_time;
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}

View File

@@ -0,0 +1,34 @@
#ifndef __GTK_SHADERTOY_H__
#define __GTK_SHADERTOY_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_SHADERTOY (gtk_shadertoy_get_type ())
#define GTK_SHADERTOY(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_SHADERTOY, \
GtkShadertoy))
#define GTK_IS_SHADERTOY(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_SHADERTOY))
typedef struct _GtkShadertoy GtkShadertoy;
typedef struct _GtkShadertoyClass GtkShadertoyClass;
struct _GtkShadertoy {
GtkGLArea parent;
};
struct _GtkShadertoyClass {
GtkGLAreaClass parent_class;
};
GType gtk_shadertoy_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_shadertoy_new (void);
const char *gtk_shadertoy_get_image_shader (GtkShadertoy *shadertoy);
void gtk_shadertoy_set_image_shader (GtkShadertoy *shadertoy,
const char *shader);
G_END_DECLS
#endif /* __GTK_SHADERTOY_H__ */

View File

@@ -1,4 +1,5 @@
/* Header Bar
* #Keywords: GtkWindowHandle, GtkWindowControls
*
* GtkHeaderBar is a container that is suitable for implementing
* window titlebars. One of its features is that it can position
@@ -48,6 +49,7 @@ do_headerbar (GtkWidget *do_widget)
gtk_box_append (GTK_BOX (box), button);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), box);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), gtk_switch_new ());
gtk_window_set_titlebar (GTK_WINDOW (window), header);

View File

@@ -1,9 +1,13 @@
/* Text View/Hypertext
* #Keywords: GtkTextView, GtkTextBuffer
*
* Usually, tags modify the appearance of text in the view, e.g. making it
* bold or colored or underlined. But tags are not restricted to appearance.
* They can also affect the behavior of mouse and key presses, as this demo
* shows.
*
* We also demonstrate adding other things to a text view, such as
* clickable icons.
*/
#include <gtk/gtk.h>
@@ -30,35 +34,103 @@ insert_link (GtkTextBuffer *buffer,
gtk_text_buffer_insert_with_tags (buffer, iter, text, -1, tag, NULL);
}
/* Quick-and-dirty text-to-speech for a single word. If you don't hear
* anything, you are missing espeak-ng on your system.
*/
static void
say_word (GtkGestureClick *gesture,
guint n_press,
double x,
double y,
const char *word)
{
const char *argv[3];
argv[0] = "espeak-ng";
argv[1] = word;
argv[2] = NULL;
g_spawn_async (NULL, (char **)argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
}
/* Fills the buffer with text and interspersed links. In any real
* hypertext app, this method would parse a file to identify the links.
*/
static void
show_page (GtkTextBuffer *buffer,
int page)
show_page (GtkTextView *text_view,
int page)
{
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkWidget *child;
GtkTextChildAnchor *anchor;
GtkEventController *controller;
buffer = gtk_text_view_get_buffer (text_view);
gtk_text_buffer_set_text (buffer, "", 0);
gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
gtk_text_buffer_begin_irreversible_action (buffer);
if (page == 1)
{
GtkIconPaintable *icon;
GtkIconTheme *theme;
gtk_text_buffer_insert (buffer, &iter, "Some text to show that simple ", -1);
insert_link (buffer, &iter, "hyper text", 3);
insert_link (buffer, &iter, "hypertext", 3);
gtk_text_buffer_insert (buffer, &iter, " can easily be realized with ", -1);
insert_link (buffer, &iter, "tags", 2);
gtk_text_buffer_insert (buffer, &iter, ".\n", -1);
gtk_text_buffer_insert (buffer, &iter,
"Of course you can also embed Emoji 😋, "
"icons ", -1);
theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
icon = gtk_icon_theme_lookup_icon (theme,
"microphone-sensitivity-high-symbolic",
NULL,
16,
1,
GTK_TEXT_DIR_LTR,
0);
gtk_text_buffer_insert_paintable (buffer, &iter, GDK_PAINTABLE (icon));
g_object_unref (icon);
gtk_text_buffer_insert (buffer, &iter, ", or even widgets ", -1);
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
child = gtk_level_bar_new_for_interval (0, 100);
gtk_level_bar_set_value (GTK_LEVEL_BAR (child), 50);
gtk_widget_set_size_request (child, 100, -1);
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
gtk_text_buffer_insert (buffer, &iter, ".", -1);
}
else if (page == 2)
{
gtk_text_buffer_insert (buffer, &iter,
"A tag is an attribute that can be applied to some range of text. "
"For example, a tag might be called \"bold\" and make the text inside "
"the tag bold. However, the tag concept is more general than that; "
"tags don't have to affect appearance. They can instead affect the "
"behavior of mouse and key presses, \"lock\" a range of text so the "
"user can't edit it, or countless other things.\n", -1);
GtkTextTag *tag;
tag = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, "tag", -1, tag, NULL);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, " /tag/ ", -1, tag, NULL);
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
child = gtk_image_new_from_icon_name ("audio-volume-high-symbolic");
gtk_widget_set_cursor_from_name (child, "pointer");
controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
g_signal_connect (controller, "pressed", G_CALLBACK (say_word), (gpointer)"tag");
gtk_widget_add_controller (child, controller);
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
gtk_text_buffer_insert (buffer, &iter, "\n"
"An attribute that can be applied to some range of text. For example, "
"a tag might be called “bold” and make the text inside the tag bold.\n"
"However, the tag concept is more general than that; "
"tags don't have to affect appearance. They can instead affect the "
"behavior of mouse and key presses, “lock” a range of text so the "
"user can't edit it, or countless other things.\n", -1);
insert_link (buffer, &iter, "Go back", 1);
}
else if (page == 3)
@@ -67,11 +139,25 @@ show_page (GtkTextBuffer *buffer,
tag = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, "hypertext:\n", -1, tag, NULL);
gtk_text_buffer_insert (buffer, &iter,
"machine-readable text that is not sequential but is organized "
"so that related items of information are connected.\n", -1);
gtk_text_buffer_insert_with_tags (buffer, &iter, "hypertext", -1, tag, NULL);
tag = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
NULL);
gtk_text_buffer_insert_with_tags (buffer, &iter, " /ˈhaɪ pərˌtɛkst/ ", -1, tag, NULL);
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
child = gtk_image_new_from_icon_name ("audio-volume-high-symbolic");
gtk_widget_set_cursor_from_name (child, "pointer");
controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
g_signal_connect (controller, "pressed", G_CALLBACK (say_word), (gpointer)"hypertext");
gtk_widget_add_controller (child, controller);
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
gtk_text_buffer_insert (buffer, &iter, "\n"
"Machine-readable text that is not sequential but is organized "
"so that related items of information are connected.\n", -1);
insert_link (buffer, &iter, "Go back", 1);
}
gtk_text_buffer_end_irreversible_action (buffer);
@@ -95,7 +181,7 @@ follow_if_link (GtkWidget *text_view,
if (page != 0)
{
show_page (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)), page);
show_page (GTK_TEXT_VIEW (text_view), page);
break;
}
}
@@ -162,7 +248,7 @@ released_cb (GtkGestureClick *gesture,
if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
return;
if (gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y))
if (gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, tx, ty))
follow_if_link (text_view, &iter);
}
@@ -172,7 +258,13 @@ motion_cb (GtkEventControllerMotion *controller,
double y,
GtkTextView *text_view)
{
set_cursor_if_appropriate (text_view, x, y);
int tx, ty;
gtk_text_view_window_to_buffer_coords (text_view,
GTK_TEXT_WINDOW_WIDGET,
x, y, &tx, &ty);
set_cursor_if_appropriate (text_view, tx, ty);
}
static gboolean hovering_over_link = FALSE;
@@ -182,9 +274,9 @@ static gboolean hovering_over_link = FALSE;
* typically used by web browsers.
*/
static void
set_cursor_if_appropriate (GtkTextView *text_view,
int x,
int y)
set_cursor_if_appropriate (GtkTextView *text_view,
int x,
int y)
{
GSList *tags = NULL, *tagp = NULL;
GtkTextIter iter;
@@ -236,13 +328,17 @@ do_hypertext (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Hypertext");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
gtk_window_set_default_size (GTK_WINDOW (window), 330, 330);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view), 10);
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed), view);
gtk_widget_add_controller (view, controller);
@@ -267,7 +363,7 @@ do_hypertext (GtkWidget *do_widget)
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), view);
show_page (buffer, 1);
show_page (GTK_TEXT_VIEW (view), 1);
}
if (!gtk_widget_get_visible (window))

View File

@@ -1,4 +1,5 @@
/* Benchmark/Scrolling
* #Keywords: GtkScrolledWindow
*
* This demo scrolls a view with various content.
*/
@@ -255,12 +256,38 @@ iconscroll_prev_clicked_cb (GtkButton *source,
set_widget_type (new_index);
}
static gboolean
update_fps (gpointer data)
{
GtkWidget *label = data;
GdkFrameClock *frame_clock;
double fps;
char *str;
frame_clock = gtk_widget_get_frame_clock (label);
fps = gdk_frame_clock_get_fps (frame_clock);
str = g_strdup_printf ("%.2f fps", fps);
gtk_label_set_label (GTK_LABEL (label), str);
g_free (str);
return G_SOURCE_CONTINUE;
}
static void
remove_timeout (gpointer data)
{
g_source_remove (GPOINTER_TO_UINT (data));
}
G_MODULE_EXPORT GtkWidget *
do_iconscroll (GtkWidget *do_widget)
{
if (!window)
{
GtkBuilder *builder;
GtkWidget *label;
guint id;
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
@@ -274,6 +301,11 @@ do_iconscroll (GtkWidget *do_widget)
vadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "vadjustment"));
set_widget_type (0);
label = GTK_WIDGET (gtk_builder_get_object (builder, "fps_label"));
id = g_timeout_add (500, update_fps, label);
g_object_set_data_full (G_OBJECT (label), "timeout",
GUINT_TO_POINTER (id), remove_timeout);
g_object_unref (builder);
}

View File

@@ -25,6 +25,13 @@
</child>
</object>
</child>
<child type="end">
<object class="GtkLabel" id="fps_label">
<attributes>
<attribute name="font-features" value="tnum=1"/>
</attributes>
</object>
</child>
</object>
</child>
<child>

View File

@@ -1,4 +1,5 @@
/* Images
* #Keywords: GdkPaintable, GtkWidgetPaintable
*
* GtkImage and GtkPicture are used to display an image; the image can be
* in a number of formats.

View File

@@ -1,4 +1,5 @@
/* Info Bars
* #Keywords: GtkInfoBar
*
* Info bar widgets are used to report important messages to the user.
*/

View File

@@ -1,4 +1,5 @@
/* Layout Manager/Transition
* #Keywords: GtkLayoutManager
*
* This demo shows a simple example of a custom layout manager
* and a widget using it. The layout manager places the children

View File

@@ -1,4 +1,5 @@
/* Layout Manager/Transformation
* #Keywords: GtkLayoutManager, GskTransform
*
* This demo shows how to use transforms in a nontrivial
* way with a custom layout manager. The layout manager places

View File

@@ -3,7 +3,6 @@
* The GtkListStore is used to store data in list form, to be used
* later on by a GtkTreeView to display it. This demo builds a
* simple GtkListStore and displays it.
*
*/
#include <gtk/gtk.h>

View File

@@ -2,7 +2,6 @@
*
* GtkListBox allows lists with complicated layouts, using
* regular widgets supporting sorting and filtering.
*
*/
#include <gtk/gtk.h>

View File

@@ -1,4 +1,5 @@
/* Lists/Application launcher
* #Keywords: GtkListItemFactory, GListModel
*
* This demo uses the GtkListView widget as a fancy application launcher.
*

View File

@@ -1,10 +1,11 @@
/* Lists/Clocks
* #Keywords: GtkGridView, GtkListItemFactory, GListModel
*
* This demo displays the time in different timezones.
*
* The goal is to show how to set up expressions that track changes
* in objects and make them update widgets. For that, we create a
* GtkClock object that updates its time every second and then use
* clock object that updates its time every second and then use
* various ways to display that time.
*
* Typically, this will be done using GtkBuilder .ui files with the

View File

@@ -1,4 +1,5 @@
/* Lists/Colors
* #Keywords: GtkSortListModel, GtkMultiSelection
*
* This demo displays a grid of colors.
*
@@ -1022,31 +1023,31 @@ do_listview_colors (GtkWidget *do_widget)
/* An empty multisorter doesn't do any sorting and the sortmodel is
* smart enough to know that.
*/
sorter = gtk_multi_sorter_new ();
sorter = GTK_SORTER (gtk_multi_sorter_new ());
set_title (sorter, "Unsorted");
g_list_store_append (sorters, sorter);
g_object_unref (sorter);
sorter = gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name"));
sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name")));
set_title (sorter, "Name");
g_list_store_append (sorters, sorter);
g_object_unref (sorter);
multi_sorter = gtk_multi_sorter_new ();
multi_sorter = GTK_SORTER (gtk_multi_sorter_new ());
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "red"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "red")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Red");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "green"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "green")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Green");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "blue"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "blue")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Blue");
g_list_store_append (sorters, sorter);
@@ -1056,21 +1057,21 @@ do_listview_colors (GtkWidget *do_widget)
g_list_store_append (sorters, multi_sorter);
g_object_unref (multi_sorter);
multi_sorter = gtk_multi_sorter_new ();
multi_sorter = GTK_SORTER (gtk_multi_sorter_new ());
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "hue"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "hue")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Hue");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "saturation"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "saturation")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Saturation");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "value"));
sorter = GTK_SORTER (gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "value")));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Value");
g_list_store_append (sorters, sorter);

View File

@@ -1,4 +1,5 @@
/* Lists/File browser
* #Keywords: GListModel
*
* This demo shows off the different layouts that are quickly achievable
* with GtkListview and GtkGridView by implementing a file browser with

View File

@@ -1,7 +1,8 @@
/* Lists/Minesweeper
* #Keywords: GtkGridView, GListModel, game
*
* This demo shows how to develop a user interface for small game using a
* gridview.
* grid view.
*
* It demonstrates how to use the activate signal and single-press behavior
* to implement rather different interaction behavior to a typical list.
@@ -428,7 +429,7 @@ sweeper_game_reveal_cell (SweeperGame *self,
sweeper_game_check_finished (self);
}
void
G_MODULE_EXPORT void
minesweeper_cell_clicked_cb (GtkGridView *gridview,
guint pos,
SweeperGame *game)
@@ -436,7 +437,7 @@ minesweeper_cell_clicked_cb (GtkGridView *gridview,
sweeper_game_reveal_cell (game, pos);
}
void
G_MODULE_EXPORT void
minesweeper_new_game_cb (GtkButton *button,
SweeperGame *game)
{

View File

@@ -1,4 +1,5 @@
/* Lists/Settings
* #Keywords: GtkListItemFactory, GListModel
*
* This demo shows a settings viewer for GSettings.
*
@@ -247,7 +248,7 @@ transform_settings_to_keys (GBinding *binding,
sort_model = gtk_sort_list_model_new (G_LIST_MODEL (store),
g_object_ref (gtk_column_view_get_sorter (GTK_COLUMN_VIEW (data))));
filter = gtk_string_filter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
filter = GTK_FILTER (gtk_string_filter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name")));
g_set_object (&current_filter, filter);
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), filter);
@@ -417,7 +418,7 @@ do_listview_settings (GtkWidget *do_widget)
g_object_unref (selection);
name_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "name_column"));
sorter = gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name")));
gtk_column_view_column_set_sorter (name_column, sorter);
g_object_unref (sorter);

View File

@@ -1,4 +1,5 @@
/* Lists/Words
* #Keywords: GtkListView, GtkFilterListModel
*
* This demo shows filtering a long list - of words.
*
@@ -179,7 +180,7 @@ do_listview_words (GtkWidget *do_widget)
}
g_object_unref (file);
filter = gtk_string_filter_new (gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string"));
filter = GTK_FILTER (gtk_string_filter_new (gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string")));
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (stringlist), filter);
gtk_filter_list_model_set_incremental (filter_model, TRUE);

View File

@@ -1,3 +1,17 @@
/* GTK Demo
*
* GTK Demo is a collection of useful examples to demonstrate
* GTK widgets and features. It is a useful example in itself.
*
* You can select examples in the sidebar or search for them by
* typing a search term. Double-clicking or hitting the “Run” button
* will run the demo. The source code and other resources used in the
* demo are shown in this area.
*
* You can also use the GTK Inspector, available from the menu on the
* top right, to poke at the running demos, and see how they are put
* together.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -28,6 +42,7 @@ struct _GtkDemo
const char *name;
const char *title;
const char **keywords;
const char *filename;
GDoDemoFunc func;
GListModel *children_model;
@@ -38,6 +53,7 @@ enum {
PROP_FILENAME,
PROP_NAME,
PROP_TITLE,
PROP_KEYWORDS,
N_PROPS
};
@@ -70,6 +86,10 @@ gtk_demo_get_property (GObject *object,
g_value_set_string (value, self->title);
break;
case PROP_KEYWORDS:
g_value_set_boxed (value, self->keywords);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -100,6 +120,12 @@ static void gtk_demo_class_init (GtkDemoClass *klass)
"title",
NULL,
G_PARAM_READABLE);
properties[PROP_KEYWORDS] =
g_param_spec_string ("keywords",
"keywords",
"keywords",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -315,12 +341,10 @@ display_text (const char *format,
g_assert (g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL));
textview = gtk_text_view_new ();
g_object_set (textview,
"left-margin", 20,
"right-margin", 20,
"top-margin", 20,
"bottom-margin", 20,
NULL);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textview), 20);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textview), 20);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (textview), 20);
gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (textview), 20);
gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
/* Make it a bit nicer for text. */
@@ -581,6 +605,9 @@ load_file (const char *demoname,
while (g_ascii_isspace (*(p + len - 1)))
len--;
if (*p == '#')
break;
if (len > 0)
{
if (in_para)
@@ -656,6 +683,7 @@ selection_cb (GtkSingleSelection *sel,
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (sel);
GtkDemo *demo;
GAction *action;
gtk_widget_set_sensitive (GTK_WIDGET (notebook), !!row);
@@ -671,6 +699,9 @@ selection_cb (GtkSingleSelection *sel,
if (demo->filename)
load_file (demo->name, demo->filename);
action = g_action_map_lookup_action (G_ACTION_MAP (toplevel), "run");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), demo->func != NULL);
gtk_window_set_title (GTK_WINDOW (toplevel), demo->title);
}
@@ -688,6 +719,21 @@ filter_demo (GtkDemo *demo)
if (g_str_match_string (search_needle[i], demo->title, TRUE))
continue;
if (demo->keywords)
{
int j;
gboolean found = FALSE;
for (j = 0; !found && demo->keywords[j]; j++)
{
if (strstr (demo->keywords[j], search_needle[i]))
found = TRUE;
}
if (found)
continue;
}
return FALSE;
}
@@ -695,9 +741,11 @@ filter_demo (GtkDemo *demo)
}
static gboolean
demo_filter_by_name (GtkTreeListRow *row,
GtkFilterListModel *model)
demo_filter_by_name (gpointer item,
gpointer user_data)
{
GtkTreeListRow *row = item;
GtkFilterListModel *model = user_data;
GListModel *children;
GtkDemo *demo;
guint i, n;
@@ -756,7 +804,7 @@ demo_search_changed_cb (GtkSearchEntry *entry,
g_clear_pointer (&search_needle, g_strfreev);
if (text && *text)
search_needle = g_strsplit (text, " ", 0);
search_needle = g_str_tokenize_and_fold (text, NULL, NULL);
gtk_filter_changed (filter, GTK_FILTER_CHANGE_DIFFERENT);
}
@@ -766,14 +814,25 @@ create_demo_model (void)
{
GListStore *store = g_list_store_new (GTK_TYPE_DEMO);
DemoData *demo = gtk_demos;
GtkDemo *d;
d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
d->name = "main";
d->title = "GTK Demo";
d->keywords = NULL;
d->filename = "main.c";
d->func = NULL;
g_list_store_append (store, d);
while (demo->title)
{
GtkDemo *d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
DemoData *children = demo->children;
d->name = demo->name;
d->title = demo->title;
d->keywords = demo->keywords;
d->filename = demo->filename;
d->func = demo->func;
@@ -789,6 +848,7 @@ create_demo_model (void)
child->name = children->name;
child->title = children->title;
child->keywords = children->keywords;
child->filename = children->filename;
child->func = children->func;
@@ -834,18 +894,16 @@ activate (GApplication *app)
GtkWidget *window, *listview, *search_entry, *search_bar;
GtkFilterListModel *filter_model;
GtkFilter *filter;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
};
GSimpleAction *action;
builder = gtk_builder_new_from_resource ("/ui/main.ui");
window = (GtkWidget *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window));
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
window);
action = g_simple_action_new ("run", NULL);
g_signal_connect (action, "activate", G_CALLBACK (activate_run), window);
g_action_map_add_action (G_ACTION_MAP (window), G_ACTION (action));
notebook = GTK_WIDGET (gtk_builder_get_object (builder, "notebook"));
@@ -865,9 +923,10 @@ activate (GApplication *app)
NULL,
NULL);
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (treemodel), NULL);
filter = gtk_custom_filter_new ((GtkCustomFilterFunc)demo_filter_by_name, filter_model, NULL);
filter = GTK_FILTER (gtk_custom_filter_new (demo_filter_by_name, filter_model, NULL));
gtk_filter_list_model_set_filter (filter_model, filter);
g_object_unref (filter);
search_entry = GTK_WIDGET (gtk_builder_get_object (builder, "search-entry"));
g_signal_connect (search_entry, "search-changed", G_CALLBACK (demo_search_changed_cb), filter);

View File

@@ -106,8 +106,9 @@
<property name="right-margin">20</property>
<property name="top-margin">20</property>
<property name="bottom-margin">20</property>
<property name="pixels-above-lines">2</property>
<property name="pixels-below-lines">2</property>
<property name="pixels-above-lines">6</property>
<property name="pixels-below-lines">6</property>
<property name="monospace">0</property>
<property name="editable">0</property>
<property name="wrap-mode">word</property>
<property name="cursor-visible">0</property>

View File

@@ -0,0 +1,95 @@
// Originally from: https://www.shadertoy.com/view/wdBfDK
// License: CC0
#define MANDELBROT_ZOOM_START 0.0
#define MANDELBROT_ITER 240
void pR(inout vec2 p, in float a) {
p = cos(a)*p + sin(a)*vec2(p.y, -p.x);
}
vec2 pMod2(inout vec2 p, in vec2 size) {
vec2 c = floor((p + size*0.5)/size);
p = mod(p + size*0.5,size) - size*0.5;
return c;
}
vec3 mandelbrot(float time, vec2 p, out float ii) {
vec3 col = vec3(0.0);
float ztime = (time - MANDELBROT_ZOOM_START)*step(MANDELBROT_ZOOM_START, time);
float zoo = 0.64 + 0.36*cos(.07*ztime);
float coa = cos(0.15*(1.0-zoo)*ztime);
float sia = sin(0.15*(1.0-zoo)*ztime);
zoo = pow(zoo,8.0);
vec2 xy = vec2( p.x*coa-p.y*sia, p.x*sia+p.y*coa);
vec2 c = vec2(-.745,.186) + xy*zoo;
const float B = 10.0;
float l = 0.0;
vec2 z = vec2(0.0);
vec2 zc = vec2(1.0);
pR(zc, ztime);
float d = 1e20;
int i = 0;
for(int j = 0; j < MANDELBROT_ITER; ++j) {
float re2 = z.x*z.x;
float im2 = z.y*z.y;
float reim= z.x*z.y;
if(re2 + im2 > (B*B)) break;
z = vec2(re2 - im2, 2.0*reim) + c;
vec2 zm = z;
vec2 n = pMod2(zm, vec2(4));
vec2 pp = zm - zc;
float dd = dot(pp, pp);
d = min(d, dd);
l += 1.0;
i = j;
}
ii = float(i)/float(MANDELBROT_ITER);
float sl = l - log2(log2(dot(z,z))) + 4.0;
vec3 dc = vec3(pow(max(1.0 - d, 0.0), 20.0));
vec3 gc = 0.5 + 0.5*cos(3.0 + sl*0.15 + vec3(0.1,0.5,0.9));
return gc + dc*smoothstep(28.8, 29.0, ztime);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
float s = 2.0/iResolution.y;
vec2 o1 = vec2(1.0/8.0, 3.0/8.0)*s;
vec2 o2 = vec2(-3.0/8.0, 1.0/8.0)*s;
vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/iResolution.y;
float ii = 0.0;
vec3 col = mandelbrot(iTime, p+o1, ii);
// "smart" AA? Is that a good idea?
vec2 dii2 = vec2(dFdx(ii), dFdy(ii));
float dii = length(dii2);
if(abs(dii) > 0.01) {
col += mandelbrot(iTime, p-o1, ii);
col += mandelbrot(iTime, p+o2, ii);
col += mandelbrot(iTime, p-o2, ii);
col *=0.25;
// col = vec3(1.0, 0.0, 0.0);
}
fragColor = vec4(col, 1.0);
}

View File

@@ -1,4 +1,5 @@
/* Text View/Markup
* #Keywords: GtkTextView
*
* GtkTextBuffer lets you define your own tags that can influence
* text formatting in a variety of ways. In this example, we show
@@ -13,9 +14,9 @@ static GtkWidget *view;
static GtkWidget *view2;
static void
source_toggled (GtkToggleButton *button)
source_toggled (GtkCheckButton *button)
{
if (gtk_toggle_button_get_active (button))
if (gtk_check_button_get_active (button))
gtk_stack_set_visible_child_name (GTK_STACK (stack), "source");
else
{

47
demos/gtk-demo/menu.c Normal file
View File

@@ -0,0 +1,47 @@
/* Menu
* #Keywords: action, zoom
*
* Demonstrates how to add a context menu to a custom widget
* and connect it with widget actions.
*
* The custom widget we create here is similar to a GtkPicture,
* but allows setting a zoom level for the displayed paintable.
*
* Our context menu has items to change the zoom level.
*/
#include <gtk/gtk.h>
#include "demo3widget.h"
GtkWidget *
do_menu (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *sw;
GtkWidget *widget;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Menu");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
sw = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), sw);
widget = demo3_widget_new ("/transparent/portland-rose.jpg");
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), widget);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -23,6 +23,7 @@ demos = files([
'editable_cells.c',
'entry_completion.c',
'entry_undo.c',
'errorstates.c',
'expander.c',
'filtermodel.c',
'fishbowl.c',
@@ -31,6 +32,7 @@ demos = files([
'gears.c',
'gestures.c',
'glarea.c',
'gltransition.c',
'headerbar.c',
'hypertext.c',
'iconscroll.c',
@@ -43,6 +45,7 @@ demos = files([
'links.c',
'listbox.c',
'listbox2.c',
'menu.c',
'flowbox.c',
'list_store.c',
'listview_applauncher.c',
@@ -59,6 +62,7 @@ demos = files([
'paint.c',
'paintable.c',
'paintable_animated.c',
'paintable_emblem.c',
'paintable_mediastream.c',
'panes.c',
'password_entry.c',
@@ -70,6 +74,7 @@ demos = files([
'scale.c',
'search_entry.c',
'search_entry2.c',
'shadertoy.c',
'shortcuts.c',
'shortcut_triggers.c',
'sidebar.c',
@@ -98,6 +103,10 @@ extra_demo_sources = files(['main.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',
'gtkshaderbin.c',
'gtkshadertoy.c',
'gtkshaderstack.c',
'gskshaderpaintable.c',
'puzzlepiece.c',
'bluroverlay.c',
'demoimage.c',
@@ -108,7 +117,8 @@ extra_demo_sources = files(['main.c',
'demo2layout.c',
'singular_value_decomposition.c',
'four_point_transform.c',
'demo2widget.c'])
'demo2widget.c',
'demo3widget.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')

220
demos/gtk-demo/neon.glsl Normal file
View File

@@ -0,0 +1,220 @@
// Originally from: https://www.shadertoy.com/view/WlByzy
// License CC0: Neonwave style road, sun and city
// The result of a bit of experimenting with neonwave style colors.
#define PI 3.141592654
#define TAU (2.0*PI)
#define TIME iTime
#define RESOLUTION iResolution
vec3 hsv2rgb(vec3 c) {
const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
float hash(in float co) {
return fract(sin(co*12.9898) * 13758.5453);
}
float hash(in vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
float psin(float a) {
return 0.5 + 0.5*sin(a);
}
float mod1(inout float p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float box(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
float planex(vec2 p, float w) {
return abs(p.y) - w;
}
float planey(vec2 p, float w) {
return abs(p.x) - w;
}
float pmin(float a, float b, float k) {
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
float pmax(float a, float b, float k) {
return -pmin(-a, -b, k);
}
float sun(vec2 p) {
const float ch = 0.0125;
vec2 sp = p;
vec2 cp = p;
mod1(cp.y, ch*6.0);
float d0 = circle(sp, 0.5);
float d1 = planex(cp, ch);
float d2 = p.y+ch*3.0;
float d = d0;
d = pmax(d, -max(d1, d2), ch*2.0);
return d;
}
float city(vec2 p) {
float sd = circle(p, 0.5);
float cd = 1E6;
const float count = 5.0;
const float width = 0.1;
for (float i = 0.0; i < count; ++i) {
vec2 pp = p;
pp.x += i*width/count;
float nn = mod1(pp.x, width);
float rr = hash(nn+sqrt(3.0)*i);
float dd = box(pp-vec2(0.0, -0.5), vec2(0.02, 0.35*(1.0-smoothstep(0.0, 5.0, abs(nn)))*rr+0.1));
cd = min(cd, dd);
}
return max(sd,cd);
}
vec3 sunEffect(vec2 p) {
float aa = 4.0 / RESOLUTION.y;
vec3 col = vec3(0.1);
vec3 skyCol1 = hsv2rgb(vec3(283.0/360.0, 0.83, 0.16));
vec3 skyCol2 = hsv2rgb(vec3(297.0/360.0, 0.79, 0.43));
col = mix(skyCol1, skyCol2, pow(clamp(0.5*(1.0+p.y+0.1*sin(4.0*p.x+TIME*0.5)), 0.0, 1.0), 4.0));
p.y -= 0.375;
float ds = sun(p);
float dc = city(p);
float dd = circle(p, 0.5);
vec3 sunCol = mix(vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 1.0), clamp(0.5 - 1.0*p.y, 0.0, 1.0));
vec3 glareCol = sqrt(sunCol);
vec3 cityCol = sunCol*sunCol;
col += glareCol*(exp(-30.0*ds))*step(0.0, ds);
float t1 = smoothstep(0.0, 0.075, -dd);
float t2 = smoothstep(0.0, 0.3, -dd);
col = mix(col, sunCol, smoothstep(-aa, 0.0, -ds));
col = mix(col, glareCol, smoothstep(-aa, 0.0, -dc)*t1);
col += vec3(0.0, 0.25, 0.0)*(exp(-90.0*dc))*step(0.0, dc)*t2;
// col += 0.3*psin(d*400);
return col;
}
float ground(vec2 p) {
p.y += TIME*80.0;
p *= 0.075;
vec2 gp = p;
gp = fract(gp) - vec2(0.5);
float d0 = abs(gp.x);
float d1 = abs(gp.y);
float d2 = circle(gp, 0.05);
const float rw = 2.5;
const float sw = 0.0125;
vec2 rp = p;
mod1(rp.y, 12.0);
float d3 = abs(rp.x) - rw;
float d4 = abs(d3) - sw*2.0;
float d5 = box(rp, vec2(sw*2.0, 2.0));
vec2 sp = p;
mod1(sp.y, 4.0);
sp.x = abs(sp.x);
sp -= vec2(rw - 0.125, 0.0);
float d6 = box(sp, vec2(sw, 1.0));
float d = d0;
d = pmin(d, d1, 0.1);
d = max(d, -d3);
d = min(d, d4);
d = min(d, d5);
d = min(d, d6);
return d;
}
vec3 groundEffect(vec2 p) {
vec3 ro = vec3(0.0, 20.0, 0.0);
vec3 ww = normalize(vec3(0.0, -0.025, 1.0));
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0), ww));
vec3 vv = normalize(cross(ww,uu));
vec3 rd = normalize(p.x*uu + p.y*vv + 2.5*ww);
float distg = (-9.0 - ro.y)/rd.y;
const vec3 shineCol = 0.75*vec3(0.5, 0.75, 1.0);
const vec3 gridCol = vec3(1.0);
vec3 col = vec3(0.0);
if (distg > 0.0) {
vec3 pg = ro + rd*distg;
float aa = length(dFdx(pg))*0.0002*RESOLUTION.x;
float dg = ground(pg.xz);
col = mix(col, gridCol, smoothstep(-aa, 0.0, -(dg+0.0175)));
col += shineCol*(exp(-10.0*clamp(dg, 0.0, 1.0)));
col = clamp(col, 0.0, 1.0);
// col += 0.3*psin(dg*100);
col *= pow(1.0-smoothstep(ro.y*3.0, 220.0+ro.y*2.0, distg), 2.0);
}
return col;
}
vec3 postProcess(vec3 col, vec2 q) {
col = clamp(col,0.0,1.0);
// col=pow(col,vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col);
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4);
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7);
return col;
}
vec3 effect(vec2 p, vec2 q) {
vec3 col = vec3(0.0);
vec2 off = vec2(0.0, 0.0);
col += sunEffect(p+off);
col += groundEffect(p+off);
col = postProcess(col, q);
return col;
}
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 q = fragCoord/iResolution.xy;
vec2 p = -1. + 2. * q;
p.x *= RESOLUTION.x / RESOLUTION.y;
vec3 col = effect(p, q);
fragColor = vec4(col, 1.0);
}

View File

@@ -1,4 +1,5 @@
/* Overlay/Interactive Overlay
* #Keywords: GtkOverlay
*
* Shows widgets in static positions over a main widget.
*

View File

@@ -1,4 +1,5 @@
/* Overlay/Decorative Overlay
* #Keywords: GtkOverlay
*
* Another example of an overlay with some decorative
* and some interactive controls.

View File

@@ -1,4 +1,5 @@
/* Printing/Page Setup
* #Keywords: GtkPageSetup
*
* GtkPageSetupUnixDialog can be used if page setup is needed
* independent of a full printing dialog.

View File

@@ -1,4 +1,5 @@
/* Paint
* #Keywords: GdkDrawingArea, GtkGesture
*
* Demonstrates practical handling of drawing tablets in a real world
* usecase.

View File

@@ -48,15 +48,17 @@ void
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
double width,
double height,
double rotation)
double rotation,
gboolean draw_background)
{
#define RADIUS 0.3
cairo_t *cr;
double size;
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 },
&GRAPHENE_RECT_INIT (0, 0, width, height));
if (draw_background)
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 },
&GRAPHENE_RECT_INIT (0, 0, width, height));
size = MIN (width, height);
cr = gtk_snapshot_append_cairo (snapshot,
@@ -93,7 +95,8 @@ gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
gtk_nuclear_snapshot (snapshot,
width, height,
nuclear->rotation);
nuclear->rotation,
TRUE);
}
static GdkPaintableFlags
@@ -161,6 +164,7 @@ do_paintable (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Nuclear Icon");
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
nuclear = gtk_nuclear_icon_new (0.0);
image = gtk_image_new_from_paintable (nuclear);

View File

@@ -6,10 +6,11 @@
void gtk_nuclear_snapshot (GtkSnapshot *snapshot,
double width,
double height,
double rotation);
double rotation,
gboolean draw_background);
GdkPaintable * gtk_nuclear_icon_new (double rotation);
GdkPaintable * gtk_nuclear_animation_new (void);
GdkPaintable * gtk_nuclear_animation_new (gboolean draw_background);
GtkMediaStream *gtk_nuclear_media_stream_new (void);
#endif /* __PAINTABLE_H__ */

View File

@@ -33,6 +33,8 @@ struct _GtkNuclearAnimation
{
GObject parent_instance;
gboolean draw_background;
/* This variable stores the progress of our animation.
* We just count upwards until we hit MAX_PROGRESS and
* then start from scratch.
@@ -64,7 +66,8 @@ gtk_nuclear_animation_snapshot (GdkPaintable *paintable,
/* We call the function from the previous example here. */
gtk_nuclear_snapshot (snapshot,
width, height,
2 * G_PI * nuclear->progress / MAX_PROGRESS);
2 * G_PI * nuclear->progress / MAX_PROGRESS,
nuclear->draw_background);
}
static GdkPaintable *
@@ -175,9 +178,15 @@ gtk_nuclear_animation_init (GtkNuclearAnimation *nuclear)
/* And finally, we add the simple constructor we declared in the header. */
GdkPaintable *
gtk_nuclear_animation_new (void)
gtk_nuclear_animation_new (gboolean draw_background)
{
return g_object_new (GTK_TYPE_NUCLEAR_ANIMATION, NULL);
GtkNuclearAnimation *nuclear;
nuclear = g_object_new (GTK_TYPE_NUCLEAR_ANIMATION, NULL);
nuclear->draw_background = draw_background;
return GDK_PAINTABLE (nuclear);
}
GtkWidget *
@@ -193,8 +202,9 @@ do_paintable_animated (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Nuclear Animation");
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
nuclear = gtk_nuclear_animation_new ();
nuclear = gtk_nuclear_animation_new (TRUE);
image = gtk_image_new_from_paintable (nuclear);
gtk_window_set_child (GTK_WINDOW (window), image);
g_object_unref (nuclear);

View File

@@ -0,0 +1,186 @@
/* Paintable/Emblems
*
* This demo shows how GdkPaintable can be used to
* overlay an emblem on top of an icon. The emblem
* can either be another icon, or an arbitrary
* paintable.
*/
#include <gtk/gtk.h>
#include "paintable.h"
static GtkWidget *window = NULL;
#define DEMO_TYPE_ICON (demo_icon_get_type ())
G_DECLARE_FINAL_TYPE (DemoIcon, demo_icon, DEMO, ICON, GObject)
struct _DemoIcon
{
GObject parent_instance;
GdkPaintable *icon;
GdkPaintable *emblem;
GdkPaintableFlags flags;
};
struct _DemoIconClass
{
GObjectClass parent_class;
};
void
demo_icon_snapshot (GdkPaintable *paintable,
GtkSnapshot *snapshot,
double width,
double height)
{
DemoIcon *self = DEMO_ICON (paintable);
gdk_paintable_snapshot (self->icon, snapshot, width, height);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (0.5 * width, 0));
gdk_paintable_snapshot (self->emblem, snapshot, 0.5 * width, 0.5 * height);
gtk_snapshot_restore (snapshot);
}
static GdkPaintableFlags
demo_icon_get_flags (GdkPaintable *paintable)
{
DemoIcon *self = DEMO_ICON (paintable);
return self->flags;
}
static void
demo_icon_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = demo_icon_snapshot;
iface->get_flags = demo_icon_get_flags;
}
G_DEFINE_TYPE_WITH_CODE (DemoIcon, demo_icon, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
demo_icon_paintable_init))
static void
demo_icon_dispose (GObject *object)
{
DemoIcon *self = DEMO_ICON (object);
g_signal_handlers_disconnect_by_func (self->emblem,
gdk_paintable_invalidate_contents,
self);
g_clear_object (&self->icon);
g_clear_object (&self->emblem);
G_OBJECT_CLASS (demo_icon_parent_class)->dispose (object);
}
static void
demo_icon_class_init (DemoIconClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = demo_icon_dispose;
}
static void
demo_icon_init (DemoIcon *self)
{
self->flags = GDK_PAINTABLE_STATIC_SIZE | GDK_PAINTABLE_STATIC_CONTENTS;
}
GdkPaintable *
demo_icon_new_with_paintable (const char *icon_name,
GdkPaintable *emblem)
{
GtkIconTheme *theme;
GtkIconPaintable *icon;
DemoIcon *self;
theme = gtk_icon_theme_get_for_display (gdk_display_get_default ());
icon = gtk_icon_theme_lookup_icon (theme,
icon_name, NULL,
128, 1,
GTK_TEXT_DIR_LTR, 0);
self = g_object_new (DEMO_TYPE_ICON, NULL);
self->icon = GDK_PAINTABLE (icon);
self->emblem = emblem;
if ((gdk_paintable_get_flags (emblem) & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
{
self->flags &= ~GDK_PAINTABLE_STATIC_CONTENTS;
g_signal_connect_swapped (emblem, "invalidate-contents",
G_CALLBACK (gdk_paintable_invalidate_contents), self);
}
return GDK_PAINTABLE (self);
}
GdkPaintable *
demo_icon_new (const char *icon_name,
const char *emblem_name)
{
GtkIconTheme *theme;
GtkIconPaintable *emblem;
theme = gtk_icon_theme_get_for_display (gdk_display_get_default ());
emblem = gtk_icon_theme_lookup_icon (theme,
emblem_name, NULL,
128, 1,
GTK_TEXT_DIR_LTR, 0);
return GDK_PAINTABLE (demo_icon_new_with_paintable (icon_name,
GDK_PAINTABLE (emblem)));
}
GtkWidget *
do_paintable_emblem (GtkWidget *do_widget)
{
GdkPaintable *icon;
GtkWidget *grid;
GtkWidget *image;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Emblems");
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
grid = gtk_grid_new ();
icon = demo_icon_new ("folder", "starred");
image = gtk_image_new_from_paintable (icon);
gtk_widget_set_hexpand (image, TRUE);
gtk_widget_set_vexpand (image, TRUE);
gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 1);
icon = demo_icon_new_with_paintable ("drive-multidisk",
gtk_nuclear_animation_new (FALSE));
image = gtk_image_new_from_paintable (icon);
gtk_widget_set_hexpand (image, TRUE);
gtk_widget_set_vexpand (image, TRUE);
gtk_grid_attach (GTK_GRID (grid), image, 1, 0, 1, 1);
gtk_window_set_child (GTK_WINDOW (window), grid);
g_object_unref (icon);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -74,7 +74,8 @@ gtk_nuclear_media_stream_snapshot (GdkPaintable *paintable,
/* We call the function from the previous example here. */
gtk_nuclear_snapshot (snapshot,
width, height,
2 * G_PI * nuclear->progress / DURATION);
2 * G_PI * nuclear->progress / DURATION,
TRUE);
}
static GdkPaintable *

View File

@@ -1,4 +1,5 @@
/* Peg Solitaire
* #Keywords: GtkGridView, game
*
* This demo demonstrates how to use drag'n'drop to implement peg solitaire.
*

View File

@@ -1,11 +1,37 @@
/* Pickers
* #Keywords: GtkColorChooser, GtkFontChooser, GtkFileChooser,
* #Keywords: GtkApplicationChooser
*
* These widgets are mainly intended for use in preference dialogs.
* They allow to select colors, fonts, files, directories and applications.
*
* This demo shows both the default appearance for these dialogs,
* as well as some of the customizations that are possible.
*/
#include <gtk/gtk.h>
static gboolean
filter_font_cb (const PangoFontFamily *family,
const PangoFontFace *face,
gpointer data)
{
const char *alias_families[] = {
"Cursive",
"Fantasy",
"Monospace",
"Sans",
"Serif",
"System-ui",
NULL
};
const char *family_name;
family_name = pango_font_family_get_name (PANGO_FONT_FAMILY (family));
return g_strv_contains (alias_families, family_name);
}
#define COLOR(r,g,b) { r/255., g/255., b/255., 1.0 }
GtkWidget *
@@ -37,6 +63,9 @@ do_pickers (GtkWidget *do_widget)
if (!window)
{
char *dir;
GFile *file;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
@@ -52,10 +81,22 @@ do_pickers (GtkWidget *do_widget)
gtk_grid_set_column_spacing (GTK_GRID (table), 10);
gtk_window_set_child (GTK_WINDOW (window), table);
label = gtk_label_new ("Standard");
gtk_widget_add_css_class (label, "title-4");
gtk_grid_attach (GTK_GRID (table), label, 1, -1, 1, 1);
label = gtk_label_new ("Custom");
gtk_widget_add_css_class (label, "title-4");
gtk_grid_attach (GTK_GRID (table), label, 2, -1, 1, 1);
label = gtk_label_new ("Color:");
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
picker = gtk_color_button_new ();
gtk_grid_attach (GTK_GRID (table), picker, 1, 0, 1, 1);
picker = gtk_color_button_new ();
gtk_color_button_set_title (GTK_COLOR_BUTTON (picker), "Solarized colors");
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (picker),
@@ -63,27 +104,58 @@ do_pickers (GtkWidget *do_widget)
9,
18,
solarized);
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (table), picker, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (table), picker, 2, 0, 1, 1);
label = gtk_label_new ("Font:");
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (label, TRUE);
picker = gtk_font_button_new ();
gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
picker = gtk_font_button_new ();
gtk_grid_attach (GTK_GRID (table), picker, 1, 1, 1, 1);
picker = gtk_font_button_new ();
gtk_font_chooser_set_level (GTK_FONT_CHOOSER (picker),
GTK_FONT_CHOOSER_LEVEL_FAMILY |
GTK_FONT_CHOOSER_LEVEL_SIZE);
gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER (picker), filter_font_cb, NULL, NULL);
gtk_grid_attach (GTK_GRID (table), picker, 2, 1, 1, 1);
label = gtk_label_new ("File:");
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
picker = gtk_file_chooser_button_new ("Pick a File",
GTK_FILE_CHOOSER_ACTION_OPEN);
gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
gtk_grid_attach (GTK_GRID (table), picker, 1, 2, 1, 1);
picker = gtk_file_chooser_button_new ("Pick a File",
GTK_FILE_CHOOSER_ACTION_OPEN);
dir = g_get_current_dir ();
file = g_file_new_for_path (dir);
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (picker), file, NULL);
g_object_unref (file);
g_free (dir);
gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (picker),
"choice",
"Encoding",
(const char *[]) { "option1", "option2", NULL },
(const char *[]) { "UTF-8", "Other Encoding", NULL });
gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (picker), "choice", "option1");
gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (picker),
"check",
"Read backwards",
NULL, NULL);
gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (picker), "check", "false");
gtk_grid_attach (GTK_GRID (table), picker, 2, 2, 1, 1);
label = gtk_label_new ("Folder:");
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);

View File

@@ -2,7 +2,6 @@
*
* GtkPrintOperation offers a simple API to support printing
* in a cross-platform way.
*
*/
#include <math.h>

View File

@@ -1,10 +1,10 @@
/* Pango/Rotated Text
*
* This demo shows how to use PangoCairo to draw rotated and transformed
* text. The right pane shows a rotated GtkLabel widget.
* text. The right pane shows a rotated GtkLabel widget.
*
* In both cases, a custom PangoCairo shape renderer is installed to draw
* a red heard using cairo drawing operations instead of the Unicode heart
* a red heart using cairo drawing operations instead of the Unicode heart
* character.
*/

View File

@@ -1,9 +1,13 @@
/* Entry/Delayed Search Entry
*
* GtkSearchEntry sets up GtkEntries ready for search. Search entries
* have their "changed" signal delayed and should be used
* when the searched operation is slow such as loads of entries
* to search, or online searches.
* GtkSearchEntry provides an entry that is ready for search.
*
* Search entries have their "changed" signal delayed and should
* be used when the searched operation is slow such as loads of
* entries to search, or online searches.
*
* GtkSearchBar allows have a hidden search entry that 'springs
* into action' upon keyboard input.
*/
#include <gtk/gtk.h>

202
demos/gtk-demo/shadertoy.c Normal file
View File

@@ -0,0 +1,202 @@
/* OpenGL/Shadertoy
* #Keywords: GtkGLArea
*
* Generate pixels using a custom fragment shader.
*
* The names of the uniforms are compatible with the shaders on shadertoy.com, so
* many of the shaders there work here too.
*/
#include <math.h>
#include <gtk/gtk.h>
#include <epoxy/gl.h>
#include "gtkshadertoy.h"
static GtkWidget *demo_window = NULL;
static GtkWidget *shadertoy = NULL;
static GtkTextBuffer *textbuffer = NULL;
static void
run (void)
{
GtkTextIter start, end;
char *text;
gtk_text_buffer_get_bounds (textbuffer, &start, &end);
text = gtk_text_buffer_get_text (textbuffer, &start, &end, FALSE);
gtk_shadertoy_set_image_shader (GTK_SHADERTOY (shadertoy), text);
g_free (text);
}
static void
run_clicked_cb (GtkWidget *button,
gpointer user_data)
{
run ();
}
static void
load_clicked_cb (GtkWidget *button,
gpointer user_data)
{
const char *path = user_data;
GBytes *initial_shader;
initial_shader = g_resources_lookup_data (path, 0, NULL);
gtk_text_buffer_set_text (textbuffer, g_bytes_get_data (initial_shader, NULL), -1);
g_bytes_unref (initial_shader);
run ();
}
static void
clear_clicked_cb (GtkWidget *button,
gpointer user_data)
{
gtk_text_buffer_set_text (textbuffer, "", 0);
}
static void
close_window (GtkWidget *widget)
{
/* Reset the state */
demo_window = NULL;
shadertoy = NULL;
textbuffer = NULL;
}
static GtkWidget *
new_shadertoy (const char *path)
{
GBytes *shader;
GtkWidget *toy;
toy = gtk_shadertoy_new ();
shader = g_resources_lookup_data (path, 0, NULL);
gtk_shadertoy_set_image_shader (GTK_SHADERTOY (toy),
g_bytes_get_data (shader, NULL));
g_bytes_unref (shader);
return toy;
}
static GtkWidget *
new_button (const char *path)
{
GtkWidget *button, *toy;
button = gtk_button_new ();
g_signal_connect (button, "clicked", G_CALLBACK (load_clicked_cb), (char *)path);
toy = new_shadertoy (path);
gtk_widget_set_size_request (toy, 64, 36);
gtk_button_set_child (GTK_BUTTON (button), toy);
return button;
}
static GtkWidget *
create_shadertoy_window (GtkWidget *do_widget)
{
GtkWidget *window, *box, *hbox, *button, *textview, *sw, *aspect, *centerbox;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Shadertoy");
gtk_window_set_default_size (GTK_WINDOW (window), 690, 740);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
gtk_box_set_spacing (GTK_BOX (box), 6);
gtk_window_set_child (GTK_WINDOW (window), box);
aspect = gtk_aspect_frame_new (0.5, 0.5, 1.77777, FALSE);
gtk_widget_set_hexpand (aspect, TRUE);
gtk_widget_set_vexpand (aspect, TRUE);
gtk_box_append (GTK_BOX (box), aspect);
shadertoy = new_shadertoy ("/shadertoy/alienplanet.glsl");
gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (aspect), shadertoy);
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 250);
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_widget_set_hexpand (sw, TRUE);
gtk_box_append (GTK_BOX (box), sw);
textview = gtk_text_view_new ();
gtk_text_view_set_monospace (GTK_TEXT_VIEW (textview), TRUE);
g_object_set (textview,
"left-margin", 20,
"right-margin", 20,
"top-margin", 20,
"bottom-margin", 20,
NULL);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), textview);
textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
gtk_text_buffer_set_text (textbuffer,
gtk_shadertoy_get_image_shader (GTK_SHADERTOY (shadertoy)),
-1);
centerbox = gtk_center_box_new ();
gtk_box_append (GTK_BOX (box), centerbox);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
gtk_box_set_spacing (GTK_BOX (hbox), 6);
gtk_center_box_set_start_widget (GTK_CENTER_BOX (centerbox), hbox);
button = gtk_button_new_from_icon_name ("view-refresh-symbolic");
gtk_widget_set_tooltip_text (button, "Restart the demo");
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
g_signal_connect (button, "clicked", G_CALLBACK (run_clicked_cb), NULL);
gtk_box_append (GTK_BOX (hbox), button);
button = gtk_button_new_from_icon_name ("edit-clear-all-symbolic");
gtk_widget_set_tooltip_text (button, "Clear the text view");
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
g_signal_connect (button, "clicked", G_CALLBACK (clear_clicked_cb), NULL);
gtk_box_append (GTK_BOX (hbox), button);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
gtk_box_set_spacing (GTK_BOX (hbox), 6);
gtk_center_box_set_end_widget (GTK_CENTER_BOX (centerbox), hbox);
button = new_button ("/shadertoy/alienplanet.glsl");
gtk_box_append (GTK_BOX (hbox), button);
button = new_button ("/shadertoy/mandelbrot.glsl");
gtk_box_append (GTK_BOX (hbox), button);
button = new_button ("/shadertoy/neon.glsl");
gtk_box_append (GTK_BOX (hbox), button);
button = new_button ("/shadertoy/cogs.glsl");
gtk_box_append (GTK_BOX (hbox), button);
button = new_button ("/shadertoy/glowingstars.glsl");
gtk_box_append (GTK_BOX (hbox), button);
return window;
}
GtkWidget *
do_shadertoy (GtkWidget *do_widget)
{
if (!demo_window)
demo_window = create_shadertoy_window (do_widget);
if (!gtk_widget_get_visible (demo_window))
gtk_widget_show (demo_window);
else
gtk_window_destroy (GTK_WINDOW (demo_window));
return demo_window;
}

View File

@@ -1,4 +1,5 @@
/* Shortcuts
* #Keywords: GtkShortcutController
*
* GtkShortcut is the abstraction used by GTK to handle shortcuts from
* keyboard or other input devices.

View File

@@ -1,9 +1,9 @@
/* Stack Sidebar
*
* GtkStackSidebar provides an automatic sidebar widget to control
* navigation of a GtkStack object. This widget automatically updates it
* content based on what is presently available in the GtkStack object,
* and using the "title" child property to set the display labels.
* navigation of a GtkStack object. This widget automatically updates
* its content based on what is presently available in the GtkStack
* object, and using the "title" child property to set the display labels.
*/
#include <glib/gi18n.h>
@@ -37,7 +37,6 @@ do_sidebar (GtkWidget *do_widget)
{
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_widget_set_size_request (window, 500, 350);
header = gtk_header_bar_new ();
gtk_window_set_titlebar (GTK_WINDOW(window), header);

View File

@@ -59,8 +59,8 @@ add_row (GtkGrid *table,
}
static void
toggle_grouping (GtkToggleButton *check_button,
GtkSizeGroup *size_group)
toggle_grouping (GtkCheckButton *check_button,
GtkSizeGroup *size_group)
{
GtkSizeGroupMode new_mode;
@@ -68,7 +68,7 @@ toggle_grouping (GtkToggleButton *check_button,
* here to show the effect of GTK_SIZE_GROUP_HORIZONTAL by
* contrast.
*/
if (gtk_toggle_button_get_active (check_button))
if (gtk_check_button_get_active (check_button))
new_mode = GTK_SIZE_GROUP_HORIZONTAL;
else
new_mode = GTK_SIZE_GROUP_NONE;

View File

@@ -1,8 +1,8 @@
/* Sliding Puzzle
* #Keywords: GdkPaintable, GdkGesture, game
*
* This demo demonstrates how to use gestures and paintables to create a
* small sliding puzzle game.
*
*/
#include <gtk/gtk.h>
@@ -437,7 +437,7 @@ do_sliding_puzzle (GtkWidget *do_widget)
choices = gtk_flow_box_new ();
gtk_widget_add_css_class (choices, "view");
add_choice (choices, puzzle);
add_choice (choices, gtk_nuclear_animation_new ());
add_choice (choices, gtk_nuclear_animation_new (TRUE));
media = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
gtk_media_stream_set_loop (media, TRUE);
gtk_media_stream_set_muted (media, TRUE);

View File

@@ -1,4 +1,5 @@
/* Spin Buttons
* #Keywords: GtkEntry
*
* GtkSpinButton provides convenient ways to input data
* that can be seen as a value in a range. The examples

View File

@@ -1,7 +1,6 @@
/* Spinner
*
* GtkSpinner allows to show that background activity is on-going.
*
*/
#include <glib/gi18n.h>

View File

@@ -22,18 +22,21 @@ do_tabs (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Tabs");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
gtk_window_set_default_size (GTK_WINDOW (window), 330, 330);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 20);
tabs = pango_tab_array_new (3, TRUE);
pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, 0);
pango_tab_array_set_tab (tabs, 1, PANGO_TAB_LEFT, 150);
pango_tab_array_set_tab (tabs, 2, PANGO_TAB_LEFT, 300);
pango_tab_array_set_tab (tabs, 1, PANGO_TAB_LEFT, 100);
pango_tab_array_set_tab (tabs, 2, PANGO_TAB_LEFT, 200);
gtk_text_view_set_tabs (GTK_TEXT_VIEW (view), tabs);
pango_tab_array_free (tabs);

View File

@@ -1,4 +1,5 @@
/* Text View/Automatic Scrolling
* #Keywords: GtkTextView, GtkScrolledWindow
*
* This example demonstrates how to use the gravity of
* GtkTextMarks to keep a text view scrolled to the bottom

View File

@@ -26,13 +26,20 @@ do_textundo (GtkWidget *do_widget)
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
gtk_window_set_default_size (GTK_WINDOW (window), 330, 330);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_title (GTK_WINDOW (window), "Undo and Redo");
view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view), 10);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 20);
gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (view), 20);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_enable_undo (buffer, TRUE);
@@ -40,10 +47,13 @@ do_textundo (GtkWidget *do_widget)
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_get_start_iter (buffer, &iter);
gtk_text_buffer_insert (buffer, &iter,
"Type to add more text.\n"
"Use Primary+Z to undo and Primary+Shift+Z to redo a previously undone action.\n"
"\n",
-1);
"The GtkTextView supports undo and redo through the use of a "
"GtkTextBuffer. You can enable or disable undo support using "
"gtk_text_buffer_set_enable_undo().\n"
"Type to add more text.\n"
"Use Control+z to undo and Control+Shift+z or Control+y to "
"redo previously undone operations.",
-1);
gtk_text_buffer_end_irreversible_action (buffer);
sw = gtk_scrolled_window_new ();

View File

@@ -142,7 +142,7 @@ insert_text (GtkTextView *view)
32, 1,
gtk_widget_get_direction (widget),
0);
nuclear = gtk_nuclear_animation_new ();
nuclear = gtk_nuclear_animation_new (TRUE);
/* get start of buffer; each insertion will revalidate the
* iterator to point to just after the inserted text.

View File

@@ -10,76 +10,6 @@
static guint tick_cb;
static gint64
guess_refresh_interval (GdkFrameClock *frame_clock)
{
gint64 interval;
gint64 i;
interval = G_MAXINT64;
for (i = gdk_frame_clock_get_history_start (frame_clock);
i < gdk_frame_clock_get_frame_counter (frame_clock);
i++)
{
GdkFrameTimings *t, *before;
gint64 ts, before_ts;
t = gdk_frame_clock_get_timings (frame_clock, i);
before = gdk_frame_clock_get_timings (frame_clock, i - 1);
if (t == NULL || before == NULL)
continue;
ts = gdk_frame_timings_get_frame_time (t);
before_ts = gdk_frame_timings_get_frame_time (before);
if (ts == 0 || before_ts == 0)
continue;
interval = MIN (interval, ts - before_ts);
}
if (interval == G_MAXINT64)
return 0;
return interval;
}
static double
frame_clock_get_fps (GdkFrameClock *frame_clock)
{
GdkFrameTimings *start, *end;
gint64 start_counter, end_counter;
gint64 start_timestamp, end_timestamp;
gint64 interval;
start_counter = gdk_frame_clock_get_history_start (frame_clock);
end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
start = gdk_frame_clock_get_timings (frame_clock, start_counter);
for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
end = gdk_frame_clock_get_timings (frame_clock, end_counter))
end_counter--;
if (end_counter - start_counter < 4)
return 0.0;
start_timestamp = gdk_frame_timings_get_presentation_time (start);
end_timestamp = gdk_frame_timings_get_presentation_time (end);
if (start_timestamp == 0 || end_timestamp == 0)
{
start_timestamp = gdk_frame_timings_get_frame_time (start);
end_timestamp = gdk_frame_timings_get_frame_time (end);
}
interval = gdk_frame_timings_get_refresh_interval (end);
if (interval == 0)
{
interval = guess_refresh_interval (frame_clock);
if (interval == 0)
return 0.0;
}
return ((double) end_counter - start_counter) * G_USEC_PER_SEC / (end_timestamp - start_timestamp);
}
typedef struct {
const char *name;
gboolean dark;
@@ -116,7 +46,7 @@ change_theme (GtkWidget *widget,
{
char *fps;
fps = g_strdup_printf ("%.2f fps", frame_clock_get_fps (frame_clock));
fps = g_strdup_printf ("%.2f fps", gdk_frame_clock_get_fps (frame_clock));
gtk_label_set_label (GTK_LABEL (label), fps);
g_free (fps);
}

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