Compare commits

...

292 Commits

Author SHA1 Message Date
Matthias Clasen
fe4f4d3719 gsk: Tweak GskGLShader long desc
Reformulate one paragraph, as suggested by Benjamin.
2020-09-28 14:01:59 -04:00
Matthias Clasen
e8d1537606 gsk: Use guint for array indices
Avoids some trivialities and static analyis complaints.
2020-09-28 13:57:54 -04:00
Matthias Clasen
2f33ec418b gsk: Cosmetic docs tweak 2020-09-28 13:55:24 -04:00
Matthias Clasen
6fc9294036 gsk: Small doc tweaks
Add an annotation, and tweak the docs for
gsk_gl_shader_node_new slightly.
2020-09-28 13:53:51 -04:00
Matthias Clasen
3297510040 gsk: Improve gsk_gl_shader_node_new preconditions
Check all that we can.
2020-09-28 13:50:15 -04:00
Matthias Clasen
a2849d3f7a gsk: Tweak shader node deserialization
Use a GskShaderArgsBuilder and make the parser
more precise about commas vs semicolons.
2020-09-28 13:38:12 -04:00
Matthias Clasen
f8dc75089e gsk: Reuse css printing function
Don't copy _gtk_css_print_string, just use it.
2020-09-28 13:10:57 -04:00
Matthias Clasen
003cf4f6ce css: Move the last parser api to the new header
This lets us use it from the render node parser
in gsk.
2020-09-28 13:09:54 -04:00
Matthias Clasen
30f2e7e153 rendernodeparser: Tweak the shader node serialization
We call it args now in the api. Follow suit for the
serialization.
2020-09-28 12:57:31 -04:00
Matthias Clasen
1ed2b1b8e3 gsk: Beef up GskShaderArgsBuilder docs
Mention that args are zero-initialized.
2020-09-28 12:51:31 -04:00
Matthias Clasen
4906779f72 gtk-demo: Simplify transitions demo
We are not using the frame clock anymore, so don't
pass it around.
2020-09-28 12:45:31 -04:00
Matthias Clasen
cda8bb4384 gtk-demo: Tweak the transition demo text
Fix some types, and say a bit more here.
2020-09-28 12:41:51 -04:00
Matthias Clasen
a801be3c97 gsk: Fix the shader example
I mixed up my variable names.
2020-09-28 12:18:37 -04:00
Alexander Larsson
59c8c75ede GskShaderArgBuilder: Use standard builder-like API
Primarily this is ref/unref vs copy, and ne wfree_to_args() method. But
also some minor renames.
2020-09-28 16:40:14 +02:00
Alexander Larsson
796b205958 gsk_gl_shader_format_args: Pass arguments by value
Primitive values are now passed by values (although vectors still
by pointer). Also since we can now no longer handle missing definitions
that is an error.
2020-09-28 16:40:14 +02:00
Alexander Larsson
947a933819 gtk-demo: Only use one GskGLShader in fishbowl
We don't want to use a new shader per paintable, because then we will
need to recompile each one. Also remove some leftover unused vars from
the cogs glsl.
2020-09-28 16:40:14 +02:00
Alexander Larsson
48cb5ca3db snapshot: Drop n_children from push_gl_shader and use custom pop
We now always assume you pass the right amount of children for the
shader, and each such child is followed by
gtk_snapshot_gl_shader_pop_texture() and then a final
gtk_snapshot_pop().

This means we handle the 0 child case ok, and that we can validate
that the number of pops of various types are correct.
2020-09-28 16:40:14 +02:00
Matthias Clasen
f19001d4c3 Add some more docs
Add an example to the GskGLShader docs.
2020-09-25 20:38:22 -04:00
Matthias Clasen
6ecf612677 Add another shader test
This one tests the convenience api for creating
uniform data.
2020-09-25 20:37:48 -04:00
Matthias Clasen
e0b3746655 gtk-demo: Add a shader paintable to the fishbowl
This gets around 500 instances at 60fps on my system.
2020-09-25 17:22:22 -04:00
Matthias Clasen
1bc81fac2a gtk-demo: Add a shader paintable demo
Add a shader paintable to the OpenGL transitions
demo. This is reusing one of the shadertoy examples,
tweaked slightly to work as a standalone fragment
shader.
2020-09-25 17:22:22 -04:00
Matthias Clasen
bdcc29ebef gtk-demo: Add a shader paintable
This is a GdkPaintable implementation wrapped
around a GskGLShader. It can optionally be hooked
up to a frame clock to update a time uniform.

