Compare commits

...

117 Commits

Author SHA1 Message Date
Matthias Clasen 3ff7c86b65 Add css parser tests for filter() 2021-02-06 19:59:45 -05:00
Matthias Clasen 79a0f183ec css: Implement filter() for images
We have all the pieces, so this is suprisingly easy.
2021-02-06 19:59:45 -05:00
Matthias Clasen e8c8be8e37 Merge branch 'matthiasc/for-master' into 'master'
Implement drop-shadow css filter

See merge request GNOME/gtk!3163
2021-02-06 22:35:23 +00:00
Matthias Clasen bfc80c32ea Add tests for the css filter property
Test that we can parse filters and that we
don't accept invalid filters.
2021-02-06 16:16:44 -05:00
Matthias Clasen 5f48764ac8 cssfiltervalue: Reject invalid filters
The Filter Effects Spec doesn't allow negative values
for most of the filter parameters.
2021-02-06 16:16:44 -05:00
Matthias Clasen cc6fcbfc09 cssfiltervalue: Fix blur filter interpretation
According to https://www.w3.org/TR/filter-effects-1/,
the length passed to blur() is the standard deviation,
and according to https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
the blur radius is twice the standard deviation.
2021-02-06 16:16:44 -05:00
Matthias Clasen ea7185bdb1 cssfiltervalue: Implement drop-shadows
We have all the pieces, so this is surprisingly easy.
2021-02-06 16:16:43 -05:00
Matthias Clasen 429dfcf483 cssshadowvalue: Add a 'filter mode'
Shadow values created by gtk_css_shadow_value_new_filter or
gtk_css_shadow_value_parse_filter interpret their radius value
as standard deviation. Add a flag for this mode, and use it
where necessary.
2021-02-06 16:10:34 -05:00
Matthias Clasen be3f352b59 cssshadowvalue: Add a parsing function
Add a variant of the parse function that parses
just a single (non-box) shadow, as required for
the drop-shadow filter.
2021-02-06 16:10:32 -05:00
Matthias Clasen 5b8896f1db cssshadowvalue: Add gtk_css_shadow_value_pop_snapshot
This is the counterpart ot gtk_css_shadow_value_push_snapshot.

To make this easy, move the determination whether we need a
shadow out of the push function and save it.
2021-02-06 16:09:21 -05:00
Matthias Clasen 4e27de7df9 cssshadowvalue: Drop the underscore
Rename _gtk_css_shadow_value_parse to drop the underscore.
It was the only underscore-prefixed function in this file.
2021-02-06 16:08:19 -05:00
Marek Černocký 2712f536c2 Updated Czech translation 2021-02-06 09:44:09 +01:00
Matthias Clasen a1f7073ff5 Add tests for the css filter property
Test that we can parse filters.
2021-02-05 21:37:47 -05:00
Matthias Clasen 9770872d12 css: Implement the drop-shadow filter
We have all the pieces, so this is surprisingly easy.
2021-02-05 21:37:14 -05:00
Matthias Clasen de24b4f91b cssshadowvalue: Add a parsing function
Add a variant of the parse function that parses
just a single (non-box) shadow, as required for
the drop-shadow filter.
2021-02-05 21:36:22 -05:00
Matthias Clasen 650fd9c291 Merge branch 'module-ext' into 'master'
meson: use correct module file extension on macOS

Closes #3645

See merge request GNOME/gtk!3162
2021-02-06 01:15:09 +00:00
David Lechner b509809f34 meson: use correct module file extension on macOS
GModule requires the .so file extension on macOS for historic reasons.
However Meson defaults to .dylib for modules, so we need to override
it to get the correct extension.

Fixes #3645.
2021-02-05 16:54:28 -06:00
Matthias Clasen 60ff231fac Merge branch 'matthiasc/for-master' into 'master'
iconbrowser: Make image dnd work again

Closes #3648

See merge request GNOME/gtk!3159
2021-02-05 12:48:10 +00:00
Emmanuele Bassi 958005317b Merge branch 'master' into 'master'
Improve the docs of GtkWidget and GtkGrid

See merge request GNOME/gtk!2946
2021-02-05 12:14:26 +00:00
Matthias Clasen 15c36aaa1e iconbrowser: Make image dnd work again
We need to drag a texture, not a paintable.

Fixes: #3648
2021-02-04 20:47:19 -05:00
Matthias Clasen 482b73c376 Merge branch 'matthiasc/for-master' into 'master'
docs: Rewrite the long description for GtkDialog

Closes #3646

See merge request GNOME/gtk!3156
2021-02-05 00:10:47 +00:00
Matthias Clasen 4a8bf6e13d Merge branch 'doc-typo' into 'master'
gtkshow: Fix doc typo

See merge request GNOME/gtk!3158
2021-02-05 00:07:18 +00:00
Maximiliano Sandoval R 3e2e6633b0 gtkshow: Fix doc typo 2021-02-04 21:02:22 +01:00
Matthias Clasen 4724f9907c docs: Rewrite the long description for GtkDialog
As was pointed out in #3646, some of the content here
was a bit outdated.

Fixes: #3646
2021-02-04 13:05:28 -05:00
Matthias Clasen 26e84a7b8c Merge branch 'matthiasc/for-master' into 'master'
More work on css transition tests

See merge request GNOME/gtk!3154
2021-02-04 13:28:59 +00:00
Matthias Clasen d5838f14f9 Drop the installed test for now
It fails in ci, and I have no idea why.
2021-02-04 07:26:10 -05:00
Matthias Clasen 5c532104e4 Merge branch 'pvs-fixes' into 'master'
Pvs fixes

See merge request GNOME/gtk!3155
2021-02-04 12:20:24 +00:00
Matthias Clasen 2f42e1fb89 treemodelfilter: Drop unreachable code
We never get here. The compiler says so.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:40:14 -05:00
Matthias Clasen b5200bd076 css: Drop a bit of unreachable code
We never get here. The compiler says so.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:39:34 -05:00
Matthias Clasen aa5bd38137 a11y: Avoid out-of-bounds access
Don't use the index before we've checked its good.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:34:05 -05:00
Matthias Clasen 0eba833595 gdk: Remove a redundant check
We already know desktop_notification_id is not NULL.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:29:51 -05:00
Matthias Clasen 1e0ea21297 messagedialog: Don't initialize twice
We don't need to set these fields more than once.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:25:36 -05:00
Matthias Clasen e91e75173d composetable: Remove a redundant check
We already know seq_index is not NULL here.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:22:52 -05:00
Matthias Clasen 927fdb9a83 x11: A case of argument order confusion
translate_keysym was expecting its arguments the
other way around.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:20:26 -05:00
Matthias Clasen 041f410838 textbtree: Avoid line vs char count confusion
The post_insert_fixup helper function was confused about
its argument order.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:17:55 -05:00
Matthias Clasen c71c8919fe listbase: Don't specify the same thing twice
We only need to set EXPLICIT_NOTIFY once.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:13:53 -05:00
Matthias Clasen 3f28399f7d css: Fix border value parsing
This function was not resetting computed as it meant
to because the last loop was never executed.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:12:51 -05:00
Matthias Clasen 3c15fa96bc vulkan: Fix image uploading by regions
This code did not make sense; it was incrementing
the wrong variable.

Pointed out in https://www.viva64.com/en/b/0793/
2021-02-04 00:12:44 -05:00
Matthias Clasen 0a0a059397 docs: Mention css drop-shadow filter
We don't support this filter, currently.
2021-02-03 22:10:13 -05:00
Matthias Clasen 18e83fe16d Add more css transition tests 2021-02-03 22:10:13 -05:00
Matthias Clasen 90d7ed5dd1 Rename test to transition
Thats what it is about, so name it clearly.

Add missing installed tests too.
2021-02-03 22:10:13 -05:00
Matthias Clasen 3c6e7569ff Add more css transition tests
Test font size transitions.
2021-02-03 22:10:13 -05:00
Matthias Clasen 4e2ec2d68d testsuite: Pass GDK_DEBUG=default-settings to css tests
Otherwise, settings might creep in and change css defaults.
2021-02-03 22:10:13 -05:00
Matthias Clasen 1af72eac21 cssvalue: Cosmetic change
Don't return FALSE from pointer-returning functions.
2021-02-03 22:10:13 -05:00
Matthias Clasen 640273a0e2 Improve the css value tests
The test code had some bugs. Fix those, and
print out useful information when tests fail.
2021-02-03 22:10:13 -05:00
Matthias Clasen a14a0c6315 css: Fix shadow value equal
This function was not doing the right thing.

Once we are doing the right thing and not compare
shadows as unequal, some reftests that inhibit
snapshots for a few frames now hang forever, since
we are no more redrawing unnecessarily. Fix that
with an explicit queue_draw.
2021-02-03 22:10:13 -05:00
Matthias Clasen 38481680e1 Merge branch 'wip/jimmac/colored-list-image-buttons' into 'master'
Adwaita: allow suggested and destructive action buttons in lists

Closes #3643

See merge request GNOME/gtk!3153
2021-02-04 01:38:47 +00:00
Matthias Clasen 12a540c284 Merge branch 'ebassi/for-master' into 'master'
Graphene is a dependency of Gsk, not Gdk

See merge request GNOME/gtk!3149
2021-02-04 01:38:09 +00:00
Jakub Steiner 289bf078bf Adwaita: allow suggested and destructive action buttons in lists
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3643
2021-02-03 23:15:30 +01:00
Matthias Clasen 58ab9ddc40 Merge branch 'x11-dnd-fix' into 'master'
x11: Handle X-specific targets in drops

Closes #3642

See merge request GNOME/gtk!3151
2021-02-03 20:11:33 +00:00
Matthias Clasen c78036fc51 x11: Handle X-specific targets in drops
This code is very similar to the handling for these
targets in the clipboard case.

Fixes: #3642
2021-02-03 14:17:04 -05:00
Matthias Clasen 120f2768e6 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!3150
2021-02-03 15:17:34 +00:00
Emmanuele Bassi 592b33cb48 Graphene is a dependency of Gsk, not Gdk
So let's put it in the right place when building the introspection data.
2021-02-03 14:05:27 +00:00
Matthias Clasen 7a9bc1f1d8 Link the data url tests statically
Thats the cleaner way to test internal apis.
2021-02-03 09:02:06 -05:00
Matthias Clasen 9cc6f3ee29 Add tests for css value transitions
Just a few cases for now, enough to test a recently
fixed regression with shadow transitions.
2021-02-03 08:56:57 -05:00
Chun-wei Fan 9efaa0b51d Merge branch 'uac.meson.master' into 'master'
gtk4-update-icon-cache: Avoid UAC on 32-bit Windows

Closes #3632

See merge request GNOME/gtk!3141
2021-02-03 02:16:58 +00:00
Chun-wei Fan f0967fa5e4 gtk4-update-icon-cache: Avoid UAC on 32-bit Windows
As the program executable name has 'update' in its filename,
gtk4-update-icon-cache.exe is considered to be an installer program on 32-bit
Windows [1], which will cause the program to fail to run unless it is running
with elevated privileges (i.e. UAC).

Avoid this situation by embedding a manifest file into the final executable
that tells Windows that this is not a program that requires elevation.

Fixes issue #3632.

[1]: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc709628(v=ws.10)?redirectedfrom=MSDN,
     under section "Installer Detection  Technology"
2021-02-03 02:16:58 +00:00
Matthias Clasen f8529983f9 Merge branch 'matthiasc/for-master' into 'master'
css: Allow transitioning different-size shadows

See merge request GNOME/gtk!3145
2021-02-03 00:43:44 +00:00
Matthias Clasen 919c08d4fd css: Allow transitioning different-size shadows
The code handles it just fine. The length check was
an erronous addition.
2021-02-02 15:27:42 -05:00
Matthias Clasen e9b06b6346 Merge branch 'im-context-work' into 'master'
Some im context work

Closes #1004, #186, and #3521

See merge request GNOME/gtk!3143
2021-02-02 17:29:14 +00:00
Matthias Clasen 949c783187 composetable: Parse hex escapes too
This was a small omission from the Compose file
syntax that doesn't cost us much to support.

Add a test for this syntax too.

Fixes: #1004
2021-02-02 12:05:19 -05:00
Matthias Clasen 814a4a781a Add tests for string values
Add a test that checks we parse values with
multiple characters correctly.
2021-02-02 11:55:00 -05:00
Matthias Clasen 676f875bf6 composetable: Support string values in the cache
Change the cache format to include the character
data that we need to hold string values in the table.
2021-02-02 11:55:00 -05:00
Matthias Clasen 140c5c5333 composetable: Don't use GSlice for big blobs
This just doesn't make sense. This will use malloc
anyway, so just call malloc directly.
2021-02-02 11:55:00 -05:00
Matthias Clasen cebf2b2009 composetable: Keep multi-char values
Keep string values in the table, and return them
from the check function. This commit temporarily
disables the table caching, since the cache format
does not handle string values yet.

Fixes: #186
2021-02-02 11:54:53 -05:00
Matthias Clasen 86b437a1b6 Merge branch 'wip/silence-bounds-warnings' into 'master'
gdk/toplevelsize: Remove warnings about exceeding bounds

Closes #3035

See merge request GNOME/gtk!3142
2021-02-02 16:38:20 +00:00
Matthias Clasen 773ae0cd0f composetable: Parse multi-char values
Rewrite the value parsing function to accept strings
that hold more than a single Unicode character.
2021-02-02 09:03:53 -05:00
Matthias Clasen 564793d5b5 composetable: Another step towards multi-char values
Change the parser data structures to hold a string, rather
than a gunichar. We still only put a single Unicode character
into it, currently.
2021-02-02 09:02:46 -05:00
Matthias Clasen 9142aa0f51 composetable: Prepare for multi character values
Make it possible for gtk_compose_table_check to return
a string instead of just a single Unicode character.
Currently, we only ever return strings holding a single
character, still.
2021-02-02 09:02:00 -05:00
Matthias Clasen af9a578d68 imcontext: Prepare for multi-char values
Reshuffle things so we can easily handle values
that are strings instead of just single Unicode
characters.
2021-02-01 23:43:59 -05:00
Matthias Clasen ecb072fdd0 composetable: Check algorithmic matching
Just some spot checks, enough to verify the
fix in the previous commit.
2021-02-01 21:59:21 -05:00
Matthias Clasen ef053ebb4a composetable: Fix algorithmic matching
The code wasn't paying attention to (lack of) nul-termination
in one place, causing it to not match when it should.
2021-02-01 21:51:51 -05:00
Matthias Clasen 8d18d93742 composetable: Add tests for compact table matching
Not very exhaustive, just some spot checks.
2021-02-01 21:10:44 -05:00
Matthias Clasen 10fcdd88e3 imcontext: Code cleanup
Get rid of auxiliary check_table function.
2021-02-01 20:41:45 -05:00
Matthias Clasen 5d9509c51b imcontext: Move code around
Move all the checking code to gtkcomposetable.c, and
add api that we can use in tests.
2021-02-01 20:27:38 -05:00
Matthias Clasen c9cac5fbc3 composetable: Add tests for matching
This tests the api we use to match key sequences
against compose tables.
2021-02-01 19:55:56 -05:00
Matthias Clasen aa9054a5f1 imcontext: Use gtk_compose_table_check
Use the just-introduced api.
2021-02-01 19:41:07 -05:00
Matthias Clasen 9ebf3fac73 composetable: Add api to check tables
This copies the check_table code from gtkimcontextsimple.c,
in order to have an api for tests.
2021-02-01 19:40:22 -05:00
Matthias Clasen 569294070b Add tests for GtkComposeTable
Add some tests for the code that parses Compose files.

This tests the fix in the previous commit.
2021-02-01 19:02:31 -05:00
Matthias Clasen be35c46ce9 composetable: Drop table debug code
This is better off in the tests that we are going to add.
2021-02-01 19:02:21 -05:00
Matthias Clasen dbbcb13721 composetable: Parser fixes
We were not handling octal escapes right.
2021-02-01 16:05:05 -05:00
Matthias Clasen edeaf9c040 imcontext: Drop GTK_MAX_COMPOSE_LEN
Drop GTK_MAX_COMPOSE_LEN from docs. It is no longer
used by GTK at all.  We leave the define in place
for now, to avoid breaking 3rd party code that might
use it.
2021-02-01 12:31:23 -05:00
Matthias Clasen 61f709811c composetable: Warn when ignoring things
We should at least give a hint that we've seen the line,
otherwise people will wonder why nothing happened.
2021-02-01 12:27:41 -05:00
Matthias Clasen f7c4375509 composetable: parse long sequences
Allow compose sequences of up to 20 code points.

Fixes: #3521
2021-02-01 12:27:35 -05:00
Matthias Clasen 52fb900ced composetable: Fix an off-by-one
Fix an off-by-one in the code parsing octal escapes
in compose files.
2021-02-01 12:10:05 -05:00
Matthias Clasen 031944ad30 imcontext: Stop using GTK_MAX_COMPOSE_LEN
Allocate the compose_buffer, and resize it when needed
to match the tables we use.
2021-02-01 12:10:05 -05:00
Matthias Clasen bf8b974f68 imcontext: Code cleanup
Use g_clear_pointer instead of opencoding it in
multiple places.
2021-02-01 12:10:05 -05:00
Jonas Ådahl 6ad2a049e7 gdk/toplevelsize: Remove warnings about exceeding bounds
Sometimes the size will exceed the minimum bounds. For example crazy
applications like the widget factory that contains the world, or when a
user interactively resizes a window to be larger than the monitor the
window is on is.

The former is questionable, but the latter is not, and from here we
can't really see the difference, so just stop complaining.

Closes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3035
2021-02-01 11:31:11 +01:00
Matthias Clasen 3d85d53e5d Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

Closes #2319

See merge request GNOME/gtk!3140
2021-02-01 06:20:40 +00:00
Matthias Clasen 094a346539 imcontext: Allow sequences of length GTK_MAX_COMPOSE_LEN
There was an off-by-one error, making us reject sequences
of this length. But the rest of the code handles them
just fine.

Fixes: #2319
2021-02-01 00:55:25 -05:00
Matthias Clasen 162814f969 imcontext: Improve an error message
This error message was misleading, as pointed out
by Ralf Jung.
2021-02-01 00:44:41 -05:00
Matthias Clasen e39b5c99f1 imcontext: Add a precondition check 2021-02-01 00:43:44 -05:00
Matthias Clasen 8883243aaa imcontext: Show preedit for compose sequences
Show the sequences as they are entered, using ⎄ for
the compose key, to match what IBus does nowadays.
Also handle backspace to allow corrections.
2021-02-01 00:37:43 -05:00
Matthias Clasen 89511eecf1 imcontext: Update our check for dead keys
A bunch of keysyms for dead keys have been added since this
code was last touched. Update the check to cover the full
range from dead_grave to dead_greek.
2021-01-31 23:56:24 -05:00
Matthias Clasen 2c304ca80d Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!3139
2021-02-01 01:48:47 +00:00
Matthias Clasen bf4102e664 Merge branch 'wip/exalm/consumes-motion' into 'master'
Drag fixes and cleanups

Closes #3513