The code is set up for this to live as public api
in GSK, if we find it useful enough.
2020-09-25 17:21:40 -04:00
Alexander Larsson
810e9c238e snapshot: Drop the varargs versions of push_gl_shader()
We can now just use gsk_gl_shader_format_args() directly, relying
on the transfer-full of the shader args argument.
2020-09-25 16:51:46 +02:00
Alexander Larsson
e4dfa5597a gtk_snapshot_push_gl_shader: Make @args transfer-full
This makes the common case of this just being created a lot easier.
2020-09-25 16:46:39 +02:00
Alexander Larsson
32aa470f68 Rename uniform_data to shader args, or just args
This makes a lot of types and function names shorter.
Also, we add a "..." version of gsk_gl_shader_format_args_va().
2020-09-25 16:38:10 +02:00
Alexander Larsson
a234ab1e55 Finish remaining renames from GLSHADER to GL_SHADER (etc)
This fixes all remaining cases in public headers.
2020-09-25 14:31:44 +02:00
Alexander Larsson
e93a51b1cc GskGLShader: Drop fallback node and add try_compile function to replace it
This removes the fallback node from GskGLShaderNode and adds
a new function gsk_gl_shader_try_compile_for() which tries to compile a
shader against a renderer. Then you can use the return value of this
both as a way to implement the fallback, and as a way to get at
the error report in a saner way.
2020-09-25 14:31:33 +02:00
Matthias Clasen
66cd15d858 Add some shader tests
These are just basic api usage tests, no rendering.
They found the issues fixed in the preceding commits.
2020-09-23 18:05:57 -04:00
Matthias Clasen
a0bc9d65da gsk: Make uniform regex more forgiving
Accept - in initializers, otherwise we don't accept
things like uniform int n = -2;
2020-09-23 18:03:52 -04:00
Matthias Clasen
a580c711e5 gsk: Make uniform regex more forgiving
Accept comments after a uniform declaration - the
very first shader example I tried had these, so we
better support it.
2020-09-23 17:48:35 -04:00
Matthias Clasen
e91d5b82ce gsk: Fix getters and setters for vector types
The types we store for the uniforms are VEC2/3/4,
even though we just store a bunch of floats.

This was found while adding some simple tests.
2020-09-23 17:42:10 -04:00
Matthias Clasen
0516c59ff5 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-23 16:17:56 -04:00
Matthias Clasen
a3ea3f94dc gsk: Add some shader debug spew
When we're done extracting uniform info from the glsl,
print out what we've found for GSK_DEBUG=shaders. If
something goes wrong, this will be useful.
2020-09-23 15:40:57 -04:00
Matthias Clasen
5e9fe2f6e8 docs: Add new snapshot apis 2020-09-23 14:59:25 -04:00
Matthias Clasen
6613c523c2 Rename gl shader snapshot apis
Rename gtk_snapshot_push_glshader and friends to
gtk_snapshot_push_gl_shader, following the similar
renaming in GSK.

Update all callers.
2020-09-23 14:53:42 -04:00
Matthias Clasen
efa0fa0bf4 gsk: Small doc fixups
Tweak the gl shader docs here and there.
2020-09-23 14:46:35 -04:00
Matthias Clasen
1b6f7917ed Add GskGLShader apis to the docs 2020-09-23 14:41:22 -04:00
Alexander Larsson
8cc18d2c82 shadertoy demo: Fix GLSL on GLES
I was getting "assignment to varying fragColor" errors
2020-09-23 17:38:03 +02:00
Alexander Larsson
d97267b897 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-23 17:28:23 +02:00
Alexander Larsson
21e0ad0561 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-23 17:01:17 +02:00
Alexander Larsson
94cccc5e71 GtkSnapshot: Add gtk_snapshot_push_glshader() 2020-09-23 17:01:13 +02:00
Alexander Larsson
111dfdf3f5 Add GskGLShaderNode
This is a rendernode that is supposed to run a GLSL fragment
shader with a set of inputs and produce outputs.
The inputs are:
 * A GskGLShader object with the source and uniforms definitions
   computed from the source.
 * A the data for the uniforms, formated according to the GskGLShader
 * a list of render nodes that are rendered to textures

Additionally there is a fallback node which is used in case
OpenGL is not supported or there is some kind of failure
with the shader code.
2020-09-23 17:01:08 +02:00
Alexander Larsson
0693deb02f 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-22 12:50:10 +02:00
Alexander Larsson
ffd39c257a 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-22 12:50:10 +02:00
Alexander Larsson
ec0ad5738c 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-22 09:40:16 +02:00
Alexander Larsson
c958fd8e86 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-22 09:40:16 +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
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
404 changed files with 50579 additions and 41673 deletions

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