See merge request GNOME/gtk!3001
2021-02-01 01:34:45 +00:00
Matthias Clasen b86153cee3 Remove a forgotten file
The example series only has 9 steps now. Remove remnants
of step 10.
2021-01-31 20:26:02 -05:00
Matthias Clasen 7985d277b3 nativedialog: Add more docs
Emphasize that native dialogs aren't widgets, and are not
kept alive by GTK.
2021-01-31 20:25:44 -05:00
Matthias Clasen 752da5c2a5 Merge branch 'tool-static' into 'master'
tools: Don't static and dynamic link on libgtk4

See merge request GNOME/gtk!3138
2021-02-01 00:44:08 +00:00
Matthias Clasen de4b8d547b Merge branch 'wip/exalm/activate' into 'master'
listitemwidget: Activate on release instead of press

Closes #3345

See merge request GNOME/gtk!3008
2021-02-01 00:32:05 +00:00
Xavier Claessens 1048ad1a01 tools: Don't static and dynamic link on libgtk4 2021-01-31 11:09:20 -05:00
Ungedummt 4d11158d97 GtkGrid: Add xml example for GtkBuildable to docs
Added an example and a short discription for the properties
2021-01-31 10:19:14 +01:00
Ungedummt 293b81cad2 Fix small typo in the docs of GtkWidget
In a XML example was MyGrid as a class defined; replaced with GtkGrid
2021-01-31 10:19:08 +01:00
Matthias Clasen 65c38111f9 4.1.0 2021-01-30 19:57:24 -05:00
Matthias Clasen ec8db379a6 tests: Disable the textview-margins reftest
It is too flaky to be useful.
2021-01-30 19:57:24 -05:00
Matthias Clasen 1484b4ae9f node editor: Add a dark mode toggle
This is useful to see light rendering clearly.
2021-01-30 19:57:24 -05:00
Rafael Fontenelle 4cecbf1654 Update Brazilian Portuguese translation
(cherry picked from commit 056c3e11a1)
2021-01-30 19:16:02 +00:00
Timm Bäder 234ba90e2b Merge branch 'mcclurgm-master-patch-63249' into 'master'
Document nullability of gtk_list_box_get_selected_row

See merge request GNOME/gtk!3137
2021-01-30 17:58:33 +00:00
Rafael Fontenelle bdd2244f75 Update Brazilian Portuguese translation
(cherry picked from commit f224c8fab9)
2021-01-30 16:00:45 +00:00
Michael McClurg cd7ec8ac92 Document nullability of gtk_list_box_get_selected_row 2021-01-30 15:23:41 +00:00
Alexander Mikhaylenko 11f3b7730c windowhandle: Use drag threshold instead of double click threshold
Now that we have gtk_drag_check_threshold_double(), be consistent with
other draggable widgets and make sure we don't take over a drag before a
child does.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3513
2021-01-29 12:01:34 +05:00
Alexander Mikhaylenko f63e6394ac dragsource: Use double coordinates for checking drag threshold
If multiple nested widgets have drag sources on them, both using bubble
phase, we need to reliably pick the inner one. Both of them will try to
start dragging, and we need to make sure there are no situations where the
outer widget starts drag earlier and cancels the inner one.

Currently, this can easily happen via integer rounding: start and current
coordinates passed into gtk_drag_check_threshold() are initially doubles
(other than in GtkNotebook and GtkIconView), and are casted to ints. Then
those rounded values are used to calculate deltas to compare to the drag
threshold, losing quite a lot of precision along the way, and often
resulting in the outer widget getting larger deltas.

To avoid it, just don't round it. Introduce a variant of the function that
operates on doubles: gtk_drag_check_threshold_double() and use it instead
of the original everywhere.
2021-01-29 12:01:34 +05:00
Alexander Mikhaylenko bbca4c38df entry: Fix drag threshold check
It was passing offsets as current oordinates.
2021-01-29 12:00:10 +05:00
Alexander Mikhaylenko 28f5d26719 windowhandle: Don't drag on capture phase
This was needed to work around widgets claiming event sequences on press,
by ignoring them and starting the drag anyway unless they have certain
event controllers on them.

The most visible offender was GtkButton, but since the last commit it
doesn't claim the sequence anymore and we can remove the hack.
2021-01-29 12:00:10 +05:00
Alexander Mikhaylenko bf2620f041 checkbutton: Claim sequence on release instead of press
Make it possible to drag windows from check buttons in future.
2021-01-29 12:00:10 +05:00
Alexander Mikhaylenko 870b82b541 button: Stop claiming event sequence on press
Currently GtkButton claims the sequence both on press and on release. Stop
claiming it on press and only do it on release, allowing drags to start
from it.

This will allow to remove a hack from GtkWindowHandle.
2021-01-29 12:00:10 +05:00
Alexander Mikhaylenko 5968b10b0b listitemwidget: Activate on release instead of press
Single click activation should only be done on release and not on press,
otherwise it breaks touch scrolling. Double-click activation still can be
done on press.