118
NEWS
View File

@@ -1,3 +1,121 @@
Overview of Changes in GTK 3.99.2
=================================
* GtkEntry:
- Fix issues with Emoji insertion
- Fix issues with dnd
- Set correct hotspot for dnd icon
* GtkPasswordEntry:
- Use non-pageable memory
* GtkSearchEntry:
- Don't handle forwarded events twice
* GtkPasswordEntry:
- Add an ::activate signal
* GtkTextView:
- Fix dnd
- Improve undo state tracking
- Speed rendering in the presence of selections
- Make clickable links work again
- Fix handling of anchored children
* GtkRevealer:
- Fix clipping issues in the swing transitions
* GtkColorChooser:
- Update the default palette
* GtkFileChooser:
- Fix a crash
- Fix setting unlisted filters
* GtkFontChooser:
- Determine sample text based on font coverage
- Allow filtering by language
* GtkStack:
- Add gtk_stack_add_child
* GtkVideo:
- Make autoplay work
* CSS:
- Allow more than 64 selectors per rule
* Adwaita:
- Improve gesture graphics
- Tweak DND highlight color
- Add spacing to .navigation-sidebar
* GDK:
- Add gdk_frame_clock_get_fps
* GSK:
- Add radial gradient 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
* Vulkan renderer:
- Fix swapchain creation
* Windows:
- Fix display of CSD windows
* Wayland
- Always ack configure to avoid jumping windows
* API cleanups:
- Make filter and sorter constructors return exact types
- Rename GdkSurfaceState to GdkToplevelState
- Remove GdkWaylandSurface::committed
- Make Wayland backend api take GdkToplevel
* Demos:
- Bug and crash fixes
- Cosmetic improvements for several demos
- Improve search in the sidebar
- Add a Shadertoy 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
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 = 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,344 @@
/*
* 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_uniform_data(). 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 *uniform_data;
gint64 start_time;
};
struct _GskShaderPaintableClass
{
GObjectClass parent_class;
};
enum {
PROP_0,
PROP_SHADER,
PROP_UNIFORM_DATA,
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->uniform_data));
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_UNIFORM_DATA:
gsk_shader_paintable_set_uniform_data (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_UNIFORM_DATA:
g_value_set_boxed (value, self->uniform_data);
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->uniform_data, 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_UNIFORM_DATA] =
g_param_spec_boxed ("uniform-data", "Uniform data", "The uniform data",
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,
"uniform-data", 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_required_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->uniform_data, 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_uniform_data:
* @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_uniform_data (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->uniform_data, g_bytes_unref);
if (data)
self->uniform_data = g_bytes_ref (data);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UNIFORM_DATA]);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
/**
* gsk_shader_paintable_get_uniform_data:
* @self: a #GskShaderPaintable
*
* Returns the uniform data set with
* gsk_shader_paintable_get_uniform_data().
*
* Returns: (transfer none): the uniform data
*/
GBytes *
gsk_shader_paintable_get_uniform_data (GskShaderPaintable *self)
{
g_return_val_if_fail (GSK_IS_SHADER_PAINTABLE (self), NULL);
return self->uniform_data;
}
/**
* 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_uniform_data() 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)
{
int size;
int offset;
guchar *data;
float time;
GBytes *uniform_data;
size = gsk_gl_shader_get_args_size (self->shader);
offset = gsk_gl_shader_get_uniform_offset (self->shader, time_idx);
data = g_new0 (guchar, size);
memcpy (data, g_bytes_get_data (self->uniform_data, NULL), size);
if (self->start_time == 0)
self->start_time = frame_time;
time = (frame_time - self->start_time) / (float)G_TIME_SPAN_SECOND;
*(float*)(data + offset) = time;
uniform_data = g_bytes_new_take (data, size);
gsk_shader_paintable_set_uniform_data (self, uniform_data);
g_bytes_unref (uniform_data);
}

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_uniform_data (GskShaderPaintable *self);
GDK_AVAILABLE_IN_ALL
void gsk_shader_paintable_set_uniform_data (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_try_compile_for (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,353 @@
#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_try_compile_for (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);
}

View File

@@ -19,7 +19,11 @@
</object>
</child>
<child type="end">
<object class="GtkLabel" id="fps"/>
<object class="GtkLabel" id="fps">
<attributes>
<attribute name="font-features" value="tnum=1"/>
</attributes>
</object>
</child>
</object>
</child>

View File

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

View File

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

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