This matches the GtkListBox behavior as well.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3345
2021-01-19 12:36:32 +05:00
124 changed files with 3203 additions and 2095 deletions
+55
View File
@@ -1,3 +1,58 @@
Overview of Changes in 4.1.0
============================
* GtkCheckButton:
- Add back an activate signal
* GtkSearchBar, GtkSearchEntry:
- Capture events in the bubble phase
* GtkEmojiChooser:
- Adapt to small screen sizes
* GtkVideo:
- Fix issues with GL support
* Themes:
- Set sort arrows in CSS
- Set menu button arrows in CSS
- Make scrollbars larger
- Supprt circular menubuttons
* CSS:
- Implement transform-origin
- Support overlines on text
- Support colors in cross-fade()
- More complete text-decoration-line support
* Text layout:
- Use subpixel positioning with new enough cairo
* Inspector:
- Fix slowness in navigation
- Redo the controllers and shortcuts pages
* Accessibility:
- Create AT context objects lazily
* Wayland:
- Fix decoration negotiation under kwin
* GSK:
- Optimize gradient shaders
- Implement repeating gradients in shaders
* Translation updates
- Czech
- Greek
- Hungarian
- Persian
- Punjabi
- Romanian
- Swedish
- Ukrainian
Overview of Changes in 4.0.2
============================
+21 -1
View File
@@ -279,11 +279,31 @@ drag_prepare_texture (GtkDragSource *source,
GtkWidget *widget)
{
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (widget));
GtkSnapshot *snapshot;
double width, height;
GskRenderNode *node;
GskRenderer *renderer;
GdkTexture *texture;
GdkContentProvider *ret;
if (!GDK_IS_PAINTABLE (paintable))
return NULL;
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
snapshot = gtk_snapshot_new ();
width = gdk_paintable_get_intrinsic_width (paintable);
height = gdk_paintable_get_intrinsic_height (paintable);
gdk_paintable_snapshot (paintable, snapshot, width, height);
node = gtk_snapshot_free_to_node (snapshot);
renderer = gtk_native_get_renderer (gtk_widget_get_native (widget));
texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
ret = gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, texture);
g_object_unref (texture);
gsk_render_node_unref (node);
return ret;
}
static GdkContentProvider *
+11
View File
@@ -700,6 +700,16 @@ out:
g_free (source_dir);
}
static void
dark_mode_cb (GtkToggleButton *button,
GParamSpec *pspec,
NodeEditorWindow *self)
{
g_object_set (gtk_widget_get_settings (GTK_WIDGET (self)),
"gtk-application-prefer-dark-theme", gtk_toggle_button_get_active (button),
NULL);
}
static void
node_editor_window_finalize (GObject *object)
{
@@ -814,6 +824,7 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_callback (widget_class, export_image_cb);
gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb);
}
static GtkWidget *
+9
View File
@@ -139,6 +139,15 @@
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="dark_bg_button">
<property name="valign">center</property>
<property name="has-frame">0</property>
<property name="icon-name">display-brightness-symbolic</property>
<property name="tooltip-text" translatable="yes">Use a dark background</property>
<signal name="notify::active" handler="dark_mode_cb" swapped="0"/>
</object>
</child>
</object>
</child>
<child>
+25
View File
@@ -80,6 +80,31 @@ and in some cases a number as arguments.
## Images
CSS allows to specify images in various forms, the most simple one being
a url for an image file. Beyond that, images can be specified as
`linear-gradient(Angle, ColorStops)`
`repeating-linear-gradient(Angle, ColorStops)`
: creates a linear gradient.
`radial-gradient(Shape, ColorStops)`
`repeating-radial-gradient(Shape, ColorStops)`
: creates a radial gradient.
`conic-gradient(Angle, ColorStops)`
: creates a conic gradient.
`cross-fade(Percentage Image,…)`
: combines two or more images.
`image(Image,… Color)`
: falls back to the first valid image, or to a solid color.
`filter(Image, Filters)`
: applies filters to an image.
For more details, see [CSS Image Level 4](https://www.w3.org/TR/css-images-4/).
GTK extends the CSS syntax for images and also uses it for specifying icons.
To load a themed icon, use
-1
View File
@@ -1831,7 +1831,6 @@ GtkIMContextSimple
gtk_im_context_simple_new
gtk_im_context_simple_add_table
gtk_im_context_simple_add_compose_file
GTK_MAX_COMPOSE_LEN
<SUBSECTION Standard>
GTK_IM_CONTEXT_SIMPLE
GTK_IS_IM_CONTEXT_SIMPLE
-293
View File
@@ -1,293 +0,0 @@
#include <gtk/gtk.h>
#include "exampleapp.h"
#include "exampleappwin.h"
struct _ExampleAppWindow
{
GtkApplicationWindow parent;
GSettings *settings;
GtkWidget *stack;
GtkWidget *search;
GtkWidget *searchbar;
GtkWidget *searchentry;
GtkWidget *gears;
GtkWidget *sidebar;
GtkWidget *words;
GtkWidget *lines;
GtkWidget *lines_label;
};
G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
static void
search_text_changed (GtkEntry *entry,
ExampleAppWindow *win)
{
const char *text;
GtkWidget *tab;
GtkWidget *view;
GtkTextBuffer *buffer;
GtkTextIter start, match_start, match_end;
text = gtk_editable_get_text (GTK_EDITABLE (entry));
if (text[0] == '\0')
return;
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
/* Very simple-minded search implementation */
gtk_text_buffer_get_start_iter (buffer, &start);
if (gtk_text_iter_forward_search (&start, text, GTK_TEXT_SEARCH_CASE_INSENSITIVE,
&match_start, &match_end, NULL))
{
gtk_text_buffer_select_range (buffer, &match_start, &match_end);
gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), &match_start,
0.0, FALSE, 0.0, 0.0);
}
}
static void
find_word (GtkButton *button,
ExampleAppWindow *win)
{
const char *word;
word = gtk_button_get_label (button);
gtk_editable_set_text (GTK_EDITABLE (win->searchentry), word);
}
static void
update_words (ExampleAppWindow *win)
{
GHashTable *strings;
GHashTableIter iter;
GtkWidget *tab, *view, *row;
GtkTextBuffer *buffer;
GtkTextIter start, end;
char *word, *key;
GtkWidget *child;
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
if (tab == NULL)
return;
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
gtk_text_buffer_get_start_iter (buffer, &start);
while (!gtk_text_iter_is_end (&start))
{
while (!gtk_text_iter_starts_word (&start))
{
if (!gtk_text_iter_forward_char (&start))
goto done;
}
end = start;
if (!gtk_text_iter_forward_word_end (&end))
goto done;
word = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
g_hash_table_add (strings, g_utf8_strdown (word, -1));
g_free (word);
start = end;
}
done:
while ((child = gtk_widget_get_first_child (win->words)))
gtk_list_box_remove (GTK_LIST_BOX (win->words), child);
g_hash_table_iter_init (&iter, strings);
while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
{
row = gtk_button_new_with_label (key);
g_signal_connect (row, "clicked",
G_CALLBACK (find_word), win);
gtk_box_append (GTK_BOX (win->words), row);
}
g_hash_table_unref (strings);
}
static void
update_lines (ExampleAppWindow *win)
{
GtkWidget *tab, *view;
GtkTextBuffer *buffer;
int count;
char *lines;
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
if (tab == NULL)
return;
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
count = gtk_text_buffer_get_line_count (buffer);
lines = g_strdup_printf ("%d", count);
gtk_label_set_text (GTK_LABEL (win->lines), lines);
g_free (lines);
}
static void
visible_child_changed (GObject *stack,
GParamSpec *pspec,
ExampleAppWindow *win)
{
if (gtk_widget_in_destruction (GTK_WIDGET (stack)))
return;
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (win->searchbar), FALSE);
update_words (win);
update_lines (win);
}
static void
words_changed (GObject *sidebar,
GParamSpec *pspec,
ExampleAppWindow *win)
{
update_words (win);
}
static void
example_app_window_init (ExampleAppWindow *win)
{
GtkBuilder *builder;
GMenuModel *menu;
GAction *action;
gtk_widget_init_template (GTK_WIDGET (win));
win->settings = g_settings_new ("org.gtk.exampleapp");
g_settings_bind (win->settings, "transition",
win->stack, "transition-type",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (win->settings, "show-words",
win->sidebar, "reveal-child",
G_SETTINGS_BIND_DEFAULT);
g_object_bind_property (win->search, "active",
win->searchbar, "search-mode-enabled",
G_BINDING_BIDIRECTIONAL);
g_signal_connect (win->sidebar, "notify::reveal-child",
G_CALLBACK (words_changed), win);
builder = gtk_builder_new_from_resource ("/org/gtk/exampleapp/gears-menu.ui");
menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (win->gears), menu);
g_object_unref (builder);
action = g_settings_create_action (win->settings, "show-words");
g_action_map_add_action (G_ACTION_MAP (win), action);
g_object_unref (action);
action = (GAction*) g_property_action_new ("show-lines", win->lines, "visible");
g_action_map_add_action (G_ACTION_MAP (win), action);
g_object_unref (action);
g_object_bind_property (win->lines, "visible",
win->lines_label, "visible",
G_BINDING_DEFAULT);
g_object_set (gtk_settings_get_default (), "gtk-shell-shows-app-menu", FALSE, NULL);
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
}
static void
example_app_window_dispose (GObject *object)
{
ExampleAppWindow *win;
win = EXAMPLE_APP_WINDOW (object);
g_clear_object (&win->settings);
G_OBJECT_CLASS (example_app_window_parent_class)->dispose (object);
}
static void
example_app_window_class_init (ExampleAppWindowClass *class)
{
G_OBJECT_CLASS (class)->dispose = example_app_window_dispose;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/exampleapp/window.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, search);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchbar);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchentry);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, gears);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, words);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, sidebar);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines_label);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed);
}
ExampleAppWindow *
example_app_window_new (ExampleApp *app)
{
return g_object_new (EXAMPLE_APP_WINDOW_TYPE, "application", app, NULL);
}
void
example_app_window_open (ExampleAppWindow *win,
GFile *file)
{
char *basename;
GtkWidget *scrolled, *view;
char *contents;
gsize length;
GtkTextBuffer *buffer;
GtkTextTag *tag;
GtkTextIter start_iter, end_iter;
basename = g_file_get_basename (file);
scrolled = gtk_scrolled_window_new ();
gtk_widget_set_hexpand (scrolled, TRUE);
gtk_widget_set_vexpand (scrolled, TRUE);
view = gtk_text_view_new ();
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), view);
gtk_stack_add_titled (GTK_STACK (win->stack), scrolled, basename, basename);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
{
gtk_text_buffer_set_text (buffer, contents, length);
g_free (contents);
}
tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
g_settings_bind (win->settings, "font",
tag, "font",
G_SETTINGS_BIND_DEFAULT);
gtk_text_buffer_get_start_iter (buffer, &start_iter);
gtk_text_buffer_get_end_iter (buffer, &end_iter);
gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);
g_free (basename);
gtk_widget_set_sensitive (win->search, TRUE);
update_words (win);
update_lines (win);
}
+1 -1
View File
@@ -173,7 +173,7 @@ stash_desktop_startup_notification_id (void)
if (!g_utf8_validate (desktop_startup_id, -1, NULL))
g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
else
startup_notification_id = g_strdup (desktop_startup_id ? desktop_startup_id : "");
startup_notification_id = g_strdup (desktop_startup_id);
}
/* Clear the environment variable so it won't be inherited by
-17
View File
@@ -149,12 +149,6 @@ gdk_toplevel_size_validate (GdkToplevelSize *size)
{
int geometry_width, geometry_height;
if (size->min_width > size->bounds_width ||
size->min_height > size->bounds_height)
g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds bounds (%d, %d)",
size->min_width, size->min_height,
size->bounds_width, size->bounds_height);
geometry_width = size->width;
geometry_height = size->height;
if (size->shadow.is_valid)
@@ -162,15 +156,4 @@ gdk_toplevel_size_validate (GdkToplevelSize *size)
geometry_width -= size->shadow.left + size->shadow.right;
geometry_height -= size->shadow.top + size->shadow.bottom;
}
if (geometry_width > size->bounds_width ||
geometry_height > size->bounds_height)
g_warning ("GdkToplevelSize: geometry size (%d, %d) exceeds bounds (%d, %d)",
size->width, size->height,
size->bounds_width, size->bounds_height);
if (size->min_width > size->width ||
size->min_height > size->height)
g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds size (%d, %d)",
size->min_width, size->min_height,
size->width, size->height);
}
+46 -5
View File
@@ -39,6 +39,7 @@
#include "gdkscreen-x11.h"
#include "gdkselectioninputstream-x11.h"
#include "gdkselectionoutputstream-x11.h"
#include "gdktextlistconverter-x11.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -103,6 +104,49 @@ static const struct {
G_DEFINE_TYPE (GdkX11Drop, gdk_x11_drop, GDK_TYPE_DROP)
static GInputStream *
text_list_convert (GdkDisplay *display,
GInputStream *stream,
const char *encoding,
int format)
{
GInputStream *converter_stream;
GConverter *converter;
converter = gdk_x11_text_list_converter_to_utf8_new (display, encoding, format);
converter_stream = g_converter_input_stream_new (stream, converter);
g_object_unref (converter);
g_object_unref (stream);
return converter_stream;
}
static GInputStream *
no_convert (GdkDisplay *display,
GInputStream *stream,
const char *encoding,
int format)
{
return stream;
}
static const struct {
const char *x_target;
const char *mime_type;
GInputStream * (* convert) (GdkDisplay *, GInputStream *, const char *, int);
const char *type;
int format;
} special_targets[] = {
{ "UTF8_STRING", "text/plain;charset=utf-8", no_convert, "UTF8_STRING", 8 },
{ "COMPOUND_TEXT", "text/plain;charset=utf-8", text_list_convert, "COMPOUND_TEXT", 8 },
{ "TEXT", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
{ "STRING", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
{ "TARGETS", NULL, NULL, "ATOM", 32 },
{ "TIMESTAMP", NULL, NULL, "INTEGER", 32 },
{ "SAVE_TARGETS", NULL, NULL, "NULL", 32 }
};
static void
gdk_x11_drop_read_got_stream (GObject *source,
GAsyncResult *res,
@@ -145,9 +189,9 @@ gdk_x11_drop_read_got_stream (GObject *source,
}
else
{
#if 0
gsize i;
const char *mime_type = ((GSList *) g_task_get_task_data (task))->data;
GdkDrop *drop = GDK_DROP (g_task_get_source_object (task));
for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
{
@@ -155,15 +199,12 @@ gdk_x11_drop_read_got_stream (GObject *source,
{
g_assert (special_targets[i].mime_type != NULL);
GDK_DISPLAY_NOTE (CLIPBOARD, g_printerr ("%s: reading with converter from %s to %s\n",
cb->selection, mime_type, special_targets[i].mime_type));
mime_type = g_intern_string (special_targets[i].mime_type);
g_task_set_task_data (task, g_slist_prepend (NULL, (gpointer) mime_type), (GDestroyNotify) g_slist_free);
stream = special_targets[i].convert (cb, stream, type, format);
stream = special_targets[i].convert (gdk_drop_get_display (drop), stream, type, format);
break;
}
}
#endif
GDK_NOTE (DND, g_printerr ("reading DND as %s now\n",
(const char *)((GSList *) g_task_get_task_data (task))->data));
+1 -1
View File
@@ -1383,7 +1383,7 @@ gdk_x11_keymap_translate_keyboard_state (GdkKeymap *keymap,
tmp_keyval = translate_keysym (keymap_x11, hardware_keycode,
group, state,
level, effective_group);
effective_group, level);
}
if (consumed_modifiers)
+1 -1
View File
@@ -718,7 +718,7 @@ gsk_vulkan_image_upload_regions (GskVulkanImage *self,
}
else
{
for (gsize r = 0; r < regions[i].height; i++)
for (gsize r = 0; r < regions[i].height; r++)
memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
}
+2 -6
View File
@@ -68,10 +68,8 @@ action_handle_method (GtkAtSpiContext *self,
g_variant_get (parameters, "(i)", &idx);
const Action *action = &actions[idx];
if (idx >= 0 && idx < n_actions)
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", action->name));
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", actions[idx].name));
else
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
@@ -129,10 +127,8 @@ action_handle_method (GtkAtSpiContext *self,
g_variant_get (parameters, "(i)", &idx);
const Action *action = &actions[idx];
if (idx >= 0 && idx < n_actions)
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", action->keybinding));
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", actions[idx].keybinding));
else
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
-4
View File
@@ -310,14 +310,10 @@ click_pressed_cb (GtkGestureClick *gesture,
{
GtkButton *button = GTK_BUTTON (widget);
GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
GdkEventSequence *sequence;
if (gtk_widget_get_focus_on_click (widget) && !gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), sequence, GTK_EVENT_SEQUENCE_CLAIMED);
if (!priv->activate_timeout)
priv->button_down = TRUE;
}
+2 -2
View File
@@ -278,8 +278,6 @@ click_pressed_cb (GtkGestureClick *gesture,
{
if (gtk_widget_get_focus_on_click (widget) && !gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}
static void
@@ -295,6 +293,8 @@ click_released_cb (GtkGestureClick *gesture,
if (priv->active && (priv->group_prev || priv->group_next))
return;
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
gtk_check_button_set_active (self, !priv->active);
if (priv->action_helper)
+2 -2
View File
@@ -39,7 +39,7 @@
#include "gtkadjustment.h"
#include "gtkgesturedrag.h"
#include "gtkeventcontrollermotion.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkeventcontrollerkey.h"
#include "gtkgestureclick.h"
@@ -1128,7 +1128,7 @@ header_drag_update (GtkGestureDrag *gesture,
if (!self->in_column_resize && !self->in_column_reorder)
{
if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0))
if (gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, 0))
{
GtkColumnViewColumn *column;
GtkWidget *header;
+567 -177
View File
@@ -26,16 +26,17 @@
#include "gtkcomposetable.h"
#include "gtkimcontextsimple.h"
#include "gtkimcontextsimpleprivate.h"
#define GTK_COMPOSE_TABLE_MAGIC "GtkComposeTable"
#define GTK_COMPOSE_TABLE_VERSION (1)
#define GTK_COMPOSE_TABLE_VERSION (2)
/* Maximum length of sequences we parse */
#define MAX_COMPOSE_LEN 20
typedef struct {
gunichar *sequence;
gunichar value[2];
char *comment;
gunichar *sequence;
char *value;
} GtkComposeData;
@@ -43,7 +44,7 @@ static void
gtk_compose_data_free (GtkComposeData *compose_data)
{
g_free (compose_data->sequence);
g_free (compose_data->comment);
g_free (compose_data->value);
g_slice_free (GtkComposeData, compose_data);
}
@@ -76,58 +77,82 @@ parse_compose_value (GtkComposeData *compose_data,
const char *val,
const char *line)
{
char **words = g_strsplit (val, "\"", 3);
gunichar uch;
char *word;
const char *p;
gsize len;
GString *value;
gunichar ch;
char *endp;
if (g_strv_length (words) < 3)
len = strlen (val);
if (val[0] != '"' || val[len - 1] != '"')
{
g_warning ("Need to double-quote the value: %s: %s", val, line);
goto fail;
}
uch = g_utf8_get_char (words[1]);
word = g_strndup (val + 1, len - 2);
if (uch == 0)
{
g_warning ("Invalid value: %s: %s", val, line);
goto fail;
}
else if (uch == '\\')
{
uch = words[1][1];
value = g_string_new ("");
/* The escaped string "\"" is separated with '\\' and '"'. */
if (uch == '\0' && words[2][0] == '"')
uch = '"';
/* The escaped octal */
else if (uch >= '0' && uch <= '8')
uch = g_ascii_strtoll(words[1] + 1, NULL, 8);
/* If we need to handle other escape sequences. */
else if (uch != '\\')
p = word;
while (*p)
{
if (*p == '\\')
{
g_warning ("Invalid escape sequence: %s: %s", val, line);
if (p[1] == '"')
{
g_string_append_c (value, '"');
p += 2;
}
else if (p[1] == '\\')
{
g_string_append_c (value, '\\');
p += 2;
}
else if (p[1] >= '0' && p[1] < '8')
{
ch = g_ascii_strtoll (p + 1, &endp, 8);
if (ch == 0)
{
g_warning ("Invalid escape sequence: %s: %s", val, line);
goto fail;
}
g_string_append_unichar (value, ch);
p = endp;
}
else if (p[1] == 'x' || p[1] == 'X')
{
ch = g_ascii_strtoll (p + 2, &endp, 16);
if (ch == 0)
{
g_warning ("Invalid escape sequence: %s: %s", val, line);
goto fail;
}
g_string_append_unichar (value, ch);
p = endp;
}
else
{
g_warning ("Invalid escape sequence: %s: %s", val, line);
goto fail;
}
}
else
{
ch = g_utf8_get_char (p);
g_string_append_unichar (value, ch);
p = g_utf8_next_char (p);
}
}
if (g_utf8_get_char (g_utf8_next_char (words[1])) > 0)
{
g_warning ("GTK supports to output one char only: %s: %s", val, line);
goto fail;
}
compose_data->value = g_string_free (value, FALSE);
compose_data->value[1] = uch;
if (uch == '"')
compose_data->comment = g_strdup (g_strstrip (words[2] + 1));
else
compose_data->comment = g_strdup (g_strstrip (words[2]));
g_strfreev (words);
g_free (word);
return TRUE;
fail:
g_strfreev (words);
return FALSE;
}
@@ -189,10 +214,10 @@ parse_compose_sequence (GtkComposeData *compose_data,
}
g_strfreev (words);
if (0 == n || n >= GTK_MAX_COMPOSE_LEN)
if (0 == n || n > MAX_COMPOSE_LEN)
{
g_warning ("The max number of sequences is %d: %s",
GTK_MAX_COMPOSE_LEN, line);
g_warning ("Suspicious compose sequence length (%d). Are you sure this is right?: %s",
n, line);
return FALSE;
}
@@ -214,7 +239,10 @@ parse_compose_line (GList **compose_list,
return;
if (g_str_has_prefix (line, "include "))
return;
{
g_warning ("include in Compose files not supported: %s", line);
return;
}
components = g_strsplit (line, ":", 2);
@@ -244,6 +272,8 @@ fail:
gtk_compose_data_free (compose_data);
}
extern const GtkComposeTableCompact gtk_compose_table_compact;
static GList *
gtk_compose_list_parse_file (const char *compose_file)
{
@@ -279,18 +309,19 @@ gtk_compose_list_check_duplicated (GList *compose_list)
for (list = compose_list; list != NULL; list = list->next)
{
static guint16 keysyms[GTK_MAX_COMPOSE_LEN + 1];
static guint16 keysyms[MAX_COMPOSE_LEN + 1];
int i;
int n_compose = 0;
gboolean compose_finish;
gunichar output_char;
char buf[8] = { 0, };
compose_data = list->data;
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
keysyms[i] = 0;
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
{
gunichar codepoint = compose_data->sequence[i];
keysyms[i] = (guint16) codepoint;
@@ -301,20 +332,21 @@ gtk_compose_list_check_duplicated (GList *compose_list)
n_compose++;
}
if (gtk_check_compact_table (&gtk_compose_table_compact,
keysyms,
n_compose,
&compose_finish,
NULL,
&output_char) &&
if (gtk_compose_table_compact_check (&gtk_compose_table_compact,
keysyms, n_compose,
&compose_finish,
NULL,
&output_char) &&
compose_finish)
{
if (compose_data->value[1] == output_char)
g_unichar_to_utf8 (output_char, buf);
if (strcmp (compose_data->value, buf) == 0)
removed_list = g_list_prepend (removed_list, compose_data);
}
else if (gtk_check_algorithmically (keysyms, n_compose, &output_char))
{
if (compose_data->value[1] == output_char)
g_unichar_to_utf8 (output_char, buf);
if (strcmp (compose_data->value, buf) == 0)
removed_list = g_list_prepend (removed_list, compose_data);
}
}
@@ -343,7 +375,7 @@ gtk_compose_list_check_uint16 (GList *compose_list)
int i;
compose_data = list->data;
for (i = 0; i < GTK_MAX_COMPOSE_LEN; i++)
for (i = 0; i < MAX_COMPOSE_LEN; i++)
{
gunichar codepoint = compose_data->sequence[i];
@@ -384,7 +416,7 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
for (list = compose_list; list != NULL; list = list->next)
{
compose_data = list->data;
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
{
codepoint = compose_data->sequence[i];
if (codepoint == 0)
@@ -401,17 +433,6 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
if (p_n_index_stride)
*p_n_index_stride = max_compose_len + 2;
for (list = compose_list; list != NULL; list = list->next)
{
compose_data = list->data;
codepoint = compose_data->value[1];
if (codepoint > 0xffff)
{
compose_data->value[0] = codepoint / 0x10000;
compose_data->value[1] = codepoint - codepoint / 0x10000 * 0x10000;
}
}
return compose_list;
}
@@ -436,61 +457,6 @@ gtk_compose_data_compare (gpointer a,
return 0;
}
static void
gtk_compose_list_print (GList *compose_list,
int max_compose_len,
int n_index_stride)
{
GList *list;
int i, j;
GtkComposeData *compose_data;
int total_size = 0;
gunichar upper;
gunichar lower;
const char *comment;
const char *keyval;
for (list = compose_list; list != NULL; list = list->next)
{
compose_data = list->data;
g_printf (" ");
for (i = 0; i < max_compose_len; i++)
{
if (compose_data->sequence[i] == 0)
{
for (j = i; j < max_compose_len; j++)
{
if (j == max_compose_len - 1)
g_printf ("0,\n");
else
g_printf ("0, ");
}
break;
}
keyval = gdk_keyval_name (compose_data->sequence[i]);
if (i == max_compose_len - 1)
g_printf ("%s,\n", keyval ? keyval : "(null)");
else
g_printf ("%s, ", keyval ? keyval : "(null)");
}
upper = compose_data->value[0];
lower = compose_data->value[1];
comment = compose_data->comment;
if (list == g_list_last (compose_list))
g_printf (" %#06X, %#06X /* %s */\n", upper, lower, comment);
else
g_printf (" %#06X, %#06X, /* %s */\n", upper, lower, comment);
total_size += n_index_stride;
}
g_printerr ("TOTAL_SIZE: %d\nMAX_COMPOSE_LEN: %d\nN_INDEX_STRIDE: %d\n",
total_size, max_compose_len, n_index_stride);
}
/* Implemented from g_str_hash() */
static guint32
gtk_compose_table_data_hash (gconstpointer v, int length)
@@ -546,6 +512,7 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
guint16 max_seq_len = compose_table->max_seq_len;
guint16 index_stride = max_seq_len + 2;
guint16 n_seqs = compose_table->n_seqs;
guint16 n_chars = compose_table->n_chars;
guint32 i;
g_return_val_if_fail (compose_table != NULL, NULL);
@@ -553,44 +520,34 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
g_return_val_if_fail (index_stride > 0, NULL);
length = strlen (header);
total_length = length + sizeof (guint16) * (3 + index_stride * n_seqs);
total_length = length + sizeof (guint16) * (4 + index_stride * n_seqs) + n_chars;
if (count)
*count = total_length;
p = contents = g_slice_alloc (total_length);
p = contents = g_malloc (total_length);
memcpy (p, header, length);
p += length;
/* Copy by byte for endian */
#define BYTE_COPY_FROM_BUF(element) \
bytes = GUINT16_TO_BE ((element)); \
memcpy (p, &bytes, length); \
p += length; \
if (p - contents > total_length) \
{ \
g_warning ("data size %lld is bigger than %" G_GSIZE_FORMAT, \
(long long) (p - contents), total_length); \
g_free (contents); \
if (count) \
{ \
*count = 0; \
} \
return NULL; \
}
#define APPEND_GUINT16(elt) \
bytes = GUINT16_TO_BE (elt); \
memcpy (p, &bytes, sizeof (guint16)); \
p += sizeof (guint16);
length = sizeof (guint16);
BYTE_COPY_FROM_BUF (version);
BYTE_COPY_FROM_BUF (max_seq_len);
BYTE_COPY_FROM_BUF (n_seqs);
APPEND_GUINT16 (version);
APPEND_GUINT16 (max_seq_len);
APPEND_GUINT16 (n_seqs);
APPEND_GUINT16 (n_chars);
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
{
BYTE_COPY_FROM_BUF (compose_table->data[i]);
APPEND_GUINT16 (compose_table->data[i]);
}
#undef BYTE_COPY_FROM_BUF
if (compose_table->n_chars > 0)
memcpy (p, compose_table->char_data, compose_table->n_chars);
#undef APPEND_GUINT16
return contents;
}
@@ -614,16 +571,17 @@ gtk_compose_table_load_cache (const char *compose_file)
GStatBuf original_buf;
GStatBuf cache_buf;
gsize total_length;
gsize length;
GError *error = NULL;
guint16 bytes;
guint16 version;
guint16 max_seq_len;
guint16 index_stride;
guint16 n_seqs;
guint16 n_chars;
guint32 i;
guint16 *gtk_compose_seqs = NULL;
GtkComposeTable *retval;
char *char_data = NULL;
hash = g_str_hash (compose_file);
if ((path = gtk_compose_hash_get_cache_path (hash)) == NULL)
@@ -642,16 +600,10 @@ gtk_compose_table_load_cache (const char *compose_file)
goto out_load_cache;
}
/* Copy by byte for endian */
#define BYTE_COPY_TO_BUF(element) \
memcpy (&bytes, p, length); \
element = GUINT16_FROM_BE (bytes); \
p += length; \
if (p - contents > total_length) \
{ \
g_warning ("Broken cache content %s in %s", path, #element); \
goto out_load_cache; \
}
#define GET_GUINT16(elt) \
memcpy (&bytes, p, sizeof (guint16)); \
elt = GUINT16_FROM_BE (bytes); \
p += sizeof (guint16);
p = contents;
if (g_ascii_strncasecmp (p, GTK_COMPOSE_TABLE_MAGIC,
@@ -660,6 +612,7 @@ gtk_compose_table_load_cache (const char *compose_file)
g_warning ("The file is not a GtkComposeTable cache file %s", path);
goto out_load_cache;
}
p += strlen (GTK_COMPOSE_TABLE_MAGIC);
if (p - contents > total_length)
{
@@ -667,9 +620,7 @@ gtk_compose_table_load_cache (const char *compose_file)
goto out_load_cache;
}
length = sizeof (guint16);
BYTE_COPY_TO_BUF (version);
GET_GUINT16 (version);
if (version != GTK_COMPOSE_TABLE_VERSION)
{
g_warning ("cache version is different %u != %u",
@@ -677,8 +628,9 @@ gtk_compose_table_load_cache (const char *compose_file)
goto out_load_cache;
}
BYTE_COPY_TO_BUF (max_seq_len);
BYTE_COPY_TO_BUF (n_seqs);
GET_GUINT16 (max_seq_len);
GET_GUINT16 (n_seqs);
GET_GUINT16 (n_chars);
if (max_seq_len == 0 || n_seqs == 0)
{
@@ -691,13 +643,22 @@ gtk_compose_table_load_cache (const char *compose_file)
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
{
BYTE_COPY_TO_BUF (gtk_compose_seqs[i]);
GET_GUINT16 (gtk_compose_seqs[i]);
}
if (n_chars > 0)
{
char_data = g_new (char, n_chars + 1);
memcpy (char_data, p, n_chars);
char_data[n_chars] = '\0';
}
retval = g_new0 (GtkComposeTable, 1);
retval->data = gtk_compose_seqs;
retval->max_seq_len = max_seq_len;
retval->n_seqs = n_seqs;
retval->char_data = char_data;
retval->n_chars = n_chars;
retval->id = hash;
g_free (contents);
@@ -705,10 +666,11 @@ gtk_compose_table_load_cache (const char *compose_file)
return retval;
#undef BYTE_COPY_TO_BUF
#undef GET_GUINT16
out_load_cache:
g_free (gtk_compose_seqs);
g_free (char_data);
g_free (contents);
g_free (path);
return NULL;
@@ -739,7 +701,7 @@ gtk_compose_table_save_cache (GtkComposeTable *compose_table)
}
out_save_cache:
g_slice_free1 (length, contents);
g_free (contents);
g_free (path);
}
@@ -756,6 +718,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
GList *list;
GtkComposeData *compose_data;
GtkComposeTable *retval = NULL;
gunichar codepoint;
GString *char_data;
g_return_val_if_fail (compose_list != NULL, NULL);
@@ -763,6 +727,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
gtk_compose_seqs = g_new0 (guint16, length * n_index_stride);
char_data = g_string_new ("");
for (list = compose_list; list != NULL; list = list->next)
{
compose_data = list->data;
@@ -776,8 +742,24 @@ gtk_compose_table_new_with_list (GList *compose_list,
}
gtk_compose_seqs[n++] = (guint16) compose_data->sequence[i];
}
gtk_compose_seqs[n++] = (guint16) compose_data->value[0];
gtk_compose_seqs[n++] = (guint16) compose_data->value[1];
if (g_utf8_strlen (compose_data->value, -1) > 1)
{
if (char_data->len > 0)
g_string_append_c (char_data, 0);
codepoint = char_data->len | (1 << 31);
g_string_append (char_data, compose_data->value);
}
else
{
codepoint = g_utf8_get_char (compose_data->value);
g_assert ((codepoint & (1 << 31)) == 0);
}
gtk_compose_seqs[n++] = (codepoint & 0xffff0000) >> 16;
gtk_compose_seqs[n++] = codepoint & 0xffff;
}
retval = g_new0 (GtkComposeTable, 1);
@@ -785,6 +767,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
retval->max_seq_len = max_compose_len;
retval->n_seqs = length;
retval->id = hash;
retval->n_chars = char_data->len;
retval->char_data = g_string_free (char_data, FALSE);
return retval;
}
@@ -816,9 +800,6 @@ gtk_compose_table_new_with_file (const char *compose_file)
return NULL;
}
if (g_getenv ("GTK_COMPOSE_TABLE_PRINT") != NULL)
gtk_compose_list_print (compose_list, max_compose_len, n_index_stride);
compose_table = gtk_compose_table_new_with_list (compose_list,
max_compose_len,
n_index_stride,
@@ -841,9 +822,10 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
guint16 *gtk_compose_seqs = NULL;
g_return_val_if_fail (data != NULL, compose_tables);
g_return_val_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN, compose_tables);
g_return_val_if_fail (max_seq_len >= 0, compose_tables);
g_return_val_if_fail (n_seqs >= 0, compose_tables);
n_index_stride = MIN (max_seq_len, GTK_MAX_COMPOSE_LEN) + 2;
n_index_stride = max_seq_len + 2;
if (!g_size_checked_mul (&length, n_index_stride, n_seqs))
{
g_critical ("Overflow in the compose sequences");
@@ -864,12 +846,14 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
compose_table->max_seq_len = max_seq_len;
compose_table->n_seqs = n_seqs;
compose_table->id = hash;
compose_table->char_data = NULL;
compose_table->n_chars = 0;
return g_slist_prepend (compose_tables, compose_table);
}
GSList *
gtk_compose_table_list_add_file (GSList *compose_tables,
gtk_compose_table_list_add_file (GSList *compose_tables,
const char *compose_file)
{
guint32 hash;
@@ -891,3 +875,409 @@ gtk_compose_table_list_add_file (GSList *compose_tables,
gtk_compose_table_save_cache (compose_table);
return g_slist_prepend (compose_tables, compose_table);
}
static int
compare_seq (const void *key, const void *value)
{
int i = 0;
const guint16 *keysyms = key;
const guint16 *seq = value;
while (keysyms[i])
{
if (keysyms[i] < seq[i])
return -1;
else if (keysyms[i] > seq[i])
return 1;
i++;
}
return 0;
}
/*
* gtk_compose_table_check:
* @table: the table to check
* @compose_buffer: the key vals to match
* @n_compose: number of non-zero key vals in @compose_buffer
* @compose_finish: (out): return location for whether there may be longer matches
* @compose_match: (out): return location for whether there is a match
* @output: (out) (caller-allocates): return location for the match values
*
* Looks for matches for a key sequence in @table.
*
* Returns: %TRUE if there were any matches, %FALSE otherwise
*/
gboolean
gtk_compose_table_check (const GtkComposeTable *table,
const guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
GString *output)
{
int row_stride = table->max_seq_len + 2;
guint16 *seq;
*compose_finish = FALSE;
*compose_match = FALSE;
g_string_set_size (output, 0);
/* Will never match, if the sequence in the compose buffer is longer
* than the sequences in the table. Further, compare_seq (key, val)
* will overrun val if key is longer than val.
*/
if (n_compose > table->max_seq_len)
return FALSE;
seq = bsearch (compose_buffer,
table->data, table->n_seqs,
sizeof (guint16) * row_stride,
compare_seq);
if (seq)
{
guint16 *prev_seq;
/* Back up to the first sequence that matches to make sure
* we find the exact match if there is one.
*/
while (seq > table->data)
{
prev_seq = seq - row_stride;
if (compare_seq (compose_buffer, prev_seq) != 0)
break;
seq = prev_seq;
}
if (n_compose == table->max_seq_len ||
seq[n_compose] == 0) /* complete sequence */
{
guint16 *next_seq;
gunichar value;
value = (seq[table->max_seq_len] << 16) | seq[table->max_seq_len + 1];
if ((value & (1 << 31)) != 0)
g_string_append (output, &table->char_data[value & ~(1 << 31)]);
else
g_string_append_unichar (output, value);
*compose_match = TRUE;
/* We found a tentative match. See if there are any longer
* sequences containing this subsequence
*/
next_seq = seq + row_stride;
if (next_seq < table->data + row_stride * table->n_seqs)
{
if (compare_seq (compose_buffer, next_seq) == 0)
return TRUE;
}
*compose_finish = TRUE;
return TRUE;
}
return TRUE;
}
return FALSE;
}
static int
compare_seq_index (const void *key, const void *value)
{
const guint16 *keysyms = key;
const guint16 *seq = value;
if (keysyms[0] < seq[0])
return -1;
else if (keysyms[0] > seq[0])
return 1;
return 0;
}
gboolean
gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
const guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
gunichar *output_char)
{
int row_stride;
guint16 *seq_index;
guint16 *seq;
int i;
gboolean match;
gunichar value;
if (compose_finish)
*compose_finish = FALSE;
if (compose_match)
*compose_match = FALSE;
if (output_char)
*output_char = 0;
/* Will never match, if the sequence in the compose buffer is longer
* than the sequences in the table. Further, compare_seq (key, val)
* will overrun val if key is longer than val.
*/
if (n_compose > table->max_seq_len)
return FALSE;
seq_index = bsearch (compose_buffer,
table->data,
table->n_index_size,
sizeof (guint16) * table->n_index_stride,
compare_seq_index);
if (!seq_index)
return FALSE;
if (n_compose == 1)
return TRUE;
seq = NULL;
match = FALSE;
value = 0;
for (i = n_compose - 1; i < table->max_seq_len; i++)
{
row_stride = i + 1;
if (seq_index[i + 1] - seq_index[i] > 0)
{
seq = bsearch (compose_buffer + 1,
table->data + seq_index[i],
(seq_index[i + 1] - seq_index[i]) / row_stride,
sizeof (guint16) * row_stride,
compare_seq);
if (seq)
{
if (i == n_compose - 1)
{
value = seq[row_stride - 1];
match = TRUE;
}
else
{
if (output_char)
*output_char = value;
if (match)
{
if (compose_match)
*compose_match = TRUE;
}
return TRUE;
}
}
}
}
if (match)
{
if (compose_match)
*compose_match = TRUE;
if (compose_finish)
*compose_finish = TRUE;
if (output_char)
*output_char = value;
return TRUE;
}
return FALSE;
}
/* Checks if a keysym is a dead key.
* Dead key keysym values are defined in ../gdk/gdkkeysyms.h and the
* first is GDK_KEY_dead_grave. As X.Org is updated, more dead keys
* are added and we need to update the upper limit.
*/
#define IS_DEAD_KEY(k) \
((k) >= GDK_KEY_dead_grave && (k) <= GDK_KEY_dead_greek)
/* This function receives a sequence of Unicode characters and tries to
* normalize it (NFC). We check for the case where the resulting string
* has length 1 (single character).
* NFC normalisation normally rearranges diacritic marks, unless these
* belong to the same Canonical Combining Class.
* If they belong to the same canonical combining class, we produce all
* permutations of the diacritic marks, then attempt to normalize.
*/
static gboolean
check_normalize_nfc (gunichar *combination_buffer,
int n_compose)
{
gunichar *combination_buffer_temp;
char *combination_utf8_temp = NULL;
char *nfc_temp = NULL;
int n_combinations;
gunichar temp_swap;
int i;
combination_buffer_temp = g_alloca (n_compose * sizeof (gunichar));
n_combinations = 1;
for (i = 1; i < n_compose; i++)
n_combinations *= i;
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
* We check if base character belongs to Greek Unicode block,
* and if so, we replace tilde with perispomeni.
*/
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
{
for (i = 1; i < n_compose; i++ )
if (combination_buffer[i] == 0x303)
combination_buffer[i] = 0x342;
}
memcpy (combination_buffer_temp, combination_buffer, n_compose * sizeof (gunichar) );
for (i = 0; i < n_combinations; i++)
{
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, n_compose, NULL, NULL, NULL);
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
if (g_utf8_strlen (nfc_temp, -1) == 1)
{
memcpy (combination_buffer, combination_buffer_temp, n_compose * sizeof (gunichar) );
g_free (combination_utf8_temp);
g_free (nfc_temp);
return TRUE;
}
g_free (combination_utf8_temp);
g_free (nfc_temp);
if (n_compose > 2)
{
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
}
else
break;
}
return FALSE;
}
gboolean
gtk_check_algorithmically (const guint16 *compose_buffer,
int n_compose,
gunichar *output_char)
{
int i;
gunichar *combination_buffer;
char *combination_utf8, *nfc;
combination_buffer = alloca (sizeof (gunichar) * (n_compose + 1));
if (output_char)
*output_char = 0;
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
;
if (i == n_compose)
return TRUE;
if (i > 0 && i == n_compose - 1)
{
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
combination_buffer[n_compose] = 0;
i--;
while (i >= 0)
{
switch (compose_buffer[i])
{
#define CASE(keysym, unicode) \
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
CASE (grave, 0x0300);
CASE (acute, 0x0301);
CASE (circumflex, 0x0302);
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
CASE (macron, 0x0304);
CASE (breve, 0x0306);
CASE (abovedot, 0x0307);
CASE (diaeresis, 0x0308);
CASE (abovering, 0x30A);
CASE (hook, 0x0309);
CASE (doubleacute, 0x030B);
CASE (caron, 0x030C);
CASE (cedilla, 0x0327);
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
CASE (iota, 0x0345);
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
CASE (belowdot, 0x0323);
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
CASE (stroke, 0x335);
CASE (abovecomma, 0x0313); /* Equivalent to psili */
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
CASE (doublegrave, 0x30F);
CASE (belowring, 0x325);
CASE (belowmacron, 0x331);
CASE (belowcircumflex, 0x32D);
CASE (belowtilde, 0x330);
CASE (belowbreve, 0x32e);
CASE (belowdiaeresis, 0x324);
CASE (invertedbreve, 0x32f);
CASE (belowcomma, 0x326);
CASE (lowline, 0x332);
CASE (aboveverticalline, 0x30D);
CASE (belowverticalline, 0x329);
CASE (longsolidusoverlay, 0x338);
CASE (a, 0x363);
CASE (A, 0x363);
CASE (e, 0x364);
CASE (E, 0x364);
CASE (i, 0x365);
CASE (I, 0x365);
CASE (o, 0x366);
CASE (O, 0x366);
CASE (u, 0x367);
CASE (U, 0x367);
CASE (small_schwa, 0x1DEA);
CASE (capital_schwa, 0x1DEA);
#undef CASE
default:
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
}
i--;
}
/* If the buffer normalizes to a single character, then modify the order
* of combination_buffer accordingly, if necessary, and return TRUE.
*/
if (check_normalize_nfc (combination_buffer, n_compose))
{
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
if (output_char)
*output_char = g_utf8_get_char (nfc);
g_free (combination_utf8);
g_free (nfc);
return TRUE;
}
}
return FALSE;
}
+28 -7
View File
@@ -29,8 +29,10 @@ typedef struct _GtkComposeTableCompact GtkComposeTableCompact;
struct _GtkComposeTable
{
guint16 *data;
char *char_data;
int max_seq_len;
int n_seqs;
int n_chars;
guint32 id;
};
@@ -42,13 +44,32 @@ struct _GtkComposeTableCompact
int n_index_stride;
};
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
GSList *gtk_compose_table_list_add_array (GSList *compose_tables,
const guint16 *data,
int max_seq_len,
int n_seqs);
GSList *gtk_compose_table_list_add_file (GSList *compose_tables,
const char *compose_file);
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
GSList * gtk_compose_table_list_add_array (GSList *compose_tables,
const guint16 *data,
int max_seq_len,
int n_seqs);
GSList * gtk_compose_table_list_add_file (GSList *compose_tables,
const char *compose_file);
gboolean gtk_compose_table_check (const GtkComposeTable *table,
const guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
GString *output);
gboolean gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
const guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
gunichar *output_char);
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
int n_compose,
gunichar *output);
G_END_DECLS
+1 -1
View File
@@ -218,7 +218,7 @@ _gtk_css_border_value_parse (GtkCssParser *parser,
}
result->is_computed = TRUE;
for (; i < 4; i++)
for (i = 0; i < 4; i++)
if (result->values[i] && !gtk_css_value_is_computed (result->values[i]))
{
result->is_computed = FALSE;
+64 -20
View File
@@ -24,6 +24,7 @@
#include "gtkcssfiltervalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssshadowvalueprivate.h"
typedef union _GtkCssFilter GtkCssFilter;
@@ -46,7 +47,7 @@ union _GtkCssFilter {
struct {
GtkCssFilterType type;
GtkCssValue *value;
} brightness, contrast, grayscale, hue_rotate, invert, opacity, saturate, sepia, blur;
} blur, brightness, contrast, drop_shadow, grayscale, hue_rotate, invert, opacity, saturate, sepia;
};
struct _GtkCssValue {
@@ -90,8 +91,10 @@ gtk_css_filter_clear (GtkCssFilter *filter)
case GTK_CSS_FILTER_BLUR:
_gtk_css_value_unref (filter->blur.value);
break;
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
_gtk_css_value_unref (filter->drop_shadow.value);
break;
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
break;
@@ -131,8 +134,10 @@ gtk_css_filter_init_identity (GtkCssFilter *filter,
case GTK_CSS_FILTER_BLUR:
filter->blur.value = _gtk_css_number_value_new (0, GTK_CSS_PX);
break;
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
filter->drop_shadow.value = gtk_css_shadow_value_new_filter ();
break;
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
break;
@@ -347,8 +352,11 @@ gtk_css_filter_compute (GtkCssFilter *dest,
dest->blur.value = _gtk_css_value_compute (src->blur.value, property_id, provider, style, parent_style);
return dest->blur.value == src->blur.value;
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
dest->drop_shadow.value = _gtk_css_value_compute (src->drop_shadow.value, property_id, provider, style, parent_style);
return dest->drop_shadow.value == src->drop_shadow.value;
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
return FALSE;
@@ -428,8 +436,10 @@ gtk_css_filter_equal (const GtkCssFilter *filter1,
case GTK_CSS_FILTER_BLUR:
return _gtk_css_value_equal (filter1->blur.value, filter2->blur.value);
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
return _gtk_css_value_equal (filter1->drop_shadow.value, filter2->drop_shadow.value);
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
return FALSE;
@@ -517,8 +527,11 @@ gtk_css_filter_transition (GtkCssFilter *result,
result->blur.value = _gtk_css_value_transition (start->blur.value, end->blur.value, property_id, progress);
break;
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
result->drop_shadow.value = _gtk_css_value_transition (start->drop_shadow.value, end->drop_shadow.value, property_id, progress);
break;
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
break;
@@ -663,8 +676,13 @@ gtk_css_filter_print (const GtkCssFilter *filter,
g_string_append (string, ")");
break;
case GTK_CSS_FILTER_NONE:
case GTK_CSS_FILTER_DROP_SHADOW:
g_string_append (string, "drop-shadow(");
_gtk_css_value_print (filter->drop_shadow.value, string);
g_string_append (string, ")");
break;
case GTK_CSS_FILTER_NONE:
default:
g_assert_not_reached ();
break;
@@ -709,12 +727,12 @@ static GtkCssValue *
gtk_css_filter_value_alloc (guint n_filters)
{
GtkCssValue *result;
g_return_val_if_fail (n_filters > 0, NULL);
result = _gtk_css_value_alloc (&GTK_CSS_VALUE_FILTER, sizeof (GtkCssValue) + sizeof (GtkCssFilter) * (n_filters - 1));
result->n_filters = n_filters;
return result;
}
@@ -737,7 +755,7 @@ gtk_css_filter_parse_number (GtkCssParser *parser,
{
GtkCssValue **values = data;
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT);
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY);
if (values[n] == NULL)
return 0;
@@ -751,7 +769,7 @@ gtk_css_filter_parse_length (GtkCssParser *parser,
{
GtkCssValue **values = data;
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH);
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH | GTK_CSS_POSITIVE_ONLY);
if (values[n] == NULL)
return 0;
@@ -772,6 +790,20 @@ gtk_css_filter_parse_angle (GtkCssParser *parser,
return 1;
}
static guint
gtk_css_filter_parse_shadow (GtkCssParser *parser,
guint n,
gpointer data)
{
GtkCssValue **values = data;
values[n] = gtk_css_shadow_value_parse_filter (parser);
if (values[n] == NULL)
return 0;
return 1;
}
GtkCssValue *
gtk_css_filter_value_parse (GtkCssParser *parser)
{
@@ -861,6 +893,14 @@ gtk_css_filter_value_parse (GtkCssParser *parser)
filter.type = GTK_CSS_FILTER_SEPIA;
computed = computed && gtk_css_value_is_computed (filter.sepia.value);
}
else if (gtk_css_parser_has_function (parser, "drop-shadow"))
{
if (!gtk_css_parser_consume_function (parser, 1, 1, gtk_css_filter_parse_shadow, &filter.drop_shadow.value))
goto fail;
filter.type = GTK_CSS_FILTER_DROP_SHADOW;
computed = computed && gtk_css_value_is_computed (filter.drop_shadow.value);
}
else
{
break;
@@ -899,7 +939,6 @@ gtk_css_filter_value_push_snapshot (const GtkCssValue *filter,
graphene_matrix_t matrix;
graphene_vec4_t offset;
int i, j;
double radius;
if (gtk_css_filter_value_is_none (filter))
return;
@@ -909,16 +948,18 @@ gtk_css_filter_value_push_snapshot (const GtkCssValue *filter,
{
j = gtk_css_filter_value_compute_matrix (filter, i, &matrix, &offset);
if (i < j)
gtk_snapshot_push_color_matrix (snapshot,
&matrix,
&offset);
gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset);
if (j < filter->n_filters)
{
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
{
radius = _gtk_css_number_value_get (filter->filters[j].blur.value, 100.0);
gtk_snapshot_push_blur (snapshot, radius);
double std_dev = _gtk_css_number_value_get (filter->filters[j].blur.value, 100.0);
gtk_snapshot_push_blur (snapshot, 2 * std_dev);
}
else if (filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
{
gtk_css_shadow_value_push_snapshot (filter->filters[j].drop_shadow.value, snapshot);
}
else
g_warning ("Don't know how to handle filter type %d", filter->filters[j].type);
@@ -942,15 +983,18 @@ gtk_css_filter_value_pop_snapshot (const GtkCssValue *filter,
{
for (j = i; j < filter->n_filters; j++)
{
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR ||
filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
break;
}
if (i < j)
gtk_snapshot_pop (snapshot);
if (j < filter->n_filters)
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
gtk_snapshot_pop (snapshot);
else if (filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
gtk_css_shadow_value_pop_snapshot (filter->filters[j].drop_shadow.value, snapshot);
i = j + 1;
}
+2
View File
@@ -35,6 +35,7 @@
#include "gtk/gtkcssimageurlprivate.h"
#include "gtk/gtkcssimagescaledprivate.h"
#include "gtk/gtkcssimagerecolorprivate.h"
#include "gtk/gtkcssimagefilterprivate.h"
G_DEFINE_ABSTRACT_TYPE (GtkCssImage, _gtk_css_image, G_TYPE_OBJECT)
@@ -524,6 +525,7 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
{ "repeating-radial-gradient", _gtk_css_image_radial_get_type },
{ "conic-gradient", gtk_css_image_conic_get_type },
{ "cross-fade", gtk_css_image_cross_fade_get_type },
{ "filter", gtk_css_image_filter_get_type },
{ "image", _gtk_css_image_fallback_get_type }
};
guint i;
+216
View File
@@ -0,0 +1,216 @@
/*
* Copyright © 2021 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 <math.h>
#include <string.h>
#include "gtkcssimagefilterprivate.h"
#include "gtkcssfiltervalueprivate.h"
G_DEFINE_TYPE (GtkCssImageFilter, gtk_css_image_filter, GTK_TYPE_CSS_IMAGE)
static int
gtk_css_image_filter_get_width (GtkCssImage *image)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return _gtk_css_image_get_width (self->image);
}
static int
gtk_css_image_filter_get_height (GtkCssImage *image)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return _gtk_css_image_get_height (self->image);
}
static gboolean
gtk_css_image_filter_equal (GtkCssImage *image1,
GtkCssImage *image2)
{
GtkCssImageFilter *filter1 = GTK_CSS_IMAGE_FILTER (image1);
GtkCssImageFilter *filter2 = GTK_CSS_IMAGE_FILTER (image2);
return _gtk_css_image_equal (filter1->image, filter2->image) &&
_gtk_css_value_equal (filter1->filter, filter2->filter);
}
static gboolean
gtk_css_image_filter_is_dynamic (GtkCssImage *image)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return gtk_css_image_is_dynamic (self->image);
}
static GtkCssImage *
gtk_css_image_filter_get_dynamic_image (GtkCssImage *image,
gint64 monotonic_time)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return gtk_css_image_filter_new (gtk_css_image_get_dynamic_image (self->image, monotonic_time),
self->filter);
}
static void
gtk_css_image_filter_snapshot (GtkCssImage *image,
GtkSnapshot *snapshot,
double width,
double height)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
gtk_css_filter_value_push_snapshot (self->filter, snapshot);
gtk_css_image_snapshot (self->image, snapshot, width, height);
gtk_css_filter_value_pop_snapshot (self->filter, snapshot);
}
static guint
gtk_css_image_filter_parse_arg (GtkCssParser *parser,
guint arg,
gpointer data)
{
GtkCssImageFilter *self = data;
switch (arg)
{
case 0:
self->image = _gtk_css_image_new_parse (parser);
if (self->image == NULL)
return 0;
return 1;
case 1:
self->filter = gtk_css_filter_value_parse (parser);
if (self->filter == NULL)
return 0;
return 1;
default:
g_assert_not_reached ();
return 0;
}
}
static gboolean
gtk_css_image_filter_parse (GtkCssImage *image,
GtkCssParser *parser)
{
if (!gtk_css_parser_has_function (parser, "filter"))
{
gtk_css_parser_error_syntax (parser, "Expected 'filter('");
return FALSE;
}
return gtk_css_parser_consume_function (parser, 2, 2, gtk_css_image_filter_parse_arg, image);
}
static void
gtk_css_image_filter_print (GtkCssImage *image,
GString *string)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
g_string_append (string, "filter(");
_gtk_css_image_print (self->image, string);
g_string_append (string, ",");
_gtk_css_value_print (self->filter, string);
g_string_append (string, ")");
}
static GtkCssImage *
gtk_css_image_filter_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return gtk_css_image_filter_new (_gtk_css_image_compute (self->image, property_id, provider, style, parent_style),
_gtk_css_value_compute (self->filter, property_id, provider, style, parent_style));
}
static void
gtk_css_image_filter_dispose (GObject *object)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (object);
g_clear_object (&self->image);
g_clear_pointer (&self->filter, _gtk_css_value_unref);
G_OBJECT_CLASS (gtk_css_image_filter_parent_class)->dispose (object);
}
static gboolean
gtk_css_image_filter_is_computed (GtkCssImage *image)
{
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
return gtk_css_image_is_computed (self->image) &&
gtk_css_value_is_computed (self->filter);
}
static void
gtk_css_image_filter_class_init (GtkCssImageFilterClass *klass)
{
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
image_class->get_width = gtk_css_image_filter_get_width;
image_class->get_height = gtk_css_image_filter_get_height;
image_class->compute = gtk_css_image_filter_compute;
image_class->equal = gtk_css_image_filter_equal;
image_class->snapshot = gtk_css_image_filter_snapshot;
image_class->is_dynamic = gtk_css_image_filter_is_dynamic;
image_class->get_dynamic_image = gtk_css_image_filter_get_dynamic_image;
image_class->parse = gtk_css_image_filter_parse;
image_class->print = gtk_css_image_filter_print;
image_class->is_computed = gtk_css_image_filter_is_computed;
object_class->dispose = gtk_css_image_filter_dispose;
}
static void
gtk_css_image_filter_init (GtkCssImageFilter *self)
{
}
GtkCssImage *
gtk_css_image_filter_new (GtkCssImage *image,
GtkCssValue *filter)
{
GtkCssImageFilter *self;
g_return_val_if_fail (GTK_IS_CSS_IMAGE (image), NULL);
self = g_object_new (GTK_TYPE_CSS_IMAGE_FILTER, NULL);
self->image = g_object_ref (image);
self->filter = gtk_css_value_ref (filter);
return GTK_CSS_IMAGE (self);
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright © 2021 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 __GTK_CSS_IMAGE_FILTER_PRIVATE_H__
#define __GTK_CSS_IMAGE_FILTER_PRIVATE_H__
#include "gtk/gtkcssimageprivate.h"
#include "gtk/gtkcssvalueprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_IMAGE_FILTER (gtk_css_image_filter_get_type ())
#define GTK_CSS_IMAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilter))
#define GTK_CSS_IMAGE_FILTER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilterClass))
#define GTK_IS_CSS_IMAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_FILTER))
#define GTK_IS_CSS_IMAGE_FILTER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_FILTER))
#define GTK_CSS_IMAGE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilterClass))
typedef struct _GtkCssImageFilter GtkCssImageFilter;
typedef struct _GtkCssImageFilterClass GtkCssImageFilterClass;
struct _GtkCssImageFilter
{
GtkCssImage parent;
GtkCssImage *image;
GtkCssValue *filter;
};
struct _GtkCssImageFilterClass
{
GtkCssImageClass parent_class;
};
GType gtk_css_image_filter_get_type (void) G_GNUC_CONST;
GtkCssImage * gtk_css_image_filter_new (GtkCssImage *image,
GtkCssValue *filter);
G_END_DECLS
#endif /* __GTK_CSS_IMAGE_FILTER_PRIVATE_H__ */
+1 -4
View File
@@ -1073,11 +1073,8 @@ parse_n_plus_b (GtkCssParser *parser,
*a = 0;
return TRUE;
}
gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
return FALSE;
}
static gboolean
parse_a_n_plus_b (GtkCssParser *parser,
int seen_sign,
+91 -31
View File
@@ -44,12 +44,14 @@ typedef struct {
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
guint is_filter : 1; /* values stored in radius are std_dev, for drop-shadow */
guint n_shadows;
ShadowValue shadows[1];
};
static GtkCssValue * gtk_css_shadow_value_new (ShadowValue *shadows,
guint n_shadows);
guint n_shadows,
gboolean is_filter);
static void
shadow_value_for_transition (ShadowValue *result,
@@ -133,7 +135,7 @@ gtk_css_value_shadow_compute (GtkCssValue *value,
shadows[i].inset = shadow->inset;
}
return gtk_css_shadow_value_new (shadows, value->n_shadows);
return gtk_css_shadow_value_new (shadows, value->n_shadows, value->is_filter);
}
static gboolean
@@ -151,11 +153,11 @@ gtk_css_value_shadow_equal (const GtkCssValue *value1,
const ShadowValue *shadow2 = &value2->shadows[i];
if (shadow1->inset != shadow2->inset ||
_gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset) ||
_gtk_css_value_equal (shadow1->voffset, shadow2->voffset) ||
_gtk_css_value_equal (shadow1->radius, shadow2->radius) ||
_gtk_css_value_equal (shadow1->spread, shadow2->spread) ||
_gtk_css_value_equal (shadow1->color, shadow2->color))
!_gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset) ||
!_gtk_css_value_equal (shadow1->voffset, shadow2->voffset) ||
!_gtk_css_value_equal (shadow1->radius, shadow2->radius) ||
!_gtk_css_value_equal (shadow1->spread, shadow2->spread) ||
!_gtk_css_value_equal (shadow1->color, shadow2->color))
return FALSE;
}
@@ -172,9 +174,6 @@ gtk_css_value_shadow_transition (GtkCssValue *start,
guint i, len;
ShadowValue *shadows;
if (start->n_shadows != end->n_shadows)
return NULL;
if (start->n_shadows > end->n_shadows)
len = start->n_shadows;
else
@@ -230,7 +229,7 @@ gtk_css_value_shadow_transition (GtkCssValue *start,
}
}
return gtk_css_shadow_value_new (shadows, len);
return gtk_css_shadow_value_new (shadows, len, start->is_filter);
}
static void
@@ -287,7 +286,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
gtk_css_value_shadow_print
};
static GtkCssValue shadow_none_singleton = { &GTK_CSS_VALUE_SHADOW, 1, TRUE, 0 };
static GtkCssValue shadow_none_singleton = { &GTK_CSS_VALUE_SHADOW, 1, TRUE, FALSE, 0 };
GtkCssValue *
gtk_css_shadow_value_new_none (void)
@@ -297,7 +296,8 @@ gtk_css_shadow_value_new_none (void)
static GtkCssValue *
gtk_css_shadow_value_new (ShadowValue *shadows,
guint n_shadows)
guint n_shadows,
gboolean is_filter)
{
GtkCssValue *retval;
guint i;
@@ -307,6 +307,7 @@ gtk_css_shadow_value_new (ShadowValue *shadows,
retval = _gtk_css_value_alloc (&GTK_CSS_VALUE_SHADOW, sizeof (GtkCssValue) + sizeof (ShadowValue) * (n_shadows - 1));
retval->n_shadows = n_shadows;
retval->is_filter = is_filter;
memcpy (retval->shadows, shadows, sizeof (ShadowValue) * n_shadows);
@@ -329,6 +330,21 @@ gtk_css_shadow_value_new (ShadowValue *shadows,
return retval;
}
GtkCssValue *
gtk_css_shadow_value_new_filter (void)
{
ShadowValue value;
value.inset = FALSE;
value.hoffset = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
value.voffset = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
value.radius = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
value.spread = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
value.color = _gtk_css_color_value_new_current_color ();
return gtk_css_shadow_value_new (&value, 1, TRUE);
}
enum {
HOFFSET,
VOFFSET,
@@ -419,9 +435,9 @@ parse_color (GtkCssParser *parser,
}
static gboolean
_gtk_css_shadow_value_parse_one (GtkCssParser *parser,
gboolean box_shadow_mode,
ShadowValue *result)
gtk_css_shadow_value_parse_one (GtkCssParser *parser,
gboolean box_shadow_mode,
ShadowValue *result)
{
GtkCssValue *values[N_VALUES] = { NULL, };
GtkCssValue *color = NULL;
@@ -467,8 +483,8 @@ fail:
#define MAX_SHADOWS 64
GtkCssValue *
_gtk_css_shadow_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode)
gtk_css_shadow_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode)
{
ShadowValue shadows[MAX_SHADOWS];
int n_shadows = 0;
@@ -478,7 +494,7 @@ _gtk_css_shadow_value_parse (GtkCssParser *parser,
return gtk_css_shadow_value_new_none ();
do {
if (_gtk_css_shadow_value_parse_one (parser, box_shadow_mode, &shadows[n_shadows]))
if (gtk_css_shadow_value_parse_one (parser, box_shadow_mode, &shadows[n_shadows]))
n_shadows++;
if (n_shadows > MAX_SHADOWS)
@@ -488,7 +504,7 @@ _gtk_css_shadow_value_parse (GtkCssParser *parser,
}
} while (gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA));
return gtk_css_shadow_value_new (shadows, n_shadows);
return gtk_css_shadow_value_new (shadows, n_shadows, FALSE);
fail:
for (i = 0; i < n_shadows; i++)
@@ -500,6 +516,17 @@ fail:
return NULL;
}
GtkCssValue *
gtk_css_shadow_value_parse_filter (GtkCssParser *parser)
{
ShadowValue shadow;
if (gtk_css_shadow_value_parse_one (parser, FALSE, &shadow))
return gtk_css_shadow_value_new (&shadow, 1, TRUE);
else
return NULL;
}
void
gtk_css_shadow_value_get_extents (const GtkCssValue *value,
GtkBorder *border)
@@ -515,6 +542,8 @@ gtk_css_shadow_value_get_extents (const GtkCssValue *value,
spread = _gtk_css_number_value_get (shadow->spread, 0);
radius = _gtk_css_number_value_get (shadow->radius, 0);
if (value->is_filter)
radius = radius * 2;
clip_radius = gsk_cairo_blur_compute_pixels (radius);
hoffset = _gtk_css_number_value_get (shadow->hoffset, 0);
voffset = _gtk_css_number_value_get (shadow->voffset, 0);
@@ -532,6 +561,8 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
const GskRoundedRect *border_box)
{
guint i;
double dx, dy, spread, radius;
const GdkRGBA *color;
g_return_if_fail (value->class == &GTK_CSS_VALUE_SHADOW);
@@ -542,17 +573,20 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
if (shadow->inset)
continue;
color = gtk_css_color_value_get_rgba (shadow->color);
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
if (gdk_rgba_is_clear (color))
continue;
gtk_snapshot_append_outset_shadow (snapshot,
border_box,
gtk_css_color_value_get_rgba (shadow->color),
_gtk_css_number_value_get (shadow->hoffset, 0),
_gtk_css_number_value_get (shadow->voffset, 0),
_gtk_css_number_value_get (shadow->spread, 0),
_gtk_css_number_value_get (shadow->radius, 0));
dx = _gtk_css_number_value_get (shadow->hoffset, 0);
dy = _gtk_css_number_value_get (shadow->voffset, 0);
spread = _gtk_css_number_value_get (shadow->spread, 0);
radius = _gtk_css_number_value_get (shadow->radius, 0);
if (value->is_filter)
radius = 2 * radius;
gtk_snapshot_append_outset_shadow (snapshot, border_box, color, dx, dy, spread, radius);
}
}
@@ -574,15 +608,18 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue *value,
if (!shadow->inset)
continue;
color = gtk_css_color_value_get_rgba (shadow->color);
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
if (gdk_rgba_is_clear (color))
continue;
dx = _gtk_css_number_value_get (shadow->hoffset, 0);
dy = _gtk_css_number_value_get (shadow->voffset, 0);
spread = _gtk_css_number_value_get (shadow->spread, 0);
radius = _gtk_css_number_value_get (shadow->radius, 0);
color = gtk_css_color_value_get_rgba (shadow->color);
if (value->is_filter)
radius = 2 * radius;
/* These are trivial to do with a color node */
if (spread == 0 && radius == 0 &&
@@ -678,7 +715,6 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
gboolean need_shadow = FALSE;
guint i;
/* TODO: We can save this as a flag once and then reuse it */
for (i = 0; i < value->n_shadows; i++)
{
const ShadowValue *shadow = &value->shadows[i];
@@ -702,6 +738,8 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
shadows[i].dy = _gtk_css_number_value_get (shadow->voffset, 0);
shadows[i].color = *gtk_css_color_value_get_rgba (shadow->color);
shadows[i].radius = _gtk_css_number_value_get (shadow->radius, 0);
if (value->is_filter)
shadows[i].radius *= 2;
}
gtk_snapshot_push_shadow (snapshot, shadows, value->n_shadows);
@@ -709,3 +747,25 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
return need_shadow;
}
void
gtk_css_shadow_value_pop_snapshot (const GtkCssValue *value,
GtkSnapshot *snapshot)
{
gboolean need_shadow = FALSE;
guint i;
for (i = 0; i < value->n_shadows; i++)
{
const ShadowValue *shadow = &value->shadows[i];
if (!gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
{
need_shadow = TRUE;
break;
}
}
if (need_shadow)
gtk_snapshot_pop (snapshot);
}
+6 -2
View File
@@ -34,10 +34,12 @@
G_BEGIN_DECLS
GtkCssValue * gtk_css_shadow_value_new_none (void);
GtkCssValue * gtk_css_shadow_value_new_none (void);
GtkCssValue * gtk_css_shadow_value_new_filter (void);
GtkCssValue * _gtk_css_shadow_value_parse (GtkCssParser *parser,
GtkCssValue * gtk_css_shadow_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode);
GtkCssValue * gtk_css_shadow_value_parse_filter (GtkCssParser *parser);
void gtk_css_shadow_value_get_extents (const GtkCssValue *shadow,
GtkBorder *border);
@@ -53,6 +55,8 @@ gboolean gtk_css_shadow_value_is_none (const GtkCssValue
gboolean gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
GtkSnapshot *snapshot);
void gtk_css_shadow_value_pop_snapshot (const GtkCssValue *value,
GtkSnapshot *snapshot);
G_END_DECLS
+2 -2
View File
@@ -512,14 +512,14 @@ static GtkCssValue *
box_shadow_value_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
{
return _gtk_css_shadow_value_parse (parser, TRUE);
return gtk_css_shadow_value_parse (parser, TRUE);
}
static GtkCssValue *
shadow_value_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
{
return _gtk_css_shadow_value_parse (parser, FALSE);
return gtk_css_shadow_value_parse (parser, FALSE);
}
static GtkCssValue *
+2 -2
View File
@@ -260,8 +260,8 @@ _gtk_css_value_transition (GtkCssValue *start,
guint property_id,
double progress)
{
gtk_internal_return_val_if_fail (start != NULL, FALSE);
gtk_internal_return_val_if_fail (end != NULL, FALSE);
gtk_internal_return_val_if_fail (start != NULL, NULL);
gtk_internal_return_val_if_fail (end != NULL, NULL);
if (start->class != end->class)
return NULL;
+25 -25
View File
@@ -48,20 +48,32 @@
* SECTION:gtkdialog
* @Short_description: Create popup windows
* @Title: GtkDialog
* @See_also: #GtkBox, #GtkWindow, #GtkButton
* @See_also: #GtkWindow, #GtkMessageDialog
*
* Dialog boxes are a convenient way to prompt the user for a small amount
* Dialogs are a convenient way to prompt the user for a small amount
* of input, e.g. to display a message, ask a question, or anything else
* that does not require extensive effort on the users part.
*
* GTK treats a dialog as a window split vertically. The top section is a
* #GtkBox, and is where widgets such as a #GtkLabel or a #GtkEntry should
* be packed. The bottom area is known as the
* action area. This is generally used for
* packing buttons into the dialog which may perform functions such as
* cancel, ok, or apply.
* The main area of a GtkDialog is called the "content area", and is yours
* to populate with widgets such a #GtkLabel or #GtkEntry, to present
* your information, questions, or tasks to the user. In addition, dialogs
* allow you to add "action widgets". Most commonly, action widgets are
* buttons. Depending on the platform, action widgets may be presented
* in the header bar at the top of the window, or at the bottom of the window.
* To add action widgets, use GtkDialog using gtk_dialog_new_with_buttons(),
* gtk_dialog_add_button(), gtk_dialog_add_buttons(), or
* gtk_dialog_add_action_widget().
*
* #GtkDialog boxes are created with a call to gtk_dialog_new() or
* Clicking a button that was added as an action widget will emit the
* #GtkDialog::response signal with a response ID that you specified.
* GTK will never assign a meaning to positive response IDs; these are
* entirely user-defined. But for convenience, you can use the response
* IDs in the #GtkResponseType enumeration (these all have values less
* than zero). If a dialog receives a delete event, the
* #GtkDialog::response signal will be emitted with the
* #GTK_RESPONSE_DELETE_EVENT response ID.
*
* Dialogs are created with a call to gtk_dialog_new() or
* gtk_dialog_new_with_buttons(). gtk_dialog_new_with_buttons() is
* recommended; it allows you to set the dialog title, some convenient
* flags, and add simple buttons.
@@ -72,20 +84,9 @@
* gtk_dialog_new() into a #GtkWindow. When using gtk_dialog_new_with_buttons()
* you can also pass the #GTK_DIALOG_MODAL flag to make a dialog modal.
*
* If you add buttons to #GtkDialog using gtk_dialog_new_with_buttons(),
* gtk_dialog_add_button(), gtk_dialog_add_buttons(), or
* gtk_dialog_add_action_widget(), clicking the button will emit a signal
* called #GtkDialog::response with a response ID that you specified. GTK
* will never assign a meaning to positive response IDs; these are entirely
* user-defined. But for convenience, you can use the response IDs in the
* #GtkResponseType enumeration (these all have values less than zero). If
* a dialog receives a delete event, the #GtkDialog::response signal will
* be emitted with a response ID of #GTK_RESPONSE_DELETE_EVENT.
*
* For the simple dialog in the following example, in reality youd probably
* use #GtkMessageDialog to save yourself some effort. But youd need to
* create the dialog contents manually if you had more than a simple message
* in the dialog.
* For the simple dialog in the following example, a #GtkMessageDialog would
* save some effort. But youd need to create the dialog contents manually if
* you had more than a simple message in the dialog.
*
* An example for simple GtkDialog usage:
* |[<!-- language="C" -->
@@ -124,8 +125,7 @@
* # GtkDialog as GtkBuildable
*
* The GtkDialog implementation of the #GtkBuildable interface exposes the
* @content_area and @action_area as internal children with the names
* content_area and action_area.
* @content_area as an internal child with the name content_area.
*
* GtkDialog supports a custom <action-widgets> element, which can contain
* multiple <action-widget> elements. The response attribute specifies a
+19 -2
View File
@@ -24,7 +24,7 @@
#include "config.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkgesturedrag.h"
#include "gtkgesturesingleprivate.h"
@@ -292,7 +292,7 @@ gtk_drag_source_update (GtkGesture *gesture,
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
if (gtk_drag_check_threshold (widget, source->start_x, source->start_y, x, y))
if (gtk_drag_check_threshold_double (widget, source->start_x, source->start_y, x, y))
{
gtk_drag_source_drag_begin (source);
}
@@ -796,3 +796,20 @@ gtk_drag_check_threshold (GtkWidget *widget,
return (ABS (current_x - start_x) > drag_threshold ||
ABS (current_y - start_y) > drag_threshold);
}
gboolean
gtk_drag_check_threshold_double (GtkWidget *widget,
double start_x,
double start_y,
double current_x,
double current_y)
{
int drag_threshold;
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
drag_threshold = gtk_settings_get_dnd_drag_threshold (gtk_widget_get_settings (widget));
return (ABS (current_x - start_x) > drag_threshold ||
ABS (current_y - start_y) > drag_threshold);
}
+33
View File
@@ -0,0 +1,33 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2020 Alexander Mikhaylenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_DRAG_SOURCE_PRIVATE_H__
#define __GTK_DRAG_SOURCE_PRIVATE_H__
#include "gtkdragsource.h"
G_BEGIN_DECLS
gboolean gtk_drag_check_threshold_double (GtkWidget *widget,
double start_x,
double start_y,
double current_x,
double current_y);
G_END_DECLS
#endif /* __GTK_DRAG_SOURCE_PRIVATE_H__ */
+7 -6
View File
@@ -65,7 +65,7 @@
#include "gtkwindow.h"
#include "gtknative.h"
#include "gtkgestureclick.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdragicon.h"
#include "gtkwidgetpaintable.h"
@@ -1586,32 +1586,33 @@ icon_released_cb (GtkGestureClick *gesture,
static void
icon_drag_update_cb (GtkGestureDrag *gesture,
double x,
double y,
double offset_x,
double offset_y,
GtkEntry *entry)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
double start_x, start_y;
GtkEntryIconPosition pos;
EntryIconInfo *icon_info;
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
icon_info = priv->icons[pos];
if (icon_info->content != NULL &&
gtk_drag_check_threshold (icon_info->widget, start_x, start_y, x, y))
gtk_drag_check_threshold_double (icon_info->widget, 0, 0, offset_x, offset_y))
{
GdkPaintable *paintable;
GdkSurface *surface;
GdkDevice *device;
GdkDrag *drag;
double start_x, start_y;
icon_info->in_drag = TRUE;
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (entry)));
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
drag = gdk_drag_begin (surface, device, icon_info->content, icon_info->actions, start_x, start_y);
paintable = gtk_widget_paintable_new (icon_info->widget);
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
+5
View File
@@ -60,6 +60,11 @@
* Showing, hiding and running the dialog is handled by the #GtkNativeDialog
* functions.
*
* Note that unlike #GtkFileChooserDialog, #GtkFileChooserNative objects are
* not toplevel widgets, and GTK does not keep them alive. It is your
* responsibility to keep a reference until you are done with the
* object.
* ## Typical usage ## {#gtkfilechoosernative-typical-usage}
*
* In the simplest of cases, you can the following code to use
+2 -2
View File
@@ -37,7 +37,7 @@
#include "gtkgesturelongpressprivate.h"
#include "gtkgestureprivate.h"
#include "gtkmarshalers.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
@@ -159,7 +159,7 @@ gtk_gesture_long_press_update (GtkGesture *gesture,
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
gtk_gesture_get_point (gesture, sequence, &x, &y);
if (gtk_drag_check_threshold (widget, priv->initial_x, priv->initial_y, x, y))
if (gtk_drag_check_threshold_double (widget, priv->initial_x, priv->initial_y, x, y))
{
if (priv->timeout_id)
{
+59
View File
@@ -48,6 +48,65 @@
* from the grid, use gtk_grid_remove(). The behaviour of GtkGrid when
* several children occupy the same grid cell is undefined.
*
* # GtkGrid as GtkBuildable
*
* Every child in a GtkGrid has access to a custom #GtkBuildable element, called ´<layout>´.
* It can by used to specify a position in the grid and optionally spans.
* All properties that can be used in the ´<layout>´ element are implemented by #GtkGridLayoutChild.
*
* It is implemented by #GtkWidget using #GtkLayoutManager.
*
* To showcase it, here is a simple example:
*
* |[
* <object class="GtkGrid" id="my_grid">
* <child>
* <object class="GtkButton" id="button1">
* <property name="label">Button 1</property>
* <layout>
* <property name="column">0</property>
* <property name="row">0</property>
* </layout>
* </object>
* </child>
* <child>
* <object class="GtkButton" id="button2">
* <property name="label">Button 2</property>
* <layout>
* <property name="column">1</property>
* <property name="row">0</property>
* </layout>
* </object>
* </child>
* <child>
* <object class="GtkButton" id="button3">
* <property name="label">Button 3</property>
* <layout>
* <property name="column">2</property>
* <property name="row">0</property>
* <property name="row-span">2</property>
* </layout>
* </object>
* </child>
* <child>
* <object class="GtkButton" id="button4">
* <property name="label">Button 4</property>
* <layout>
* <property name="column">0</property>
* <property name="row">1</property>
* <property name="column-span">2</property>
* </layout>
* </object>
* </child>
* </object>
* ]|
*
* It organizes the first two buttons side-by-side in one cell each.
* The third button is in the last column but spans across two rows.
* This is defined by the ´row-span´ property.
* The last button is located in the second row and spans across two columns,
* which is defined by the ´column-span´ property.
*
* # CSS nodes
*
* GtkGrid uses a single CSS node with name `grid`.
+5 -5
View File
@@ -26,7 +26,7 @@
#include "gtkcellrenderer.h"
#include "gtkcellrendererpixbuf.h"
#include "gtkcellrenderertext.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkentry.h"
#include "gtkintl.h"
#include "gtkmain.h"
@@ -5884,10 +5884,10 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
if (icon_view->priv->pressed_button < 0)
goto out;
if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
icon_view->priv->press_start_x,
icon_view->priv->press_start_y,
x, y))
if (!gtk_drag_check_threshold_double (GTK_WIDGET (icon_view),
icon_view->priv->press_start_x,
icon_view->priv->press_start_y,
x, y))
goto out;
model = gtk_icon_view_get_model (icon_view);
+2 -2
View File
@@ -133,8 +133,8 @@ struct _GtkIconViewPrivate
/* Drag-and-drop. */
GdkModifierType start_button_mask;
int pressed_button;
int press_start_x;
int press_start_y;
double press_start_x;
double press_start_y;
GdkContentFormats *source_formats;
GtkDropTargetAsync *dest;
+176 -486
View File
@@ -32,7 +32,6 @@
#include "gtkcomposetable.h"
#include "gtkimmoduleprivate.h"
#include "gtkimcontextsimpleprivate.h"
#include "gtkimcontextsimpleseqs.h"
#include "gdk/gdkprofilerprivate.h"
@@ -61,8 +60,9 @@
struct _GtkIMContextSimplePrivate
{
guint16 compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
gunichar tentative_match;
guint16 *compose_buffer;
int compose_buffer_len;
GString *tentative_match;
int tentative_match_len;
guint in_hex_sequence : 1;
@@ -174,8 +174,7 @@ gtk_im_context_simple_init_compose_table (void)
g_free (path);
return;
}
g_free (path);
path = NULL;
g_clear_pointer (&path, g_free);
home = g_get_home_dir ();
if (home == NULL)
@@ -190,8 +189,7 @@ gtk_im_context_simple_init_compose_table (void)
g_free (path);
return;
}
g_free (path);
path = NULL;
g_clear_pointer (&path, g_free);
locale = g_getenv ("LC_CTYPE");
if (locale == NULL)
@@ -224,8 +222,7 @@ gtk_im_context_simple_init_compose_table (void)
if (g_file_test (path, G_FILE_TEST_EXISTS))
break;
g_free (path);
path = NULL;
g_clear_pointer (&path, g_free);
}
g_free (x11_compose_file_dir);
@@ -237,8 +234,7 @@ gtk_im_context_simple_init_compose_table (void)
global_tables = gtk_compose_table_list_add_file (global_tables, path);
G_UNLOCK (global_tables);
}
g_free (path);
path = NULL;
g_clear_pointer (&path, g_free);
}
static void
@@ -271,14 +267,27 @@ init_compose_table_async (GCancellable *cancellable,
}
static void
gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
gtk_im_context_simple_init (GtkIMContextSimple *context_simple)
{
im_context_simple->priv = gtk_im_context_simple_get_instance_private (im_context_simple);
GtkIMContextSimplePrivate *priv;
priv = context_simple->priv = gtk_im_context_simple_get_instance_private (context_simple);
priv->compose_buffer_len = gtk_compose_table_compact.max_seq_len + 1;
priv->compose_buffer = g_new0 (guint16, priv->compose_buffer_len);
priv->tentative_match = g_string_new ("");
priv->tentative_match_len = 0;
}
static void
gtk_im_context_simple_finalize (GObject *obj)
{
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj);
GtkIMContextSimplePrivate *priv = context_simple->priv;;
g_free (priv->compose_buffer);
g_string_free (priv->tentative_match, TRUE);
G_OBJECT_CLASS (gtk_im_context_simple_parent_class)->finalize (obj);
}
@@ -296,396 +305,29 @@ gtk_im_context_simple_new (void)
}
static void
gtk_im_context_simple_commit_char (GtkIMContext *context,
gunichar ch)
{
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
GtkIMContextSimplePrivate *priv = context_simple->priv;
char buf[10];
int len;
g_return_if_fail (g_unichar_validate (ch));
len = g_unichar_to_utf8 (ch, buf);
buf[len] = '\0';
if (priv->tentative_match || priv->in_hex_sequence)
{
priv->in_hex_sequence = FALSE;
priv->tentative_match = 0;
priv->tentative_match_len = 0;
g_signal_emit_by_name (context_simple, "preedit-changed");
g_signal_emit_by_name (context_simple, "preedit-end");
}
g_signal_emit_by_name (context, "commit", &buf);
}
static int
compare_seq_index (const void *key, const void *value)
{
const guint16 *keysyms = key;
const guint16 *seq = value;
if (keysyms[0] < seq[0])
return -1;
else if (keysyms[0] > seq[0])
return 1;
return 0;
}
static int
compare_seq (const void *key, const void *value)
{
int i = 0;
const guint16 *keysyms = key;
const guint16 *seq = value;
while (keysyms[i])
{
if (keysyms[i] < seq[i])
return -1;
else if (keysyms[i] > seq[i])
return 1;
i++;
}
return 0;
}
static gboolean
check_table (GtkIMContextSimple *context_simple,
const GtkComposeTable *table,
int n_compose)
gtk_im_context_simple_commit_string (GtkIMContextSimple *context_simple,
const char *str)
{
GtkIMContextSimplePrivate *priv = context_simple->priv;
int row_stride = table->max_seq_len + 2;
guint16 *seq;
/* Will never match, if the sequence in the compose buffer is longer
* than the sequences in the table. Further, compare_seq (key, val)
* will overrun val if key is longer than val. */
if (n_compose > table->max_seq_len)
return FALSE;
seq = bsearch (priv->compose_buffer,
table->data, table->n_seqs,
sizeof (guint16) * row_stride,
compare_seq);
priv->in_hex_sequence = FALSE;
g_string_set_size (priv->tentative_match, 0);
priv->tentative_match_len = 0;
priv->compose_buffer[0] = 0;
if (seq)
{
guint16 *prev_seq;
/* Back up to the first sequence that matches to make sure
* we find the exact match if there is one.
*/
while (seq > table->data)
{
prev_seq = seq - row_stride;
if (compare_seq (priv->compose_buffer, prev_seq) != 0)
break;
seq = prev_seq;
}
if (n_compose == table->max_seq_len ||
seq[n_compose] == 0) /* complete sequence */
{
guint16 *next_seq;
gunichar value =
0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1];
/* We found a tentative match. See if there are any longer
* sequences containing this subsequence
*/
next_seq = seq + row_stride;
if (next_seq < table->data + row_stride * table->n_seqs)
{
if (compare_seq (priv->compose_buffer, next_seq) == 0)
{
priv->tentative_match = value;
priv->tentative_match_len = n_compose;
g_signal_emit_by_name (context_simple, "preedit-changed");
return TRUE;
}
}
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
priv->compose_buffer[0] = 0;
}
return TRUE;
}
return FALSE;
g_signal_emit_by_name (context_simple, "preedit-changed");
g_signal_emit_by_name (context_simple, "preedit-end");
g_signal_emit_by_name (context_simple, "commit", str);
}
/* Checks if a keysym is a dead key. Dead key keysym values are defined in
* ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated,
* more dead keys are added and we need to update the upper limit.
* Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with
* a temporary issue in the X.Org header files.
* In future versions it will be just the keysym (no +1).
*/
#define IS_DEAD_KEY(k) \
((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
gboolean
gtk_check_compact_table (const GtkComposeTableCompact *table,
guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
gunichar *output_char)
static void
gtk_im_context_simple_commit_char (GtkIMContextSimple *context_simple,
gunichar ch)
{
int row_stride;
guint16 *seq_index;
guint16 *seq;
int i;
gboolean match;
gunichar value;
char buf[8] = { 0, };
if (compose_finish)
*compose_finish = FALSE;
if (compose_match)
*compose_match = FALSE;
if (output_char)
*output_char = 0;
g_unichar_to_utf8 (ch, buf);
/* Will never match, if the sequence in the compose buffer is longer
* than the sequences in the table. Further, compare_seq (key, val)
* will overrun val if key is longer than val.
*/
if (n_compose > table->max_seq_len)
return FALSE;
seq_index = bsearch (compose_buffer,
table->data,
table->n_index_size,
sizeof (guint16) * table->n_index_stride,
compare_seq_index);
if (!seq_index)
return FALSE;
if (seq_index && n_compose == 1)
return TRUE;
seq = NULL;
match = FALSE;
value = 0;
for (i = n_compose - 1; i < table->max_seq_len; i++)
{
row_stride = i + 1;
if (seq_index[i + 1] - seq_index[i] > 0)
{
seq = bsearch (compose_buffer + 1,
table->data + seq_index[i],
(seq_index[i + 1] - seq_index[i]) / row_stride,
sizeof (guint16) * row_stride,
compare_seq);
if (seq)
{
if (i == n_compose - 1)
{
value = seq[row_stride - 1];
match = TRUE;
}
else
{
if (output_char)
*output_char = value;
if (match)
{
if (compose_match)
*compose_match = TRUE;
}
return TRUE;
}
}
}
}
if (match)
{
if (compose_match)
*compose_match = TRUE;
if (compose_finish)
*compose_finish = TRUE;
if (output_char)
*output_char = value;
return TRUE;
}
return FALSE;
}
/* This function receives a sequence of Unicode characters and tries to
* normalize it (NFC). We check for the case where the resulting string
* has length 1 (single character).
* NFC normalisation normally rearranges diacritic marks, unless these
* belong to the same Canonical Combining Class.
* If they belong to the same canonical combining class, we produce all
* permutations of the diacritic marks, then attempt to normalize.
*/
static gboolean
check_normalize_nfc (gunichar* combination_buffer, int n_compose)
{
gunichar combination_buffer_temp[GTK_MAX_COMPOSE_LEN];
char *combination_utf8_temp = NULL;
char *nfc_temp = NULL;
int n_combinations;
gunichar temp_swap;
int i;
n_combinations = 1;
for (i = 1; i < n_compose; i++ )
n_combinations *= i;
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
* We check if base character belongs to Greek Unicode block,
* and if so, we replace tilde with perispomeni.
*/
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
{
for (i = 1; i < n_compose; i++ )
if (combination_buffer[i] == 0x303)
combination_buffer[i] = 0x342;
}
memcpy (combination_buffer_temp, combination_buffer, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
for (i = 0; i < n_combinations; i++ )
{
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, NULL, NULL, NULL);
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
if (g_utf8_strlen (nfc_temp, -1) == 1)
{
memcpy (combination_buffer, combination_buffer_temp, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
g_free (combination_utf8_temp);
g_free (nfc_temp);
return TRUE;
}
g_free (combination_utf8_temp);
g_free (nfc_temp);
if (n_compose > 2)
{
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
}
else
break;
}
return FALSE;
}
gboolean
gtk_check_algorithmically (const guint16 *compose_buffer,
int n_compose,
gunichar *output_char)
{
int i;
gunichar combination_buffer[GTK_MAX_COMPOSE_LEN];
char *combination_utf8, *nfc;
if (output_char)
*output_char = 0;
if (n_compose >= GTK_MAX_COMPOSE_LEN)
return FALSE;
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
;
if (i == n_compose)
return TRUE;
if (i > 0 && i == n_compose - 1)
{
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
combination_buffer[n_compose] = 0;
i--;
while (i >= 0)
{
switch (compose_buffer[i])
{
#define CASE(keysym, unicode) \
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
CASE (grave, 0x0300);
CASE (acute, 0x0301);
CASE (circumflex, 0x0302);
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
CASE (macron, 0x0304);
CASE (breve, 0x0306);
CASE (abovedot, 0x0307);
CASE (diaeresis, 0x0308);
CASE (hook, 0x0309);
CASE (abovering, 0x030A);
CASE (doubleacute, 0x030B);
CASE (caron, 0x030C);
CASE (abovecomma, 0x0313); /* Equivalent to psili */
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
CASE (belowdot, 0x0323);
CASE (cedilla, 0x0327);
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
CASE (iota, 0x0345);
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
/* The following cases are to be removed once xkeyboard-config,
* xorg are fully updated.
*/
/* Workaround for typo in 1.4.x xserver-xorg */
case 0xfe66: combination_buffer[i+1] = 0x314; break;
/* CASE (dasia, 0x314); */
/* CASE (perispomeni, 0x342); */
/* CASE (psili, 0x343); */
#undef CASE
default:
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
}
i--;
}
/* If the buffer normalizes to a single character, then modify the order
* of combination_buffer accordingly, if necessary, and return TRUE.
*/
if (check_normalize_nfc (combination_buffer, n_compose))
{
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
if (output_char)
*output_char = g_utf8_get_char (nfc);
g_free (combination_utf8);
g_free (nfc);
return TRUE;
}
}
return FALSE;
gtk_im_context_simple_commit_string (context_simple, buf);
}
/* In addition to the table-driven sequences, we allow Unicode hex
@@ -716,7 +358,7 @@ check_hex (GtkIMContextSimple *context_simple,
char *nptr = NULL;
char buf[7];
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
priv->tentative_match_len = 0;
str = g_string_new (NULL);
@@ -756,7 +398,8 @@ check_hex (GtkIMContextSimple *context_simple,
if (g_unichar_validate (n))
{
priv->tentative_match = n;
g_string_set_size (priv->tentative_match, 0);
g_string_append_unichar (priv->tentative_match, n);
priv->tentative_match_len = n_compose;
}
@@ -792,18 +435,25 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
/* No compose sequences found, check first if we have a partial
* match pending.
*/
if (priv->tentative_match)
if (priv->tentative_match_len > 0)
{
int len = priv->tentative_match_len;
int i;
gtk_im_context_simple_commit_char (context, priv->tentative_match);
priv->compose_buffer[0] = 0;
guint16 *compose_buffer;
char *str;
compose_buffer = alloca (sizeof (guint16) * priv->compose_buffer_len);
memcpy (compose_buffer, priv->compose_buffer, sizeof (guint16) * priv->compose_buffer_len);
str = g_strdup (priv->tentative_match->str);
gtk_im_context_simple_commit_string (context_simple, str);
g_free (str);
for (i = 0; i < n_compose - len - 1; i++)
{
{
GdkTranslatedKey translated;
translated.keyval = priv->compose_buffer[len + i];
translated.keyval = compose_buffer[len + i];
translated.consumed = 0;
translated.layout = 0;
translated.level = 0;
@@ -811,7 +461,7 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
gdk_event_get_surface (event),
gdk_event_get_device (event),
gdk_event_get_time (event),
priv->compose_buffer[len + i],
compose_buffer[len + i],
gdk_event_get_modifier_state (event),
FALSE,
&translated,
@@ -831,13 +481,15 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
if (n_compose > 1) /* Invalid sequence */
{
beep_surface (gdk_event_get_surface (event));
g_signal_emit_by_name (context, "preedit-changed");
g_signal_emit_by_name (context, "preedit-end");
return TRUE;
}
ch = gdk_keyval_to_unicode (keyval);
if (ch != 0 && !g_unichar_iscntrl (ch))
{
gtk_im_context_simple_commit_char (context, ch);
gtk_im_context_simple_commit_char (context_simple, ch);
return TRUE;
}
else
@@ -921,7 +573,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
gunichar output_char;
guint keyval, state;
while (priv->compose_buffer[n_compose] != 0)
while (priv->compose_buffer[n_compose] != 0 && n_compose < priv->compose_buffer_len)
n_compose++;
keyval = gdk_key_event_get_keyval (event);
@@ -933,11 +585,11 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
(keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R ||
keyval == GDK_KEY_Shift_L || keyval == GDK_KEY_Shift_R))
{
if (priv->tentative_match &&
g_unichar_validate (priv->tentative_match))
if (priv->tentative_match->len > 0)
{
gtk_im_context_simple_commit_char (context, priv->tentative_match);
priv->compose_buffer[0] = 0;
char *str = g_strdup (priv->tentative_match->str);
gtk_im_context_simple_commit_string (context_simple, str);
g_free (str);
return TRUE;
}
@@ -952,7 +604,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
/* invalid hex sequence */
beep_surface (surface);
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
priv->in_hex_sequence = FALSE;
priv->compose_buffer[0] = 0;
@@ -1036,14 +688,27 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
return TRUE;
}
if (!priv->in_hex_sequence && n_compose > 0 && is_backspace)
{
n_compose--;
priv->compose_buffer[n_compose] = 0;
g_signal_emit_by_name (context_simple, "preedit-changed");
if (n_compose == 0)
g_signal_emit_by_name (context_simple, "preedit-end");
return TRUE;
}
/* Check for hex sequence restart */
if (priv->in_hex_sequence && have_hex_mods && is_hex_start)
{
if (priv->tentative_match &&
g_unichar_validate (priv->tentative_match))
if (priv->tentative_match->len > 0)
{
gtk_im_context_simple_commit_char (context, priv->tentative_match);
priv->compose_buffer[0] = 0;
char *str = g_strdup (priv->tentative_match->str);
gtk_im_context_simple_commit_string (context_simple, str);
g_free (str);
}
else
{
@@ -1051,7 +716,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
if (n_compose > 0)
beep_surface (surface);
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
priv->in_hex_sequence = FALSE;
priv->compose_buffer[0] = 0;
}
@@ -1063,7 +728,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
priv->compose_buffer[0] = 0;
priv->in_hex_sequence = TRUE;
priv->modifiers_dropped = FALSE;
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
g_signal_emit_by_name (context_simple, "preedit-start");
g_signal_emit_by_name (context_simple, "preedit-changed");
@@ -1074,7 +739,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
/* Then, check for compose sequences */
if (priv->in_hex_sequence)
{
if (hex_keyval)
if (hex_keyval && n_compose < 6)
priv->compose_buffer[n_compose++] = hex_keyval;
else if (is_escape)
{
@@ -1083,13 +748,21 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
}
else if (!is_hex_end)
{
/* non-hex character in hex sequence */
/* non-hex character in hex sequence, or sequence too long */
beep_surface (surface);
return TRUE;
}
}
else
priv->compose_buffer[n_compose++] = keyval;
{
if (n_compose + 1 == priv->compose_buffer_len)
{
priv->compose_buffer_len += 1;
priv->compose_buffer = g_renew (guint16, priv->compose_buffer, priv->compose_buffer_len);
}
priv->compose_buffer[n_compose++] = keyval;
}
priv->compose_buffer[n_compose] = 0;
@@ -1101,18 +774,18 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
/* space or return ends the sequence, and we eat the key */
if (n_compose > 0 && is_hex_end)
{
if (priv->tentative_match &&
g_unichar_validate (priv->tentative_match))
if (priv->tentative_match->len > 0)
{
gtk_im_context_simple_commit_char (context, priv->tentative_match);
priv->compose_buffer[0] = 0;
char *str = g_strdup (priv->tentative_match->str);
gtk_im_context_simple_commit_string (context_simple, str);
g_free (str);
}
else
{
/* invalid hex sequence */
beep_surface (surface);
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
priv->in_hex_sequence = FALSE;
priv->compose_buffer[0] = 0;
}
@@ -1131,65 +804,81 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
else
{
gboolean success = FALSE;
GString *output;
output = g_string_new ("");
G_LOCK (global_tables);
tmp_list = global_tables;
while (tmp_list)
{
if (check_table (context_simple, tmp_list->data, n_compose))
if (gtk_compose_table_check ((GtkComposeTable *)tmp_list->data,
priv->compose_buffer, n_compose,
&compose_finish, &compose_match,
output))
{
if (compose_finish)
{
if (compose_match)
gtk_im_context_simple_commit_string (context_simple, output->str);
}
else
{
if (compose_match)
{
g_string_assign (priv->tentative_match, output->str);
priv->tentative_match_len = n_compose;
}
g_signal_emit_by_name (context_simple, "preedit-changed");
}
success = TRUE;
break;
}
tmp_list = tmp_list->next;
}
G_UNLOCK (global_tables);
g_string_free (output, TRUE);
if (success)
return TRUE;
if (gtk_check_compact_table (&gtk_compose_table_compact,
priv->compose_buffer,
n_compose, &compose_finish,
&compose_match, &output_char))
if (gtk_compose_table_compact_check (&gtk_compose_table_compact,
priv->compose_buffer, n_compose,
&compose_finish, &compose_match,
&output_char))
{
if (compose_finish)
{
if (compose_match)
{
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
output_char);
priv->compose_buffer[0] = 0;
}
gtk_im_context_simple_commit_char (context_simple, output_char);
}
else
{
if (compose_match)
{
priv->tentative_match = output_char;
g_string_set_size (priv->tentative_match, 0);
g_string_append_unichar (priv->tentative_match, output_char);
priv->tentative_match_len = n_compose;
}
if (output_char)
g_signal_emit_by_name (context_simple, "preedit-changed");
g_signal_emit_by_name (context_simple, "preedit-changed");
}
return TRUE;
}
if (gtk_check_algorithmically (priv->compose_buffer, n_compose, &output_char))
{
if (output_char)
{
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
output_char);
priv->compose_buffer[0] = 0;
}
return TRUE;
gtk_im_context_simple_commit_char (context_simple, output_char);
return TRUE;
}
}
/* The current compose_buffer doesn't match anything */
return no_sequence_matches (context_simple, n_compose, (GdkEvent *)event);
}
@@ -1202,66 +891,69 @@ gtk_im_context_simple_reset (GtkIMContext *context)
priv->compose_buffer[0] = 0;
if (priv->tentative_match || priv->in_hex_sequence)
if (priv->tentative_match->len > 0 || priv->in_hex_sequence)
{
priv->in_hex_sequence = FALSE;
priv->tentative_match = 0;
g_string_set_size (priv->tentative_match, 0);
priv->tentative_match_len = 0;
g_signal_emit_by_name (context_simple, "preedit-changed");
g_signal_emit_by_name (context_simple, "preedit-end");
}
}
static void
static void
gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
char **str,
PangoAttrList **attrs,
int *cursor_pos)
char **str,
PangoAttrList **attrs,
int *cursor_pos)
{
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
GtkIMContextSimplePrivate *priv = context_simple->priv;
char outbuf[37]; /* up to 6 hex digits */
int len = 0;
GString *s;
int i;
s = g_string_new ("");
if (priv->in_hex_sequence)
{
int hexchars = 0;
outbuf[0] = 'u';
len = 1;
g_string_append_c (s, 'u');
while (priv->compose_buffer[hexchars] != 0)
{
len += g_unichar_to_utf8 (gdk_keyval_to_unicode (priv->compose_buffer[hexchars]),
outbuf + len);
++hexchars;
}
g_assert (len < 25);
for (i = 0; priv->compose_buffer[i]; i++)
g_string_append_unichar (s, gdk_keyval_to_unicode (priv->compose_buffer[i]));
}
else if (priv->tentative_match->len > 0 && priv->compose_buffer[0] != 0)
{
g_string_append (s, priv->tentative_match->str);
}
else
{
for (i = 0; priv->compose_buffer[i]; i++)
{
if (priv->compose_buffer[i] == GDK_KEY_Multi_key)
g_string_append_unichar (s, 0x2384); /* U+2384 COMPOSITION SYMBOL */
else
g_string_append_unichar (s, gdk_keyval_to_unicode (priv->compose_buffer[i]));
}
}
else if (priv->tentative_match)
len = g_unichar_to_utf8 (priv->tentative_match, outbuf);
outbuf[len] = '\0';
if (str)
*str = g_strdup (outbuf);
if (cursor_pos)
*cursor_pos = s->len;
if (attrs)
{
*attrs = pango_attr_list_new ();
if (len)
{
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
attr->start_index = 0;
attr->end_index = len;
pango_attr_list_insert (*attrs, attr);
}
if (s->len)
{
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
attr->start_index = 0;
attr->end_index = s->len;
pango_attr_list_insert (*attrs, attr);
}
}
if (cursor_pos)
*cursor_pos = len;
if (str)
*str = g_string_free (s, FALSE);
}
/**
@@ -1269,7 +961,6 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
* @context_simple: A #GtkIMContextSimple
* @data: (array): the table
* @max_seq_len: Maximum length of a sequence in the table
* (cannot be greater than #GTK_MAX_COMPOSE_LEN)
* @n_seqs: number of sequences in the table
*
* Adds an additional table to search to the input context.
@@ -1313,8 +1004,7 @@ gtk_im_context_simple_add_compose_file (GtkIMContextSimple *context_simple,
G_LOCK (global_tables);
global_tables = gtk_compose_table_list_add_file (global_tables,
compose_file);
global_tables = gtk_compose_table_list_add_file (global_tables, compose_file);
G_UNLOCK (global_tables);
}
+3 -4
View File
@@ -27,10 +27,9 @@
G_BEGIN_DECLS
/**
* GTK_MAX_COMPOSE_LEN:
*
* The maximum length of sequences in compose tables.
/*
* No longer used by GTK, just left here on the off chance that some
* 3rd party code used this define.
*/
#define GTK_MAX_COMPOSE_LEN 7
-42
View File
@@ -1,42 +0,0 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2000 Red Hat Software
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
#define __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
#include <glib.h>
#include "gdk/gdkkeysyms.h"
G_BEGIN_DECLS
extern const GtkComposeTableCompact gtk_compose_table_compact;
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
int n_compose,
gunichar *output);
gboolean gtk_check_compact_table (const GtkComposeTableCompact *table,
guint16 *compose_buffer,
int n_compose,
gboolean *compose_finish,
gboolean *compose_match,
gunichar *output_char);
G_END_DECLS
#endif /* __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__ */
+5 -4
View File
@@ -21,6 +21,7 @@
#include <string.h>
#include <wayland-client-protocol.h>
#include "gtk/gtkdragsourceprivate.h"
#include "gtk/gtkimcontextwayland.h"
#include "gtk/gtkintl.h"
#include "gtk/gtkimmoduleprivate.h"
@@ -524,10 +525,10 @@ released_cb (GtkGestureClick *gesture,
if (global->focused &&
n_press == 1 &&
(hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
!gtk_drag_check_threshold (context->widget,
context->press_x,
context->press_y,
x, y))
!gtk_drag_check_threshold_double (context->widget,
context->press_x,
context->press_y,
x, y))
{
zwp_text_input_v3_enable (global->text_input);
g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
+2 -2
View File
@@ -49,7 +49,7 @@
#include "gtkwidgetprivate.h"
#include "gtkpopovermenu.h"
#include "gtknative.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdragicon.h"
#include "gtkcsscolorvalueprivate.h"
@@ -4273,7 +4273,7 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture,
if (info->in_drag)
{
if (gtk_drag_check_threshold (widget, info->drag_start_x, info->drag_start_y, x, y))
if (gtk_drag_check_threshold_double (widget, info->drag_start_x, info->drag_start_y, x, y))
{
GdkDrag *drag;
GdkSurface *surface;
+3 -3
View File
@@ -23,7 +23,7 @@
#include "gtkadjustment.h"
#include "gtkbitset.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdropcontrollermotion.h"
#include "gtkgesturedrag.h"
#include "gtkgizmoprivate.h"
@@ -1147,7 +1147,7 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
P_("The orientation of the orientable"),
GTK_TYPE_ORIENTATION,
GTK_ORIENTATION_VERTICAL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_EXPLICIT_NOTIFY);
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
@@ -1709,7 +1709,7 @@ gtk_list_base_drag_update (GtkGestureDrag *gesture,
if (!priv->rubberband)
{
if (!gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
if (!gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
return;
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+3 -3
View File
@@ -724,13 +724,13 @@ gtk_list_box_init (GtkListBox *box)
* gtk_list_box_get_selected_row:
* @box: a #GtkListBox
*
* Gets the selected row.
* Gets the selected row, or %NULL if no rows are selected.
*
* Note that the box may allow multiple selection, in which
* case you should use gtk_list_box_selected_foreach() to
* find all selected rows.
*
* Returns: (transfer none): the selected row
* Returns: (transfer none) (nullable): the selected row or %NULL
*/
GtkListBoxRow *
gtk_list_box_get_selected_row (GtkListBox *box)
@@ -746,7 +746,7 @@ gtk_list_box_get_selected_row (GtkListBox *box)
* @index_: the index of the row
*
* Gets the n-th child in the list (not counting headers).
* If @_index is negative or larger than the number of items in the
* If @index_ is negative or larger than the number of items in the
* list, %NULL is returned.
*
* Returns: (transfer none) (nullable): the child #GtkWidget or %NULL
+11 -1
View File
@@ -332,7 +332,7 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
if (!priv->list_item || priv->list_item->activatable)
{
if (n_press == 2 || priv->single_click_activate)
if (n_press == 2 && !priv->single_click_activate)
{
gtk_widget_activate_action (GTK_WIDGET (self),
"list.activate-item",
@@ -356,6 +356,16 @@ gtk_list_item_widget_click_gesture_released (GtkGestureClick *gesture,
{
GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
if (priv->single_click_activate)
{
gtk_widget_activate_action (GTK_WIDGET (self),
"list.activate-item",
"u",
priv->position);
return;
}
if (!priv->list_item || priv->list_item->selectable)
{
GdkModifierType state;
-2
View File
@@ -454,8 +454,6 @@ gtk_message_dialog_init (GtkMessageDialog *dialog)
GtkSettings *settings;
gboolean use_caret;
priv->has_primary_markup = FALSE;
priv->has_secondary_text = FALSE;
priv->has_primary_markup = FALSE;
priv->has_secondary_text = FALSE;
priv->message_type = GTK_MESSAGE_OTHER;
+5
View File
@@ -52,6 +52,11 @@
* various common properties on the dialog, as well as show and hide
* it and get a #GtkNativeDialog::response signal when the user finished
* with the dialog.
*
* Note that unlike #GtkDialog, #GtkNativeDialog objects are not
* toplevel widgets, and GTK does not keep them alive. It is your
* responsibility to keep a reference until you are done with the
* object.
*/
typedef struct _GtkNativeDialogPrivate GtkNativeDialogPrivate;
+10 -7
View File
@@ -50,7 +50,7 @@
#include "gtkstack.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkwidgetpaintable.h"
#include "gtknative.h"
@@ -248,14 +248,14 @@ struct _GtkNotebook
GList *first_tab; /* The first tab visible (for scrolling notebooks) */
GList *focus_tab;
int drag_begin_x;
int drag_begin_y;
double drag_begin_x;
double drag_begin_y;
int drag_offset_x;
int drag_offset_y;
int drag_surface_x;
int drag_surface_y;
int mouse_x;
int mouse_y;
double mouse_x;
double mouse_y;
int pressed_button;
GQuark group;
@@ -2934,8 +2934,11 @@ gtk_notebook_motion (GtkEventController *controller,
if (page->reorderable &&
(notebook->operation == DRAG_OPERATION_REORDER ||
gtk_drag_check_threshold (widget, notebook->drag_begin_x, notebook->drag_begin_y,
notebook->mouse_x, notebook->mouse_y)))
gtk_drag_check_threshold_double (widget,
notebook->drag_begin_x,
notebook->drag_begin_y,
notebook->mouse_x,
notebook->mouse_y)))
{
GtkNotebookPointerPosition pointer_position = get_pointer_position (notebook);
+2 -2
View File
@@ -60,7 +60,7 @@
#include "gtkgestureclick.h"
#include "gtkgesturedrag.h"
#include "gtknative.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdragicon.h"
/*< private >
@@ -3451,7 +3451,7 @@ on_row_dragged (GtkGestureDrag *gesture,
return;
}
if (gtk_drag_check_threshold (GTK_WIDGET (row), 0, 0, x, y))
if (gtk_drag_check_threshold_double (GTK_WIDGET (row), 0, 0, x, y))
{
double start_x, start_y;
double drag_x, drag_y;
+3 -3
View File
@@ -29,7 +29,7 @@
#include "gtkadjustment.h"
#include "gtkadjustmentprivate.h"
#include "gtkbuildable.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerprivate.h"
@@ -953,8 +953,8 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
GtkAdjustment *vadjustment;
double dx, dy;
if (!gtk_drag_check_threshold (GTK_WIDGET (scrolled_window),
0, 0, offset_x, offset_y))
if (!gtk_drag_check_threshold_double (GTK_WIDGET (scrolled_window),
0, 0, offset_x, offset_y))
return;
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
+1 -1
View File
@@ -139,7 +139,7 @@ gtk_show_uri_full (GtkWindow *parent,
* @result: #GAsyncResult that was passed to @callback
* @error: return location for an error
*
* Finished the gtk_show_uri() call and returns the result
* Finishes the gtk_show_uri() call and returns the result
* of the operation.
*
* Returns: %TRUE if the URI was shown successfully.
+2 -4
View File
@@ -29,7 +29,7 @@
#include "gtkbutton.h"
#include "gtkdebug.h"
#include "gtkdragicon.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdroptarget.h"
#include "gtkeditable.h"
#include "gtkemojichooser.h"
@@ -2941,9 +2941,7 @@ gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
if (priv->in_drag)
{
if (gtk_text_get_display_mode (self) == DISPLAY_NORMAL &&
gtk_drag_check_threshold (widget,
priv->drag_start_x, priv->drag_start_y,
x, y))
gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
{
int *ranges;
int n_ranges;
+2 -2
View File
@@ -257,8 +257,8 @@ static void gtk_text_btree_rebalance (GtkTextBTree
static GtkTextLine * get_last_line (GtkTextBTree *tree);
static void post_insert_fixup (GtkTextBTree *tree,
GtkTextLine *insert_line,
int char_count_delta,
int line_count_delta);
int line_count_delta,
int char_count_delta);
static void gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode *node,
GtkTextTagInfo *info,
int adjust);
+3 -2
View File
@@ -32,6 +32,7 @@
#include "gtkadjustmentprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkdebug.h"
#include "gtkdragsourceprivate.h"
#include "gtkdropcontrollermotion.h"
#include "gtkintl.h"
#include "gtkmain.h"
@@ -7232,7 +7233,7 @@ gtk_text_view_drag_gesture_update (GtkGestureDrag *gesture,
/* If no data is attached, the initial press happened within the current
* text selection, check for drag and drop to be initiated.
*/
if (gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
if (gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
{
if (!is_touchscreen)
{
@@ -7366,7 +7367,7 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
if ((is_touchscreen || clicked_in_selection) &&
!gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
!gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
{
GtkTextIter iter;
-3
View File
@@ -3285,9 +3285,6 @@ gtk_tree_model_filter_iter_children (GtkTreeModel *model,
return TRUE;
}
iter->stamp = 0;
return FALSE;
}
static gboolean
+2 -2
View File
@@ -28,7 +28,7 @@
#include "gtkcellrenderer.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkdragicon.h"
#include "gtkdroptargetasync.h"
#include "gtkentryprivate.h"
@@ -7052,7 +7052,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (priv->drag_gesture),
&offset_x, &offset_y);
if (!gtk_drag_check_threshold (widget, 0, 0, offset_x, offset_y))
if (!gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
goto out;
model = gtk_tree_view_get_model (tree_view);
+2 -2
View File
@@ -24,7 +24,7 @@
#include "gtkcellareabox.h"
#include "gtkcellareacontext.h"
#include "gtkcelllayout.h"
#include "gtkdragsource.h"
#include "gtkdragsourceprivate.h"
#include "gtkframe.h"
#include "gtkimage.h"
#include "gtkintl.h"
@@ -1072,7 +1072,7 @@ column_button_drag_update (GtkGestureDrag *gesture,
{
GtkTreeViewColumnPrivate *priv = column->priv;
if (gtk_drag_check_threshold (priv->button, 0, 0, offset_x, offset_y))
if (gtk_drag_check_threshold_double (priv->button, 0, 0, offset_x, offset_y))
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
_gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column,
+1 -34
View File
@@ -257,7 +257,7 @@
* custom `<layout>` element, used to define layout properties:
*
* |[<!-- language="xml" -->
* <object class="MyGrid" id="grid1">
* <object class="GtkGrid" id="my_grid">
* <child>
* <object class="GtkLabel" id="label1">
* <property name="label">Description</property>
@@ -11304,39 +11304,6 @@ gtk_widget_remove_controller (GtkWidget *widget,
gtk_list_list_model_item_removed (priv->controller_observer, before);
}
gboolean
gtk_widget_consumes_motion (GtkWidget *widget,
GtkWidget *parent,
GdkEventSequence *sequence)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
while (widget != NULL && widget != parent)
{
GList *l;
for (l = priv->event_controllers; l; l = l->next)
{
GtkEventController *controller = l->data;
if (controller == NULL ||
!GTK_IS_GESTURE (controller))
continue;
if ((!GTK_IS_GESTURE_SINGLE (controller) ||
GTK_IS_GESTURE_DRAG (controller) ||
GTK_IS_GESTURE_SWIPE (controller)) &&
gtk_gesture_handles_sequence (GTK_GESTURE (controller), sequence))
return TRUE;
}
widget = priv->parent;
priv = gtk_widget_get_instance_private (widget);
}
return FALSE;
}
void
gtk_widget_reset_controllers (GtkWidget *widget)
{
-4
View File
@@ -278,10 +278,6 @@ void _gtk_widget_update_parent_muxer (GtkWidget *widget
GtkActionMuxer * _gtk_widget_get_action_muxer (GtkWidget *widget,
gboolean create);
gboolean gtk_widget_consumes_motion (GtkWidget *widget,
GtkWidget *parent,
GdkEventSequence *sequence);
gboolean gtk_widget_has_tick_callback (GtkWidget *widget);
gboolean gtk_widget_has_size_request (GtkWidget *widget);
+6 -57
View File
@@ -24,6 +24,7 @@
#include "gtkbinlayout.h"
#include "gtkbox.h"
#include "gtkbuildable.h"
#include "gtkdragsourceprivate.h"
#include "gtkgestureclick.h"
#include "gtkgesturedrag.h"
#include "gtkgestureprivate.h"
@@ -60,7 +61,6 @@ struct _GtkWindowHandle {
GtkGesture *click_gesture;
GtkGesture *drag_gesture;
GtkGesture *bubble_drag_gesture;
GtkWidget *child;
GtkWidget *fallback_menu;
@@ -389,47 +389,14 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
double offset_y,
GtkWindowHandle *self)
{
int double_click_distance;
GtkSettings *settings;
settings = gtk_widget_get_settings (GTK_WIDGET (self));
g_object_get (settings,
"gtk-double-click-distance", &double_click_distance,
NULL);
if (ABS (offset_x) > double_click_distance ||
ABS (offset_y) > double_click_distance)
if (gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
{
GdkEventSequence *sequence;
double start_x, start_y;
double native_x, native_y;
double window_x, window_y;
GtkNative *native;
GdkSurface *surface;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (gtk_event_controller_get_propagation_phase (GTK_EVENT_CONTROLLER (gesture)) == GTK_PHASE_CAPTURE)
{
GtkWidget *event_widget = gtk_gesture_get_last_target (GTK_GESTURE (gesture), sequence);
/* Check whether the target widget should be left alone at handling
* the sequence, this is better done late to give room for gestures
* there to go denied.
*
* Besides claiming gestures, we must bail out too if there's gestures
* in the "none" state at this point, as those are still handling events
* and can potentially go claimed, and we don't want to stop the target
* widget from doing anything.
*/
if (event_widget != GTK_WIDGET (self) &&
gtk_widget_consumes_motion (event_widget, GTK_WIDGET (self), sequence))
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
}
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
@@ -458,19 +425,6 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
}
}
static GtkGesture *
create_drag_gesture (GtkWindowHandle *self)
{
GtkGesture *gesture;
gesture = gtk_gesture_drag_new ();
g_signal_connect (gesture, "drag-update",
G_CALLBACK (drag_gesture_update_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
return gesture;
}
static void
gtk_window_handle_unrealize (GtkWidget *widget)
{
@@ -562,19 +516,14 @@ gtk_window_handle_init (GtkWindowHandle *self)
{
self->click_gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->click_gesture), 0);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->click_gesture),
GTK_PHASE_BUBBLE);
g_signal_connect (self->click_gesture, "pressed",
G_CALLBACK (click_gesture_pressed_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->click_gesture));
self->drag_gesture = create_drag_gesture (self);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->drag_gesture),
GTK_PHASE_CAPTURE);
self->bubble_drag_gesture = create_drag_gesture (self);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->bubble_drag_gesture),
GTK_PHASE_BUBBLE);
self->drag_gesture = gtk_gesture_drag_new ();
g_signal_connect (self->drag_gesture, "drag-update",
G_CALLBACK (drag_gesture_update_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drag_gesture));
}
static GtkBuildableIface *parent_buildable_iface;
+7 -6
View File
@@ -66,6 +66,7 @@ gtk_private_sources = files([
'gtkcssimageconic.c',
'gtkcssimagecrossfade.c',
'gtkcssimagefallback.c',
'gtkcssimagefilter.c',
'gtkcssimageicontheme.c',
'gtkcssimageinvalid.c',
'gtkcssimagelinear.c',
@@ -1142,12 +1143,6 @@ if build_gir
# the installed one
gdk_gir_inc = [ 'cairo-1.0', 'Gio-2.0', ]
if graphene_dep.type_name() == 'internal'
gdk_gir_inc += subproject('graphene').get_variable('graphene_gir').get(0)
else
gdk_gir_inc += 'Graphene-1.0'
endif
if pixbuf_dep.type_name() == 'internal'
gdk_gir_inc += subproject('gdk-pixbuf').get_variable('gdkpixbuf_gir').get(0)
else
@@ -1211,6 +1206,12 @@ if build_gir
gsk_gir_inc = [ gdk_gir[0] ]
if graphene_dep.type_name() == 'internal'
gsk_gir_inc += subproject('graphene').get_variable('graphene_gir').get(0)
else
gsk_gir_inc += 'Graphene-1.0'
endif
gsk_gir = gnome.generate_gir(libgtk,
sources: gsk_public_headers + gsk_public_sources + [ gskenum_h ],
namespace: 'Gsk',
+8
View File
@@ -933,6 +933,14 @@ list > row button.image-button:not(.flat) {
&:hover { @include button(hover); }
&:active,
&:checked { @include button(active); }
@each $b_type, $b_color in (suggested-action, $selected_bg_color),
(destructive-action, $destructive_color) {
&.#{$b_type} { // allow colored buttons in lists #3643
@include button(normal, $b_color, white);
@include focus-ring($fc: $alt_focus_border_color);
}
}
}
/*********
+7
View File
@@ -85,6 +85,13 @@ gtk_library_version = '1.@0@.@1@'.format(gtk_binary_age - gtk_interface_age, gtk
gtk_api_version = '4.0'
module_suffix = []
# GModule requires file extension to be .so, not .dylib on Mac.
# https://gitlab.gnome.org/GNOME/glib/issues/520
if ['darwin', 'ios'].contains(host_machine.system())
module_suffix = 'so'
endif
x11_enabled = get_option('x11-backend')
wayland_enabled = get_option('wayland-backend')
broadway_enabled = get_option('broadway-backend')
+2
View File
@@ -35,6 +35,7 @@ if ffmpeg_found
sources: 'gtkffmediafile.c',
c_args: extra_c_args,
dependencies: [ libgtk_dep, ffmpeg_deps ],
name_suffix: module_suffix,
install_dir: media_install_dir,
install: true,
)
@@ -56,6 +57,7 @@ if gstplayer_dep.found() and gstgl_dep.found()
],
c_args: extra_c_args,
dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ],
name_suffix: module_suffix,
install_dir: media_install_dir,
install: true,
)
+4
View File
@@ -22,6 +22,7 @@ if cups_dep.found()
],
c_args: printbackends_args,
dependencies: [libgtk_dep, cups_dep, colord_dep],
name_suffix: module_suffix,
install_dir: printbackends_install_dir,
install: true,
)
@@ -32,6 +33,7 @@ else
sources: 'gtkprintbackendlpr.c',
c_args: printbackends_args,
dependencies: libgtk_dep,
name_suffix: module_suffix,
install_dir: printbackends_install_dir,
install: true,
)
@@ -49,6 +51,7 @@ if rest_dep.found() and json_glib_dep.found()
],
c_args: printbackends_args,
dependencies: [ libgtk_dep, rest_dep, json_glib_dep ],
name_suffix: module_suffix,
install_dir: printbackends_install_dir,
install: true)
endif
@@ -59,6 +62,7 @@ shared_module('printbackend-file',
sources: 'gtkprintbackendfile.c',
c_args: printbackends_args,
dependencies: libgtk_dep,
name_suffix: module_suffix,
install_dir: printbackends_install_dir,
install: true,
)
+468 -458
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -97,7 +97,7 @@ msgstr "Backspace"
#: gdk/keyname-table.h:6844
msgctxt "keyboard label"
msgid "Tab"
msgstr "Tabulátor"
msgstr "Tab"
#: gdk/keyname-table.h:6845
msgctxt "keyboard label"
@@ -122,7 +122,7 @@ msgstr "Sys_Req"
#: gdk/keyname-table.h:6849
msgctxt "keyboard label"
msgid "Escape"
msgstr "Escape"
msgstr "Esc"
#: gdk/keyname-table.h:6850
msgctxt "keyboard label"
+186 -322
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
[Test]
Exec=/bin/sh -c "env G_ENABLE_DIAGNOSTIC=0 GTK_A11Y=test @libexecdir@/installed-tests/gtk-4.0/css/data --tap -k"
Type=session
Output=TAP
+25 -2
View File
@@ -6,6 +6,7 @@ csstest_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
csstest_env.set('GIO_USE_VFS', 'local')
csstest_env.set('GSETTINGS_BACKEND', 'memory')
csstest_env.set('G_ENABLE_DIAGNOSTIC', '0')
csstest_env.set('GDK_DEBUG', 'default-settings')
subdir('parser')
subdir('nodes')
@@ -29,10 +30,10 @@ test('api', test_api,
suite: 'css',
)
test_data = executable('data', ['data.c', '../../gtk/css/gtkcssdataurl.c'],
test_data = executable('data', 'data.c',
c_args: common_cflags,
include_directories: [confinc, ],
dependencies: gtk_deps,
dependencies: libgtk_static_dep,
install: get_option('install-tests'),
install_dir: testexecdir,
)
@@ -44,6 +45,20 @@ test('data', test_data,
suite: 'css',
)
transition = executable('transition', 'transition.c',
c_args: common_cflags,
dependencies: libgtk_static_dep,
install: get_option('install-tests'),
install_dir: testexecdir,
)
test('transition', transition,
args: [ '--tap', '-k' ],
protocol: 'tap',
env: csstest_env,
suite: 'css'
)
if get_option('install-tests')
conf = configuration_data()
conf.set('libexecdir', gtk_libexecdir)
@@ -52,6 +67,14 @@ if get_option('install-tests')
configuration: conf,
install_dir: testdatadir,
)
conf = configuration_data()
conf.set('libexecdir', gtk_libexecdir)
configure_file(input: 'data.test.in',
output: 'data.test',
configuration: conf,
install_dir: testdatadir,
)
endif
if false and get_option ('profiler')
@@ -74,3 +74,11 @@ r {
s {
background-image: -gtk-scaled(-gtk-icontheme("object-select-symbolic"),linear-gradient(yellow, blue));
}
t {
background-image: cross-fade(10% image(red), 20% image(yellow), linear-gradient(blue, black));
}
u {
background-image: filter(url("test.png"), grayscale(100%) invert(50%));
}
@@ -73,3 +73,11 @@ r {
s {
background-image: -gtk-scaled(-gtk-icontheme("object-select-symbolic"),1,linear-gradient(rgb(255,255,0), rgb(0,0,255)),2);
}
t {
background-image: cross-fade(10% image(rgb(255,0,0)), 20% image(rgb(255,255,0)), linear-gradient(rgb(0,0,255), rgb(0,0,0)));
}
u {
background-image: filter(none /* FIXME */,grayscale(100%) invert(50%));
}
+3
View File
@@ -0,0 +1,3 @@
a {
filter: blur(-1px);
}
@@ -0,0 +1 @@
filter-invalid1.css:2:16-20: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: brightness(-100%);
}
@@ -0,0 +1 @@
filter-invalid2.css:2:22-27: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: contrast(-100%);
}
@@ -0,0 +1 @@
filter-invalid3.css:2:20-25: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: grayscale(-100%);
}
@@ -0,0 +1 @@
filter-invalid4.css:2:21-26: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: invert(-100%);
}
@@ -0,0 +1 @@
filter-invalid5.css:2:18-23: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: opacity(-100%);
}
@@ -0,0 +1 @@
filter-invalid6.css:2:19-24: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: saturate(-100%);
}
@@ -0,0 +1 @@
filter-invalid7.css:2:20-25: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: sepia(-100%);
}
@@ -0,0 +1 @@
filter-invalid8.css:2:17-22: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
+3
View File
@@ -0,0 +1,3 @@
a {
filter: drop-shadow(none);
}
@@ -0,0 +1 @@
filter-invalid9.css:2:23-27: error: GTK_CSS_PARSER_ERROR_SYNTAX
+23
View File
@@ -0,0 +1,23 @@
a {
filter: initial;
}
b {
filter: inherit;
}
c {
filter: unset;
}
d {
filter: none;
}
e {
filter: blur(2px) brightness(20%) contrast(120%) grayscale(100%) hue-rotate(45deg) invert(50%) opacity(25%) saturate(90%) sepia(100%);
}
f {
filter: drop-shadow(rgb(255,0,0) 1px 2px);
}

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