Compare commits

..

322 Commits

Author SHA1 Message Date
Matthias Clasen
a59ef54dc8 searchengine: Implement GListModel
This is a quick attempt to turn GtkSearchEngine
into a GListModel.
2020-06-11 00:41:50 -04:00
Matthias Clasen
63692a491d Merge branch 'michaelweghorn/master_issue1820_gtkfilechoosernative_get_filter' into 'master'
filechoosernative: Make get_filter work for (non-portal) native chooser (master, issue #1820)

Closes #1820

See merge request GNOME/gtk!2069
2020-06-10 14:47:36 +00:00
Emmanuele Bassi
bbe79c1ef9 Merge branch 'wip/carlosg/zoom-no-touchpad-warnings' into 'master'
gtkgesturezoom: Do not check touchpad phase on generic events

Closes #2825

See merge request GNOME/gtk!2071
2020-06-10 14:35:10 +00:00
Matthias Clasen
4b241f8da2 Merge branch 'scroll-compression' into 'master'
gdk: Compress scroll events

Closes #2800

See merge request GNOME/gtk!2066
2020-06-10 14:35:01 +00:00
Matthias Clasen
bdd6ae3252 Merge branch 'device-cleanup' into 'master'
Device cleanup

See merge request GNOME/gtk!2068
2020-06-10 13:06:13 +00:00
sicklylife
24a3ff3aef Update Japanese translation 2020-06-10 12:34:42 +00:00
Carlos Garnacho
ba988cd899 gtkgesturezoom: Do not check touchpad phase on generic events
This gesture handles both individual touch events and touchpad gesture
events, and was checking the touchpad phase in generic code paths. This
is dubious since event methods error out on the wrong GdkEventTypes.

Check the touchpad gesture phase within the branch handling touchpad
events, and make it clear which is the gesture phase of all that we are
ignoring.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2825
2020-06-10 14:30:58 +02:00
sicklylife
1bf1646d25 Update Japanese translation 2020-06-10 12:18:55 +00:00
Matthias Clasen
2c82151d65 gdk: Drop axis labels
This was only ever implemented on X11, and the labels
here were atom names, so unlikely to be useful for
anything interesting.
2020-06-10 07:36:30 -04:00
Alexander Larsson
d2235b71f3 Merge branch 'win32-use-g-stat' into 'master'
gtkiconcache: Use g_stat instead of fstat

See merge request GNOME/gtk!2019
2020-06-10 07:19:22 +00:00
Michael Weghorn
57135acd2d filechoosernative: Make get_filter work for (non-portal) native chooser
'gtk_file_chooser_get_filter' did not work for GtkFileChooserNative,
since the previous way did not properly handle the delegate dialog,
s.a. commit a136cbae8f
("filechoosernative: forward current_filter to delegate dialog",
2018-11-29) for details, wich basiscally fixed the same thing for
the 'gtk_file_chooser_set_filter' case.

This fixes #1820 for the fallback dialog. A solution for the portal
one (which also requires changes to xdg-desktop-portal and
xdg-desktop-portal-gtk as well) will be suggested in a subsequent step.

Bug: #1820
2020-06-09 22:59:34 +02:00
Matthias Clasen
54c098761f gdk: Drop gdk_device_set_axis_use
If you need some axes changed, you can just flip
the values when you receive them.
2020-06-09 15:27:34 -04:00
Matthias Clasen
2f98400b80 gdk: Drop gdk_device_get/set_keys
This functionality was only ever half-implemented
on X11, and is not useful enough to keep around.
2020-06-09 15:27:33 -04:00
Matthias Clasen
ea7c9b93ea x11: Stop setting device keys
This is very vestigial functionality, and basically
unused.
2020-06-09 15:05:55 -04:00
Matthias Clasen
4317c008f0 Address review comments
We were casting scroll events to motion events
rather carelessly. Don't do that.
2020-06-09 14:13:22 -04:00
Matthias Clasen
d605d9ae73 gdk: Add documentation
Add some useful information about event history.
2020-06-09 13:59:26 -04:00
Matthias Clasen
c9fad25131 gdk: Rename gdk_motion_event_get_history
Scroll events can have history too, so make a
getter that works for both. This drops the
gdk_scroll_event_get_history getter that was
added a few commits earlier, since we now
store scroll history in the same way as
motion history.

Update the docs, and all callers.
2020-06-09 13:43:12 -04:00
Matthias Clasen
693200f1eb gdk: Shrink GdkTimeCoord
There is really no need to store 128 doubles as axes,
ever. We can do just fine with 10. At the same time,
add a GdkAxisFlags member, so we can interpret the
values without having to go chasing the right device
for this information.
2020-06-09 13:43:03 -04:00
Matthias Clasen
5f087a9dff gdk: Add scroll delta x/y as device axes
They really are axes, and having them present
in these enums lets use store delta values in
GdkTimeCoord for keeping history.
2020-06-09 13:43:03 -04:00
Matthias Clasen
b9cde6f8ea Keep scroll history
Similar to how we keep motion history for compressed
events, keep scroll history for compressed scroll
events.
2020-06-09 13:43:03 -04:00
Matthias Clasen
86eece78b1 gdk: Compress scroll events
Only return one accumulated scroll event per frame.
Compress them by adding up the deltas.

Still missing: a way to capture history, like
we do for motion events.

Fixes: #2800
2020-06-09 13:43:03 -04:00
Daniel Mustieles
8cb50ac6e9 Updated Spanish translation 2020-06-09 17:19:50 +02:00
Matthias Clasen
997fbbde8f Merge branch 'drop-device-history' into 'master'
Drop device history

See merge request GNOME/gtk!2065
2020-06-08 23:56:30 +00:00
Matthias Clasen
805ddc3c3a gdk: Drop gdk_device_get_history
This function is not implemented anywhere.
2020-06-08 18:24:20 -04:00
Matthias Clasen
da9b3a9256 win32: Drop pointless vfuncs
These are not useful.
2020-06-08 18:24:20 -04:00
Matthias Clasen
876560924f wayland: Drop a pointless vfunc
A vfunc that just returns FALSE is not useful.
2020-06-08 18:24:20 -04:00
Matthias Clasen
ca1c89c5bd broadway: Drop a pointless vfunc
A vfunc that just returns FALSE is not useful.
2020-06-08 18:24:20 -04:00
Jordi Mas
7875e28d9f Update Catalan translation 2020-06-08 22:50:03 +02:00
Benjamin Otte
bd2f2a6f65 Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2064
2020-06-08 18:43:31 +00:00
Benjamin Otte
541aaa2392 selectionmodel: Add unselect_rest argument to select_callback
This is not just about consistency with other functions.

It is about avoiding reentrancy problems.

GtkListBase first doing an unselect_all() will then force the
SelectionModel to consider a state where all items are unselected
(and potentially deciding to autoselect one) and then cause a
"selection-changed" emission that unselects all items and potentially
updates all the list item widgets in the GtkListBase to the unselected
state.

After this, GtkListBase selects new items, but to the SelectionModel and
the list item widgets this looks like an enitrely new operation and
there is no way to associate it with the previous state, so the
SelectionModel cannot undo any previous actions it took when
unselecting.
And all listitem widgets will now think they were just selected and
start running animations about selecting.
2020-06-08 19:06:56 +02:00
Benjamin Otte
d294b01cee selectionmodel: Rename "exclusive" to "unselect_rest"
The name is better at explaining what this boolean is meant to do.
2020-06-08 18:26:48 +02:00
Benjamin Otte
5d9dc25115 listitemmanager: Update selections properly
Replace a previous fix with a more correct one: Update the
selected state from the model instead of reusing the old state, the
model might have updated the selected state.
2020-06-08 18:14:24 +02:00
Daniel Mustieles
c8988ec784 Updated Spanish translation 2020-06-08 17:21:58 +02:00
Daniel Mustieles
071dbc1115 Updated Spanish translation 2020-06-08 16:11:28 +02:00
Matthias Clasen
80c5e4a156 Merge branch 'matthiasc/for-master' into 'master'
dropdown: Use our own CSS name

See merge request GNOME/gtk!2061
2020-06-08 11:15:28 +00:00
Emmanuele Bassi
6eac3063fa Merge branch 'tintou/places-sidebar-cloudproviders' into 'master'
placessidebar: Fix build with libcloudproviders

See merge request GNOME/gtk!2062
2020-06-08 09:35:23 +00:00
Corentin Noël
27925fcb0e placessidebar: Fix build with libcloudproviders
Make it build with cloudproviders=true as the GtkPopover API for menus is now in GtkPopoverMenu.

Fix some leaks while looking at the code.
2020-06-08 10:40:46 +02:00
Matthias Clasen
5f4d21422a Merge branch 'fix-cell-editing' into 'master'
Fix cell editing

Closes #2831

See merge request GNOME/gtk!2060
2020-06-07 14:54:37 +00:00
Matthias Clasen
b0bb413faa dropdown: Use our own CSS name
Use the name dropdown for the css node, and document it.
2020-06-07 09:01:20 -04:00
Matthias Clasen
37633985bd Drop gtknativeprivate.h
No need to ship empty headers.
2020-06-07 08:52:45 -04:00
Matthias Clasen
6ff8f1b2fd Merge branch 'gtk-demo-tweaks' into 'master'
Gtk demo tweaks

See merge request GNOME/gtk!2059
2020-06-07 12:51:34 +00:00
Matthias Clasen
d13a3c7540 Fix cell editing
When translating coordinates from an event, we need to
take the surface transform into account. This makes
double-clicking on editable cells in treeviews work
again.

Fixes: #2831
2020-06-07 08:46:31 -04:00
Yuri Chornoivan
0a469d7bd6 Update Ukrainian translation 2020-06-07 08:51:44 +00:00
Piotr Drąg
115edc5fd1 Update POTFILES.in 2020-06-07 09:27:34 +02:00
Matthias Clasen
a28c75f215 gtk-demo: Expand the sidebar by default
Seems better to show what we have. Plus, clicking
those arrows is a little fiddly.
2020-06-06 22:12:12 -04:00
Matthias Clasen
b9d7dab329 gtk-demo: Improve display of image sources
Make the images expand to fill the space.
2020-06-06 22:12:12 -04:00
Matthias Clasen
bb7500e984 gtk-demo: Cosmetics
Tweak the formatting of the descriptions of
various demos.
2020-06-06 22:05:52 -04:00
Matthias Clasen
e94268944b gtk-demo: Cosmetics
Make the titles of some demos match between sidebar
and window.
2020-06-06 21:42:42 -04:00
Emmanuele Bassi
3225b487e8 Merge branch 'ebassi/for-master' into 'master'
Annotate the GtkSelectionModel callbacks

See merge request GNOME/gtk!2057
2020-06-07 01:42:21 +00:00
Matthias Clasen
e35c0e043e gtk-demo: Add overline to the markup demo
This is a new-ish Pango feature.
2020-06-06 21:38:31 -04:00
Matthias Clasen
b251893030 Drop pango version checks
We are requiring pango 1.45.0 now, so no need to
Keep these ifdefs in the code any longer.
2020-06-06 21:32:55 -04:00
Matthias Clasen
15257e3922 gtk-demo: Fix a leak
The themes demo was leaking its builder, and
therefore couldn't be closed.
2020-06-06 20:09:42 -04:00
Matthias Clasen
180a5a1ad7 gtk-demo: Cosmetic changes to the dropdown demo
Match the window title and the sidebar.
2020-06-06 20:08:50 -04:00
Matthias Clasen
11f971d870 gtk-demo: Cosmetic improvements to clocks demo
Reformat the code comments, and add a 10th clock.
2020-06-06 19:43:21 -04:00
Emmanuele Bassi
7c382c6b47 Annotate the GtkSelectionModel callbacks
We need a scope for the select and unselect callback arguments.
2020-06-07 00:39:33 +01:00
Jordi Mas
087f42d998 Update Catalan translation 2020-06-06 23:13:17 +02:00
Matthias Clasen
2abb5b6419 3.98.5 2020-06-06 16:03:38 -04:00
Matthias Clasen
f2259adcdc Disable a failing test
For some reason, empty-linear-gradient is failing here,
with the broadway and opengl renderers, and I don't
know why. Disable it for now.
2020-06-06 15:32:26 -04:00
Matthias Clasen
a73457237d Skip broken a11y tests 2020-06-06 14:18:44 -04:00
Matthias Clasen
9f335d3ee6 docs: Regroup the tree support parts
Give the chapter a title, and put some things in sections.
2020-06-06 13:54:58 -04:00
Matthias Clasen
856c8950ff docs: Put selection models into a section
This makes the documentation structure a bit clearer.
2020-06-06 13:54:58 -04:00
Matthias Clasen
61ccf4e719 docs: Fix up the GtkNativeDialog section
Without GtkNativeDialog in the section list,
links are not generated from the object hierarchy.
2020-06-06 13:54:58 -04:00
Matthias Clasen
1567db1f02 Merge branch 'misc-multiselection' into 'master'
Misc multiselection

See merge request GNOME/gtk!2055
2020-06-06 17:54:42 +00:00
Matthias Clasen
8316d5e366 Merge branch 'list-arrows' into 'master'
listbase: Make up/down arrows work

See merge request GNOME/gtk!2056
2020-06-06 17:47:05 +00:00
Matthias Clasen
8fca040163 Merge branch 'property-selection' into 'master'
Property selection

Closes #2826

See merge request GNOME/gtk!2054
2020-06-06 17:35:05 +00:00
Matthias Clasen
c0fe1a7ffe listbase: Make up/down arrows work
We were missing a binding for up/down without modifiers.
2020-06-06 12:33:12 -04:00
Matthias Clasen
e72c243aca singleselection: Clarify docs
Mention persistence and sorting.
2020-06-06 11:53:33 -04:00
Matthias Clasen
14605d4b92 gtk-demo: Use a property selection in the colors demo
This makes the property persist across sort changes.
2020-06-06 11:41:51 -04:00
Matthias Clasen
d1509971d8 Add GtkPropertySelection
This is a selection model that stores the selection
state in a boolean property of the items, and thus
persists across reordering and similar changes.

Fixes: #2826
2020-06-06 11:41:51 -04:00
Matthias Clasen
951c9c5d73 Merge branch 'listitemmanager-selection' into 'master'
listitemmanager: Handle selection-changes properly

Closes #2827

See merge request GNOME/gtk!2053
2020-06-06 15:23:40 +00:00
Matthias Clasen
3e6e247e56 multiselection: Rewrite the select_callback implementation
Use a for loop to make this more obvious, and add some
assertions that the callback is behaving properly.
2020-06-06 11:22:48 -04:00
Matthias Clasen
27ce68b74a Add tests for select_callback 2020-06-06 11:22:48 -04:00
Matthias Clasen
b0cf7a95b0 Add a forgotten export
gtk_selection_model_unselect_callback needs to be exported.
2020-06-06 11:22:48 -04:00
Matthias Clasen
fd7f19c934 selectionmodel: Document the callback apis 2020-06-06 10:36:57 -04:00
Matthias Clasen
8090e213de Add a test for multiselection persistence
Add a test that verifies that newly added items
are always unselected.
2020-06-06 10:24:14 -04:00
Matthias Clasen
de6327a885 multiselection: Clarify docs
Make it clear that GtkMultiSelection is not persistent
across resorting.
2020-06-06 10:24:14 -04:00
Yuri Chornoivan
8699c0f340 Update Ukrainian translation 2020-06-06 13:46:40 +00:00
Yuri Chornoivan
bda5454549 Update Ukrainian translation 2020-06-06 13:44:29 +00:00
Matthias Clasen
c3a6e35070 Drop an unnecessary include 2020-06-06 09:39:36 -04:00
Matthias Clasen
71c29bfcff listitemmanager: Handle selection-changes properly
The selection model will only emit one of items-changed
or selection-changed, so when we handle an items-changed,
we must assume that selection state may have changed for
any of the newly added items.

This fixes lingering selection state in the visible range
if you change the sorting of the colors demo.

Fixes: #2827
2020-06-06 08:36:11 -04:00
Piotr Drąg
647ed59d11 Update POTFILES.in and POTFILES.skip 2020-06-06 14:00:43 +02:00
Matthias Clasen
a0c489048a Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2052
2020-06-06 05:30:30 +00:00
Benjamin Otte
0f9def660d Merge branch 'wip/otte/for-master' into 'master'
multiselection: Remove unused code

See merge request GNOME/gtk!2051
2020-06-06 05:16:47 +00:00
Matthias Clasen
9fa65eadae listitemwidget: Don't look at rubberbanding
Move the selection changes to button release, to
avoid conflict with the drag gesture for rubberbanding.
This avoids peeking at the parent, and is generally
nicer.

Among other things, you can now shift-click to select
a range in the colors demo in gtk4-demo.
2020-06-06 00:23:04 -04:00
Matthias Clasen
facfff0022 listbase: Fix an off-by-one error
We were accidentally cutting off the set one-too-early,
which showed up as single clicks not selecting an item
anymore.
2020-06-06 00:15:50 -04:00
Matthias Clasen
f8b4083f47 listbase: Fix a problem with rubberbands
When I changed things to only collect the set
in the stop() function, I overlooked that this
has the side-effect of only handling items which
are backed by a widget at the time stop() is called.
If we make a big rubberband and autoscroll down too
far, we loose the items that go out the visible range
at the top. Fix that by maintaining the set as we go.
2020-06-05 23:18:00 -04:00
Matthias Clasen
b047b7838d multiselection: Don't emit nonsensical signals
I forgot to add a check here. We only want to emit
a ::selection-changed if we actually changed it.
2020-06-05 23:15:20 -04:00
Benjamin Otte
b1c00ecee6 multiselection: Remove unused code
This is leftover code from an earlier SelectionModel API.
2020-06-06 05:02:37 +02:00
Matthias Clasen
93abd8da59 NEWS: Updates 2020-06-05 22:50:30 -04:00
Matthias Clasen
3412f0554f gtk: Documentation fixups
Document missing symbols, and other cleanups.
2020-06-05 22:50:30 -04:00
Matthias Clasen
61c83f9ffe gdk: Documentation fixups
Document some missing symbols.
2020-06-05 20:59:51 -04:00
Matthias Clasen
3d7c1f8950 gsk: Documentation fixups
Document a few missing symbols.
2020-06-05 20:19:45 -04:00
Matthias Clasen
b0e81acc12 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2050
2020-06-05 23:55:12 +00:00
Matthias Clasen
a682d97663 Merge branch 'wip/ebassi/a11y-2' into 'master'
Accessibility cleanup

See merge request GNOME/gtk!2049
2020-06-05 23:04:21 +00:00
Matthias Clasen
0e5137ae61 NEWS: Updates 2020-06-05 18:40:53 -04:00
Matthias Clasen
005a3da18f gtk-demo: Another way to trigger theme benchmark
The click on the headerbar seems broken atm, so add
an explicit button to trigger the cycling among the
themes.
2020-06-05 18:40:24 -04:00
Matthias Clasen
be6bcf882d spinbuttonaccessible: Fix an oversight
We need to pass the accessible to the signal handler.
2020-06-05 17:21:26 -04:00
Matthias Clasen
fb344e8108 Trivial typo fix 2020-06-05 17:08:43 -04:00
Emmanuele Bassi
b99389bcb8 a11y: Drop GtkWidgetAccessibleClass.notify_gtk
It's finally unused.

Accessible types should either watch properties they are interested in
directly, or should have (private) API to allow widgets to update the
accessible state directly.
2020-06-05 20:35:11 +01:00
Emmanuele Bassi
0fefdc99b2 a11y: Simplify GtkEntryAccessible
Now that we don't have any additional subclasses of GtkEntryAccessible
in GTK, we can drop all the conditional fluff in the base class.

We still need to subscribe to the global notify signal, because of the
sheer amount of properties watched by GtkEntryAccessible.
2020-06-05 20:35:11 +01:00
Emmanuele Bassi
e63419fbf4 a11y: Implement GtkPasswordEntryAccessible properly
GtkPasswordEntryAccessible is not a GtkEntryAccessible any more, so it
will need a proper implementation of various interfaces and
functionality in order to work like any other entry.
2020-06-05 20:35:11 +01:00
Emmanuele Bassi
428bb09a35 a11y: Make GtkSearchEntryAccessible a full GtkWidgetAccessible
We should not inherit from GtkEntryAccessible, given that GtkSearchEntry
is *not* a GtkEntry.
2020-06-05 20:35:11 +01:00
Emmanuele Bassi
7c2c795681 a11y: Simplify GtkScrollbarAccessible 2020-06-05 20:35:11 +01:00
Emmanuele Bassi
165f352c58 a11y: Simplify GtkScaleButtonAccessible 2020-06-05 20:35:11 +01:00
Emmanuele Bassi
3d6e702f63 a11y: Simplify GtkSpinButtonAccessible
We're already listening to the adjustment property on the spin button,
there's no need to reset the adjustment on widget set/unset, since the
accessible instance is always tied to the same widget.
2020-06-05 20:35:11 +01:00
Emmanuele Bassi
597e9a96b4 a11y: Simplify GtkTextAccessible 2020-06-05 20:35:11 +01:00
Emmanuele Bassi
6f4ed6c105 a11y: Simplify GtkTextViewAccessible
Drop the GtkWidgetAccessible.notify_gtk override.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
c3eafed472 a11y: Simplify GtkColorSwatchAccessible
Drop the GtkWidgetAccessible.notify_gtk override.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
7480fb703e a11y: Simplify GtkNotebookAccessible
Let the GtkNotebook explicitly update the accessible object that the
current page has changed, instead of overriding
GtkWidgetAccessible.notify_gtk.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
24e8b484e0 a11y: Simplify GtkWindowAccessible
Have GtkWindow notify of title changes, instead of overriding
GtkWidgetAccessible.notify_gtk.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
d60f7f2e7a a11y: Simplify GtkExpanderAccessible
Drop the GtkWidgetAccessible.notify_gtk and AtkObject.initialize
overrides, and have GtkExpander update the state of the accessible
object directly.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
0dcffe7c33 a11y: Simplify GtkLevelBarAccessible
Drop the GtkWidgetAccessible.notify_gtk and AtkObject.initialize
overrides, and have GtkLevelBar notify the accessible object of value
changes.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
9f09cfcfbd a11y: Split GtkSearchEntryAccessible from GtkEntryAccessible
Use a separate accessible object for the GtkSearchEntry, just like we
did for GtkPasswordEntry.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
7373cd962c a11y: Split password entry accessible from GtkEntryAccessible
Use a separate accessible object.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
ac3f0df083 a11y: Simplify GtkProgressBarAccessible
Drop the GtkWidgetAccessibleClass.notify_gtk and the
AtkObjectClass.initialize overrides: they don't do anything relevant.

Instead, have GtkProgressBar update the accessible state when the
fraction changes.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
f95d54a13d a11y: Use G_DECLARE macro for GtkWidgetAccessible
Allows us to drop the Private structure typedef.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
fc512f0b9f a11y: Update the accessible state when GtkIconView:model changes
Do not use a generic "notify" signal handler.

Additionally, clean up the GtkIconViewAccessible implementation to bring
it up with modern idiomatic GObject.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
f5ed59b7f2 a11y: Drop notify_gtk() from GtkRangeAccessible
Let the GtkRange notify the accessible instance when the adjustment
changes.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
9d51aa1443 a11y: Drop notify_gtk() from GtkButtonAccessible
Make GtkButton notify the accessible state directly when updating the
label.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
f0bdc865b9 a11y: Remove GtkToggleButtonAccessible notify_gtk implementation
The base GtkWidgetAccessible class does the right thing by default.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
eda1703f9d a11y: Update accessible state for GtkTreeView directly
Do not use GtkWidgetAccessibleClass.notify_gtk().
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
51fc382582 Notify accessibility state changes from GtkWidget
Piggybacking on blanket GObject::notify is not very efficient.
2020-06-05 20:35:10 +01:00
Emmanuele Bassi
6e52ef96a4 Move orientable style classes into GtkWidget
It feels slightly wrong to have GtkOrientable operate on widgets, but at
least what happens when an orientable widget changes orientation should
be part of GtkWidget.

This will allow to add more state changes without accessing widget state
from the outside of gtkwidget.c.
2020-06-05 20:35:09 +01:00
Emmanuele Bassi
9606c1eee9 Notify mapped state to the accessible object directly
Do not use signal connections: if we have an accessible object, notify
it directly when getting mapped and unmapped.
2020-06-05 20:32:27 +01:00
Emmanuele Bassi
959c101400 Drop unused AtkRegistry path
We expect widgets to use their own derived GtkWidgetAccessible type,
these days, and given that we hard code the default accessible type of a
GtkWidget to GtkWidgetAccessible, and that we enforce the dependency of
the type passed to gtk_widget_class_set_accessible_type(), the registry
code path is clearly unused.
2020-06-05 20:32:27 +01:00
Emmanuele Bassi
6b096e5c5b Make tooltip properties idiomatic
The tooltip handling in GtkWidget is "special":

 - the string is stored inside the qdata instead of the private
   instance data
 - the accessors call g_object_set() and g_object_get(), and the
   logic is all inside the property implementation, instead of
   being the other way around
 - the getters return a copy of the string
 - the setters don't really notify all the involved properties

The GtkWidgetAccessible uses the (escaped) tooltip text as a source for
the accessible object description, which means it has to store the
tooltip inside the object qdata, and update its copy at construction and
property notification time.

We can simplify this whole circus by making the tooltip properties (text
and markup) more idiomatic:

 - notify all side-effect properties
 - return a constant string from the getter
 - if tooltip-text is set:
   - store the text as is
   - escape the markup and store it separately for the markup getter
 - if tooltip-markup is set:
   - store the markup as is
   - parse the markup and store it separately for the text getter

The part of the testtooltips interactive test that checks that the
getters are doing the right thing is now part of the gtk testsuite, so
we ensure we don't regress in behaviour.
2020-06-05 20:32:26 +01:00
Emmanuele Bassi
9ac1eacdc8 Use modern GObject macros for GtkAccessible 2020-06-05 20:32:26 +01:00
Matthias Clasen
8e7395a7e3 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2048
2020-06-05 19:25:46 +00:00
Matthias Clasen
80fbc1b72d multiselection: Fix the select_range implementation
When exclusive is TRUE, we would not always emit a
::selection-changed signal that covers all the items
that were unselected.

This commit includes a test.
2020-06-05 14:57:59 -04:00
Matthias Clasen
17ea03eee2 set: Fix gtk_set_get_max
This function had an off-by-one error. Thankfully,
our selection tests are thorough enough to catch it.
2020-06-05 14:57:32 -04:00
Matthias Clasen
985b5a052e dropdown: Connect a forgotten signal handler
The code was exporting a search_stop function, but
the ui file didn't connect it to the ::stop-search
signal. Fix that.
2020-06-05 14:34:38 -04:00
Matthias Clasen
ed1872f0a8 Merge branch 'frame-clock-start-time' into 'master'
Tweaks to frame clock for better ties to vsync

See merge request GNOME/gtk!2043
2020-06-05 18:33:48 +00:00
Matthias Clasen
34841c3a5f Merge branch 'master.msvc' into 'master'
Fix latest GTK master on Visual Studio

See merge request GNOME/gtk!2028
2020-06-05 18:31:08 +00:00
Matthias Clasen
185f0181ac Merge branch 'columnview-reorder-cells' into 'master'
Columnview reorder cells

See merge request GNOME/gtk!2047
2020-06-05 18:29:26 +00:00
Matthias Clasen
60d6a0f2d5 Merge branch 'rubberband-again' into 'master'
Rubberband again

See merge request GNOME/gtk!2041
2020-06-05 17:59:15 +00:00
Matthias Clasen
99a1d10bf1 multiselection: Fix the select_range implementation
When exclusive is TRUE, we would not always emit a
::selection-changed signal that covers all the items
that were unselected.

This commit includes a test.
2020-06-05 13:50:30 -04:00
Matthias Clasen
2f1028ed79 set: Add a few useful functions
Allow to find out if a set is empty, and its
min and max.
2020-06-05 13:49:23 -04:00
Matthias Clasen
f631e0e1e0 columnview: Update column positions on reordering
Tell reordered columns to reorder their cells to
the new position. This is necessary to get things
like separators right. The visible symptom of this
problem was the lack of the right border when the
last column is reorder to another position, since
the title widget was still the last in its container,
so :last-child applied.
2020-06-05 13:28:44 -04:00
Matthias Clasen
6df489d5a9 columnviewcolumn: Add private api to set the position
This is needed to make columns reorder their cells when
their position in the column views list of columns
changes.
2020-06-05 13:28:44 -04:00
Matthias Clasen
15c6ad88c0 listitemwidget: Add api to reorder children
We need this to keep the rows in sync with the columns
when they are reordered.
2020-06-05 13:28:44 -04:00
Matthias Clasen
40f6a9d830 columnviewlayout: Handle for_size propertly
When we are given a for_size as width for the whole
column view, we need to distribute it over the columns
as gtk_column_view_allocate_columns would, in order
to find out which for_size to give to each cell.

This is a bit recursive, but works. Since we are
doing this recursion for every row, we should consider
adding a cache for those distributed widths.
2020-06-05 13:27:50 -04:00
Ray Strode
bd06c00f3a Merge branch 'wip/damaged-but-no-frost-bite' into 'master'
x11: defer _NET_WM_FRAME_DRAWN update until frame usable by compositor

See merge request GNOME/gtk!1982
2020-06-05 15:58:37 +00:00
Matthias Clasen
f6d23f0c29 Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Bring back the applauncher demo

See merge request GNOME/gtk!2040
2020-06-05 15:38:03 +00:00
Emmanuele Bassi
2a24459b92 Merge branch 'ebassi/for-master' into 'master'
Add missing annotation

See merge request GNOME/gtk!2046
2020-06-05 15:29:41 +00:00
Matthias Clasen
f6da324670 columnview: Split gtk_column_view_allocate_columns
Split off a helper function that just distributes
the widths, without actually allocating the columns.

This will be used in measuring in the future.
2020-06-05 11:27:40 -04:00
Matthias Clasen
11a18bd61a columnview: Take column width into account for measuring
When measuring the height of a cell, we need to give
it it the width of its column, if we expect realistic
results.
2020-06-05 10:42:20 -04:00
Ray Strode
972134abe4 x11: Defer _NET_WM_FRAME_DRAWN update until frame usable by compositor
With the vendor provided Nvidia driver there is a small window of time
after drawing to a GL surface before the updates to that surface
can be used by the compositor.

Drawing is already coordinated with the compositor through the frame
synchronization protocol detailed here:

https://fishsoup.net/misc/wm-spec-synchronization.html

Unfortunately, at the moment, GdkX11Surface tells the compositor the
frame is ready immediately after drawing to the surface, not later,
when it's consumable by the compositor.

This commit defers announcing the frame as ready until it's consumable
by the compositor. It does this by listening for the X server to announce
damage events associated with the frame drawing.  It tries to find the
right damage event by waiting until fence placed at buffer swap time
signals.
2020-06-05 10:01:13 -04:00
Ray Strode
f8770b78ea x11: Factor out some of frame sync code into subroutines
This commit moves some of the end frame sync counter handling
code to subroutines.

It's a minor readability win, but the main motivation is to
make it easier in a subsequent commit to defer updating the
sync counter until a more appropriate time.
2020-06-05 10:01:13 -04:00
Ray Strode
10f2b11fda x11: Add back support for the damage extension
commit 14bf58ec5d dropped support
for using the DAMAGE extension since there was no code that
needed it.

We're going to need it again, however, to address an NVidia
vendor driver issue.

This commit does the plumbing to add it back.
2020-06-05 10:01:13 -04:00
Timm Bäder
ea1cc4b991 filechooserwidget: Avoid an uninitialised value
For NULL filters, we were never calling g_list_store_find, so leaving
filter_index undefined.
2020-06-05 15:38:55 +02:00
Timm Bäder
8bee3e2fe0 demos: Avoid shadowing a global from time.h
Sad but true.
2020-06-05 15:38:55 +02:00
Timm Bäder
1f7adfd9ff filterlistmodel: Fix fallthrough annotations in unreachable code
They are only unreachable in debug builds but still break the build on
clang.
2020-06-05 15:38:55 +02:00
Matthias Clasen
9e55cd68e4 columview: Make cells propagate request mode
I think this is necessary to make wrapping
labels work.
2020-06-05 09:37:21 -04:00
Matthias Clasen
2a6dc67fd7 gtk-demo: Improve wrapping in settings demo
The columnview overrides the width of its content,
so if a label is not willing to wrap its content
below a certain width, it will just get cut off.

Avoid that by not setting width-chars on the wrapping
content.
2020-06-05 09:35:56 -04:00
Emmanuele Bassi
1061ad289a Add missing annotation 2020-06-05 14:33:17 +01:00
Matthias Clasen
0f81b58545 columviewlayout: Skip children when we should
Every layout manager should call gtk_widget_should_layout
on their children before measuring or allocating them.
So do it here too.
2020-06-05 08:44:23 -04:00
Matthias Clasen
2437c5a0ae listview: Add an example to the docs
The example is an excerpt from the applauncher
demo in gtk4-demo.
2020-06-05 08:22:48 -04:00
Matthias Clasen
669a6ddeaa gtk-demo: Bring back the applauncher demo
Just without the coverflow. It was a well-documented
demo, so it is useful to keep around.
2020-06-05 08:22:48 -04:00
Yariv Barkan
f5de46670b frame clock: schedule in refresh intervals
When the application does not receive "frame drawn" signals we schedule
the clock to run more or less at intervals equal to the last known
refresh interval. In order to minimize clock skew we have to aim for
exact intervals.
2020-06-05 11:57:49 +02:00
Alexander Larsson
91af8a705b frame clock: Better handle non-regular clock cycles
We try to step the frame clock in whole refresh_interval steps, but to
avoid drift and rounding issues we additionally try to converge it to
be synced to the physical vblank (actually the time we get the
frame-drawn message from the compositor, but these are tied together).

However, the convergence to vsync only really makes sense if the new
frame_time actually is tied to the vsync. It may very well be that
some other kind of event (say a network or mouse event) triggered
the redraw, and not a vsync presentation.

We used to assume that all frames that are close in time (< 4 frames
apart) were regular and thus tied to the vsync, but there is really no
guarantee of that. Even non regular times could be rapid.

This commit changes the code to only do the convergence-to-real-time
if the cause of the clock cycle was a thaw (i.e. last frame drawn and
animating). Paint cycles for any other kind of reason are always
scheduled an integer number of frames after the last cycle that was
caused by a thaw.
2020-06-05 11:30:47 +02:00
Alexander Larsson
82c314f1af frame clock: Track if paint is caused by thaw or not
When we get to a paint cycle we now know if this was caused by a
thaw, which typically means last frame was drawn, or some other event.

In the first case the time of the cycle is tied to the vblank in some
sense, and in the others it is essentially random. We can use this
information to compute better frame times. (Will be done in later
commits.)
2020-06-05 11:16:57 +02:00
Benjamin Otte
672413f1f6 Merge branch 'cleanup-snapshot-inhibit' into 'master'
reftest: Clean up reftest_inhibit_snapshot()

See merge request GNOME/gtk!2034
2020-06-05 07:38:52 +00:00
Matthias Clasen
843bf23f84 Drop gtk_multi_selection-copy
It is not used anymore.
2020-06-05 00:51:35 -04:00
Matthias Clasen
eeb2d2cc38 listbase: Redo rubberbanding
Make it so that the selection is only updated in the end.
2020-06-05 00:51:35 -04:00
Chun-wei Fan
c370b8f309 demos/gtk-demo/listview*.c: Include stdlib.h
atoi() and qsort() both require this header for them to be defined
2020-06-05 11:16:45 +08:00
Chun-wei Fan
acd9c12667 modules: Fix build on Visual Studio
Visual Studio does not allow decorating functions with '__declspec (dllexport)'
if a prototype exists and is not decorated with '__declspec (dllexport)' as
well, so we cannot just decorate g_io_module_[load|unload|query] in the various
module sources with G_MODULE_EXPORT because the prototypes of these functions
have been marked with _GLIB_EXTERN, which equates to 'extern' unless overridden

Fix this by overriding _GLIB_EXTERN with the appropriate visibility flag, as we
have used to define _GDK_EXTERN.  Unfortunately, we can't just use _GDK_EXTERN
G_MODULE_EXPORT as they may have not been defined yet for our use

Do this across the board for all modules, even if they are not buildable on
Visual Studio nor Windows, for consistency's sake.
2020-06-05 11:16:45 +08:00
Timm Bäder
5535b26395 Merge branch 'fix-quadratic-add' into 'master'
Avoid quadratic slowdown in gtk_widget_add()

See merge request GNOME/gtk!2027
2020-06-05 02:57:38 +00:00
Matthias Clasen
20611cf68c Add gtk_selection_model_[un]select_callback
Add a methods to add or remove a whole set
(specified via a query-range style callback).
2020-06-04 22:28:54 -04:00
Matthias Clasen
06c34ce02f set: Add a few useful functions
Allow to find out if a set is empty, and its
min and max.
2020-06-04 21:36:23 -04:00
Matthias Clasen
4fb50c7408 Merge branch 'matthiasc/for-master' into 'master'
more documentation for list widgets

See merge request GNOME/gtk!2039
2020-06-04 21:17:21 +00:00
Matthias Clasen
c37bea1676 Merge branch 'fribidi-include' into 'master'
wayland: Remove unused fribidi include

See merge request GNOME/gtk!2037
2020-06-04 20:03:13 +00:00
Matthias Clasen
ed985640e8 docs: Expand list widget docs
Begin to flesh out the long descriptions for GtkListView,
GtkGridView and GtkColumnView.
2020-06-04 15:33:53 -04:00
Sebastian Keller
2bd938952d wayland: Remove unused fribidi include
The included fribidi header is not used in gdkkeys-wayland.c and already
included in gdk.c which causes linker issues due to the header defining
a global variable.
2020-06-04 20:44:55 +02:00
Matthias Clasen
623a56391c gtk-demo: Cosmetics
Remove a few instances of double semicolon.
2020-06-04 13:30:13 -04:00
Matthias Clasen
1b7fb10361 Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Allow editing in the settings demo

See merge request GNOME/gtk!2033
2020-06-04 16:32:21 +00:00
Matthias Clasen
f6b6688186 Merge branch 'list-widget-styles' into 'master'
List widget styles

Closes #2818

See merge request GNOME/gtk!2035
2020-06-04 16:27:37 +00:00
Matthias Clasen
99453e937c Merge branch 'demo-drop-awards' into 'master'
gtk-demo: Drop the awards

See merge request GNOME/gtk!2036
2020-06-04 15:27:23 +00:00
Alexander Larsson
d3e0a1f68c Avoid quadratic slowdown in gtk_widget_add()
If you add a widget to a parent, this will invalidate the css nodes
for parent/siblings. Afterwards, if the parent is mapped, we will
realize the new child. This calls gtk_widget_update_alpha() which
needs the css opacity, so it revalidates the css.

Thus, for each widget_add (while visible) will trigger a full
revalidation of each sibling. If you add N children to a parent that
leads to O(N^2) revalidations.

To demo this I changed gtk-demo to always double the count
(independent of the fps) and print the time it took. Here is the
results (after a bit):

Setting fishbowl count=256 took 3,4 msec
Setting fishbowl count=512 took 10,1 msec
Setting fishbowl count=1024 took 34,1 msec
Setting fishbowl count=2048 took 126,3 msec
Setting fishbowl count=4096 took 480,3 msec
Setting fishbowl count=8192 took 1892,7 msec
Setting fishbowl count=16384 took 7751,0 msec
Setting fishbowl count=32768 took 38097,7 msec
Setting fishbowl count=65536 took 191987,7 msec

To fix this we drop gtk_widget_update_alpha() and just
calculate it when needed (which is only in a single place).
It was really only necessary because we previously set
the alpha on the surface.

With this fix the above becomes:

Setting fishbowl count=256 took 1,0 msec
Setting fishbowl count=512 took 1,9 msec
Setting fishbowl count=1024 took 3,7 msec
Setting fishbowl count=2048 took 7,4 msec
Setting fishbowl count=4096 took 18,1 msec
Setting fishbowl count=8192 took 31,0 msec
Setting fishbowl count=16384 took 66,3 msec
Setting fishbowl count=32768 took 126,7 msec
Setting fishbowl count=65536 took 244,6 msec
Setting fishbowl count=131072 took 492,2 msec
Setting fishbowl count=262144 took 984,3 msec
2020-06-04 16:42:59 +02:00
Matthias Clasen
76ff1a2a49 gtk-demo: Drop the awards
This was a neat idea, but maintaining it at a sufficient
level is too much work.
2020-06-04 10:19:44 -04:00
Matthias Clasen
51c6ce1734 list widgets: Document css structure
We didn't fill in this expected part of the widget
documentation yet.
2020-06-04 10:05:17 -04:00
Benjamin Otte
1998b673f4 Merge branch 'ensure-style-no-recurse' into 'master'
Avoid recursion in gtk_css_node_ensure_style()

See merge request GNOME/gtk!2031
2020-06-04 14:04:55 +00:00
Matthias Clasen
627497f942 docs: Fix a parameter name mismatch 2020-06-04 09:52:17 -04:00
Matthias Clasen
f9287941b4 Change css names of list widget
The new names are

GtkListView - listview row
GtkGridView - gridview child
GtkColumView - columnview header
               columnview listview row

Adwaita css has been updated to preserve
existing styles.

Fixes: #2818
2020-06-04 09:51:49 -04:00
Alexander Larsson
5059854a2e reftest: Clean up reftest_inhibit_snapshot()
This was done in a weird way where we always call reftest_uninhibit_snapshot()
on paint, and then re-inhibited it if it wasn't inhibited. To make this
work it also started with an extra inhibit.

This is very contorted and based on how this historically worked. This
changes it to just do:

  if (inhibit_count > 0)
    return;

And keep inhibit_count at its initial zero value unless it is actually
inhibited.
2020-06-04 15:45:29 +02:00
Benjamin Otte
aa8a061a83 Merge branch 'fix-snapshot' into 'master'
snapshot: Fix assert if paint gets scheduled immediately

See merge request GNOME/gtk!2032
2020-06-04 13:43:44 +00:00
Matthias Clasen
3f2d44d517 gtk-demo: Allow editing in the settings demo
This gives us an example of a columnview with editable
content, which we didn't have so far.
2020-06-04 08:45:47 -04:00
Alexander Larsson
b4af23be23 snapshot: Fix assert in inhibition
In https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2027 i was getting

Bail out! ERROR:../testsuite/reftests/reftest-snapshot.c:212:reftest_uninhibit_snapshot: assertion failed: (inhibit_count > 0)

In (for example the box-shadow-changes-modify-clip reftest. I can reproduce this (on master) with:

```
$ xvfb-run -a -s "-screen 0 1024x768x24" meson test --suite gtk:reftest "reftest box-shadow-changes-modify-clip.ui"
...
1/1 gtk:reftest / reftest box-shadow-changes-modify-clip.ui ERROR          0.77s
``

Fix this by re-inhibiting if we didn't draw anything, or we will get an assert the next paint.
2020-06-04 14:22:27 +02:00
Matthias Clasen
8ddf1f1ea5 Merge branch 'kjellahl/flowboxremove' into 'master'
flowbox: Don't use a removed and destroyed child

See merge request GNOME/gtk!2029
2020-06-04 12:13:57 +00:00
Matthias Clasen
475d8c4c11 Merge branch 'fishbowl-children' into 'master'
gtk-demo: Avoid list for children in GtkFishBowl

See merge request GNOME/gtk!2030
2020-06-04 12:10:51 +00:00
Alexander Larsson
fc823eb610 Avoid recursion in gtk_css_node_ensure_style()
gtk_css_node_ensure_style() recurses over previous siblings to ensure
these have a style before its following sibling.  As seen in
https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2027 this can
cause us to stack overflow and crash if we have a lot of children.

And even if we don't have *that* many children its still somewhat
bad to have stack depths of the same magnitude as the number of
children, both for performance reasons and debuggability.
2020-06-04 12:10:31 +02:00
Alexander Larsson
8707bab450 gtk-demo: Avoid list for children in GtkFishBowl
This is a demo that measures performance, so keep the child
info in a hashtable instead of a list. This means adding or removing
a child is not O(n-children).
2020-06-04 12:06:42 +02:00
Kjell Ahlstedt
612955f2b7 flowbox: Don't use a removed child after it has been unparented
In gtk_flow_box_remove(), call g_sequence_remove() before the child is unparented.

See MR !2029
2020-06-04 11:23:46 +02:00
Timm Bäder
36314c3ff7 Merge branch 'santo/gtk4_spelling_fix' into 'master'
docs: Fix spelling of GDK_VERSION_MIN_REQUIRED.

See merge request GNOME/gtk!2026
2020-06-04 07:38:58 +00:00
Daniel Mustieles
33fb38d8de Updated Spanish translation 2020-06-04 09:18:01 +02:00
Daniel Mustieles
38e2a910df Updated Spanish translation 2020-06-04 09:17:16 +02:00
Santosh Mahto
ef32df77be docs: Fix spelling of GDK_VERSION_MIN_REQUIRED. 2020-06-04 12:12:36 +05:30
Matthias Clasen
5154693ea4 Merge branch 'columnview-separators' into 'master'
Columnview separators

See merge request GNOME/gtk!2025
2020-06-03 23:34:48 +00:00
Matthias Clasen
4b68362981 columnview: Add a property for column separators
Rename the show-separators property to show-row-separators,
and add a matching show-column-separators property. It is
implemented by setting the .column-separators style class
on the column view.
2020-06-03 17:57:23 -04:00
Matthias Clasen
658e4c5357 listview: Use gtk_widget_add_css_class
No need to use the style context api for this anymore.
2020-06-03 17:51:22 -04:00
Matthias Clasen
ce0dd650d7 settings demo: Don't select rows
We want no selection here, so use GtkNoSelection.
2020-06-03 17:51:22 -04:00
Matthias Clasen
77b65ada4f Merge branch 'columnview-printdialog' into 'master'
Port the printdialog to column view

See merge request GNOME/gtk!2010
2020-06-03 21:47:58 +00:00
Matthias Clasen
fa37225a42 Merge branch 'columnview-rubberbanding' into 'master'
columnview: Implement rubberbanding

See merge request GNOME/gtk!2008
2020-06-03 21:46:13 +00:00
Matthias Clasen
78a06859b9 Merge branch 'columnview-expand' into 'master'
columnview: Implement expanding columns

See merge request GNOME/gtk!2007
2020-06-03 21:39:33 +00:00
Matthias Clasen
3ec8f4e84e Merge branch 'columnview-reordering' into 'master'
columnview: Implement interactive reordering

See merge request GNOME/gtk!2006
2020-06-03 21:38:59 +00:00
Matthias Clasen
f13a596d15 Merge branch 'columnview-resizing' into 'master'
columnview: Implement interactive resizing

See merge request GNOME/gtk!2004
2020-06-03 20:04:17 +00:00
Matthias Clasen
94f14778a3 Merge branch 'columnview-scrolling' into 'master'
columnview: Implement horizontal scrolling

See merge request GNOME/gtk!1998
2020-06-03 19:50:59 +00:00
Benjamin Otte
7312284e4f Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2024
2020-06-03 17:40:26 +00:00
Matthias Clasen
ebc07d1458 printdialog: Port to column view 2020-06-03 13:35:09 -04:00
Matthias Clasen
510f719975 gtk-demo: Make gridview demo use rubberbanding 2020-06-03 13:34:28 -04:00
Matthias Clasen
03c2202942 Add rubberband api
Add an ::enable-rubberband property to GtkListView,
GtkGridView and GtkColumnView.
2020-06-03 13:34:27 -04:00
Matthias Clasen
b3a97cb755 listbase: Simplify rubberbanding
The new approach is:
 - plain: clear and start a new selection
 - extend: add to the existing selection
 - modify: subtract from the existing selection
2020-06-03 13:32:57 -04:00
Matthias Clasen
a9273e1c73 listbase: Split off rubberband data 2020-06-03 13:32:57 -04:00
Matthias Clasen
14d11ebcab listbase: Use a widget for the rubberband
We no longer need to juggle manual css nodes. Just create
a widget for the rubberband, and update its allocation
as we rubberband.
2020-06-03 13:32:57 -04:00
Matthias Clasen
7dc458d925 Add autoscroll
This is an expected feature with rubberband selection:
as you get close to the edge while doing rubberband
selection, the list scrolls to extend your selection.
2020-06-03 13:32:57 -04:00
Matthias Clasen
a0f04bdcf3 listbase: Add rubberband selection
Implement the typical rubberband selection, including
autoscroll. This is only useful with multiselection,
and not very compatible with single-click-activate.
Therefore, it is not enabled by default, and needs
to be turned on explicitly.
2020-06-03 13:32:57 -04:00
Matthias Clasen
28f6e27276 Add GtkMultiSelection
This is implemented using a private GtkSet helper.

Includes tests.
2020-06-03 13:32:57 -04:00
Matthias Clasen
5ef427bd65 gtk-demo: Expand columns in the settings demo
Expand the columns that are likely to appear
at the end.
2020-06-03 13:32:15 -04:00
Matthias Clasen
03c1fa43f4 inspector: Expand the actions list 2020-06-03 13:32:15 -04:00
Matthias Clasen
3b9f0ab866 inspector: Expand the resource list
This is an experiment with adding a filler column.
2020-06-03 13:32:15 -04:00
Matthias Clasen
9617a00ae3 inspector: Expand the property list
It looks better this way.
2020-06-03 13:32:15 -04:00
Matthias Clasen
1408199957 inspector: Expand the object tree
This is how it used to look, and it looks better that way.
2020-06-03 13:32:15 -04:00
Matthias Clasen
067df8d4dd columnview: Take expand into account
When allocating columns, distribute extra space
to columns that have expand set to TRUE.
2020-06-03 13:32:15 -04:00
Matthias Clasen
2ab1b13092 columnview: Add a GtkColumnViewColumn:expand property
This will be used to determine how to distribute
available extra space in a column view.
2020-06-03 13:32:15 -04:00
Matthias Clasen
964d0c219a columnview: Add autoscroll
Autoscroll when the pointer gets close to the
edge during column resizing or reordering. This
is similar to what the treeview does, but it is
implemented using a tick callback, and has
variable speed.
2020-06-03 13:31:39 -04:00
Matthias Clasen
c58eb9c276 columnview: Allow to cancel reorder with Escape
The treeview does this too.
2020-06-03 13:31:39 -04:00
Matthias Clasen
5d4893b3f0 columnview: Interactive column reordering
Allow rearranging columns by dragging, in the same
way the treeview does.

We add the "dnd" style class to the header while
it is dragged, and we move the header of the dragged
column to the end of its parents children, so that
it gets drawn on top.
2020-06-03 13:31:39 -04:00
Matthias Clasen
11b4e0d4c0 columnview: Add a GtkColumnView:reorderable property
This property controls if users can reorder columns
by drag-and-drop. It defaults to TRUE.
2020-06-03 13:31:39 -04:00
Matthias Clasen
e637693131 columnviewlayout: Use header allocation for titles
Normally, this will be identical to the column
allocation, but we will temporarily change it
during column reordering.
2020-06-03 13:31:39 -04:00
Matthias Clasen
c9d5b77403 columnviewcolumn: Add reordering helpers
Add helper functions that let us temporarily give
a different allocation to headers. These will be
used to implement interactive column reordering
in GtkColumnView.
2020-06-03 13:31:39 -04:00
Matthias Clasen
574595993c columnviewtitle: Trigger action on release
This is necessary to make drag-to-reorder work
without triggering resorting.
2020-06-03 13:31:31 -04:00
Matthias Clasen
50f4e53aef Merge branch 'matthiasc/for-master' into 'master'
gtk-demo: Add a dropdown demo

See merge request GNOME/gtk!2023
2020-06-03 17:30:19 +00:00
Matthias Clasen
ac082e5504 gtk-demo: Make some columns resizable
Make the columns in the List > Settings demo
resizable, to demonstrate this functionality.
2020-06-03 12:49:40 -04:00
Matthias Clasen
f65f9591a1 columnview: Interactive column resizing
This copies just enough of the treeview code to
get columns moving.
2020-06-03 12:49:40 -04:00
Matthias Clasen
a1eadde25b columnviewcolumn: Add a helper
We need to check whether clicks are in the headers
of columns, so let the column view get at the the
header widget.
2020-06-03 12:49:40 -04:00
Matthias Clasen
66e5027756 columnview: Add a GtkColumnViewColumn:resizable property
This will be used for interactive column resizing
in the future.
2020-06-03 12:49:38 -04:00
Matthias Clasen
aa2d339508 columnview: Add a helper
The column code needs to get access to the
listitem widgets that are children of the listview,
so add a getter.
2020-06-03 12:48:56 -04:00
Matthias Clasen
d43aacefc9 columnview: Add GtkColumnViewColumn:fixed-width
Add a fixed-width property similar to the same property
of GtkTreeViewColumn.
2020-06-03 12:48:39 -04:00
Matthias Clasen
f0a0e20b2f columnview: Implement horizontal scrolling
The listview inside always thinks it gets its full size,
and updates its horizontal adjustment accordingly.

So keep our own adjustment, and update it when allocating.
2020-06-03 12:48:20 -04:00
Matthias Clasen
befdd8bb66 columnview: Revise scroll-minimum handling
Tweak the behavior slightly. We don't show
a scrollbar as long as we have at least
min-size available, but we still give the
entire size to the child, up to nat-size.

This matches how viewports handle scroll-minimum.
2020-06-03 12:48:20 -04:00
Benjamin Otte
27ed2cc009 Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2022
2020-06-03 16:33:54 +00:00
Benjamin Otte
a60c866a12 listbase: Don't grab_focus() when moving focus
We want to call gtk_widget_child_focus() to have Tab focus the right
widget.
2020-06-03 18:12:49 +02:00
Benjamin Otte
a84f6228ca listitemwidget: Fix focus handling for columnview
ListItemWidget needs to be aware of potentially having multiple
children, so make it aware.
2020-06-03 18:12:00 +02:00
Matthias Clasen
19da93b675 Merge branch 'columnview-menu' into 'master'
columnview: Add header menus

See merge request GNOME/gtk!2001
2020-06-03 15:51:26 +00:00
Benjamin Otte
aa38fc712f listbase: Fix leak
We were leaking the temporary tracker here.
2020-06-03 17:49:04 +02:00
Matthias Clasen
0b1c91dc7c gtk-demo: Add a dropdown demo
This shows a few examples of GtkDropDown.
Mostly taken from tests/testdropdown.c.
2020-06-03 11:34:06 -04:00
Matthias Clasen
ab2c8de4de Merge branch 'matthiasc/for-master' into 'master'
selection model: Further documentation tweaks

See merge request GNOME/gtk!2021
2020-06-03 15:11:59 +00:00
Benjamin Otte
00f2b134e3 columnview: Make sure focus can move into cells
The cells themselves should never be focusable though.
2020-06-03 16:55:39 +02:00
Benjamin Otte
0b8cebd6ef ffmediafile: Add fixes for recent cflags changes
Related: #2771
2020-06-03 16:23:49 +02:00
Matthias Clasen
53a9b7f6c0 selection model: Further documentation tweaks
Reword this to use plain language instead of throwing
arond reentrancy and ordering.
2020-06-03 07:51:29 -04:00
Matthias Clasen
667fd927ee Merge branch 'selection-model-docs' into 'master'
selectionmodel: Clarify docs

Closes #2806

See merge request GNOME/gtk!2017
2020-06-03 05:27:46 +00:00
Matthias Clasen
a8956838d3 selectionmodel: Clarify docs
Clarify some things that were not clear to me before
discussing them.

Fixes: #2806
2020-06-02 15:09:16 -04:00
Christoph Reiter
e7c9e2060c gtkiconcache: Use g_stat instead of fstat
stat/fstat aren't compatible with GStatBuf on Windows in all cases.
Since we don't really need the file descriptor anyway here replace it with
a g_stat call.

This fixes a compiler warning with 64bit mingw.
And lets us remove this scary ifdeffery.
2020-06-02 20:35:56 +02:00
Matthias Clasen
f6be407e33 Merge branch 'carlosgc/emoji-chooser-fixes' into 'master'
Fix emoji chooser warnings on destroy

See merge request GNOME/gtk!2016
2020-06-02 16:06:47 +00:00
Carlos Garcia Campos
2bf9b37e59 emojichooser: Unparent the variations popup on dispose and before adding a new one
This was causing warnings when destroying the emoji chooser because it
had children left.
2020-06-02 16:47:56 +02:00
Carlos Garcia Campos
d2e0ada794 textview: Unparent the emoji chooser on dispose
This was causing the warning "GtkEmojiChooser is not a child of
GtkTextView" when destroying a GtkTextView if the emoji chooser was
shown.
2020-06-02 16:47:56 +02:00
Matthias Clasen
c07ae5806e Merge branch 'matthiasc/for-master' into 'master'
Cosmetic improvements to the filebrowser demo

See merge request GNOME/gtk!2015
2020-06-02 04:30:29 +00:00
Matthias Clasen
5afe6f7825 Cosmetic improvements to the filebrowser demo
Make it look good.
2020-06-01 23:13:20 -04:00
Matthias Clasen
d02c48f987 Add more columns to the settings demo
Flesh out this demo more, so we can have a
non-trivial column editor here at some point.
2020-06-01 22:10:53 -04:00
Matthias Clasen
c835214540 Add a header menu to settings demo
Allow toggling column visibility from here.
2020-06-01 22:10:53 -04:00
Matthias Clasen
cb2901ec40 columnviewtitle: Display a context menu
When the ::header-menu property is set on the
column, use the menu model to create and show
a context menu.
2020-06-01 22:10:53 -04:00
Matthias Clasen
f27bd061fb columnviewcolumn: Add a menu property
Add a ::header-menu property that will be used
to create a context menu for the header of the
column.
2020-06-01 22:10:53 -04:00
Matthias Clasen
572386e4ce Merge branch 'matthiasc/for-master' into 'master'
print backend: Fix list model handling in dispose

See merge request GNOME/gtk!2013
2020-06-02 00:07:45 +00:00
Matthias Clasen
67a972182e Merge branch 'ebassi/expression-type' into 'master'
Ebassi/expression type

See merge request GNOME/gtk!2014
2020-06-01 22:48:26 +00:00
Matej Urbančič
5955e11a5a Added Slovenian translation 2020-06-01 22:19:55 +02:00
Emmanuele Bassi
8daaafc864 Document how to define properties using GtkExpression
Use the GtkParamSpecExpression type to describe the property, and the
GValue API to set and get the expression instance.
2020-06-01 21:17:34 +01:00
Emmanuele Bassi
ebaa96c0fa Turn GtkExpression into a GTypeInstance
Since it's a type with sub-classes, we need to use GTypeInstance (at the
very least), otherwise we won't be able to address each sub-class as
such.

This is similar to how GskRenderNode and GdkEvent are handled, with the
added difficulty that GtkExpression is meant to be used in properties,
in order to be deserialised by GtkBuilder. This requires adding a
GParamSpec sub-class that we can match on from within GtkBuilder,
alongside some convenience API for storing a GtkExpression inside a
GValue.
2020-06-01 21:07:53 +01:00
Emmanuele Bassi
fb3d08c651 Print out the file name we're testing
We're printing out the file we're testing once we succeed, but it's hard
to know which file caused a failure. Let's add a g_test_message()
directive so we can look in our logs.
2020-06-01 21:06:04 +01:00
Matthias Clasen
9d15e64f0b gtk-demo: Plug a leak
We were leaking a reference to the settings demo.
This showed up as gtk4-demo --run listview_settings
not exiting when the window is closed.
2020-06-01 15:17:21 -04:00
Matthias Clasen
b62564fd98 columnviewcolumn: Fix visibility implementation
We were not properly syncing initial visibility
with widgets.
2020-06-01 14:47:12 -04:00
Matthias Clasen
0266bcab7a Add a test for the previous fix
This checks that action muxer hierarchy is properly
updated when muxers appear in the middle.
2020-06-01 13:52:50 -04:00
Matthias Clasen
6652e14662 Update action muxer hierarchy propertly
When a new muxer appears, we must not only make it
inherit from the parent, we also have to update all
children to inherit from it.
2020-06-01 13:52:42 -04:00
Matthias Clasen
7a50f86f3f print backend: Fix list model handling in dispose
The print backends do some complicated dispose handling
where the implementations call gtk_print_backend_destroy().

Our tests (in particular, the templates test) trigger
situations where we use print backends after dispose,
and they can't handle the printers listmodel being
NULL at that time. So just remove the printers in
dispose, keep the empty liststore until finalize.
2020-06-01 13:52:21 -04:00
Kukuh Syafaat
59218d02c8 Update Indonesian translation 2020-06-01 13:29:20 +00:00
Matthias Clasen
fe73730d21 Merge branch 'gtk-demo-run-no-main-window' into 'master'
gtk-demo: Don't show main window if --run is passed in

See merge request GNOME/gtk!1979
2020-06-01 12:26:15 +00:00
Matthias Clasen
b814970bdd Merge branch 'fix-frameclock-going-backwards' into 'master'
Fix frameclock going backwards

See merge request GNOME/gtk!2011
2020-06-01 12:25:20 +00:00
Matthias Clasen
8dfbef5e6f Merge branch 'matthiasc/for-master' into 'master'
columnview: Add column reordering

See merge request GNOME/gtk!2005
2020-06-01 11:28:28 +00:00
Emmanuele Bassi
0b9a3fc160 Merge branch 'ebassi/scroll-position' into 'master'
Remove position from GdkScrollEvent

See merge request GNOME/gtk!2012
2020-06-01 10:32:55 +00:00
Emmanuele Bassi
79105962a7 Remove position from GdkScrollEvent
Scroll events do not have a position, so they shouldn't implement the
GdkEventClass.get_position() virtual function; nor they should have an x
and y fields that never get updated.
2020-06-01 10:49:33 +01:00
Alexander Larsson
a36e2bc764 Fix frameclock going backwards
When we run the frameclock RUN_FLUSH_IDLE idle before the paint,
then gdk_frame_clock_flush_idle() sets
```
  priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT
```
at the end if there is a paint comming.

But, before doing the paint cycle it may handle other X events, and
during that time the phase is set to BEFORE_PAINT. This means that the
current check on whether we're inside a paint is wrong:

```
  if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
     priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS)
    return priv->smoothed_frame_time_base;
```

This caused us to sometimes use this smoothed_frame_time_base even
though we previously reported a later value during PHASE_NONE, thus
being non-monotonic.

We can't just additionally check for the BEGIN_PAINT phase though,
becasue if we are in the paint loop actually doing that phase we
should use the time base. Instead we check for `!(BEFORE_PAINT &&
in_paint_idle)`.
2020-06-01 10:53:24 +02:00
Matthias Clasen
cc878160bd gtk-demo: Fix a crash in the puzzle
Avoid a crash when clicking the refresh button
after solving the puzzle.
2020-06-01 00:11:50 -04:00
Matthias Clasen
382153e82d gtk-demo: Fix keynav in the puzzle
We need to make shortcut controller have global
scope, otherwise the shortcuts lose against the
window keybindings.
2020-06-01 00:11:43 -04:00
Matthias Clasen
e195341e30 gtk-demo: Flesh out the settings demo
Add columns for type and default value.
2020-05-31 23:43:58 -04:00
Matthias Clasen
c6c8263704 columnview: Add column reordering
Add an API to allow reordering columns.
2020-05-31 21:56:30 -04:00
Matthias Clasen
ed02bea20d Merge branch 'action-tests' into 'master'
Action tests

See merge request GNOME/gtk!2003
2020-05-31 23:32:44 +00:00
Matthias Clasen
f89a1b05fe Merge branch 'matthiasc/for-master' into 'master'
Add a forgotten export

See merge request GNOME/gtk!2002
2020-05-31 22:54:38 +00:00
Matthias Clasen
af65b7e6d7 More action tests
Test actions under hierarchy changes.
2020-05-31 18:13:50 -04:00
Matthias Clasen
1995ad6d63 Add a forgotten export
gtk_column_view_sort_by was missing a GDK_AVAILABLE_IN_ALL
annotation, causing it to not be exported.
2020-05-31 16:47:53 -04:00
Matthias Clasen
83c0937a46 testsuite: Beef up action tests
Check return values from  gtk_widget_activate.
2020-05-31 16:40:50 -04:00
Matthias Clasen
f5cc2c0d20 Merge branch 'column-visible' into 'master'
columnview: Add a GtkColumnViewColumn:visible property

See merge request GNOME/gtk!1997
2020-05-31 20:39:06 +00:00
Emmanuele Bassi
931d68bc92 Merge branch 'drop-coverflow' into 'master'
Drop GtkCoverFlow for now

See merge request GNOME/gtk!2000
2020-05-31 19:12:32 +00:00
Yuri Chornoivan
06946c35d3 Update Ukrainian translation 2020-05-31 19:05:20 +00:00
Matthias Clasen
cbe81fd443 Merge branch 'drop-fallback-c89' into 'master'
Drop fallback-c89.c

See merge request GNOME/gtk!1999
2020-05-31 18:14:14 +00:00
Matthias Clasen
173e919d2a Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!1995
2020-05-31 18:13:36 +00:00
Matthias Clasen
73fdb8f7b0 Drop GtkCoverFlow for now
There is no agreement that a coverflow widget is
appropriate for GTK 4.

It would be ok as a demo if it could live in gtk-demo,
but that requires us to make GtkListBase public first.
The demo is also somewhat rough and needs more work
to look plausible.

Drop GtkCoverFlow and the related demo for now.
2020-05-31 13:15:51 -04:00
Matthias Clasen
8e0ba37866 gtk-demo: Fixes for the sliding puzzle
We were calling check_solved only for key presses,
meaning you could never solve the puzzle with the
mouse.
2020-05-31 13:01:17 -04:00
Matthias Clasen
8780f50e7e gtk-demo: Some fixes to awards
Fix things up enough to make the list show up.
Still not a working example, but closer.
2020-05-31 13:01:17 -04:00
Matthias Clasen
06dc357ea0 printer: Fix the default value of icon-name
Just set this to "printer", so we don't have
to fix it up in the print dialog.
2020-05-31 13:01:17 -04:00
Matthias Clasen
fb587cb529 printbackend: Add a list model getter
Now that we have a list model for printers,
we can start using it.
2020-05-31 13:01:17 -04:00
Matthias Clasen
a026677849 printbackend: Use a list store 2020-05-31 13:01:17 -04:00
Matthias Clasen
1c389b1f24 gtk-demo: Add more scrolling benchmarks
Add a listview and gridview to the scrolling
benchmarks.
2020-05-31 13:01:17 -04:00
Emmanuele Bassi
55b9aa0309 Merge branch 'ebassi/annotations' into 'master'
Ebassi/annotations

See merge request GNOME/gtk!1996
2020-05-31 15:18:36 +00:00
Christoph Reiter
2d5cf2b4c4 Drop fallback-c89.c
We require a C compiler supporting C99 now. The main purpose of
these fallbacks was for MSVC. From what I can see this is now all supported
by MSVC 2015+ anyway.

The only other change this includes is to replace isnanf() with the
(type infering) C99 isnan() macro, because MSVC doesn't provide isnanf().
2020-05-31 17:09:23 +02:00
Matthias Clasen
4877bb5b5c columnviewcolumn: Add a visible property
This lets us hide columns, which is an expected
feature of columned lists.
2020-05-31 10:47:48 -04:00
Emmanuele Bassi
b9269d5644 Annotate the GtkFunctionListItemFactory constructor
But skip it, since it cannot really be used by language bindings, as it
binds the same user data to two separate functions.
2020-05-31 15:14:26 +01:00
Emmanuele Bassi
1a4723988e Fix annotations for gtk_cclosure_expression_new()
Missing scope annotations for the various functions.
2020-05-31 15:10:27 +01:00
Matthias Clasen
93353888ca Merge branch 'columnview-1' into 'master'
Convert the inspector to column views

See merge request GNOME/gtk!1994
2020-05-31 14:06:31 +00:00
Emmanuele Bassi
c3a90b76d0 Add missing separator
An annotation is separated from the description by a ':'.
2020-05-31 15:05:59 +01:00
Emmanuele Bassi
43e5ca9a1b docs: Fix annotations
- Use the same name for the argument in the declaration, definition,
   and documentation
 - Use "optional" instead of the deprecated "allow-none"
2020-05-31 15:04:51 +01:00
Christoph Reiter
c5829bd0e2 fallback-c89: Try to make isnanf work 2020-05-31 15:50:09 +02:00
Matthias Clasen
2a9d2cc7e9 inspector: Touch up list styling
This is just the minimal amount of work to make
headers recognizable.
2020-05-31 09:24:19 -04:00
Matthias Clasen
0d9873d8bc inspector: Use a column view for actions
A straight conversion from list box to column view.
2020-05-31 09:24:12 -04:00
Matthias Clasen
23bc38ed06 inspector: Make the resource list sortable
This is using a GtkTreeListRowSorter to keep expanded
state of the tree while changing the sorting.
2020-05-31 09:24:04 -04:00
Matthias Clasen
42d26b4b05 inspector: Use a column view for the resource list
A conversion from tree view to column view.
2020-05-31 09:23:51 -04:00
Matthias Clasen
04700789e1 inspector: Use a column view for properties
Just a straight conversion from list box to column view.
2020-05-31 09:23:45 -04:00
Matthias Clasen
e23baa59f0 inspector: Add columns to the object tree
Add columnview columns in the object tree.
We do the same for treeview columns.
2020-05-31 09:23:37 -04:00
Matthias Clasen
e8e28b61db Merge branch 'fix-mnemonic-zero' into 'master'
label: Fix mnemonic zero

Closes #2805

See merge request GNOME/gtk!1993
2020-05-31 13:02:51 +00:00
Yuri Chornoivan
b766707f28 Update Ukrainian translation 2020-05-31 06:12:49 +00:00
Yuri Chornoivan
0787f262a0 Update Ukrainian translation 2020-05-31 06:09:05 +00:00
Matthias Clasen
d833f4a632 Merge branch 'dropdown-for-merge' into 'master'
Dropdown for merge

Closes #2214

See merge request GNOME/gtk!1992
2020-05-31 05:34:18 +00:00
Matthias Clasen
ce1e364ab8 Merge branch 'listview-for-merge' into 'master'
Listview for merge

Closes #2214

See merge request GNOME/gtk!1991
2020-05-31 05:32:37 +00:00
Matthias Clasen
adb5b299c9 label: Fix mnemonic zero
We were confusing '\0' and '0' when parsing the label
for mnemonics.

Fixes: #2805
2020-05-30 21:42:54 -04:00
Alexander Larsson
0bd039a524 gtk-demo: Don't show main window if --run is passed in
Also, in that case, exit when the demo window is closed.
2020-05-29 13:51:31 +02:00
267 changed files with 15873 additions and 12089 deletions

89
NEWS
View File

@@ -1,3 +1,92 @@
Overview of Changes in GTK 3.98.5
=================================
* Introduce new list widgets and supporting infrastructure.
The main APIs are:
- GtkListView
- GtkGridView
- GtkColumnView and GtkColumnViewColumn
- GtkDropDown
- GtkListItemFactory and implementations
- GtkExpression
- GtkFilter and subclasses, and GtkFilterListModel
- GtkSorter and subclasses, and GtkSortListModel
- GtkSelectionModel and subclasses
- GtkTreeListModel, GtkTreeExpander and GtkTreeListRowSorter
* GtkFileChooser:
- Add a tracker3-based search engine implementation
- Rate-limit updates from the trash monitor
* GtkWindow:
- Redo the css node setup. There is now a single 'window' node
- Fix rounded corners on tiled windows
* GtkApplication:
- Drop app menu support. Menubar support is still there
* GtkFixed:
- Change coordinate APIs to take doubles
* GtkOverlay:
- Make GtkOverlayLayout public
* GtkTooltips:
- Fix line wrapping of tooltips
* Shortcuts:
- Fix mnemonic cycling
- Fix using '0' as a mnemonic
* Menus:
- Differentiate keypad keys in accelerators
* GtkIMContext:
- Add gtk_im_context_filter_key to allow event reinjection
* Themes:
- Adwaita: Limit the scope of backdrop
* Accessibility:
- Clean up and reorganize the code to prepare for the
dropping of ATK
* GDK:
- Drop unused enum and struct definitions from headers
- Make keymap translation API public again. Still needed
- Frameclock: Always use compositor refresh rate info
- Frameclock: Use quadratic correction for frame time jitter
- Frameclock: Ensure monotonicity
- Frameclock: Track resason for paint
- X11: Improve sync when the Nvidia driver is used
* GSK:
- GL renderer: Fix blurred outset shadows
- GL renderer: handle nested transform nodes properly
- GL renderer: Optimize clip handling
* gtk-demo:
- Improve the Drag-and-Drop demo with proper drag icons
- Don't show the main window if --run is given
- Add demos for list widgets and GtkDropDrown
* Documentation:
- Convert freestanding sections to markdown
- Drop the glossary
- Expand and improve the migration guide
* Build:
- We require pandoc now, for building the documentation
- Require Pango 1.45
* Translation updates:
Polish
Romanian
Slovenian
Turkish
Ukrainian
Overview of Changes in GTK 3.98.4
=================================

View File

@@ -27,18 +27,6 @@
/* Define to 1 if you have the `dcgettext' function. */
#mesondefine HAVE_DCGETTEXT
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISINF
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISNAN
/* Define to 1 if you have the declaration of `isnanf', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISNANF
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
@@ -84,9 +72,6 @@
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP
/* Define to 1 if you have the `nearbyint' function. */
#mesondefine HAVE_NEARBYINT
/* Define to 1 if you have the `posix_fallocate' function. */
#mesondefine HAVE_POSIX_FALLOCATE
@@ -96,21 +81,9 @@
/* Have the Xrandr 1.5 extension library */
#mesondefine HAVE_RANDR15
/* Define to 1 if you have the `rint' function. */
#mesondefine HAVE_RINT
/* Define to 1 if you have the `round' function. */
#mesondefine HAVE_ROUND
/* Define to 1 if you have the `sincos' function. */
#mesondefine HAVE_SINCOS
/* Define to 1 if you have the `log2` function */
#mesondefine HAVE_LOG2
/* Define to 1 if you ahve the `exp2` function */
#mesondefine HAVE_EXP2
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
@@ -150,6 +123,9 @@
/* Have the Xcursor library */
#mesondefine HAVE_XCURSOR
/* Have the XDAMAGE X extension */
#mesondefine HAVE_XDAMAGE
/* Have the XFIXES X extension */
#mesondefine HAVE_XFIXES

View File

@@ -1,247 +0,0 @@
/*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "award.h"
struct _GtkAward
{
GObject parent;
char *explanation;
char *name;
char *title;
GDateTime *granted; /* or NULL if not granted */
};
enum {
PROP_0,
PROP_EXPLANATION,
PROP_NAME,
PROP_TITLE,
PROP_GRANTED,
N_PROPS,
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkAward, gtk_award, G_TYPE_OBJECT)
static void
gtk_award_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
self->explanation = g_value_dup_string (value);
break;
case PROP_NAME:
self->name = g_value_dup_string (value);
break;
case PROP_TITLE:
self->title = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
g_value_set_string (value, self->explanation);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_GRANTED:
g_value_set_boxed (value, self->granted);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_dispose (GObject *object)
{
GtkAward *self = GTK_AWARD (object);
g_clear_pointer (&self->name, g_free);
g_clear_pointer (&self->title, g_free);
g_clear_pointer (&self->granted, g_date_time_unref);
G_OBJECT_CLASS (gtk_award_parent_class)->dispose (object);
}
static void
gtk_award_class_init (GtkAwardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = gtk_award_set_property;
gobject_class->get_property = gtk_award_get_property;
gobject_class->dispose = gtk_award_dispose;
properties[PROP_EXPLANATION] =
g_param_spec_string ("explanation",
"Explanation",
"How to get the title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"internal name of the award",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"user-visible title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_GRANTED] =
g_param_spec_boxed ("granted",
"Granted",
"Timestamp the award was granted or NULL if not granted yet",
G_TYPE_DATE_TIME,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_award_init (GtkAward *self)
{
}
GListModel *
gtk_award_get_list (void)
{
static GListModel *list = NULL;
if (list == NULL)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_AWARD);
builder = gtk_builder_new_from_resource ("/awards.ui");
list = G_LIST_MODEL (gtk_builder_get_object (builder, "list"));
g_object_ref (list);
g_object_unref (builder);
}
return g_object_ref (list);
}
const char *
gtk_award_get_name (GtkAward *award)
{
return award->name;
}
const char *
gtk_award_get_title (GtkAward *award)
{
return award->title;
}
GDateTime *
gtk_award_get_granted (GtkAward *award)
{
return award->granted;
}
GtkAward *
award_find (const char *name)
{
GListModel *list;
GtkAward *self;
guint i;
list = gtk_award_get_list ();
g_object_unref (list);
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
self = g_list_model_get_item (list, i);
g_object_unref (self);
if (g_ascii_strcasecmp (name, self->name) == 0)
return self;
}
return NULL;
}
void
award (const char *name)
{
GtkAward *self;
GNotification *notification;
self = award_find (name);
if (self == NULL)
{
g_warning ("Did not find award \"%s\"", name);
return;
}
if (self->granted)
return;
self->granted = g_date_time_new_now_utc ();
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_GRANTED]);
notification = g_notification_new ("You won an award!");
g_notification_set_body (notification, self->title);
g_application_send_notification (g_application_get_default (), NULL, notification);
g_object_unref (notification);
}

View File

@@ -1,18 +0,0 @@
#ifndef __AWARD_H__
#define __AWARD_H__
#include <gtk/gtk.h>
#define GTK_TYPE_AWARD (gtk_award_get_type ())
G_DECLARE_FINAL_TYPE (GtkAward, gtk_award, GTK, AWARD, GObject)
GListModel * gtk_award_get_list (void);
const char * gtk_award_get_name (GtkAward *award);
const char * gtk_award_get_title (GtkAward *award);
GDateTime * gtk_award_get_granted (GtkAward *award);
void award (const char *name);
#endif /* __AWARD_H__ */

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="label" bind-source="GtkListItem" bind-property="position"></property>
<property name="margin">6</property>
</object>
</property>
</template>
</interface>

View File

@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="list">
<property name="item-type">GtkAward</property>
<child>
<object class="GtkAward">
<property name="name">demo-inspector</property>
<!-- Transformers -->
<property name="title" translatable="yes">You got a high-rise double-pump carburetor.</property>
<property name="explanation" translatable="yes">Launch the inspector</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">demo-start</property>
<!-- The Matrix -->
<property name="title" translatable="yes">After this, there is no turning back.</property>
<property name="explanation" translatable="yes">Start gtk-demo</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-reshare</property>
<!-- Mean Girls -->
<property name="title" translatable="yes">Trying to make fetch happen</property>
<property name="explanation" translatable="yes">Reshare a tweet</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-100th-row</property>
<!-- Aladdin -->
<property name="title" translatable="yes">The ever impressive, long contained, often imitated, but never duplicated Genie of the lamp.</property>
<property name="explanation" translatable="yes">Select a 100th row in a list</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-best</property>
<!-- Spaceballs -->
<property name="title" translatable="yes">I've got the same combination on my luggage!</property>
<property name="explanation" translatable="yes">Use "12345" as the password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-correct</property>
<!-- Stanley Parable -->
<property name="title" translatable="yes">Night Shark 1-1-5</property>
<property name="explanation" translatable="yes">Correctly enter a password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-give-up</property>
<!-- Pretty Woman -->
<property name="title" translatable="yes">Big Mistake. Big. Huge!</property>
<property name="explanation" translatable="yes">Close the puzzle without finishing it</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve</property>
<!-- The Incredibles -->
<property name="title" translatable="yes">That was totally wicked!</property>
<property name="explanation" translatable="yes">Solve a puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-animated</property>
<!-- The Phantom Menace -->
<property name="title" translatable="yes">A surprise to be sure but a welcome one.</property>
<property name="explanation" translatable="yes">Solve an animated puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-large</property>
<!-- Portal -->
<property name="title" translatable="yes">Science isn't about WHY. It's about WHY NOT?!</property>
<property name="explanation" translatable="yes">Solve a puzzle with at least 20 pieces</property>
</object>
</child>
</object>
</interface>

View File

@@ -1,48 +0,0 @@
/* Awards
*
* This demo demonstrates how to use lists to show the awards you have collected
* while exploring this demo.
*
*/
#include <gtk/gtk.h>
/* Include the header for accessing the awards */
#include "award.h"
static GtkWidget *window = NULL;
GtkWidget *
do_awardview (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *sw, *listview;
GListModel *list;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Awards");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
listview = gtk_list_view_new_with_factory (
gtk_builder_list_item_factory_new_from_resource (NULL, "/awardview/awardlistitem.ui"));
list = gtk_award_get_list ();
gtk_list_view_set_model (GTK_LIST_VIEW (listview), list);
g_object_unref (list);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,7 +1,7 @@
/* Constraints/Interactive
*
* Demonstrate how constraints can be updates during
* user interaction.
* Demonstrate how constraints can be updates during user interaction.
* The vertical edge between the buttons can be dragged with the mouse.
*/
#include <glib/gi18n.h>

View File

@@ -1,9 +1,8 @@
/* Cursors
*
* Demonstrates a useful set of available cursors. The cursors shown here are the ones
* defined by CSS, which we assume to be available.
*
* The example shows creating cursors by name or from an image, with or without a fallback.
* Demonstrates a useful set of available cursors. The cursors shown here are the
* ones defined by CSS, which we assume to be available. The example shows creating
* cursors by name or from an image, with or without a fallback.
*/
#include <gtk/gtk.h>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file>awards.ui</file>
</gresource>
<gresource prefix="/ui">
<file preprocess="xml-stripblanks">main.ui</file>
@@ -12,9 +11,6 @@
<file>application.ui</file>
<file>menus.ui</file>
</gresource>
<gresource prefix="/awardview">
<file>awardlistitem.ui</file>
</gresource>
<gresource prefix="/builder">
<file>demo.ui</file>
</gresource>
@@ -127,6 +123,7 @@
</gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
<file>listview_filebrowser.css</file>
</gresource>
<gresource prefix="/listview_minesweeper">
<file>listview_minesweeper.ui</file>
@@ -177,7 +174,6 @@
</gresource>
<gresource prefix="/sources">
<file>application_demo.c</file>
<file>awardview.c</file>
<file>assistant.c</file>
<file>builder.c</file>
<file>clipboard.c</file>
@@ -194,6 +190,7 @@
<file>cursors.c</file>
<file>dialog.c</file>
<file>drawingarea.c</file>
<file>dropdown.c</file>
<file>dnd.c</file>
<file>editable_cells.c</file>
<file>entry_completion.c</file>

305
demos/gtk-demo/dropdown.c Normal file
View File

@@ -0,0 +1,305 @@
/* Drop Downs
*
* The GtkDropDown widget is a modern alternative to GtkComboBox.
* It uses list models instead of tree models, and the content is
* displayed using widgets instead of cell renderers.
*
* The examples here demonstrate how to use different kinds of
* list models with GtkDropDown, how to use search and how to
* display the selected item differently from the presentation
* in the popup.
*/
#include <gtk/gtk.h>
#define STRING_TYPE_HOLDER (string_holder_get_type ())
G_DECLARE_FINAL_TYPE (StringHolder, string_holder, STRING, HOLDER, GObject)
struct _StringHolder {
GObject parent_instance;
char *title;
char *icon;
char *description;
};
G_DEFINE_TYPE (StringHolder, string_holder, G_TYPE_OBJECT);
static void
string_holder_init (StringHolder *holder)
{
}
static void
string_holder_finalize (GObject *object)
{
StringHolder *holder = STRING_HOLDER (object);
g_free (holder->title);
g_free (holder->icon);
g_free (holder->description);
G_OBJECT_CLASS (string_holder_parent_class)->finalize (object);
}
static void
string_holder_class_init (StringHolderClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = string_holder_finalize;
}
static StringHolder *
string_holder_new (const char *title, const char *icon, const char *description)
{
StringHolder *holder = g_object_new (STRING_TYPE_HOLDER, NULL);
holder->title = g_strdup (title);
holder->icon = g_strdup (icon);
holder->description = g_strdup (description);
return holder;
}
static void
strings_setup_item_single_line (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *image, *title;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
image = gtk_image_new ();
title = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), title);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
gtk_list_item_set_child (item, box);
}
static void
strings_setup_item_full (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *box2, *image, *title, *description;
image = gtk_image_new ();
title = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
description = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (description), 0.0);
gtk_style_context_add_class (gtk_widget_get_style_context (description), "dim-label");
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), box2);
gtk_box_append (GTK_BOX (box2), title);
gtk_box_append (GTK_BOX (box2), description);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
g_object_set_data (G_OBJECT (item), "description", description);
gtk_list_item_set_child (item, box);
}
static void
strings_bind_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *image, *title, *description;
StringHolder *holder;
holder = gtk_list_item_get_item (item);
title = g_object_get_data (G_OBJECT (item), "title");
image = g_object_get_data (G_OBJECT (item), "image");
description = g_object_get_data (G_OBJECT (item), "description");
gtk_label_set_label (GTK_LABEL (title), holder->title);
if (image)
{
gtk_image_set_from_icon_name (GTK_IMAGE (image), holder->icon);
gtk_widget_set_visible (image, holder->icon != NULL);
}
if (description)
{
gtk_label_set_label (GTK_LABEL (description), holder->description);
gtk_widget_set_visible (description , holder->description != NULL);
}
}
static GtkListItemFactory *
strings_factory_new (gboolean full)
{
GtkListItemFactory *factory;
factory = gtk_signal_list_item_factory_new ();
if (full)
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_full), NULL);
else
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_single_line), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (strings_bind_item), NULL);
return factory;
}
static GListModel *
strings_model_new (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GListStore *store;
int i;
store = g_list_store_new (STRING_TYPE_HOLDER);
for (i = 0; titles[i]; i++)
{
StringHolder *holder = string_holder_new (titles[i],
icons ? icons[i] : NULL,
descriptions ? descriptions[i] : NULL);
g_list_store_append (store, holder);
g_object_unref (holder);
}
return G_LIST_MODEL (store);
}
static GtkWidget *
drop_down_new_from_strings (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GtkWidget *widget;
GListModel *model;
GtkListItemFactory *factory;
GtkListItemFactory *list_factory;
g_return_val_if_fail (titles != NULL, NULL);
g_return_val_if_fail (icons == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)titles), NULL);
g_return_val_if_fail (descriptions == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)descriptions), NULL);
model = strings_model_new (titles, icons, descriptions);
factory = strings_factory_new (FALSE);
if (icons != NULL || descriptions != NULL)
list_factory = strings_factory_new (TRUE);
else
list_factory = NULL;
widget = g_object_new (GTK_TYPE_DROP_DOWN,
"model", model,
"factory", factory,
"list-factory", list_factory,
NULL);
g_object_unref (model);
g_object_unref (factory);
if (list_factory)
g_object_unref (list_factory);
return widget;
}
static char *
get_family_name (gpointer item)
{
return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
}
static char *
get_title (gpointer item)
{
return g_strdup (STRING_HOLDER (item)->title);
}
GtkWidget *
do_dropdown (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *button, *box, *spin, *check;
GListModel *model;
GtkExpression *expression;
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL };
const char * const many_times[] = {
"1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
"25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
"55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
"8 hours", "9 hours", "10 hours", "11 hours", "12 hours", NULL
};
const char * const device_titles[] = { "Digital Output", "Headphones", "Digital Output", "Analog Output", NULL };
const char * const device_icons[] = { "audio-card-symbolic", "audio-headphones-symbolic", "audio-card-symbolic", "audio-card-symbolic", NULL };
const char * const device_descriptions[] = {
"Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio", "Thinkpad Tunderbolt 3 Dock USB Audio", NULL
};
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Drop Downs");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_start (box, 10);
gtk_widget_set_margin_end (box, 10);
gtk_widget_set_margin_top (box, 10);
gtk_widget_set_margin_bottom (box, 10);
gtk_window_set_child (GTK_WINDOW (window), box);
button = gtk_drop_down_new ();
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_family_name,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
spin = gtk_spin_button_new_with_range (-1, g_list_model_get_n_items (G_LIST_MODEL (model)), 1);
gtk_widget_set_halign (spin, GTK_ALIGN_START);
g_object_bind_property (button, "selected", spin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), spin);
check = gtk_check_button_new_with_label ("Enable search");
g_object_bind_property (button, "enable-search", check, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), check);
g_object_unref (model);
button = drop_down_new_from_strings (times, NULL, NULL);
gtk_box_append (GTK_BOX (box), button);
button = drop_down_new_from_strings (many_times, NULL, NULL);
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions);
gtk_box_append (GTK_BOX (box), button);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,4 +1,4 @@
/* Fixed layout
/* Fixed Layout
*
* GtkFixed is a container that allows placing and transforming
* widgets manually.
@@ -126,7 +126,7 @@ create_demo_window (GtkWidget *do_widget)
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Fixed layout");
gtk_window_set_title (GTK_WINDOW (window), "Fixed Layout");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);

View File

@@ -1,9 +1,8 @@
/* Flow Box
*
* GtkFlowBox allows flexible and responsive grids which reflow
* as needed and support sorting and filtering.
*
* The children of a GtkFlowBox are regular widgets
* as needed and support sorting and filtering. The children of
* a GtkFlowBox are regular widgets
*
* The dataset used here has 665 colors.
*/

View File

@@ -25,7 +25,7 @@ typedef struct _GtkFishbowlChild GtkFishbowlChild;
struct _GtkFishbowlPrivate
{
GtkFishCreationFunc creation_func;
GList *children;
GHashTable *children;
guint count;
gint64 last_frame_time;
@@ -67,6 +67,8 @@ gtk_fishbowl_init (GtkFishbowl *fishbowl)
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
priv->update_delay = G_USEC_PER_SEC;
priv->children = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
}
/**
@@ -93,16 +95,18 @@ gtk_fishbowl_measure (GtkWidget *widget,
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GHashTableIter iter;
gpointer key, value;
GtkFishbowlChild *child;
GList *children;
gint child_min, child_nat;
*minimum = 0;
*natural = 0;
for (children = priv->children; children; children = children->next)
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
{
child = children->data;
child = value;
if (!gtk_widget_get_visible (child->widget))
continue;
@@ -136,11 +140,13 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
GtkFishbowlChild *child;
GtkAllocation child_allocation;
GtkRequisition child_requisition;
GList *children;
GHashTableIter iter;
gpointer key, value;
for (children = priv->children; children; children = children->next)
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
{
child = children->data;
child = value;
if (!gtk_widget_get_visible (child->widget))
continue;
@@ -181,7 +187,7 @@ gtk_fishbowl_add (GtkFishbowl *fishbowl,
gtk_widget_set_parent (widget, GTK_WIDGET (fishbowl));
priv->children = g_list_prepend (priv->children, child_info);
g_hash_table_insert (priv->children, widget, child_info);
priv->count++;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
}
@@ -191,34 +197,32 @@ gtk_fishbowl_remove (GtkFishbowl *fishbowl,
GtkWidget *widget)
{
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GtkWidget *widget_bowl = GTK_WIDGET (fishbowl);
GList *children;
for (children = priv->children; children; children = children->next)
if (g_hash_table_remove (priv->children, widget))
{
child = children->data;
gboolean was_visible = gtk_widget_get_visible (widget);
if (child->widget == widget)
{
gboolean was_visible = gtk_widget_get_visible (widget);
gtk_widget_unparent (widget);
gtk_widget_unparent (widget);
if (was_visible && gtk_widget_get_visible (widget_bowl))
gtk_widget_queue_resize (widget_bowl);
priv->children = g_list_remove_link (priv->children, children);
g_list_free (children);
g_free (child);
if (was_visible && gtk_widget_get_visible (widget_bowl))
gtk_widget_queue_resize (widget_bowl);
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
break;
}
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
}
}
static void
gtk_fishbowl_finalize (GObject *object)
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (object);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
g_hash_table_destroy (priv->children);
priv->children = NULL;
}
static void
gtk_fishbowl_dispose (GObject *object)
{
@@ -304,6 +308,7 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gtk_fishbowl_finalize;
object_class->dispose = gtk_fishbowl_dispose;
object_class->set_property = gtk_fishbowl_set_property;
object_class->get_property = gtk_fishbowl_get_property;
@@ -535,8 +540,9 @@ gtk_fishbowl_tick (GtkWidget *widget,
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GList *l;
gint64 frame_time, elapsed;
GHashTableIter iter;
gpointer key, value;
gboolean do_update;
frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
@@ -548,9 +554,10 @@ gtk_fishbowl_tick (GtkWidget *widget,
if (elapsed == frame_time)
return G_SOURCE_CONTINUE;
for (l = priv->children; l; l = l->next)
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
{
child = l->data;
child = value;
child->x += child->dx * ((double) elapsed / G_USEC_PER_SEC);
child->y += child->dy * ((double) elapsed / G_USEC_PER_SEC);

View File

@@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include "award.h"
static GdkPixbuf *avatar_pixbuf_other;
static GtkWidget *window = NULL;
@@ -235,7 +234,6 @@ reshare_clicked (GtkMessageRow *row,
{
GtkMessageRowPrivate *priv = row->priv;
award ("listbox-reshare");
priv->message->n_reshares++;
gtk_message_row_update (row);
}
@@ -262,8 +260,6 @@ gtk_message_row_state_flags_changed (GtkWidget *widget,
visible = flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED) ? TRUE : FALSE;
gtk_widget_set_visible (priv->extra_buttons_box, visible);
if (visible && gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (widget)) % 100 == 99)
award ("listbox-100th-row");
GTK_WIDGET_CLASS (gtk_message_row_parent_class)->state_flags_changed (widget, previous_state_flags);
}

View File

@@ -1,6 +1,6 @@
/* Lists/Application launcher
*
* This demo uses the GtkCoverFlow widget as a fancy application launcher.
* This demo uses the GtkListView widget as a fancy application launcher.
*
* It is also a very small introduction to listviews.
*/
@@ -30,9 +30,7 @@ create_application_list (void)
apps = g_app_info_get_all ();
for (l = apps; l; l = l->next)
{
g_list_store_append (store, l->data);
}
g_list_store_append (store, l->data);
g_list_free_full (apps, g_object_unref);
@@ -40,19 +38,24 @@ create_application_list (void)
}
/* This is the function we use for setting up new listitems to display.
* We add just a #GtkImage here to display the application's icon as this is just
* a simple demo.
* We add just an #GtkImage and a #GtkKabel here to display the application's
* icon and name, as this is just a simple demo.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box;
GtkWidget *image;
GtkWidget *label;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
image = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_list_item_set_child (list_item, image);
gtk_box_append (GTK_BOX (box), image);
label = gtk_label_new ("");
gtk_box_append (GTK_BOX (box), label);
gtk_list_item_set_child (list_item, box);
}
/* Here we need to prepare the listitem for displaying its item. We get the
@@ -66,12 +69,15 @@ bind_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
GtkWidget *label;
GAppInfo *app_info;
image = gtk_list_item_get_child (list_item);
image = gtk_widget_get_first_child (gtk_list_item_get_child (list_item));
label = gtk_widget_get_next_sibling (image);
app_info = gtk_list_item_get_item (list_item);
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
gtk_label_set_label (GTK_LABEL (label), g_app_info_get_display_name (app_info));
}
/* In more complex code, we would also need functions to unbind and teardown
@@ -90,7 +96,7 @@ bind_listitem_cb (GtkListItemFactory *factory,
* above, but this is a simple demo, so we'll use the simple way.
*/
static void
activate_cb (GtkCoverFlow *coverflow,
activate_cb (GtkListView *list,
guint position,
gpointer unused)
{
@@ -98,15 +104,15 @@ activate_cb (GtkCoverFlow *coverflow,
GdkAppLaunchContext *context;
GError *error = NULL;
app_info = g_list_model_get_item (gtk_cover_flow_get_model (coverflow), position);
app_info = g_list_model_get_item (gtk_list_view_get_model (list), position);
/* Prepare the context for launching the application and launch it. This
* code is explained in detail in the documentation for #GdkAppLaunchContext
* and #GAppInfo.
*/
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (coverflow)));
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (list)));
if (!g_app_info_launch (app_info,
NULL,
NULL,
G_APP_LAUNCH_CONTEXT (context),
&error))
{
@@ -115,7 +121,7 @@ activate_cb (GtkCoverFlow *coverflow,
/* And because error handling is important, even a simple demo has it:
* We display an error dialog that something went wrong.
*/
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (coverflow))),
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (list))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
@@ -136,7 +142,7 @@ do_listview_applauncher (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *coverflow, *sw;;
GtkWidget *list, *sw;
GListModel *model;
GtkListItemFactory *factory;
@@ -147,7 +153,7 @@ do_listview_applauncher (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
/* The #GtkListitemFactory is what is used to create #GtkListItems
* to display the data from the model. So it is absolutely necessary
* to create one.
@@ -160,25 +166,22 @@ do_listview_applauncher (GtkWidget *do_widget)
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
/* Create the list widget here: We use a coverflow widget because it's
* the coolest one. We could just as well use other list widgets such
* as a #GtkListView or a #GtkGridView and the code would look very
* similar.
/* Create the list widget here.
*/
coverflow = gtk_cover_flow_new_with_factory (factory);
list = gtk_list_view_new_with_factory (factory);
/* We connect the activate signal here. It's the function we defined
* above for launching the selected application.
*/
g_signal_connect (coverflow, "activate", G_CALLBACK (activate_cb), NULL);
g_signal_connect (list, "activate", G_CALLBACK (activate_cb), NULL);
/* And of course we need to set the data model. Here we call the function
* we wrote above that gives us the list of applications. Then we set
* it on the coverflow list widget.
* The coverflow will now take items from the model and use the factory
* it on the list widget.
* The list will now take items from the model and use the factory
* to create as many listitems as it needs to show itself to the user.
*/
model = create_application_list ();
gtk_cover_flow_set_model (GTK_COVER_FLOW (coverflow), model);
gtk_list_view_set_model (GTK_LIST_VIEW (list), model);
g_object_unref (model);
/* List widgets should always be contained in a #GtkScrolledWindow,
@@ -187,7 +190,7 @@ do_listview_applauncher (GtkWidget *do_widget)
*/
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), coverflow);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
}
if (!gtk_widget_get_visible (window))

View File

@@ -3,10 +3,9 @@
* This demo displays the time in different timezones.
*
* The goal is to show how to set up expressions that track changes
* in objects and make them update widgets.
*
* For that, we create a GtkClock object that updates its time every
* second and then use various ways to display that time.
* in objects and make them update widgets. For that, we create a
* GtkClock object that updates its time every second and then use
* various ways to display that time.
*
* Typically, this will be done using GtkBuilder .ui files with the
* help of the <binding> tag, but this demo shows the code that runs
@@ -41,7 +40,8 @@ enum {
/* This function returns the current time in the clock's timezone.
* Note that this returns a new object every time, so we need to
* remember to unref it after use. */
* remember to unref it after use.
*/
static GDateTime *
gtk_clock_get_time (GtkClock *clock)
{
@@ -51,10 +51,11 @@ gtk_clock_get_time (GtkClock *clock)
return g_date_time_new_now_local ();
}
/* Here, we implement the functionality required by the GdkPaintable interface.
* This way we have a trivial way to display an analog clock.
* It also allows demonstrating how to directly use objects in the listview
* later by making this object do something interesting. */
/* Here, we implement the functionality required by the GdkPaintable
* interface. This way we have a trivial way to display an analog clock.
* It also allows demonstrating how to directly use objects in the
* listview later by making this object do something interesting.
*/
static void
gtk_clock_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
@@ -68,26 +69,31 @@ gtk_clock_snapshot (GdkPaintable *paintable,
#define BLACK ((GdkRGBA) { 0, 0, 0, 1 })
/* save/restore() is necessary so we can undo the transforms we start
* out with. */
* out with.
*/
gtk_snapshot_save (snapshot);
/* First, we move the (0, 0) point to the center of the area so
* we can draw everything relative to it. */
* we can draw everything relative to it.
*/
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2, height / 2));
/* Next we scale it, so that we can pretend that the clock is
* 100px in size. That way, we don't need to do any complicated
* math later.
* We use MIN() here so that we use the smaller dimension for sizing.
* That way we don't overdraw but keep the aspect ratio. */
* math later. We use MIN() here so that we use the smaller
* dimension for sizing. That way we don't overdraw but keep
* the aspect ratio.
*/
gtk_snapshot_scale (snapshot, MIN (width, height) / 100.0, MIN (width, height) / 100.0);
/* Now we have a circle with diameter 100px (and radius 50px) that
* has its (0, 0) point at the center.
* Let's draw a simple clock into it. */
/* Now we have a circle with diameter 100px (and radius 50px) that
* has its (0, 0) point at the center. Let's draw a simple clock into it.
*/
time = gtk_clock_get_time (self);
/* First, draw a circle. This is a neat little trick to draw a circle
* without requiring Cairo. */
* without requiring Cairo.
*/
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-50, -50, 100, 100), 50);
gtk_snapshot_append_border (snapshot,
&outline,
@@ -95,9 +101,11 @@ gtk_clock_snapshot (GdkPaintable *paintable,
(GdkRGBA [4]) { BLACK, BLACK, BLACK, BLACK });
/* Next, draw the hour hand.
* We do this using tranforms again: Instead of computing where the angle points
* to, we just rotate everything and then draw the hand as if if was :00.
* We don't even need to care about am/pm here because rotations just work. */
* We do this using tranforms again: Instead of computing where the angle
* points to, we just rotate everything and then draw the hand as if it
* was :00. We don't even need to care about am/pm here because rotations
* just work.
*/
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 30 * g_date_time_get_hour (time) + 0.5 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -23, 4, 25), 2);
@@ -107,7 +115,8 @@ gtk_clock_snapshot (GdkPaintable *paintable,
gtk_snapshot_restore (snapshot);
/* And the same as above for the minute hand. Just make this one longer
* so people can tell the hands apart. */
* so people can tell the hands apart.
*/
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 45), 2);
@@ -125,8 +134,9 @@ gtk_clock_snapshot (GdkPaintable *paintable,
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And finally, don't forget to restore the initial save() that we did for
* the initial transformations. */
/* And finally, don't forget to restore the initial save() that
* we did for the initial transformations.
*/
gtk_snapshot_restore (snapshot);
g_date_time_unref (time);
@@ -145,10 +155,9 @@ gtk_clock_get_intrinsic_height (GdkPaintable *paintable)
return 100;
}
/* Initialize the paintable interface. This way we turn our clock objects
* into objects that can be drawn.
* There are more functions to this interface to define desired size,
* but this is enough.
/* Initialize the paintable interface. This way we turn our clocks
* into objects that can be drawn. There are more functions to this
* interface to define desired size, but this is enough.
*/
static void
gtk_clock_paintable_init (GdkPaintableInterface *iface)
@@ -158,8 +167,9 @@ gtk_clock_paintable_init (GdkPaintableInterface *iface)
iface->get_intrinsic_height = gtk_clock_get_intrinsic_height;
}
/* Finally, we define the type. The important part is adding the paintable
* interface, so GTK knows that this object can indeed be drawm.
/* Finally, we define the type. The important part is adding the
* paintable interface, so GTK knows that this object can indeed
* be drawn.
*/
G_DEFINE_TYPE_WITH_CODE (GtkClock, gtk_clock, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
@@ -221,11 +231,14 @@ gtk_clock_set_property (GObject *object,
/* This is the list of all the ticking clocks */
static GSList *ticking_clocks = NULL;
/* This is the id of the timeout source that is updating all ticking clocks */
/* This is the ID of the timeout source that is updating all
* ticking clocks.
*/
static guint ticking_clock_id = 0;
/* Every second, this function is called to tell everybody that the
* clocks are ticking.
/* Every second, this function is called to tell everybody that
* the clocks are ticking.
*/
static gboolean
gtk_clock_tick (gpointer unused)
@@ -240,6 +253,7 @@ gtk_clock_tick (gpointer unused)
* so notify about that.
*/
g_object_notify_by_pspec (G_OBJECT (clock), properties[PROP_TIME]);
/* We will also draw the hands of the clock differently.
* So notify about that, too.
*/
@@ -309,16 +323,16 @@ gtk_clock_init (GtkClock *self)
static GtkClock *
gtk_clock_new (const char *location,
GTimeZone *timezone)
GTimeZone *_timezone)
{
GtkClock *result;
result = g_object_new (GTK_TYPE_CLOCK,
"location", location,
"timezone", timezone,
"timezone", _timezone,
NULL);
g_clear_pointer (&timezone, g_time_zone_unref);
g_clear_pointer (&_timezone, g_time_zone_unref);
return result;
}
@@ -343,6 +357,9 @@ create_clocks_model (void)
clock = gtk_clock_new ("San Francisco", g_time_zone_new ("America/Los_Angeles"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Xalapa", g_time_zone_new ("America/Mexico_City"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Boston", g_time_zone_new ("America/New_York"));
g_list_store_append (result, clock);
g_object_unref (clock);

View File

@@ -6,11 +6,13 @@
* and sort the data in various ways. The controls for
* this are implemented using GtkDropDown.
*
* The dataset used here has 9283 items.
* The dataset used here has 9283 items.
*/
#include <gtk/gtk.h>
#include <stdlib.h>
#define GTK_TYPE_COLOR (gtk_color_get_type ())
G_DECLARE_FINAL_TYPE (GtkColor, gtk_color, GTK, COLOR, GObject)
@@ -23,6 +25,7 @@ struct _GtkColor
char *name;
GdkRGBA *color;
int h, s, v;
gboolean selected;
};
enum {
@@ -35,6 +38,7 @@ enum {
PROP_HUE,
PROP_SATURATION,
PROP_VALUE,
PROP_SELECTED,
N_PROPS
};
@@ -122,6 +126,10 @@ gtk_color_get_property (GObject *object,
g_value_set_int (value, self->v);
break;
case PROP_SELECTED:
g_value_set_boolean (value, self->selected);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -158,6 +166,10 @@ gtk_color_set_property (GObject *object,
self->v = g_value_get_int (value);
break;
case PROP_SELECTED:
self->selected = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -200,6 +212,8 @@ gtk_color_class_init (GtkColorClass *klass)
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_VALUE] =
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_SELECTED] =
g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -259,7 +273,7 @@ create_colors_model (void)
h = atoi (fields[9]);
s = atoi (fields[10]);
v = atoi (fields[11]);
color = gtk_color_new (name, red / 255., green / 255., blue / 255., h, s, v);
g_list_store_append (result, color);
g_object_unref (color);
@@ -320,7 +334,7 @@ static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *name_label, *rgb_label, *hsv_label;;
GtkWidget *box, *picture, *name_label, *rgb_label, *hsv_label;
GtkExpression *color_expression, *expression;
GtkExpression *params[1];
@@ -420,12 +434,12 @@ create_color_grid (void)
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
gtk_grid_view_set_factory (GTK_GRID_VIEW (gridview), factory);
g_object_unref (factory);
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
model = G_LIST_MODEL (gtk_sort_list_model_new (create_colors_model (), NULL));
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
selection = G_LIST_MODEL (gtk_property_selection_new (model, "selected"));
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
g_object_unref (selection);
g_object_unref (model);

View File

@@ -18,6 +18,7 @@ struct _FileBrowserView
GtkListItemFactory *factory;
char *icon_name;
char *title;
GtkOrientation orientation;
};
@@ -25,6 +26,7 @@ enum {
PROP_0,
PROP_FACTORY,
PROP_ICON_NAME,
PROP_TITLE,
PROP_ORIENTATION,
N_PROPS
@@ -54,6 +56,10 @@ file_browser_view_get_property (GObject *object,
g_value_set_string (value, self->icon_name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, self->orientation);
break;
@@ -83,6 +89,11 @@ file_browser_view_set_property (GObject *object,
self->icon_name = g_value_dup_string (value);
break;
case PROP_TITLE:
g_free (self->title);
self->title = g_value_dup_string (value);
break;
case PROP_ORIENTATION:
self->orientation = g_value_get_enum (value);
break;
@@ -100,6 +111,7 @@ file_browser_view_finalize (GObject *object)
g_object_unref (self->factory);
g_free (self->icon_name);
g_free (self->title);
G_OBJECT_CLASS (file_browser_view_parent_class)->dispose (object);
}
@@ -125,6 +137,12 @@ file_browser_view_class_init (FileBrowserViewClass *klass)
"icon to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"title",
"title to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_ORIENTATION] =
g_param_spec_enum ("orientation",
"orientation",
@@ -224,6 +242,14 @@ do_listview_filebrowser (GtkWidget *do_widget)
GtkDirectoryList *dirlist;
GFile *file;
char *cwd;
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/listview_filebrowser/listview_filebrowser.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/listview_filebrowser/listview_filebrowser.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));

View File

@@ -0,0 +1,11 @@
list.viewswitcher {
border: 1px solid gray;
}
list.viewswitcher > row {
padding: 5px;
}
list.viewswitcher row:selected {
background: gray;
}

View File

@@ -39,12 +39,14 @@
</object>
</property>
<property name="icon-name">view-list-symbolic</property>
<property name="title" translatable="yes">List</property>
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-grid-symbolic</property>
<property name="title" translatable="yes">Grid</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
@@ -92,6 +94,7 @@
<child>
<object class="FileBrowserView">
<property name="icon-name">view-paged-symbolic</property>
<property name="title" translatable="yes">Paged</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
@@ -174,7 +177,7 @@
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="icon-name">go-up</property>
<property name="icon-name">go-up-symbolic</property>
<signal name="clicked" handler="filebrowser_up_clicked_cb" object="dirlist" swapped="no"/>
</object>
</child>
@@ -184,6 +187,7 @@
<property name="orientation">horizontal</property>
<style>
<class name="linked"/>
<class name="viewswitcher"/>
</style>
<property name="model">
<object class="GtkSingleSelection" id="selected-view">
@@ -203,6 +207,11 @@
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
<binding name="tooltip-text">
<lookup type="FileBrowserView" name="title">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>

View File

@@ -9,6 +9,8 @@
#include <gtk/gtk.h>
#include <stdlib.h>
/* Create an object that wraps GSettingsSchemaKey because that's a boxed type */
typedef struct _SettingsKey SettingsKey;
struct _SettingsKey
@@ -25,6 +27,8 @@ enum {
PROP_SUMMARY,
PROP_DESCRIPTION,
PROP_VALUE,
PROP_TYPE,
PROP_DEFAULT_VALUE,
N_PROPS
};
@@ -65,6 +69,21 @@ settings_key_get_property (GObject *object,
}
break;
case PROP_TYPE:
{
const GVariantType *type = g_settings_schema_key_get_value_type (self->key);
g_value_set_string (value, g_variant_type_peek_string (type));
}
break;
case PROP_DEFAULT_VALUE:
{
GVariant *variant = g_settings_schema_key_get_default_value (self->key);
g_value_take_string (value, g_variant_print (variant, FALSE));
g_variant_unref (variant);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -98,6 +117,10 @@ settings_key_class_init (SettingsKeyClass *klass)
g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_VALUE] =
g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_TYPE] =
g_param_spec_string ("type", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_DEFAULT_VALUE] =
g_param_spec_string ("default-value", NULL, NULL, NULL, G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -119,6 +142,43 @@ settings_key_new (GSettings *settings,
return result;
}
static void
item_value_changed (GtkListItem *item,
GtkEntry *entry)
{
SettingsKey *self;
const char *text;
const GVariantType *type;
GVariant *variant;
GError *error = NULL;
const char *name;
text = gtk_editable_get_text (GTK_EDITABLE (entry));
g_object_get (item, "item", &self, NULL);
g_object_unref (self);
type = g_settings_schema_key_get_value_type (self->key);
name = g_settings_schema_key_get_name (self->key);
variant = g_variant_parse (type, text, NULL, NULL, &error);
if (!variant)
{
g_warning ("%s", error->message);
g_clear_error (&error);
return;
}
if (!g_settings_schema_key_range_check (self->key, variant))
{
g_warning ("Not a valid value for %s", name);
return;
}
g_settings_set_value (self->settings, name, variant);
g_variant_unref (variant);
}
static int
strvcmp (gconstpointer p1,
gconstpointer p2)
@@ -144,6 +204,7 @@ transform_settings_to_keys (GBinding *binding,
GtkSortListModel *sort_model;
GtkFilterListModel *filter_model;
GtkFilter *filter;
GtkNoSelection *selection_model;
GtkExpression *expression;
char **keys;
guint i;
@@ -186,7 +247,10 @@ transform_settings_to_keys (GBinding *binding,
g_object_unref (filter);
g_value_take_object (to_value, filter_model);
selection_model = gtk_no_selection_new (G_LIST_MODEL (filter_model));
g_object_unref (filter_model);
g_value_take_object (to_value, selection_model);
return TRUE;
}
@@ -279,7 +343,13 @@ do_listview_settings (GtkWidget *do_widget)
GtkBuilderScope *scope;
GtkBuilder *builder;
GtkColumnViewColumn *name_column;
GtkColumnViewColumn *type_column;
GtkColumnViewColumn *default_column;
GtkColumnViewColumn *summary_column;
GtkColumnViewColumn *description_column;
GtkSorter *sorter;
GActionGroup *actions;
GAction *action;
g_type_ensure (SETTINGS_TYPE_KEY);
@@ -287,6 +357,7 @@ do_listview_settings (GtkWidget *do_widget)
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_enabled", (GCallback)search_enabled);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_changed", (GCallback)search_changed);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "stop_search", (GCallback)stop_search);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "item_value_changed", (GCallback)item_value_changed);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
@@ -299,6 +370,32 @@ do_listview_settings (GtkWidget *do_widget)
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview"));
type_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "type_column"));
default_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "default_column"));
summary_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "summary_column"));
description_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "description_column"));
actions = G_ACTION_GROUP (g_simple_action_group_new ());
action = G_ACTION (g_property_action_new ("show-type", type_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-default", default_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-summary", summary_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-description", description_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
gtk_widget_insert_action_group (columnview, "columnview", actions);
g_object_unref (actions);
model = create_settings_model (NULL, NULL);
treemodel = gtk_tree_list_model_new (FALSE,
model,
@@ -322,6 +419,8 @@ do_listview_settings (GtkWidget *do_widget)
sorter = gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
gtk_column_view_column_set_sorter (name_column, sorter);
g_object_unref (sorter);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))

View File

@@ -77,6 +77,7 @@
<child>
<object class="GtkColumnViewColumn" id="name_column">
<property name="title">Name</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
@@ -103,6 +104,37 @@
<child>
<object class="GtkColumnViewColumn">
<property name="title">Value</property>
<property name="resizable">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkEntry">
<signal name="activate" handler="item_value_changed" object="GtkListItem" swapped="yes"/>
<property name="xalign">0</property>
<binding name="text">
<lookup name="value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="type_column">
<property name="title">Type</property>
<property name="resizable">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
@@ -113,7 +145,98 @@
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="value" type="SettingsKey">
<lookup name="type" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="default_column">
<property name="title">Default</property>
<property name="resizable">1</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="default-value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="summary_column">
<property name="title">Summary</property>
<property name="resizable">1</property>
<property name="visible">0</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="summary" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="description_column">
<property name="title">Description</property>
<property name="resizable">1</property>
<property name="visible">0</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="description" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
@@ -135,4 +258,24 @@
</object>
</child>
</object>
<menu id="header_menu">
<section>
<item>
<attribute name="label" translatable="yes">Type</attribute>
<attribute name="action">columnview.show-type</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Default value</attribute>
<attribute name="action">columnview.show-default</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Summary</attribute>
<attribute name="action">columnview.show-summary</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Description</attribute>
<attribute name="action">columnview.show-description</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -11,7 +11,7 @@
* A GtkNoSelectionModel is used to make sure no item in the list can be
* selected. All other interactions with the items is still possible.
*
* The dataset used here has 70000 items.
* The dataset used here has 70000 items.
*/
#include <gtk/gtk.h>
@@ -78,13 +78,13 @@ gtk_weather_info_new (GDateTime *timestamp,
static GDateTime *
parse_timestamp (const char *string,
GTimeZone *timezone)
GTimeZone *_timezone)
{
char *with_seconds;
GDateTime *result;
with_seconds = g_strconcat (string, ":00", NULL);
result = g_date_time_new_from_iso8601 (with_seconds, timezone);
result = g_date_time_new_from_iso8601 (with_seconds, _timezone);
g_free (with_seconds);
return result;
@@ -301,7 +301,7 @@ do_listview_weather (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *sw;;
GtkWidget *listview, *sw;
window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);

View File

@@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include <glib/gstdio.h>
#include "award.h"
#include "demos.h"
static GtkWidget *info_view;
@@ -213,7 +212,6 @@ activate_inspector (GSimpleAction *action,
gpointer user_data)
{
gtk_window_set_interactive_debugging (TRUE);
award ("demo-inspector");
}
static void
@@ -601,7 +599,7 @@ display_image (const char *resource)
{
GtkWidget *sw, *image;
image = gtk_image_new_from_resource (resource);
image = gtk_picture_new_for_resource (resource);
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
sw = gtk_scrolled_window_new (NULL, NULL);
@@ -1042,7 +1040,7 @@ activate (GApplication *app)
listmodel = create_demo_model ();
treemodel = gtk_tree_list_model_new (FALSE,
G_LIST_MODEL (listmodel),
FALSE,
TRUE,
get_child_model,
NULL,
NULL);
@@ -1051,10 +1049,6 @@ activate (GApplication *app)
gtk_list_view_set_model (GTK_LIST_VIEW (listview),
G_LIST_MODEL (selection));
award ("demo-start");
gtk_widget_show (GTK_WIDGET (window));
g_object_unref (builder);
}
@@ -1113,11 +1107,11 @@ command_line (GApplication *app,
return 0;
}
window = gtk_application_get_windows (GTK_APPLICATION (app))->data;
if (name == NULL)
goto out;
window = gtk_application_get_windows (GTK_APPLICATION (app))->data;
d = gtk_demos;
while (d->title)
@@ -1147,7 +1141,11 @@ out:
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
g_signal_connect_swapped (G_OBJECT (demo), "destroy", G_CALLBACK (g_application_quit), app);
}
else
gtk_widget_show (GTK_WIDGET (window));
if (autoquit)
g_timeout_add_seconds (1, auto_quit, app);

View File

@@ -5,7 +5,7 @@ Text <span color="gray">c<span color="green">o</span>l<span color="tomato">o</sp
Colorful <span underline="low" underline-color="blue"><span underline="double" underline-color="red">under</span>lines</span> and <span background="pink"><span underline="error">mo</span><span underline="error" underline-color="green">re</span></span>
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span>
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span> and <span overline="single" overline_color="green">overlines</span>
Superscripts and subscripts: 𝜀<span rise="-6000" size="x-small" font_desc="italic">0</span> = 𝜔<span rise="8000" size="smaller">𝜔<span rise="14000" size="smaller">𝜔<span rise="20000">.<span rise="23000">.<span rise="26000">.</span></span></span></span></span>

View File

@@ -3,7 +3,6 @@
demos = files([
'application_demo.c',
'assistant.c',
'awardview.c',
'builder.c',
'clipboard.c',
'combobox.c',
@@ -19,6 +18,7 @@ demos = files([
'cursors.c',
'dialog.c',
'drawingarea.c',
'dropdown.c',
'dnd.c',
'editable_cells.c',
'entry_completion.c',
@@ -92,7 +92,6 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
extra_demo_sources = files(['main.c',
'award.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',

View File

@@ -11,7 +11,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "award.h"
static GtkWidget *entry;
static GtkWidget *entry2;
@@ -27,17 +26,12 @@ update_button (GObject *object,
gtk_widget_set_sensitive (button,
text[0] != '\0' && g_str_equal (text, text2));
if (g_str_equal (text, text2) &&
g_ascii_strcasecmp (text, "12345") == 0)
award ("password-best");
}
static void
button_pressed (GtkButton *widget,
GtkWidget *window)
{
award ("password-correct");
gtk_window_destroy (GTK_WINDOW (window));
}

View File

@@ -1,4 +1,4 @@
/* Sliding puzzle
/* Sliding Puzzle
*
* This demo demonstrates how to use gestures and paintables to create a
* small sliding puzzle game.
@@ -11,8 +11,6 @@
#include "puzzlepiece.h"
#include "paintable.h"
/* Give out awards */
#include "award.h"
static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
@@ -159,14 +157,6 @@ check_solved (GtkWidget *grid)
picture = gtk_grid_get_child_at (GTK_GRID (grid), pos_x, pos_y);
gtk_picture_set_paintable (GTK_PICTURE (picture), piece);
/* Hand out a bunch of awards
*/
award ("puzzle-solve");
if ((gdk_paintable_get_flags (piece) & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
award ("puzzle-solve-animated");
if (height * width > 20)
award ("puzzle-solve-large");
return TRUE;
}
@@ -251,6 +241,8 @@ puzzle_button_pressed (GtkGestureClick *gesture,
{
gtk_widget_error_bell (grid);
}
check_solved (grid);
}
static void
@@ -291,6 +283,8 @@ start_puzzle (GdkPaintable *paintable)
/* Add shortcuts so people can use the arrow
* keys to move the puzzle */
controller = gtk_shortcut_controller_new ();
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
GTK_SHORTCUT_SCOPE_GLOBAL);
add_move_binding (GTK_SHORTCUT_CONTROLLER (controller),
GDK_KEY_Left, GDK_KEY_KP_Left,
-1, 0);
@@ -351,11 +345,16 @@ reshuffle (void)
{
GtkWidget *grid;
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
if (solved)
start_puzzle (puzzle);
{
start_puzzle (puzzle);
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
}
else
shuffle_puzzle (grid);
{
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
shuffle_puzzle (grid);
}
gtk_widget_grab_focus (grid);
}
@@ -407,9 +406,6 @@ widget_destroyed (gpointer data,
{
if (data)
*(gpointer *) data = NULL;
if (!solved)
award ("puzzle-give-up");
}

View File

@@ -92,12 +92,11 @@ static Theme themes[] = {
static int theme;
static gboolean
change_theme (GtkWidget *widget,
change_theme (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer data)
gpointer data)
{
GtkBuilder *builder = data;
GtkWidget *label;
GtkWidget *label = data;
Theme next = themes[theme++ % G_N_ELEMENTS (themes)];
char *name;
@@ -110,7 +109,6 @@ change_theme (GtkWidget *widget,
gtk_window_set_title (GTK_WINDOW (widget), name);
g_free (name);
label = GTK_WIDGET (gtk_builder_get_object (builder, "fps"));
if (frame_clock)
{
char *fps;
@@ -127,10 +125,10 @@ change_theme (GtkWidget *widget,
static void
clicked (GtkGestureClick *gesture,
int n_press,
double x,
double y,
gpointer data)
int n_press,
double x,
double y,
gpointer data)
{
GtkWidget *window;
GdkEvent *event;
@@ -165,6 +163,29 @@ clicked (GtkGestureClick *gesture,
}
}
static void
toggle_cycle (GObject *button,
GParamSpec *pspec,
gpointer data)
{
gboolean active;
GtkWidget *window;
g_object_get (button, "active", &active, NULL);
window = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW);
if (active && !tick_cb)
{
tick_cb = gtk_widget_add_tick_callback (window, change_theme, data, NULL);
}
else if (!active && tick_cb)
{
gtk_widget_remove_tick_callback (window, tick_cb);
tick_cb = 0;
}
}
GtkWidget *
do_themes (GtkWidget *do_widget)
{
@@ -174,6 +195,8 @@ do_themes (GtkWidget *do_widget)
{
GtkBuilder *builder;
GtkWidget *header;
GtkWidget *button;
GtkWidget *label;
GtkGesture *gesture;
builder = gtk_builder_new_from_resource ("/themes/themes.ui");
@@ -183,11 +206,17 @@ do_themes (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
header = GTK_WIDGET (gtk_builder_get_object (builder, "header"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "fps"));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), builder);
g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), label);
gtk_widget_add_controller (header, GTK_EVENT_CONTROLLER (gesture));
button = GTK_WIDGET (gtk_builder_get_object (builder, "toggle"));
g_signal_connect (button, "notify::active", G_CALLBACK (toggle_cycle), label);
gtk_widget_realize (window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))

View File

@@ -5,6 +5,11 @@
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkToggleButton" id="toggle">
<property name="label">Cycle</property>
</object>
</child>
<child type="end">
<object class="GtkLabel" id="fps"/>
</child>

View File

@@ -93,7 +93,6 @@ gdk_display_get_clipboard
gdk_display_get_primary_clipboard
gdk_display_get_setting
gdk_display_get_startup_notification_id
gdk_display_setup_window_visual
<SUBSECTION>
gdk_display_put_event
@@ -358,9 +357,6 @@ gdk_device_get_name
gdk_device_get_vendor_id
gdk_device_get_product_id
gdk_device_get_source
gdk_device_set_key
gdk_device_get_key
gdk_device_set_axis_use
gdk_device_get_axis_use
gdk_device_get_associated_device
gdk_device_list_slave_devices
@@ -368,7 +364,6 @@ gdk_device_get_device_type
gdk_device_get_display
gdk_device_get_has_cursor
gdk_device_get_n_axes
gdk_device_get_n_keys
gdk_device_get_axes
gdk_device_get_seat
gdk_device_get_num_touches
@@ -383,8 +378,6 @@ gdk_device_has_bidi_layouts
<SUBSECTION>
gdk_device_get_state
gdk_device_get_surface_at_position
gdk_device_get_history
gdk_device_free_history
GdkTimeCoord
gdk_device_get_axis
gdk_device_get_axis_names
@@ -501,7 +494,9 @@ gdk_event_get_modifier_state
gdk_event_get_position
gdk_event_get_axes
gdk_event_get_axis
gdk_event_get_history
gdk_event_get_pointer_emulated
gdk_event_triggers_context_menu
gdk_button_event_get_button
gdk_scroll_event_get_direction
gdk_scroll_event_get_deltas
@@ -520,6 +515,7 @@ gdk_crossing_event_get_mode
gdk_crossing_event_get_detail
gdk_crossing_event_get_focus
gdk_grab_broken_event_get_grab_surface
gdk_grab_broken_event_get_implicit
gdk_dnd_event_get_drop
gdk_configure_event_get_size
gdk_touchpad_event_get_gesture_phase
@@ -530,7 +526,6 @@ gdk_touchpad_event_get_pinch_scale
gdk_pad_event_get_axis_value
gdk_pad_event_get_button
gdk_pad_event_get_group_mode
gdk_motion_event_get_history
<SUBSECTION>
gdk_events_get_angle
@@ -545,8 +540,23 @@ GDK_TYPE_CROSSING_MODE
GDK_TYPE_SCROLL_DIRECTION
GDK_TYPE_NOTIFY_TYPE
GDK_IS_EVENT
gdk_event_get_type
gdk_event_sequence_get_type
gdk_button_event_get_type
gdk_configure_event_get_type
gdk_crossing_event_get_type
gdk_delete_event_get_type
gdk_dnd_event_get_type
gdk_focus_event_get_type
gdk_grab_broken_event_get_type
gdk_key_event_get_type
gdk_motion_event_get_type
gdk_pad_event_get_type
gdk_proximity_event_get_type
gdk_scroll_event_get_type
gdk_touch_event_get_type
gdk_touchpad_event_get_type
</SECTION>
<SECTION>

View File

@@ -27,15 +27,19 @@ private_headers = [
'gdkmonitorprivate.h',
'gdkmemorytextureprivate.h',
'gdkpipeiostreamprivate.h',
'gdkpopupprivate.h',
'gdkprofilerprivate.h',
'gdkscreenprivate.h',
'gdkseatdefaultprivate.h',
'gdkseatprivate.h',
'gdksnapshotprivate.h',
'gdksurfaceimpl.h',
'gdksurfaceprivate.h',
'gdktextureprivate.h',
'gdktoplevelprivate.h',
'gdkvulkancontextprivate.h',
'keyname-table.h',
'gdkprivate-x11.h',
'x11/gdkprivate-x11.h',
'x11/gdkeventsource.h',
'gtk-primary-selection-client-protocol.h',
'gtk-shell-client-protocol.h',

View File

@@ -236,7 +236,6 @@ gsk_transform_to_translate
gsk_transform_transform
gsk_transform_invert
gsk_transform_matrix
gsk_transform_matrix_with_category
gsk_transform_translate
gsk_transform_translate_3d
gsk_transform_rotate

View File

@@ -9,9 +9,11 @@ private_headers = [
'gskprofilerprivate.h',
'gskrendererprivate.h',
'gskrendernodeprivate.h',
'gskrendernodeparserprivate.h',
'gskroundedrectprivate.h',
'gskshaderbuilderprivate.h',
'gsktextureprivate.h',
'gsktransformprivate.h',
'gskvulkanblendpipelineprivate.h',
'gskvulkanborderpipelineprivate.h',
'gskvulkanboxshadowpipelineprivate.h',

View File

@@ -37,7 +37,7 @@ this range will trigger compiler warnings.
Here is how you would compile hello.c if you want to allow it
to use symbols that were not deprecated in 4.2:
```
$ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MIN_REQIRED=GDK_VERSION_4_2 hello.c -o hello `pkg-config --libs gtk4`
$ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_4_2 hello.c -o hello `pkg-config --libs gtk4`
```
And here is how you would compile hello.c if you don't want

View File

@@ -68,8 +68,12 @@
<xi:include href="xml/gtkmultisorter.xml" />
</section>
<xi:include href="xml/gtkselectionmodel.xml" />
<xi:include href="xml/gtknoselection.xml" />
<xi:include href="xml/gtksingleselection.xml" />
<section>
<xi:include href="xml/gtknoselection.xml" />
<xi:include href="xml/gtksingleselection.xml" />
<xi:include href="xml/gtkmultiselection.xml" />
<xi:include href="xml/gtkpropertyselection.xml" />
</section>
<xi:include href="xml/gtkdirectorylist.xml" />
</chapter>
@@ -90,8 +94,11 @@
</chapter>
<chapter id="Trees">
<xi:include href="xml/gtktreelistrow.xml" />
<title>Tree support</title>
<xi:include href="xml/gtktreelistmodel.xml" />
<section>
<xi:include href="xml/gtktreelistrow.xml" />
</section>
<xi:include href="xml/gtktreelistrowsorter.xml" />
<xi:include href="xml/gtktreeexpander.xml" />
</chapter>
@@ -120,6 +127,7 @@
<xi:include href="xml/gtkaboutdialog.xml" />
<xi:include href="xml/gtkassistant.xml" />
<xi:include href="xml/gtkwindowgroup.xml" />
<xi:include href="xml/gtknativedialog.xml" />
</chapter>
<chapter id="LayoutContainers">

View File

@@ -350,6 +350,9 @@ gtk_selection_model_select_range
gtk_selection_model_unselect_range
gtk_selection_model_select_all
gtk_selection_model_unselect_all
GtkSelectionCallback
gtk_selection_model_select_callback
gtk_selection_model_unselect_callback
gtk_selection_model_query_range
<SUBSECTION>
gtk_selection_model_selection_changed
@@ -392,6 +395,24 @@ gtk_single_selection_set_can_unselect
gtk_single_selection_get_type
</SECTION>
<SECTION>
<FILE>gtkmultiselection</FILE>
<TITLE>GtkMultiSeledction</TITLE>
GtkMultiSelection
gtk_multi_selection_new
<SUBSECTION Private>
gtk_multi_selection_get_type
</SECTION>
<SECTION>
<FILE>gtkpropertyselection</FILE>
<TITLE>GtkPropertySelection</TITLE>
GtkPropertySelection
gtk_property_selection_new
<SUBSECTION Private>
gtk_property_selection_get_type
</SECTION>
<SECTION>
<FILE>gtklistitem</FILE>
<TITLE>GtkListItem</TITLE>
@@ -481,9 +502,6 @@ gtk_list_view_set_single_click_activate
gtk_list_view_get_single_click_activate
gtk_list_view_set_enable_rubberband
gtk_list_view_get_enable_rubberband
gtk_list_view_set_search_filter
gtk_list_view_get_search_filter
gtk_list_view_next_match
<SUBSECTION Standard>
GTK_LIST_VIEW
GTK_LIST_VIEW_CLASS
@@ -507,16 +525,17 @@ gtk_column_view_get_columns
gtk_column_view_get_model
gtk_column_view_set_model
gtk_column_view_get_sorter
gtk_column_view_get_show_separators
gtk_column_view_set_show_separators
gtk_column_view_get_show_row_separators
gtk_column_view_set_show_row_separators
gtk_column_view_get_show_column_separators
gtk_column_view_set_show_column_separators
gtk_column_view_sort_by_column
gtk_column_view_set_single_click_activate
gtk_column_view_get_single_click_activate
gtk_column_view_set_reorderable
gtk_column_view_get_reorderable
gtk_column_view_set_enable_rubberband
gtk_column_view_get_enable_rubberband
gtk_column_view_set_search_filter
gtk_column_view_get_search_filter
gtk_column_view_next_match
<SUBSECTION Standard>
GTK_COLUMN_VIEW
GTK_COLUMN_VIEW_CLASS
@@ -543,8 +562,15 @@ gtk_column_view_column_set_sorter
gtk_column_view_column_get_sorter
gtk_column_view_column_set_visible
gtk_column_view_column_get_visible
gtk_column_view_column_set_resizable
gtk_column_view_column_get_resizable
gtk_column_view_column_set_header_menu
gtk_column_view_column_get_header_menu
gtk_column_view_column_set_fixed_width
gtk_column_view_column_get_fixed_width
gtk_column_view_column_set_expand
gtk_column_view_column_get_expand
<SUBSECTION Standard>
GTK_COLUMN_VIEW_COLUMN
GTK_COLUMN_VIEW_COLUMN_CLASS
@@ -571,9 +597,6 @@ gtk_grid_view_set_single_click_activate
gtk_grid_view_get_single_click_activate
gtk_grid_view_set_enable_rubberband
gtk_grid_view_get_enable_rubberband
gtk_grid_view_set_search_filter
gtk_grid_view_get_search_filter
gtk_grid_view_next_match
<SUBSECTION Standard>
GTK_GRID_VIEW
GTK_GRID_VIEW_CLASS
@@ -1443,7 +1466,6 @@ gtk_custom_filter_get_type
<FILE>gtkfilterlistmodel</FILE>
<TITLE>GtkFilterListModel</TITLE>
GtkFilterListModel
GtkFilterListModelFilterFunc
gtk_filter_list_model_new
gtk_filter_list_model_new_for_type
gtk_filter_list_model_set_model
@@ -2033,7 +2055,7 @@ gtk_info_bar_get_type
<SECTION>
<FILE>gtknativedialog</FILE>
<TITLE>GtkNativeDialog</TITLE>
GTK_TYPE_NATIVE_DIALOG
GtkNativeDialog
GtkNativeDialogClass
gtk_native_dialog_show
gtk_native_dialog_hide
@@ -2045,9 +2067,8 @@ gtk_native_dialog_set_title
gtk_native_dialog_get_title
gtk_native_dialog_set_transient_for
gtk_native_dialog_get_transient_for
<SUBSECTION Standard>
GtkNativeDialog
<SUBSECTION Private>
GTK_TYPE_NATIVE_DIALOG
gtk_native_dialog_get_type
</SECTION>
@@ -2121,12 +2142,18 @@ GtkNotebookPrivate
<TITLE>GtkPaned</TITLE>
GtkPaned
gtk_paned_new
gtk_paned_add1
gtk_paned_add2
gtk_paned_pack1
gtk_paned_pack2
gtk_paned_get_child1
gtk_paned_get_child2
gtk_paned_set_start_child
gtk_paned_get_start_child
gtk_paned_set_end_child
gtk_paned_get_end_child
gtk_paned_set_resize_start_child
gtk_paned_get_resize_start_child
gtk_paned_set_resize_end_child
gtk_paned_get_resize_end_child
gtk_paned_set_shrink_start_child
gtk_paned_get_shrink_start_child
gtk_paned_set_shrink_end_child
gtk_paned_get_shrink_end_child
gtk_paned_set_position
gtk_paned_get_position
gtk_paned_set_wide_handle

View File

@@ -139,6 +139,7 @@ gtk_menu_button_get_type
gtk_message_dialog_get_type
gtk_mount_operation_get_type
gtk_multi_filter_get_type
gtk_multi_selection_get_type
gtk_multi_sorter_get_type
gtk_native_get_type
gtk_native_dialog_get_type
@@ -168,6 +169,7 @@ gtk_print_operation_preview_get_type
gtk_print_settings_get_type
@DISABLE_ON_W32@gtk_print_unix_dialog_get_type
gtk_progress_bar_get_type
gtk_property_selection_get_type
gtk_radio_button_get_type
gtk_range_get_type
gtk_recent_manager_get_type

View File

@@ -1,101 +0,0 @@
# List widgets
GTK provides powerful widgets to display and edit lists of data. This document gives an overview over the concepts and how they work together to allow developers to implement lists.
Lists are intended to be used whenever developers want to display lists of objects in roughly the same way.
Lists are perfectly fine to be used for very short list of only 2 or 3 elements, but generally scale fine to millions of items. Of course, the larger the list grows, the more care needs to be taken to choose the right data structures to keep things running well.
Lists are meant to be used with changing data, both with the items itself changing as well as the list adding and removing items. Of course, they work just as well with static data.
## Terminology
These terms are used throughout the documentation when talking about lists and you should be aware of what they refer to. These are often generic terms that have a specific meaning in this context.
**_Views_** or **_list widgets_** are the widgets that hold and manage the lists. Examples of thse widgets would be #GtkListView or #GtkGridView.
Views display data from a **_model_**. A model is a #GListModel and models can be provided in 3 ways or combinations thereof:
* Many list models implementations already exist. There are models that provide specific data, like #GtkDirectoryList. And there are models like #GListStore that allow building lists manually.
* Wrapping list models exists like #GtkFilterListModel or #GtkSortListModel that modify or adapt or combine other models.
* Last but not least, developers are encouraged to create their own #GListModel implementations. The interface is kept deliberately small to make this easy.
The same model can be used in multiple different views and wrapped with multiple different models at once.
The elements in a model are called **_items_**. All items are #GObjects.
Every item in a model has a **_position_** which is the unsigned integer that describes where in the model the item is located. This position can of course change as items are added or removed from the model.
It is important to be aware of the difference between items and positions because the mapping from position to item is not permanent, so developers should think about whether they want to track items or positions when working with models. Oftentimes some things are really hard to do one way but very easy the other way.
The other important part of a view is a **_factory_**. Each factory is a #GtkListItemFactory implementation that takes care of mapping the items of the model to widgets that can be shown in the view.
The way factories do this is by creating a **_listitem_** for each item that is currently in use. Listitems are always #GtkListItem objects. They are only ever created by GTK and provide information about what item they are meant to display.
Different factory implementations use various different methods to allow developers to add the right widgets to listitems and to link those widgets with the item managed by the listitem. Finding a suitable factory implementation for the data displayed, the programming language and development environment is an important task that can simplify setting up the view tremendously.
Views support selections via a **_selection model_**. A selection model is an implementation of the #GtkSelectionModel interface on top of the #GListModel interface that allows marking each item in a model as either selected or not selected. Just like regular models, this can be implemented either by implementing #GtkSelectionModel directly or by wrapping a model with one of the GTK models provided for this purposes, such as #GtkNoSelection or #GtkSingleSelection. The behavior of selection models - ie which items they allow selecting and what effect this has on other items - is completely up to the selection model. As such, single-selections, multi-selections or sharing selection state between different selection models and/or views is possible. The selection state of an item is exposed in the listitem via the GtkListItem:selected property.
Views and listitems also support activation. Activation means that double clicking or pressing enter while inside a focused row will cause the view to emit and activation signal such as GtkListView::activate. This provides an easy way to set up lists, but can also be turned off on listitems if undesired.
Both selections and activation are supported among other things via widget actions (FIXME: Link docs). This allows developers to add widgets to their lists that cause selections to change or to trigger activation via the #GtkActionable interface. For a list of all supported actions see the relevant documentation. (FIXME: where do we document actions and how to I link that?)
## Behind the scenes
While for short lists it is not a problem to instantiate widgets for every item in the model, once lists grow to thousands or millions of elements, this gets less feasible. Because of this, the views only create a limited amount of listitems and recycle them by binding them to new items. In general, views try to keep listitems available only for the items that can actually be seen on screen.
While this behavior allows views to scale effortlessly to huge lists, it has a few implication on what can be done with views. For example, it is not possible to query a view for a listitem used for a certain position - there might not be one and even if there is, that listitem might soon be recycled for a new position.
It is also important that developers save state they care about in the item and do not rely on the widgets they created as those widgets can be recycled for a new position at any time causing any state to be lost.
Another important requirement for views is that they need to know which items are not visible so they can be recycled. Views achieve that by implementing the #GtkScrollable interface and expecting to be placed directly into a #GtkScrolledWindow.
Of course, if you are only using models with few items, this is not important and you can treat views like any other widget. But if you use large lists and your performance suffers, you should be aware of this. Views also allow tuning the number of listitems they create such as with gtk_grid_view_set_max_columns(), and developers running into performance problems should definitely study the tradeoffs of those and experiment with them.
## Displaying trees
While #GtkTreeView provided builtin support for trees, the list widgets, and in particular #GListModel do not. This was a design choice because the common use case is displaying lists and not trees and it greatly simplifies the API interface provided.
However, GTK provides functionality to make trees look and behave like lists for the people who still want to display lists. This is achieved by using the #GtkTreeListModel model to flatten a tree into a list. The #GtkTreeExpander widget can then be used inside a listitem to allow users to expand and collapse rows and provide a similar experience to #GtkTreeView.
Developers should refer to those objects' API reference for more discussion on the topic.
## comparison to GtkTreeView
Developers familiar with #GtkTreeView may wonder how this way of doing lists compares to the way they know. This section will try to outline the similarities and differences between the two.
This new approach tries to provide roughly the same functionality as the old approach but often uses a very different approach to achieve these goals.
The main difference and one of the primary reasons for this new development is that items can be displayed using regular widgets and #GtkCellRenderer is no longer necessary. This allows all benefits that widgets provide, such as complex layout and animating widgets and not only makes cell renderers obsolete, but also #GtkCellArea.
The other big difference is the massive change to the data model. #GtkTreeModel was a rather complex interface for a tree data structure and #GListModel was deliberately designed to be a simple data structure for lists only. (See above (FIXME: link) for how to still do trees with this new model.) Another big change is that the new model allows for bulk changes via the #GListModel:items-changed signal while #GtkTreeModel only allows a single item to change at once. The goal here is of course to encourage implementation of custom list models.
Another consequence of the new model is that it is now easily possible to refer to the contents of a row in the model directly by keeping the item, while #GtkTreeRowReference was a very slow mechanism to achieve the same. And because the items are real objects, developers can make them emit change signals causing listitems and their children to update, which wasn't possible with #GtkTreeModel.
The selection handling is also different. While selections used to be managed via custom code in each widget, selection state is now meant to be managed by the selection models. In particular this allows for complex use cases with specialized requirements (FIXME: Can I add a shoutout to @mitch here because I vividly remember a huge discussion about GtkTreeView's selection behavior and the Gimp).
Finally here's a quick list of equivalent functionality to look for when transitioning code for easy lookup:
| old | new |
| ------------------- | ----------------------------------- |
| #GtkTreeModel | #GListModel |
| #GtkTreePath | #guint position, #GtkTreeListRow |
| #GtkTreeIter | #guint position |
| GtkTreeRowReference | #GObject item |
| #GtkListStore | #GListStore |
| #GtkTreeStore | #GtkTreeListModel, #GtkTreeExpander |
| #GtkTreeSelection | #GtkSelectionModel |
| #GtkTreeViewColumn | #GtkColumnView |
| #GtkTreeView | #GtkListView, #GtkColumnView |
| #GtkCellView | |
| #GtkComboBox | |
| #GtkIconView | #GtkGridView |
| #GtkTreeSortable | |
| #GtkTreeModelSort | #GtkSortListModel |
| #GtkTreeModelFilter | #GtkFilterListModel |
| #GtkCellLayout | #GtkListItemFactory |
| #GtkCellArea | #GtkWidget |
| #GtkCellRenderer | #GtkWidget |

View File

@@ -13,6 +13,7 @@ private_headers = [
'gtkappchooserprivate.h',
'gtkapplicationaccelsprivate.h',
'gtkapplicationprivate.h',
'gtkarrayimplprivate.h',
'gtkbindingsprivate.h',
'gtkbitmaskprivate.h',
'gtkbuilderprivate.h',
@@ -148,11 +149,14 @@ private_headers = [
'gtkmagnifierprivate.h',
'gtkmediafileprivate.h',
'gtkmenubuttonprivate.h',
'gtkmenusectionboxprivate.h',
'gtkmenutrackeritemprivate.h',
'gtkmenutrackerprivate.h',
'gtkmodulesprivate.h',
'gtkmountoperationprivate.h',
'gtknativedialogprivate.h',
'gtknomediafileprivate.h',
'gtkorientableprivate.h',
'gtkpango.h',
'gtkplacessidebarprivate.h',
'gtkplacesviewprivate.h',
'gtkplacesviewrowprivate.h',
@@ -162,6 +166,7 @@ private_headers = [
'gtkprintoperation-private.h',
'gtkprivate.h',
'gtkprogresstrackerprivate.h',
'gtkquery.h',
'gtkrangeprivate.h',
'gtkrbtreeprivate.h',
'gtkrenderbackgroundprivate.h',
@@ -171,7 +176,9 @@ private_headers = [
'gtkroundedboxprivate.h',
'gtkscalerprivate.h',
'gtksearchentryprivate.h',
'gtkset.h',
'gtksettingsprivate.h',
'gtkshortcutcontrollerprivate.h',
'gtkshortcutsshortcutprivate.h',
'gtkshortcutswindowprivate.h',
'gtksidebarrowprivate.h',
@@ -198,7 +205,9 @@ private_headers = [
'gtktoolbarprivate.h',
'gtktooltipprivate.h',
'gtktooltipwindowprivate.h',
'gtktreepopoverprivate.h',
'gtktreeprivate.h',
'gtktreerbtreeprivate.h',
'gtkutilsprivate.h',
'gtkwidgetpaintableprivate.h',
'gtkwidgetpathprivate.h',

View File

@@ -1,85 +1,181 @@
# List Widget Overview {#ListWidget}
GTK provides powerful widgets to display and edit lists of data. This document gives an overview over the concepts and how they work together to allow developers to implement lists.
GTK provides powerful widgets to display and edit lists of data. This document
gives an overview over the concepts and how they work together to allow
developers to implement lists.
Lists are intended to be used whenever developers want to display lists of objects in roughly the same way.
Lists are intended to be used whenever developers want to display lists of
objects in roughly the same way.
Lists are perfectly fine to be used for very short list of only 2 or 3 elements, but generally scale fine to millions of items. Of course, the larger the list grows, the more care needs to be taken to choose the right data structures to keep things running well.
Lists are perfectly fine to be used for very short list of only 2 or 3 elements,
but generally scale fine to millions of items. Of course, the larger the list
grows, the more care needs to be taken to choose the right data structures to
keep things running well.
Lists are meant to be used with changing data, both with the items itself changing as well as the list adding and removing items. Of course, they work just as well with static data.
Lists are meant to be used with changing data, both with the items itself changing
as well as the list adding and removing items. Of course, they work just as well
with static data.
## Terminology
These terms are used throughout the documentation when talking about lists and you should be aware of what they refer to. These are often generic terms that have a specific meaning in this context.
These terms are used throughout the documentation when talking about lists and
you should be aware of what they refer to. These are often generic terms that
have a specific meaning in this context.
**_Views_** or **_list widgets_** are the widgets that hold and manage the lists. Examples of thse widgets would be #GtkListView or #GtkGridView.
**_Views_** or **_list widgets_** are the widgets that hold and manage the lists.
Examples of these widgets would be #GtkListView or #GtkGridView.
Views display data from a **_model_**. A model is a #GListModel and models can be provided in 3 ways or combinations thereof:
Views display data from a **_model_**. A model is a #GListModel and models can
be provided in 3 ways or combinations thereof:
* Many list models implementations already exist. There are models that provide specific data, like #GtkDirectoryList. And there are models like #GListStore that allow building lists manually.
* Many list models implementations already exist. There are models that provide
specific data, like #GtkDirectoryList. And there are models like #GListStore
that allow building lists manually.
* Wrapping list models exists like #GtkFilterListModel or #GtkSortListModel that modify or adapt or combine other models.
* Wrapping list models exists like #GtkFilterListModel or #GtkSortListModel
that modify or adapt or combine other models.
* Last but not least, developers are encouraged to create their own #GListModel implementations. The interface is kept deliberately small to make this easy.
* Last but not least, developers are encouraged to create their own #GListModel
implementations. The interface is kept deliberately small to make this easy.
The same model can be used in multiple different views and wrapped with multiple different models at once.
The same model can be used in multiple different views and wrapped with
multiple different models at once.
The elements in a model are called **_items_**. All items are #GObjects.
Every item in a model has a **_position_** which is the unsigned integer that describes where in the model the item is located. This position can of course change as items are added or removed from the model.
Every item in a model has a **_position_** which is the unsigned integer that
describes where in the model the item is located. This position can of course
change as items are added or removed from the model.
It is important to be aware of the difference between items and positions because the mapping from position to item is not permanent, so developers should think about whether they want to track items or positions when working with models. Oftentimes some things are really hard to do one way but very easy the other way.
It is important to be aware of the difference between items and positions
because the mapping from position to item is not permanent, so developers
should think about whether they want to track items or positions when working
with models. Oftentimes some things are really hard to do one way but very easy
the other way.
The other important part of a view is a **_factory_**. Each factory is a #GtkListItemFactory implementation that takes care of mapping the items of the model to widgets that can be shown in the view.
The other important part of a view is a **_factory_**. Each factory is
a #GtkListItemFactory implementation that takes care of mapping the items
of the model to widgets that can be shown in the view.
The way factories do this is by creating a **_listitem_** for each item that is currently in use. Listitems are always #GtkListItem objects. They are only ever created by GTK and provide information about what item they are meant to display.
The way factories do this is by creating a **_listitem_** for each item that
is currently in use. Listitems are always #GtkListItem objects. They are only
ever created by GTK and provide information about what item they are meant
to display.
Different factory implementations use various different methods to allow developers to add the right widgets to listitems and to link those widgets with the item managed by the listitem. Finding a suitable factory implementation for the data displayed, the programming language and development environment is an important task that can simplify setting up the view tremendously.
Different factory implementations use various different methods to allow
developers to add the right widgets to listitems and to link those widgets
with the item managed by the listitem. Finding a suitable factory implementation
for the data displayed, the programming language and development environment
is an important task that can simplify setting up the view tremendously.
Views support selections via a **_selection model_**. A selection model is an implementation of the #GtkSelectionModel interface on top of the #GListModel interface that allows marking each item in a model as either selected or not selected. Just like regular models, this can be implemented either by implementing #GtkSelectionModel directly or by wrapping a model with one of the GTK models provided for this purposes, such as #GtkNoSelection or #GtkSingleSelection.
The behavior of selection models - ie which items they allow selecting and what effect this has on other items - is completely up to the selection model. As such, single-selections, multi-selections or sharing selection state between different selection models and/or views is possible.
The selection state of an item is exposed in the listitem via the GtkListItem:selected property.
Views support selections via a **_selection model_**. A selection model is an
implementation of the #GtkSelectionModel interface on top of the #GListModel
interface that allows marking each item in a model as either selected or not
selected. Just like regular models, this can be implemented either by
implementing #GtkSelectionModel directly or by wrapping a model with one of
the GTK models provided for this purposes, such as #GtkNoSelection
or #GtkSingleSelection.
Views and listitems also support activation. Activation means that double clicking or pressing enter while inside a focused row will cause the view to emit and activation signal such as GtkListView::activate. This provides an easy way to set up lists, but can also be turned off on listitems if undesired.
The behavior of selection models - ie which items they allow selecting and
what effect this has on other items - is completely up to the selection model.
As such, single-selections, multi-selections or sharing selection state between
different selection models and/or views is possible. The selection state of an
item is exposed in the listitem via the GtkListItem:selected property.
Both selections and activation are supported among other things via widget actions (FIXME: Link docs). This allows developers to add widgets to their lists that cause selections to change or to trigger activation via the #GtkActionable interface. For a list of all supported actions see the relevant documentation. (FIXME: where do we document actions and how to I link that?)
Views and listitems also support activation. Activation means that double
clicking or pressing enter while inside a focused row will cause the view
to emit and activation signal such as #GtkListView::activate. This provides
an easy way to set up lists, but can also be turned off on listitems if undesired.
Both selections and activation are supported among other things via widget
[actions](#actions-overview). This allows developers to add widgets to their
lists that cause selections to change or to trigger activation via
the #GtkActionable interface. For a list of all supported actions see the
relevant documentation.
## Behind the scenes
While for short lists it is not a problem to instantiate widgets for every item in the model, once lists grow to thousands or millions of elements, this gets less feasible. Because of this, the views only create a limited amount of listitems and recycle them by binding them to new items. In general, views try to keep listitems available only for the items that can actually be seen on screen.
While for short lists it is not a problem to instantiate widgets for every
item in the model, once lists grow to thousands or millions of elements, this
gets less feasible. Because of this, the views only create a limited amount of
listitems and recycle them by binding them to new items. In general, views try
to keep listitems available only for the items that can actually be seen on screen.
While this behavior allows views to scale effortlessly to huge lists, it has a few implication on what can be done with views. For example, it is not possible to query a view for a listitem used for a certain position - there might not be one and even if there is, that listitem might soon be recycled for a new position.
While this behavior allows views to scale effortlessly to huge lists, it has a
few implication on what can be done with views. For example, it is not possible
to query a view for a listitem used for a certain position - there might not be
one and even if there is, that listitem might soon be recycled for a new position.
It is also important that developers save state they care about in the item and do not rely on the widgets they created as those widgets can be recycled for a new position at any time causing any state to be lost.
It is also important that developers save state they care about in the item and
do not rely on the widgets they created as those widgets can be recycled for a
new position at any time causing any state to be lost.
Another important requirement for views is that they need to know which items are not visible so they can be recycled. Views achieve that by implementing the #GtkScrollable interface and expecting to be placed directly into a #GtkScrolledWindow.
Another important requirement for views is that they need to know which items
are not visible so they can be recycled. Views achieve that by implementing
the #GtkScrollable interface and expecting to be placed directly into
a #GtkScrolledWindow.
Of course, if you are only using models with few items, this is not important and you can treat views like any other widget. But if you use large lists and your performance suffers, you should be aware of this. Views also allow tuning the number of listitems they create such as with gtk_grid_view_set_max_columns(), and developers running into performance problems should definitely study the tradeoffs of those and experiment with them.
Of course, if you are only using models with few items, this is not important
and you can treat views like any other widget. But if you use large lists and
your performance suffers, you should be aware of this. Views also allow tuning
the number of listitems they create such as with gtk_grid_view_set_max_columns(),
and developers running into performance problems should definitely study the
tradeoffs of those and experiment with them.
## Displaying trees
## Displaying trees {#displaying-trees}
While #GtkTreeView provided builtin support for trees, the list widgets, and in particular #GListModel do not. This was a design choice because the common use case is displaying lists and not trees and it greatly simplifies the API interface provided.
While #GtkTreeView provided built-in support for trees, the list widgets, and
in particular #GListModel do not. This was a design choice because the common
use case is displaying lists and not trees and it greatly simplifies the API
interface provided.
However, GTK provides functionality to make trees look and behave like lists for the people who still want to display lists. This is achieved by using the #GtkTreeListModel model to flatten a tree into a list. The #GtkTreeExpander widget can then be used inside a listitem to allow users to expand and collapse rows and provide a similar experience to #GtkTreeView.
However, GTK provides functionality to make trees look and behave like lists
for the people who still want to display lists. This is achieved by using
the #GtkTreeListModel model to flatten a tree into a list. The #GtkTreeExpander
widget can then be used inside a listitem to allow users to expand and collapse
rows and provide a similar experience to #GtkTreeView.
Developers should refer to those objects' API reference for more discussion on the topic.
Developers should refer to those objects' API reference for more discussion
on the topic.
## comparison to GtkTreeView
## Comparison to GtkTreeView
Developers familiar with #GtkTreeView may wonder how this way of doing lists compares to the way they know. This section will try to outline the similarities and differences between the two.
Developers familiar with #GtkTreeView may wonder how this way of doing lists
compares to the way they know. This section will try to outline the similarities
and differences between the two.
This new approach tries to provide roughly the same functionality as the old approach but often uses a very different approach to achieve these goals.
This new approach tries to provide roughly the same functionality as the old
approach but often uses a very different approach to achieve these goals.
The main difference and one of the primary reasons for this new development is that items can be displayed using regular widgets and #GtkCellRenderer is no longer necessary. This allows all benefits that widgets provide, such as complex layout and animating widgets and not only makes cell renderers obsolete, but also #GtkCellArea.
The main difference and one of the primary reasons for this new development is
that items can be displayed using regular widgets and #GtkCellRenderer is no
longer necessary. This allows all benefits that widgets provide, such as complex
layout and animating widgets and not only makes cell renderers obsolete, but
also #GtkCellArea.
The other big difference is the massive change to the data model. #GtkTreeModel was a rather complex interface for a tree data structure and #GListModel was deliberately designed to be a simple data structure for lists only. (See above (FIXME: link) for how to still do trees with this new model.) Another big change is that the new model allows for bulk changes via the #GListModel:items-changed signal while #GtkTreeModel only allows a single item to change at once.
The goal here is of course to encourage implementation of custom list models.
The other big difference is the massive change to the data model. #GtkTreeModel
was a rather complex interface for a tree data structure and #GListModel was
deliberately designed to be a simple data structure for lists only. (See
[above](#displaying-trees)) for how to still do trees with this new model.)
Another big change is that the new model allows for bulk changes via
the #GListModel:items-changed signal while #GtkTreeModel only allows a single
item to change at once. The goal here is of course to encourage implementation
of custom list models.
Another consequence of the new model is that it is now easily possible to refer to the contents of a row in the model directly by keeping the item, while #GtkTreeRowReference was a very slow mechanism to achieve the same. And because the items are real objects, developers can make them emit change signals causing listitems and their children to update, which wasn't possible with #GtkTreeModel.
Another consequence of the new model is that it is now easily possible to
refer to the contents of a row in the model directly by keeping the item,
while #GtkTreeRowReference was a very slow mechanism to achieve the same.
And because the items are real objects, developers can make them emit change
signals causing listitems and their children to update, which wasn't possible
with #GtkTreeModel.
The selection handling is also different. While selections used to be managed via custom code in each widget, selection state is now meant to be managed by the selection models. In particular this allows for complex use cases with specialized requirements (FIXME: Can I add a shoutout to @mitch here because I vividly remember a huge discussion about GtkTreeView's selection behavior and the Gimp).
The selection handling is also different. While selections used to be managed
via custom code in each widget, selection state is now meant to be managed by
the selection models. In particular this allows for complex use cases with
specialized requirements.
Finally here's a quick list of equivalent functionality to look for when transitioning code for easy lookup:
Finally here's a quick list of equivalent functionality to look for when
transitioning code for easy lookup:
| Old | New |
| ------------------- | ----------------------------------- |

View File

@@ -23,12 +23,6 @@
#include "gdksurfaceprivate.h"
#include "gdkprivate-broadway.h"
static gboolean gdk_broadway_device_get_history (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events);
static void gdk_broadway_device_get_state (GdkDevice *device,
GdkSurface *surface,
gdouble *axes,
@@ -64,7 +58,6 @@ gdk_broadway_device_class_init (GdkBroadwayDeviceClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_broadway_device_get_history;
device_class->get_state = gdk_broadway_device_get_state;
device_class->set_surface_cursor = gdk_broadway_device_set_surface_cursor;
device_class->query_state = gdk_broadway_device_query_state;
@@ -80,19 +73,8 @@ gdk_broadway_device_init (GdkBroadwayDevice *device_core)
device = GDK_DEVICE (device_core);
_gdk_device_add_axis (device, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean
gdk_broadway_device_get_history (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
return FALSE;
_gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1);
}
static void

View File

@@ -1,58 +0,0 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Chun-wei Fan <fanc999@yahoo.com.tw>
*
* Author: Chun-wei Fan <fanc999@yahoo.com.tw>
*
* 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/>.
*/
#include "config.h"
#include <float.h>
#ifndef HAVE_DECL_ISNAN
/* it seems of the supported compilers only
* MSVC does not have isnan(), but it does
* have _isnan() which does the same as isnan()
*/
static inline gboolean
isnan (double x)
{
return _isnan (x);
}
#endif
#ifndef HAVE_DECL_ISINF
/* Unfortunately MSVC does not have finite()
* but it does have _finite() which is the same
* as finite() except when x is a NaN
*/
static inline gboolean
isinf (double x)
{
return (!_finite (x) && !_isnan (x));
}
#endif
/* Workaround for round() for non-GCC/non-C99 compilers */
#ifndef HAVE_ROUND
static inline double
round (double x)
{
if (x >= 0)
return floor (x + 0.5);
else
return ceil (x - 0.5);
}
#endif

View File

@@ -26,9 +26,6 @@
#include "gdkintl.h"
#include "gdkkeysprivate.h"
/* for the use of round() */
#include "fallback-c89.c"
/**
* SECTION:gdkdevice
* @Short_description: Object representing an input device
@@ -54,9 +51,7 @@ typedef struct _GdkAxisInfo GdkAxisInfo;
struct _GdkAxisInfo
{
char *label;
GdkAxisUse use;
gdouble min_axis;
gdouble max_axis;
gdouble min_value;
@@ -369,19 +364,10 @@ gdk_device_class_init (GdkDeviceClass *klass)
G_TYPE_NONE, 1, GDK_TYPE_DEVICE_TOOL);
}
static void
gdk_device_axis_info_clear (gpointer data)
{
GdkAxisInfo *info = data;
g_free (info->label);
}
static void
gdk_device_init (GdkDevice *device)
{
device->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
g_array_set_clear_func (device->axes, gdk_device_axis_info_clear);
}
static void
@@ -396,7 +382,6 @@ gdk_device_finalize (GObject *object)
}
g_clear_pointer (&device->name, g_free);
g_clear_pointer (&device->keys, g_free);
g_clear_pointer (&device->vendor_id, g_free);
g_clear_pointer (&device->product_id, g_free);
@@ -638,93 +623,6 @@ gdk_device_get_surface_at_position (GdkDevice *device,
return surface;
}
/**
* gdk_device_get_history: (skip)
* @device: a #GdkDevice
* @surface: the surface with respect to which the event coordinates will be reported
* @start: starting timestamp for range of events to return
* @stop: ending timestamp for the range of events to return
* @events: (array length=n_events) (out) (transfer full) (optional):
* location to store a newly-allocated array of #GdkTimeCoord, or
* %NULL
* @n_events: (out) (optional): location to store the length of
* @events, or %NULL
*
* Obtains the motion history for a pointer device; given a starting and
* ending timestamp, return all events in the motion history for
* the device in the given range of time. Some windowing systems
* do not support motion history, in which case, %FALSE will
* be returned. (This is not distinguishable from the case where
* motion history is supported and no events were found.)
*
* Note that there is also gdk_surface_set_event_compression() to get
* more motion events delivered directly, independent of the windowing
* system.
*
* Returns: %TRUE if the windowing system supports motion history and
* at least one event was found.
**/
gboolean
gdk_device_get_history (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, FALSE);
g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
if (n_events)
*n_events = 0;
if (events)
*events = NULL;
if (GDK_SURFACE_DESTROYED (surface))
return FALSE;
if (!GDK_DEVICE_GET_CLASS (device)->get_history)
return FALSE;
return GDK_DEVICE_GET_CLASS (device)->get_history (device, surface,
start, stop,
events, n_events);
}
GdkTimeCoord **
_gdk_device_allocate_history (GdkDevice *device,
gint n_events)
{
GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
gint i;
for (i = 0; i < n_events; i++)
result[i] = g_malloc (sizeof (GdkTimeCoord) -
sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->axes->len));
return result;
}
/**
* gdk_device_free_history: (skip)
* @events: (array length=n_events): an array of #GdkTimeCoord.
* @n_events: the length of the array.
*
* Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history().
*/
void
gdk_device_free_history (GdkTimeCoord **events,
gint n_events)
{
gint i;
for (i = 0; i < n_events; i++)
g_free (events[i]);
g_free (events);
}
/**
* gdk_device_get_name:
* @device: a #GdkDevice
@@ -774,79 +672,6 @@ gdk_device_get_source (GdkDevice *device)
return device->source;
}
/**
* gdk_device_get_n_keys:
* @device: a #GdkDevice
*
* Returns the number of keys the device currently has.
*
* Returns: the number of keys.
**/
gint
gdk_device_get_n_keys (GdkDevice *device)
{
g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
return device->num_keys;
}
/**
* gdk_device_get_key:
* @device: a #GdkDevice.
* @index_: the index of the macro button to get.
* @keyval: (out): return value for the keyval.
* @modifiers: (out): return value for modifiers.
*
* If @index_ has a valid keyval, this function will return %TRUE
* and fill in @keyval and @modifiers with the keyval settings.
*
* Returns: %TRUE if keyval is set for @index.
**/
gboolean
gdk_device_get_key (GdkDevice *device,
guint index_,
guint *keyval,
GdkModifierType *modifiers)
{
g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
g_return_val_if_fail (index_ < device->num_keys, FALSE);
if (!device->keys[index_].keyval &&
!device->keys[index_].modifiers)
return FALSE;
if (keyval)
*keyval = device->keys[index_].keyval;
if (modifiers)
*modifiers = device->keys[index_].modifiers;
return TRUE;
}
/**
* gdk_device_set_key:
* @device: a #GdkDevice
* @index_: the index of the macro button to set
* @keyval: the keyval to generate
* @modifiers: the modifiers to set
*
* Specifies the X key event to generate when a macro button of a device
* is pressed.
**/
void
gdk_device_set_key (GdkDevice *device,
guint index_,
guint keyval,
GdkModifierType modifiers)
{
g_return_if_fail (GDK_IS_DEVICE (device));
g_return_if_fail (index_ < device->num_keys);
device->keys[index_].keyval = keyval;
device->keys[index_].modifiers = modifiers;
}
/**
* gdk_device_get_axis_use:
* @device: a pointer #GdkDevice.
@@ -871,47 +696,6 @@ gdk_device_get_axis_use (GdkDevice *device,
return info->use;
}
/**
* gdk_device_set_axis_use:
* @device: a pointer #GdkDevice
* @index_: the index of the axis
* @use: specifies how the axis is used
*
* Specifies how an axis of a device is used.
**/
void
gdk_device_set_axis_use (GdkDevice *device,
guint index_,
GdkAxisUse use)
{
GdkAxisInfo *info;
g_return_if_fail (GDK_IS_DEVICE (device));
g_return_if_fail (device->source != GDK_SOURCE_KEYBOARD);
g_return_if_fail (index_ < device->axes->len);
info = &g_array_index (device->axes, GdkAxisInfo, index_);
info->use = use;
switch ((guint) use)
{
case GDK_AXIS_X:
case GDK_AXIS_Y:
info->min_axis = 0;
info->max_axis = 0;
break;
case GDK_AXIS_XTILT:
case GDK_AXIS_YTILT:
info->min_axis = -1;
info->max_axis = 1;
break;
default:
info->min_axis = 0;
info->max_axis = 1;
break;
}
}
/**
* gdk_device_get_display:
* @device: a #GdkDevice
@@ -1077,89 +861,6 @@ gdk_device_get_n_axes (GdkDevice *device)
return device->axes->len;
}
/**
* gdk_device_get_axis_names:
* @device: a #GdkDevice
*
* Returns a null-terminated array of strings, containing the labels for
* the axes that @device currently has.
* If the device has no axes, %NULL is returned.
*
* Returns: (nullable) (transfer full): A null-terminated string array,
* free with g_strfreev().
**/
char **
gdk_device_get_axis_names (GdkDevice *device)
{
GPtrArray *axes;
gint i;
g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, NULL);
if (device->axes->len == 0)
return NULL;
axes = g_ptr_array_new ();
for (i = 0; i < device->axes->len; i++)
{
GdkAxisInfo axis_info;
axis_info = g_array_index (device->axes, GdkAxisInfo, i);
g_ptr_array_add (axes, g_strdup (axis_info.label));
}
g_ptr_array_add (axes, NULL);
return (char **) g_ptr_array_free (axes, FALSE);
}
/**
* gdk_device_get_axis_value: (skip)
* @device: a pointer #GdkDevice.
* @axes: (array): pointer to an array of axes
* @axis_label: name of the label
* @value: (out): location to store the found value.
*
* Interprets an array of double as axis values for a given device,
* and locates the value in the array for a given axis label, as returned
* by gdk_device_get_axes()
*
* Returns: %TRUE if the given axis use was found, otherwise %FALSE.
**/
gboolean
gdk_device_get_axis_value (GdkDevice *device,
gdouble *axes,
const char *axis_label,
gdouble *value)
{
gint i;
g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, FALSE);
if (axes == NULL)
return FALSE;
for (i = 0; i < device->axes->len; i++)
{
GdkAxisInfo axis_info;
axis_info = g_array_index (device->axes, GdkAxisInfo, i);
if (!g_str_equal (axis_info.label, axis_label))
continue;
if (value)
*value = axes[i];
return TRUE;
}
return FALSE;
}
/**
* gdk_device_get_axis: (skip)
* @device: a #GdkDevice
@@ -1296,7 +997,6 @@ _gdk_device_reset_axes (GdkDevice *device)
guint
_gdk_device_add_axis (GdkDevice *device,
const char *label_name,
GdkAxisUse use,
gdouble min_value,
gdouble max_value,
@@ -1306,7 +1006,6 @@ _gdk_device_add_axis (GdkDevice *device,
guint pos;
axis_info.use = use;
axis_info.label = g_strdup (label_name);
axis_info.min_value = min_value;
axis_info.max_value = max_value;
axis_info.resolution = resolution;
@@ -1342,12 +1041,11 @@ _gdk_device_add_axis (GdkDevice *device,
void
_gdk_device_get_axis_info (GdkDevice *device,
guint index_,
const char **label_name,
GdkAxisUse *use,
gdouble *min_value,
gdouble *max_value,
gdouble *resolution)
guint index_,
GdkAxisUse *use,
gdouble *min_value,
gdouble *max_value,
gdouble *resolution)
{
GdkAxisInfo *info;
@@ -1356,23 +1054,12 @@ _gdk_device_get_axis_info (GdkDevice *device,
info = &g_array_index (device->axes, GdkAxisInfo, index_);
*label_name = info->label;
*use = info->use;
*min_value = info->min_value;
*max_value = info->max_value;
*resolution = info->resolution;
}
void
_gdk_device_set_keys (GdkDevice *device,
guint num_keys)
{
g_free (device->keys);
device->num_keys = num_keys;
device->keys = g_new0 (GdkDeviceKey, num_keys);
}
static GdkAxisInfo *
find_axis_info (GArray *array,
GdkAxisUse use)
@@ -1393,10 +1080,10 @@ find_axis_info (GArray *array,
gboolean
_gdk_device_translate_surface_coord (GdkDevice *device,
GdkSurface *surface,
guint index_,
gdouble value,
gdouble *axis_value)
GdkSurface *surface,
guint index_,
gdouble value,
gdouble *axis_value)
{
GdkAxisInfo axis_info;
GdkAxisInfo *axis_info_x, *axis_info_y;
@@ -1778,6 +1465,15 @@ gdk_device_get_device_tool (GdkDevice *device)
return device->last_tool;
}
/**
* gdk_device_get_caps_lock_state:
* @device: a #GdkDevice
*
* Retrieves whether the Caps Lock modifier of the
* keyboard is locked, if @device is a keyboard device.
*
* Returns: %TRUE if Caps Lock is on for @device
*/
gboolean
gdk_device_get_caps_lock_state (GdkDevice *device)
{
@@ -1789,6 +1485,15 @@ gdk_device_get_caps_lock_state (GdkDevice *device)
return FALSE;
}
/**
* gdk_device_get_num_lock_state:
* @device: a #GdkDevice
*
* Retrieves whether the Num Lock modifier of the
* keyboard is locked, if @device is a keyboard device.
*
* Returns: %TRUE if Num Lock is on for @device
*/
gboolean
gdk_device_get_num_lock_state (GdkDevice *device)
{
@@ -1800,6 +1505,15 @@ gdk_device_get_num_lock_state (GdkDevice *device)
return FALSE;
}
/**
* gdk_device_get_scroll_lock_state:
* @device: a #GdkDevice
*
* Retrieves whether the Scroll Lock modifier of the
* keyboard is locked, if @device is a keyboard device.
*
* Returns: %TRUE if Scroll Lock is on for @device
*/
gboolean
gdk_device_get_scroll_lock_state (GdkDevice *device)
{
@@ -1811,6 +1525,15 @@ gdk_device_get_scroll_lock_state (GdkDevice *device)
return FALSE;
}
/**
* gdk_device_get_modifier_state:
* @device: a #GdkDevice
*
* Retrieves the current modifier state of the keyboard,
* if @device is a keyboard device.
*
* Returns: the current modifier state
*/
GdkModifierType
gdk_device_get_modifier_state (GdkDevice *device)
{
@@ -1822,6 +1545,20 @@ gdk_device_get_modifier_state (GdkDevice *device)
return 0;
}
/**
* gdk_device_get_direction:
* @device: a #GdkDevice
*
* Returns the direction of effective layout of the keyboard,
* if @device is a keyboard device.
*
* The direction of a layout is the direction of the majority
* of its symbols. See pango_unichar_direction().
*
* Returns: %PANGO_DIRECTION_LTR or %PANGO_DIRECTION_RTL
* if it can determine the direction. %PANGO_DIRECTION_NEUTRAL
* otherwise
*/
PangoDirection
gdk_device_get_direction (GdkDevice *device)
{
@@ -1833,6 +1570,17 @@ gdk_device_get_direction (GdkDevice *device)
return PANGO_DIRECTION_NEUTRAL;
}
/**
* gdk_device_has_bidi_layouts:
* @device: a #GdkDevice
*
* Determines if keyboard layouts for both right-to-left and
* left-to-right languages are in use on the keyboard, if
* @device is a keyboard device.
*
* Returns: %TRUE if there are layouts with both directions,
* %FALSE otherwise
*/
gboolean
gdk_device_has_bidi_layouts (GdkDevice *device)
{

View File

@@ -85,22 +85,20 @@ typedef enum {
GDK_DEVICE_TYPE_FLOATING
} GdkDeviceType;
/* We don't allocate each coordinate this big, but we use it to
* be ANSI compliant and avoid accessing past the defined limits.
*/
#define GDK_MAX_TIMECOORD_AXES 128
/**
* GdkTimeCoord:
* @time: The timestamp for this event.
* @axes: the values of the devices axes.
* @flags: Flags indicating what axes are present
* @axes: axis values
*
* A #GdkTimeCoord stores a single event in a motion history.
*/
struct _GdkTimeCoord
{
guint32 time;
gdouble axes[GDK_MAX_TIMECOORD_AXES];
GdkAxisFlags flags;
double axes[GDK_AXIS_LAST];
};
GDK_AVAILABLE_IN_ALL
@@ -115,26 +113,9 @@ gboolean gdk_device_get_has_cursor (GdkDevice *device);
GDK_AVAILABLE_IN_ALL
GdkInputSource gdk_device_get_source (GdkDevice *device);
GDK_AVAILABLE_IN_ALL
gint gdk_device_get_n_keys (GdkDevice *device);
GDK_AVAILABLE_IN_ALL
gboolean gdk_device_get_key (GdkDevice *device,
guint index_,
guint *keyval,
GdkModifierType *modifiers);
GDK_AVAILABLE_IN_ALL
void gdk_device_set_key (GdkDevice *device,
guint index_,
guint keyval,
GdkModifierType modifiers);
GDK_AVAILABLE_IN_ALL
GdkAxisUse gdk_device_get_axis_use (GdkDevice *device,
guint index_);
GDK_AVAILABLE_IN_ALL
void gdk_device_set_axis_use (GdkDevice *device,
guint index_,
GdkAxisUse use);
GDK_AVAILABLE_IN_ALL
@@ -146,25 +127,12 @@ GDK_AVAILABLE_IN_ALL
GdkSurface * gdk_device_get_surface_at_position (GdkDevice *device,
double *win_x,
double *win_y);
GDK_AVAILABLE_IN_ALL
gboolean gdk_device_get_history (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events);
GDK_AVAILABLE_IN_ALL
void gdk_device_free_history (GdkTimeCoord **events,
gint n_events);
GDK_AVAILABLE_IN_ALL
gint gdk_device_get_n_axes (GdkDevice *device);
GDK_AVAILABLE_IN_ALL
char ** gdk_device_get_axis_names (GdkDevice *device);
GDK_AVAILABLE_IN_ALL
gboolean gdk_device_get_axis_value (GdkDevice *device,
gdouble *axes,
const char *axis_label,
gdouble *value);
GDK_AVAILABLE_IN_ALL

View File

@@ -31,13 +31,6 @@ G_BEGIN_DECLS
#define GDK_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE, GdkDeviceClass))
typedef struct _GdkDeviceClass GdkDeviceClass;
typedef struct _GdkDeviceKey GdkDeviceKey;
struct _GdkDeviceKey
{
guint keyval;
GdkModifierType modifiers;
};
struct _GdkDevice
{
@@ -46,9 +39,7 @@ struct _GdkDevice
gchar *name;
GdkInputSource source;
gboolean has_cursor;
gint num_keys;
GdkAxisFlags axis_flags;
GdkDeviceKey *keys;
GdkDisplay *display;
/* Paired master for master,
* associated master for slaves
@@ -70,13 +61,6 @@ struct _GdkDeviceClass
{
GObjectClass parent_class;
gboolean (* get_history) (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events);
void (* get_state) (GdkDevice *device,
GdkSurface *surface,
gdouble *axes,
@@ -113,21 +97,16 @@ void _gdk_device_set_associated_device (GdkDevice *device,
void _gdk_device_reset_axes (GdkDevice *device);
guint _gdk_device_add_axis (GdkDevice *device,
const char *label_atom,
GdkAxisUse use,
gdouble min_value,
gdouble max_value,
gdouble resolution);
void _gdk_device_get_axis_info (GdkDevice *device,
guint index,
const char**label_atom,
GdkAxisUse *use,
gdouble *min_value,
gdouble *max_value,
gdouble *resolution);
void _gdk_device_set_keys (GdkDevice *device,
guint num_keys);
guint index,
GdkAxisUse *use,
gdouble *min_value,
gdouble *max_value,
gdouble *resolution);
gboolean _gdk_device_translate_surface_coord (GdkDevice *device,
GdkSurface *surface,

View File

@@ -38,9 +38,6 @@
#include <math.h>
#include <glib.h>
/* for the use of round() */
#include "fallback-c89.c"
/**
* SECTION:gdkdisplay
* @Short_description: Controls a set of monitors and their associated input devices
@@ -1735,11 +1732,11 @@ gdk_display_map_keycode (GdkDisplay *display,
* @keycode: a keycode
* @state: a modifier state
* @group: active keyboard group
* @keyval: (out) (allow-none): return location for keyval, or %NULL
* @effective_group: (out) (allow-none): return location for effective
* @keyval: (out) (optional): return location for keyval, or %NULL
* @effective_group: (out) (optional): return location for effective
* group, or %NULL
* @level: (out) (allow-none): return location for level, or %NULL
* @consumed_modifiers: (out) (allow-none): return location for modifiers
* @level: (out) (optional): return location for level, or %NULL
* @consumed: (out) (optional): return location for modifiers
* that were used to determine the group or level, or %NULL
*
* Translates the contents of a #GdkEventKey (ie @keycode, @state, and @group)

View File

@@ -619,6 +619,114 @@ _gdk_event_unqueue (GdkDisplay *display)
return event;
}
/*
* If the last N events in the event queue are smooth scroll events
* for the same surface and device, combine them into one.
*/
void
gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
{
GList *l;
GdkSurface *surface = NULL;
GdkDevice *device = NULL;
GdkEvent *last_event = NULL;
GList *scrolls = NULL;
double delta_x, delta_y;
GArray *history = NULL;
GdkTimeCoord hist;
l = g_queue_peek_tail_link (&display->queued_events);
while (l)
{
GdkEvent *event = l->data;
if (event->flags & GDK_EVENT_PENDING)
break;
if (event->event_type != GDK_SCROLL ||
gdk_scroll_event_get_direction (event) != GDK_SCROLL_SMOOTH)
break;
if (surface != NULL &&
surface != event->surface)
break;
if (device != NULL &&
device != event->device)
break;
if (!last_event)
last_event = event;
surface = event->surface;
device = event->device;
scrolls = l;
l = l->prev;
}
delta_x = delta_y = 0;
while (scrolls && scrolls->next != NULL)
{
GdkEvent *event = scrolls->data;
GList *next = scrolls->next;
double dx, dy;
if (!history)
history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
gdk_scroll_event_get_deltas (event, &dx, &dy);
delta_x += dx;
delta_y += dy;
memset (&hist, 0, sizeof (GdkTimeCoord));
hist.time = gdk_event_get_time (event);
hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
hist.axes[GDK_AXIS_DELTA_X] = dx;
hist.axes[GDK_AXIS_DELTA_Y] = dy;
g_array_append_val (history, hist);
gdk_event_unref (event);
g_queue_delete_link (&display->queued_events, scrolls);
scrolls = next;
}
if (scrolls)
{
GdkEvent *old_event, *event;
double dx, dy;
old_event = scrolls->data;
gdk_scroll_event_get_deltas (old_event, &dx, &dy);
event = gdk_scroll_event_new (surface,
device,
gdk_event_get_source_device (old_event),
gdk_event_get_device_tool (old_event),
gdk_event_get_time (old_event),
gdk_event_get_modifier_state (old_event),
delta_x + dx,
delta_y + dy,
gdk_scroll_event_is_stop (old_event));
((GdkScrollEvent *)event)->history = history;
g_queue_delete_link (&display->queued_events, scrolls);
g_queue_push_tail (&display->queued_events, event);
}
if (g_queue_get_length (&display->queued_events) == 1 &&
g_queue_peek_head_link (&display->queued_events) == scrolls)
{
GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
if (clock) /* might be NULL if surface was destroyed */
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
}
}
static void
gdk_motion_event_push_history (GdkEvent *event,
GdkEvent *history_event)
@@ -634,14 +742,20 @@ gdk_motion_event_push_history (GdkEvent *event,
device = gdk_event_get_device (history_event);
n_axes = gdk_device_get_n_axes (device);
for (i = 0; i <= MIN (n_axes, GDK_MAX_TIMECOORD_AXES); i++)
gdk_event_get_axis (history_event, i, &hist.axes[i]);
memset (&hist, 0, sizeof (GdkTimeCoord));
hist.time = gdk_event_get_time (history_event);
hist.flags = gdk_device_get_axes (device);
for (i = 0; i < n_axes; i++)
{
GdkAxisUse use = gdk_device_get_axis_use (device, i);
gdk_event_get_axis (history_event, use, &hist.axes[use]);
}
if (G_UNLIKELY (!self->history))
self->history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
g_array_append_val (self->history, hist);
}
void
@@ -710,7 +824,7 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
{
GdkFrameClock *clock = gdk_surface_get_frame_clock (pending_motion_surface);
if (clock) /* might be NULL if surface was destroyed */
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
}
}
@@ -2130,7 +2244,7 @@ gdk_focus_event_new (GdkSurface *surface,
/**
* gdk_focus_event_get_in:
* @event: (type GdkScrollEvent): a focus change event
* @event: (type GdkFocusEvent): a focus change event
*
* Extracts whether this event is about focus entering or
* leaving the surface.
@@ -2152,21 +2266,14 @@ gdk_focus_event_get_in (GdkEvent *event)
/* {{{ GdkScrollEvent */
static void
gdk_scroll_event_init (GdkEvent *event)
{
GdkScrollEvent *self = (GdkScrollEvent *) event;
self->x = NAN;
self->y = NAN;
}
static void
gdk_scroll_event_finalize (GdkEvent *event)
{
GdkScrollEvent *self = (GdkScrollEvent *) event;
g_clear_object (&self->tool);
if (self->history)
g_array_free (self->history, TRUE);
GDK_EVENT_SUPER (self)->finalize (event);
}
@@ -2179,19 +2286,6 @@ gdk_scroll_event_get_state (GdkEvent *event)
return self->state;
}
static gboolean
gdk_scroll_event_get_position (GdkEvent *event,
double *x,
double *y)
{
GdkScrollEvent *self = (GdkScrollEvent *) event;
*x = self->x;
*y = self->y;
return TRUE;
}
static GdkDeviceTool *
gdk_scroll_event_get_tool (GdkEvent *event)
{
@@ -2202,10 +2296,10 @@ gdk_scroll_event_get_tool (GdkEvent *event)
static const GdkEventTypeInfo gdk_scroll_event_info = {
sizeof (GdkScrollEvent),
gdk_scroll_event_init,
NULL,
gdk_scroll_event_finalize,
gdk_scroll_event_get_state,
gdk_scroll_event_get_position,
NULL,
NULL,
gdk_scroll_event_get_tool,
NULL,
@@ -2799,35 +2893,51 @@ gdk_motion_event_new (GdkSurface *surface,
}
/**
* gdk_motion_event_get_history:
* @event: (type GdkMotionEvent): a motion #GdkEvent
* gdk_event_get_history:
* @event: a motion or scroll #GdkEvent
* @out_n_coords: (out): Return location for the length of the returned array
*
* Retrieves the history of the @event motion, as a list of time and
* coordinates.
* Retrieves the history of the @event, as a list of time and coordinates.
*
* The history includes events that are not delivered to the application
* because they occurred in the same frame as @event.
*
* Note that only motion and scroll events record history, and motion
* events only if one of the mouse buttons is down.
*
* Returns: (transfer container) (array length=out_n_coords) (nullable): an
* array of time and coordinates
*/
GdkTimeCoord *
gdk_motion_event_get_history (GdkEvent *event,
guint *out_n_coords)
gdk_event_get_history (GdkEvent *event,
guint *out_n_coords)
{
GdkMotionEvent *self = (GdkMotionEvent *) event;
GArray *history;
g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY), NULL);
g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY) ||
GDK_IS_EVENT_TYPE (event, GDK_SCROLL), NULL);
g_return_val_if_fail (out_n_coords != NULL, NULL);
if (self->history &&
self->history->len > 0)
if (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY))
{
GdkMotionEvent *self = (GdkMotionEvent *) event;
history = self->history;
}
else
{
GdkScrollEvent *self = (GdkScrollEvent *) event;
history = self->history;
}
if (history && history->len > 0)
{
GdkTimeCoord *result;
*out_n_coords = self->history->len;
*out_n_coords = history->len;
result = g_malloc (sizeof (GdkTimeCoord) * self->history->len);
memcpy (result, self->history->data, sizeof (GdkTimeCoord) * self->history->len);
result = g_malloc (sizeof (GdkTimeCoord) * history->len);
memcpy (result, history->data, sizeof (GdkTimeCoord) * history->len);
return result;
}

View File

@@ -378,6 +378,9 @@ gboolean gdk_event_get_axis (GdkEvent *event,
GdkAxisUse axis_use,
double *value);
GDK_AVAILABLE_IN_ALL
GdkTimeCoord * gdk_event_get_history (GdkEvent *event,
guint *out_n_coords);
GDK_AVAILABLE_IN_ALL
gboolean gdk_event_get_pointer_emulated (GdkEvent *event);
GDK_AVAILABLE_IN_ALL
@@ -392,6 +395,7 @@ GDK_AVAILABLE_IN_ALL
void gdk_scroll_event_get_deltas (GdkEvent *event,
double *delta_x,
double *delta_y);
GDK_AVAILABLE_IN_ALL
gboolean gdk_scroll_event_is_stop (GdkEvent *event);
GDK_AVAILABLE_IN_ALL
@@ -470,9 +474,6 @@ gboolean gdk_grab_broken_event_get_implicit (GdkEvent *event)
GDK_AVAILABLE_IN_ALL
GType gdk_motion_event_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GdkTimeCoord * gdk_motion_event_get_history (GdkEvent *event,
guint *out_n_coords);
GDK_AVAILABLE_IN_ALL
GType gdk_delete_event_get_type (void) G_GNUC_CONST;

View File

@@ -211,6 +211,9 @@ struct _GdkTouchEvent
* @pointer_emulated: whether the scroll event was the result of
* a pointer emulation
* @tool: a #GdkDeviceTool
* @history: (element-type GdkScrollHistory): array of times and deltas
* for other scroll events that were compressed before delivering the
* current event
*
* Generated from button presses for the buttons 4 to 7. Wheel mice are
* usually configured to generate button press events for buttons 4 and 5
@@ -225,8 +228,6 @@ struct _GdkScrollEvent
{
GdkEvent parent_instance;
double x;
double y;
GdkModifierType state;
GdkScrollDirection direction;
double delta_x;
@@ -234,6 +235,7 @@ struct _GdkScrollEvent
gboolean pointer_emulated;
gboolean is_stop;
GdkDeviceTool *tool;
GArray *history; /* <GdkScrollHistory> */
};
/*

View File

@@ -56,6 +56,7 @@ struct _GdkFrameClockIdlePrivate
GdkFrameClockPhase phase;
guint in_paint_idle : 1;
guint paint_is_thaw : 1;
#ifdef G_OS_WIN32
guint begin_period : 1;
#endif
@@ -162,7 +163,7 @@ gdk_frame_clock_idle_dispose (GObject *object)
static gint64
compute_smooth_frame_time (GdkFrameClock *clock,
gint64 new_frame_time,
gboolean new_frame_time_is_regular,
gboolean new_frame_time_is_vsync_related,
gint64 smoothed_frame_time_base,
gint64 frame_interval)
{
@@ -204,13 +205,13 @@ compute_smooth_frame_time (GdkFrameClock *clock,
* (current_error/frame_interval)*(current_error/frame_interval)*frame_interval
* But this can be simplified as below.
*
* Note: We only do this correction if we're regularly animating (no
* or low frame skip). If the last frame was a long time ago, or if
* we're not doing this in the frame cycle this call was likely
* triggered by an input event and new_frame_time is essentially
* random and not tied to the presentation time.
* Note: We only do this correction if the new frame is caused by a
* thaw of the frame clock, so that we know the time is actually
* related to the physical vblank. For frameclock cycles triggered
* by other events we always step up in whole frames from the last
* reported time.
*/
if (new_frame_time_is_regular)
if (new_frame_time_is_vsync_related)
{
current_error = new_smoothed_time - new_frame_time;
correction_magnitude = current_error * current_error / frame_interval; /* Note, this is always > 0 due to the square */
@@ -236,7 +237,8 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
/* can't change frame time during a paint */
if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS)
priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS &&
(priv->phase != GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT || priv->in_paint_idle))
return priv->smoothed_frame_time_base;
/* Outside a paint, pick something smoothed close to now */
@@ -274,7 +276,8 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
(priv)->updating_count > 0))
static void
maybe_start_idle (GdkFrameClockIdle *clock_idle)
maybe_start_idle (GdkFrameClockIdle *clock_idle,
gboolean caused_by_thaw)
{
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
@@ -302,6 +305,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
if (!priv->in_paint_idle &&
priv->paint_idle_id == 0 && RUN_PAINT_IDLE (priv))
{
priv->paint_is_thaw = caused_by_thaw;
priv->paint_idle_id = g_timeout_add_full (GDK_PRIORITY_REDRAW,
min_interval,
gdk_frame_clock_paint_idle,
@@ -408,7 +412,6 @@ gdk_frame_clock_paint_idle (void *data)
{
gint64 frame_interval = FRAME_INTERVAL;
GdkFrameTimings *prev_timings = gdk_frame_clock_get_current_timings (clock);
gint64 old_frame_time = priv->frame_time;
if (prev_timings && prev_timings->refresh_interval)
frame_interval = prev_timings->refresh_interval;
@@ -423,11 +426,9 @@ gdk_frame_clock_paint_idle (void *data)
}
else
{
/* For long delays, cycle was probably caused by input event rather than animation */
gboolean is_regular = priv->frame_time - old_frame_time < 4 * FRAME_INTERVAL;
priv->smoothed_frame_time_base =
compute_smooth_frame_time (clock, priv->frame_time,
is_regular,
priv->paint_is_thaw,
priv->smoothed_frame_time_base,
priv->smoothed_frame_time_period);
priv->smoothed_frame_time_period = frame_interval;
@@ -558,8 +559,8 @@ gdk_frame_clock_paint_idle (void *data)
if (priv->freeze_count == 0)
{
priv->min_next_frame_time = compute_min_next_frame_time (clock_idle,
priv->frame_time);
maybe_start_idle (clock_idle);
priv->smoothed_frame_time_base);
maybe_start_idle (clock_idle, FALSE);
}
if (priv->freeze_count == 0)
@@ -579,7 +580,7 @@ gdk_frame_clock_idle_request_phase (GdkFrameClock *clock,
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
priv->requested |= phase;
maybe_start_idle (clock_idle);
maybe_start_idle (clock_idle, FALSE);
}
static void
@@ -598,7 +599,7 @@ gdk_frame_clock_idle_begin_updating (GdkFrameClock *clock)
#endif
priv->updating_count++;
maybe_start_idle (clock_idle);
maybe_start_idle (clock_idle, FALSE);
}
static void
@@ -648,7 +649,7 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
priv->freeze_count--;
if (priv->freeze_count == 0)
{
maybe_start_idle (clock_idle);
maybe_start_idle (clock_idle, TRUE);
/* If nothing is requested so we didn't start an idle, we need
* to skip to the end of the state chain, since the idle won't
* run and do it for us.

View File

@@ -123,6 +123,7 @@ GList* _gdk_event_queue_append (GdkDisplay *display,
GdkEvent *event);
void _gdk_event_queue_handle_motion_compression (GdkDisplay *display);
void gdk_event_queue_handle_scroll_compression (GdkDisplay *display);
void _gdk_event_queue_flush (GdkDisplay *display);
gboolean _gdk_cairo_surface_extents (cairo_surface_t *surface,

View File

@@ -71,6 +71,8 @@ typedef enum
/**
* GdkPopupLayout:
*
* Struct containing information for gdk_popup_present()
*/
typedef struct _GdkPopupLayout GdkPopupLayout;

View File

@@ -30,8 +30,6 @@
#include <errno.h>
#include <math.h>
#include "fallback-c89.c"
/**
* SECTION:rgba_colors
* @Short_description: RGBA colors

View File

@@ -47,9 +47,6 @@
#include <epoxy/gl.h>
/* for the use of round() */
#include "fallback-c89.c"
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#endif
@@ -2369,6 +2366,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
* candidate it queues up flushing the event queue.
*/
_gdk_event_queue_handle_motion_compression (display);
gdk_event_queue_handle_scroll_compression (display);
}
/**

View File

@@ -31,6 +31,8 @@ G_BEGIN_DECLS
/**
* GdkTopLevelLayout:
*
* Struct containing information for gdk_toplevel_present()
*/
typedef struct _GdkToplevelLayout GdkToplevelLayout;

View File

@@ -247,6 +247,8 @@ typedef enum {
* @GDK_AXIS_IGNORE: the axis is ignored.
* @GDK_AXIS_X: the axis is used as the x axis.
* @GDK_AXIS_Y: the axis is used as the y axis.
* @GDK_AXIS_DELTA_X: the axis is used as the scroll x delta
* @GDK_AXIS_DELTA_Y: the axis is used as the scroll y delta
* @GDK_AXIS_PRESSURE: the axis is used for pressure information.
* @GDK_AXIS_XTILT: the axis is used for x tilt information.
* @GDK_AXIS_YTILT: the axis is used for y tilt information.
@@ -269,6 +271,8 @@ typedef enum
GDK_AXIS_IGNORE,
GDK_AXIS_X,
GDK_AXIS_Y,
GDK_AXIS_DELTA_X,
GDK_AXIS_DELTA_Y,
GDK_AXIS_PRESSURE,
GDK_AXIS_XTILT,
GDK_AXIS_YTILT,
@@ -283,6 +287,8 @@ typedef enum
* GdkAxisFlags:
* @GDK_AXIS_FLAG_X: X axis is present
* @GDK_AXIS_FLAG_Y: Y axis is present
* @GDK_AXIS_FLAG_DELTA_X: Scroll X delta axis is present
* @GDK_AXIS_FLAG_DELTA_Y: Scroll Y delta axis is present
* @GDK_AXIS_FLAG_PRESSURE: Pressure axis is present
* @GDK_AXIS_FLAG_XTILT: X tilt axis is present
* @GDK_AXIS_FLAG_YTILT: Y tilt axis is present
@@ -297,6 +303,8 @@ typedef enum
{
GDK_AXIS_FLAG_X = 1 << GDK_AXIS_X,
GDK_AXIS_FLAG_Y = 1 << GDK_AXIS_Y,
GDK_AXIS_FLAG_DELTA_X = 1 << GDK_AXIS_DELTA_X,
GDK_AXIS_FLAG_DELTA_Y = 1 << GDK_AXIS_DELTA_Y,
GDK_AXIS_FLAG_PRESSURE = 1 << GDK_AXIS_PRESSURE,
GDK_AXIS_FLAG_XTILT = 1 << GDK_AXIS_XTILT,
GDK_AXIS_FLAG_YTILT = 1 << GDK_AXIS_YTILT,

View File

@@ -309,17 +309,6 @@ static void deliver_key_event (GdkWaylandSeat *seat,
uint32_t state,
gboolean from_key_repeat);
static gboolean
gdk_wayland_device_get_history (GdkDevice *device,
GdkSurface *surface,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
return FALSE;
}
static void
gdk_wayland_device_get_state (GdkDevice *device,
GdkSurface *surface,
@@ -828,7 +817,6 @@ gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_wayland_device_get_history;
device_class->get_state = gdk_wayland_device_get_state;
device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor;
device_class->query_state = gdk_wayland_device_query_state;
@@ -844,8 +832,8 @@ gdk_wayland_device_init (GdkWaylandDevice *device_core)
device = GDK_DEVICE (device_core);
_gdk_device_add_axis (device, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, NULL, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1);
}
static gint
@@ -3398,42 +3386,42 @@ gdk_wayland_device_tablet_clone_tool_axes (GdkWaylandTabletData *tablet,
g_object_freeze_notify (G_OBJECT (tablet->current_device));
_gdk_device_reset_axes (tablet->current_device);
_gdk_device_add_axis (tablet->current_device, NULL, GDK_AXIS_X, 0, 0, 0);
_gdk_device_add_axis (tablet->current_device, NULL, GDK_AXIS_Y, 0, 0, 0);
_gdk_device_add_axis (tablet->current_device, GDK_AXIS_X, 0, 0, 0);
_gdk_device_add_axis (tablet->current_device, GDK_AXIS_Y, 0, 0, 0);
if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT))
{
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_XTILT, -90, 90, 0);
tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos;
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_YTILT, -90, 90, 0);
tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_DISTANCE)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_DISTANCE, 0, 65535, 0);
tablet->axis_indices[GDK_AXIS_DISTANCE] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_PRESSURE, 0, 65535, 0);
tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_ROTATION, 0, 360, 0);
tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos;
}
if (tool->tool_axes & GDK_AXIS_FLAG_SLIDER)
{
axis_pos = _gdk_device_add_axis (tablet->current_device, NULL,
axis_pos = _gdk_device_add_axis (tablet->current_device,
GDK_AXIS_SLIDER, -65535, 65535, 0);
tablet->axis_indices[GDK_AXIS_SLIDER] = axis_pos;
}
@@ -3452,7 +3440,6 @@ gdk_wayland_mimic_device_axes (GdkDevice *master,
GdkDevice *slave)
{
gdouble axis_min, axis_max, axis_resolution;
const char *axis_label;
GdkAxisUse axis_use;
gint axis_count;
gint i;
@@ -3463,9 +3450,9 @@ gdk_wayland_mimic_device_axes (GdkDevice *master,
for (i = 0; i < axis_count; i++)
{
_gdk_device_get_axis_info (slave, i, &axis_label, &axis_use, &axis_min,
_gdk_device_get_axis_info (slave, i, &axis_use, &axis_min,
&axis_max, &axis_resolution);
_gdk_device_add_axis (master, axis_label, axis_use, axis_min,
_gdk_device_add_axis (master, axis_use, axis_min,
axis_max, axis_resolution);
}

View File

@@ -31,7 +31,6 @@
#include <limits.h>
#include <errno.h>
#include <sys/mman.h>
#include <fribidi.h>
#include "gdk.h"
#include "gdkwayland.h"

View File

@@ -32,11 +32,10 @@ G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE)
void
_gdk_device_virtual_set_active (GdkDevice *device,
GdkDevice *new_active)
GdkDevice *new_active)
{
GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
int n_axes, i;
const char *label_atom;
GdkAxisUse use;
gdouble min_value, max_value, resolution;
@@ -50,31 +49,16 @@ _gdk_device_virtual_set_active (GdkDevice *device,
_gdk_device_reset_axes (device);
n_axes = gdk_device_get_n_axes (new_active);
for (i = 0; i < n_axes; i++)
{
_gdk_device_get_axis_info (new_active, i,
&label_atom, &use,
&min_value, &max_value, &resolution);
_gdk_device_add_axis (device,
label_atom, use,
min_value, max_value, resolution);
}
{
_gdk_device_get_axis_info (new_active, i, &use,
&min_value, &max_value, &resolution);
_gdk_device_add_axis (device, use, min_value, max_value, resolution);
}
}
g_signal_emit_by_name (G_OBJECT (device), "changed");
}
static gboolean
gdk_device_virtual_get_history (GdkDevice *device,
GdkSurface *window,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
/* History is only per slave device */
return FALSE;
}
static void
gdk_device_virtual_get_state (GdkDevice *device,
GdkSurface *window,
@@ -188,7 +172,6 @@ gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_device_virtual_get_history;
device_class->get_state = gdk_device_virtual_get_state;
device_class->set_surface_cursor = gdk_device_virtual_set_surface_cursor;
device_class->query_state = gdk_device_virtual_query_state;

View File

@@ -29,17 +29,6 @@
G_DEFINE_TYPE (GdkDeviceWin32, gdk_device_win32, GDK_TYPE_DEVICE)
static gboolean
gdk_device_win32_get_history (GdkDevice *device,
GdkSurface *window,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
return FALSE;
}
static void
gdk_device_win32_get_state (GdkDevice *device,
GdkSurface *window,
@@ -235,7 +224,6 @@ gdk_device_win32_class_init (GdkDeviceWin32Class *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_device_win32_get_history;
device_class->get_state = gdk_device_win32_get_state;
device_class->set_surface_cursor = gdk_device_win32_set_surface_cursor;
device_class->query_state = gdk_device_win32_query_state;
@@ -251,6 +239,6 @@ gdk_device_win32_init (GdkDeviceWin32 *device_win32)
device = GDK_DEVICE (device_win32);
_gdk_device_add_axis (device, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, NULL, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1);
}

View File

@@ -28,17 +28,6 @@
G_DEFINE_TYPE (GdkDeviceWintab, gdk_device_wintab, GDK_TYPE_DEVICE)
static gboolean
gdk_device_wintab_get_history (GdkDevice *device,
GdkSurface *window,
guint32 start,
guint32 stop,
GdkTimeCoord ***events,
gint *n_events)
{
return FALSE;
}
static GdkModifierType
get_current_mask (void)
{
@@ -267,7 +256,6 @@ gdk_device_wintab_class_init (GdkDeviceWintabClass *klass)
{
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
device_class->get_history = gdk_device_wintab_get_history;
device_class->get_state = gdk_device_wintab_get_state;
device_class->set_surface_cursor = gdk_device_wintab_set_surface_cursor;
device_class->query_state = gdk_device_wintab_query_state;

View File

@@ -577,7 +577,6 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
if (device->pktdata & PK_X)
{
_gdk_device_add_axis (GDK_DEVICE (device),
NULL,
GDK_AXIS_X,
axis_x.axMin,
axis_x.axMax,
@@ -588,7 +587,6 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
if (device->pktdata & PK_Y)
{
_gdk_device_add_axis (GDK_DEVICE (device),
NULL,
GDK_AXIS_Y,
axis_y.axMin,
axis_y.axMax,
@@ -600,7 +598,6 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
if (device->pktdata & PK_NORMAL_PRESSURE)
{
_gdk_device_add_axis (GDK_DEVICE (device),
NULL,
GDK_AXIS_PRESSURE,
axis_npressure.axMin,
axis_npressure.axMax,
@@ -617,14 +614,12 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
* we convert to x and y tilt in the -1000..1000 range
*/
_gdk_device_add_axis (GDK_DEVICE (device),
NULL,
GDK_AXIS_XTILT,
-1000,
1000,
1000);
_gdk_device_add_axis (GDK_DEVICE (device),
NULL,
GDK_AXIS_YTILT,
-1000,
1000,

View File

@@ -49,7 +49,6 @@
#include <cairo-win32.h>
#include <dwmapi.h>
#include <math.h>
#include "fallback-c89.c"
static void gdk_surface_win32_finalize (GObject *object);

View File

@@ -211,7 +211,6 @@ translate_valuator_class (GdkDisplay *display,
static gboolean initialized = FALSE;
static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
GdkAxisUse use = GDK_AXIS_IGNORE;
const char *label;
gint i;
if (!initialized)
@@ -234,13 +233,18 @@ translate_valuator_class (GdkDisplay *display,
}
}
if (valuator_label != None)
label = gdk_x11_get_xatom_name_for_display (display, valuator_label);
else
label = NULL;
_gdk_device_add_axis (device, use, min, max, resolution);
GDK_DISPLAY_NOTE (display, INPUT,
{
const char *label;
_gdk_device_add_axis (device, label, use, min, max, resolution);
GDK_DISPLAY_NOTE (display, INPUT, g_message ("\n\taxis: %s %s", label, use == GDK_AXIS_IGNORE ? "(ignored)" : "(used)"));
if (valuator_label != None)
label = gdk_x11_get_xatom_name_for_display (display, valuator_label);
else
label = NULL;
g_message ("\n\taxis: %s %s", label, use == GDK_AXIS_IGNORE ? "(ignored)" : "(used)");
});
}
static void
@@ -261,13 +265,7 @@ translate_device_classes (GdkDisplay *display,
{
case XIKeyClass:
{
XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
gint j;
_gdk_device_set_keys (device, key_info->num_keycodes);
for (j = 0; j < key_info->num_keycodes; j++)
gdk_device_set_key (device, j, key_info->keycodes[j], 0);
/* Not used */
}
break;
case XIValuatorClass:

View File

@@ -1603,6 +1603,14 @@ gdk_x11_display_open (const gchar *display_name)
}
#endif
#ifdef HAVE_XDAMAGE
display_x11->have_damage = FALSE;
if (XDamageQueryExtension (display_x11->xdisplay,
&display_x11->damage_event_base,
&display_x11->damage_error_base))
display_x11->have_damage = TRUE;
#endif
display->clipboard = gdk_x11_clipboard_new (display, "CLIPBOARD");
display->primary_clipboard = gdk_x11_clipboard_new (display, "PRIMARY");

View File

@@ -149,6 +149,13 @@ struct _GdkX11Display
guint has_glx_multisample : 1;
guint has_glx_visual_rating : 1;
guint has_glx_create_es2_context : 1;
guint has_async_glx_swap_buffers : 1;
#ifdef HAVE_XDAMAGE
gint damage_event_base;
gint damage_error_base;
guint have_damage;
#endif
};
struct _GdkX11DisplayClass

View File

@@ -183,6 +183,22 @@ gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
gdk_x11_surface_pre_damage (surface);
#ifdef HAVE_XDAMAGE
if (context_x11->xdamage != 0)
{
g_assert (context_x11->frame_fence == 0);
context_x11->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
/* We consider the frame still getting painted until the GL operation is
* finished, and the window gets damage reported from the X server.
* It's only at this point the compositor can be sure it has full
* access to the new updates.
*/
_gdk_x11_surface_set_frame_still_painting (surface, TRUE);
}
#endif
glXSwapBuffers (dpy, drawable);
if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync)
@@ -565,6 +581,81 @@ create_legacy_context (GdkDisplay *display,
return res;
}
#ifdef HAVE_XDAMAGE
static gboolean
on_gl_surface_xevent (GdkGLContext *context,
XEvent *xevent,
GdkX11Display *display_x11)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
XDamageNotifyEvent *damage_xevent;
if (!context_x11->is_attached)
return FALSE;
if (xevent->type != (display_x11->damage_event_base + XDamageNotify))
return FALSE;
damage_xevent = (XDamageNotifyEvent *) xevent;
if (damage_xevent->damage != context_x11->xdamage)
return FALSE;
if (context_x11->frame_fence)
{
GLenum wait_result;
wait_result = glClientWaitSync (context_x11->frame_fence, 0, 0);
switch (wait_result)
{
/* We assume that if the fence has been signaled, that this damage
* event is the damage event that was triggered by the GL drawing
* associated with the fence. That's, technically, not necessarly
* always true. The X server could have generated damage for
* an unrelated event (say the size of the window changing), at
* just the right moment such that we're picking it up instead.
*
* We're choosing not to handle this edge case, but if it does ever
* happen in the wild, it could lead to slight underdrawing by
* the compositor for one frame. In the future, if we find out
* this edge case is noticeable, we can compensate by copying the
* painted region from gdk_x11_gl_context_end_frame and subtracting
* damaged areas from the copy as they come in. Once the copied
* region goes empty, we know that there won't be any underdraw,
* and can mark painting has finished. It's not worth the added
* complexity and resource usage to do this bookkeeping, however,
* unless the problem is practically visible.
*/
case GL_ALREADY_SIGNALED:
case GL_CONDITION_SATISFIED:
case GL_WAIT_FAILED:
if (wait_result == GL_WAIT_FAILED)
g_warning ("failed to wait on GL fence associated with last swap buffers call");
glDeleteSync (context_x11->frame_fence);
context_x11->frame_fence = 0;
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
break;
/* We assume that if the fence hasn't been signaled, that this
* damage event is not the damage event that was triggered by the
* GL drawing associated with the fence. That's only true for
* the Nvidia vendor driver. When using open source drivers, damage
* is emitted immediately on swap buffers, before the fence ever
* has a chance to signal.
*/
case GL_TIMEOUT_EXPIRED:
break;
default:
g_assert_not_reached ();
}
}
return FALSE;
}
#endif
static gboolean
gdk_x11_gl_context_realize (GdkGLContext *context,
GError **error)
@@ -737,6 +828,24 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
context_x11->attached_drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_surface_get_xid (surface);
context_x11->unattached_drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
#ifdef HAVE_XDAMAGE
if (display_x11->have_damage && display_x11->has_async_glx_swap_buffers)
{
gdk_x11_display_error_trap_push (display);
context_x11->xdamage = XDamageCreate (dpy,
gdk_x11_surface_get_xid (surface),
XDamageReportRawRectangles);
if (gdk_x11_display_error_trap_pop (display))
context_x11->xdamage = 0;
else
g_signal_connect_object (G_OBJECT (display),
"xevent",
G_CALLBACK (on_gl_surface_xevent),
context,
G_CONNECT_SWAPPED);
}
#endif
context_x11->is_direct = glXIsDirect (dpy, context_x11->glx_context);
GDK_DISPLAY_NOTE (display, OPENGL,
@@ -766,6 +875,10 @@ gdk_x11_gl_context_dispose (GObject *gobject)
context_x11->glx_context = NULL;
}
#ifdef HAVE_XDAMAGE
context_x11->xdamage = 0;
#endif
G_OBJECT_CLASS (gdk_x11_gl_context_parent_class)->dispose (gobject);
}
@@ -841,6 +954,21 @@ gdk_x11_screen_init_gl (GdkX11Screen *screen)
display_x11->has_glx_visual_rating =
epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
{
/* With the mesa based drivers, we can safely assume the compositor can
* access the updated surface texture immediately after glXSwapBuffers is
* run, because the kernel ensures there is an implicit synchronization
* operation upon texture access. This is not true with the Nvidia vendor
* driver. There is a window of time after glXSwapBuffers before other
* processes can see the updated drawing. We need to take special care,
* in that case, to defer telling the compositor our latest frame is
* ready until after the GPU has completed all issued commands related
* to the frame, and that the X server says the frame has been drawn.
*/
display_x11->has_async_glx_swap_buffers = TRUE;
}
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("GLX version %d.%d found\n"
" - Vendor: %s\n"

View File

@@ -24,6 +24,10 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#include <epoxy/gl.h>
#include <epoxy/glx.h>
@@ -44,6 +48,11 @@ struct _GdkX11GLContext
GLXDrawable attached_drawable;
GLXDrawable unattached_drawable;
#ifdef HAVE_XDAMAGE
GLsync frame_fence;
Damage xdamage;
#endif
guint is_attached : 1;
guint is_direct : 1;
guint do_frame_sync : 1;

View File

@@ -104,6 +104,11 @@ void _gdk_x11_surface_grab_check_unmap (GdkSurface *window,
gulong serial);
void _gdk_x11_surface_grab_check_destroy (GdkSurface *window);
#ifdef HAVE_XDAMAGE
void _gdk_x11_surface_set_frame_still_painting (GdkSurface *surface,
gboolean painting);
#endif
gboolean _gdk_x11_display_is_root_window (GdkDisplay *display,
Window xroot_window);

View File

@@ -360,6 +360,77 @@ gdk_x11_surface_begin_frame (GdkSurface *surface,
}
}
static gboolean
should_sync_frame_drawing (GdkSurface *surface)
{
GdkX11Surface *impl = GDK_X11_SURFACE (surface);
/* disabled client side */
if (!impl->frame_sync_enabled)
return FALSE;
/* disabled compositor side */
if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
return FALSE;
return TRUE;
}
static void
sync_counter_for_end_frame (GdkSurface *surface)
{
GdkX11Surface *impl = GDK_X11_SURFACE (surface);
g_assert (!impl->toplevel->in_frame);
g_assert (impl->toplevel->extended_update_counter != None);
g_assert ((impl->toplevel->current_counter_value % 2) == 0);
set_sync_counter (GDK_SURFACE_XDISPLAY (surface),
impl->toplevel->extended_update_counter,
impl->toplevel->current_counter_value);
}
static void
maybe_sync_counter_for_end_frame (GdkSurface *surface)
{
GdkX11Surface *impl = GDK_X11_SURFACE (surface);
gboolean frame_sync_negotiated = should_sync_frame_drawing (surface);
gboolean frame_done_painting = !impl->toplevel->frame_pending;
#ifdef HAVE_XDAMAGE
frame_done_painting = !impl->toplevel->frame_still_painting && frame_sync_negotiated;
#endif
if (!impl->toplevel->frame_pending)
{
if (!frame_sync_negotiated || frame_done_painting)
sync_counter_for_end_frame (surface);
}
else
{
if (frame_done_painting)
sync_counter_for_end_frame (surface);
}
}
#ifdef HAVE_XDAMAGE
void
_gdk_x11_surface_set_frame_still_painting (GdkSurface *surface,
gboolean painting)
{
GdkX11Surface *impl = GDK_X11_SURFACE (surface);
if (impl->toplevel->frame_still_painting == painting)
return;
impl->toplevel->frame_still_painting = painting;
if (!impl->toplevel->frame_still_painting)
maybe_sync_counter_for_end_frame (surface);
}
#endif
static void
gdk_x11_surface_end_frame (GdkSurface *surface)
{
@@ -405,13 +476,9 @@ gdk_x11_surface_end_frame (GdkSurface *surface)
else
impl->toplevel->current_counter_value += 1;
set_sync_counter(GDK_SURFACE_XDISPLAY (surface),
impl->toplevel->extended_update_counter,
impl->toplevel->current_counter_value);
maybe_sync_counter_for_end_frame (surface);
if (impl->frame_sync_enabled &&
gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (surface),
g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
if (should_sync_frame_drawing (surface))
{
impl->toplevel->frame_pending = TRUE;
gdk_surface_freeze_updates (surface);

View File

@@ -124,6 +124,9 @@ struct _GdkToplevelX11
guint in_frame : 1;
/* If we're waiting for damage from the X server after painting a frame */
guint frame_still_painting : 1;
/* If we're expecting a response from the compositor after painting a frame */
guint frame_pending : 1;

View File

@@ -65,6 +65,7 @@ gdk_x11_deps = [
xext_dep,
x11_dep,
xcursor_dep,
xdamage_dep,
xfixes_dep,
xcomposite_dep,
xrandr_dep,

View File

@@ -370,7 +370,7 @@ gsk_linear_gradient_node_get_n_color_stops (GskRenderNode *node)
* @node: (type GskLinearGradientNode): a #GskRenderNode for a linear gradient
* @n_stops: (out) (optional): the number of color stops in the returned array
*
* Retrievs the color stops in the gradient.
* Retrieves the color stops in the gradient.
*
* Returns: (array length=n_stops): the color stops in the gradient
*/
@@ -555,6 +555,14 @@ gsk_border_node_diff (GskRenderNode *node1,
gsk_render_node_diff_impossible (node1, node2, region);
}
/**
* gsk_border_node_peek_outline:
* @node: (type GskBorderNode): a #GskRenderNode for a border
*
* Retrieves the outline of the border.
*
* Returns: the outline of the border
*/
const GskRoundedRect *
gsk_border_node_peek_outline (GskRenderNode *node)
{
@@ -563,6 +571,15 @@ gsk_border_node_peek_outline (GskRenderNode *node)
return &self->outline;
}
/**
* gsk_border_node_peek_widths:
* @node: (type GskBorderNode): a #GskRenderNode for a border
*
* Retrieves the stroke widths of the border.
*
* Returns: (transfer none): an array of 4 floats for the top,
* right, bottom and left stroke width of the border
*/
const float *
gsk_border_node_peek_widths (GskRenderNode *node)
{
@@ -571,6 +588,15 @@ gsk_border_node_peek_widths (GskRenderNode *node)
return self->border_width;
}
/**
* gsk_border_node_peek_colors:
* @node: (type GskBorderNode): a #GskRenderNode for a border
*
* Retrieves the colors of the border.
*
* Returns: (transfer none): an array of 4 #GdkRGBA structs
* for the top, right, bottom and left color of the border
*/
const GdkRGBA *
gsk_border_node_peek_colors (GskRenderNode *node)
{
@@ -3626,6 +3652,14 @@ gsk_text_node_has_color_glyphs (GskRenderNode *node)
return self->has_color_glyphs;
}
/**
* gsk_text_node_get_num_glyphs:
* @node: (type GskTextNode): a text #GskRenderNode
*
* Retrieves the number of glyphs in the text node.
*
* Returns: the number of glyphs
*/
guint
gsk_text_node_get_num_glyphs (GskRenderNode *node)
{

View File

@@ -171,37 +171,30 @@ gtk_button_accessible_ref_state_set (AtkObject *obj)
return state_set;
}
static void
gtk_button_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
void
gtk_button_accessible_update_label (GtkButtonAccessible *self)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject *atk_obj = gtk_widget_get_accessible (widget);
g_return_if_fail (GTK_IS_BUTTON_ACCESSIBLE (self));
if (strcmp (pspec->name, "label") == 0)
{
if (atk_obj->name == NULL)
g_object_notify (G_OBJECT (atk_obj), "accessible-name");
/* If we don't have an overridden name, we use the label as the
* accessible name
*/
if (atk_object_get_name (ATK_OBJECT (self)) == NULL)
g_object_notify (G_OBJECT (self), "accessible-name");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_button_accessible_parent_class)->notify_gtk (obj, pspec);
g_signal_emit_by_name (self, "visible-data-changed");
}
static void
gtk_button_accessible_class_init (GtkButtonAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
class->get_name = gtk_button_accessible_get_name;
class->get_n_children = gtk_button_accessible_get_n_children;
class->ref_child = gtk_button_accessible_ref_child;
class->ref_state_set = gtk_button_accessible_ref_state_set;
class->initialize = gtk_button_accessible_initialize;
widget_class->notify_gtk = gtk_button_accessible_notify_gtk;
}
static void

View File

@@ -52,6 +52,9 @@ struct _GtkButtonAccessibleClass
GDK_AVAILABLE_IN_ALL
GType gtk_button_accessible_get_type (void);
/*< private >*/
void gtk_button_accessible_update_label (GtkButtonAccessible *self);
G_END_DECLS
#endif /* __GTK_BUTTON_ACCESSIBLE_H__ */

View File

@@ -17,10 +17,10 @@
#include "config.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "gtkcolorswatchprivate.h"
#include "gtkcolorswatchaccessibleprivate.h"
#include "gtkcolorswatchprivate.h"
#include <glib/gi18n-lib.h>
static void atk_action_interface_init (AtkActionIface *iface);
@@ -29,9 +29,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkColorSwatchAccessible, _gtk_color_swatch_accessible,
static void
state_changed_cb (GtkWidget *widget,
GtkStateFlags previous_flags)
GtkStateFlags previous_flags,
AtkObject *accessible)
{
AtkObject *accessible;
GtkStateFlags flags;
gboolean was_selected;
gboolean selected;
@@ -41,23 +41,46 @@ state_changed_cb (GtkWidget *widget,
was_selected = (previous_flags & GTK_STATE_FLAG_SELECTED) != 0;
selected = (flags & GTK_STATE_FLAG_SELECTED) != 0;
accessible = gtk_widget_get_accessible (widget);
if (selected && !was_selected)
atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, TRUE);
else if (!selected && was_selected)
atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, FALSE);
}
static void
on_selectable_changed_cb (GObject *gobject,
GParamSpec *pspec,
AtkObject *accessible)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (gobject);
AtkRole role;
if (gtk_color_swatch_get_selectable (swatch))
role = ATK_ROLE_RADIO_BUTTON;
else
role = ATK_ROLE_PUSH_BUTTON;
atk_object_set_role (accessible, role);
}
static void
gtk_color_swatch_accessible_initialize (AtkObject *obj,
gpointer data)
{
GtkColorSwatch *swatch = data;
ATK_OBJECT_CLASS (_gtk_color_swatch_accessible_parent_class)->initialize (obj, data);
g_signal_connect (data, "state-flags-changed",
G_CALLBACK (state_changed_cb), NULL);
G_CALLBACK (state_changed_cb),
obj);
g_signal_connect (data, "notify::selectable",
G_CALLBACK (on_selectable_changed_cb),
obj);
atk_object_set_role (obj, ATK_ROLE_RADIO_BUTTON);
obj->role = gtk_color_swatch_get_selectable (swatch)
? ATK_ROLE_RADIO_BUTTON
: ATK_ROLE_PUSH_BUTTON;
}
static AtkStateSet *
@@ -78,39 +101,19 @@ gtk_color_swatch_accessible_ref_state_set (AtkObject *accessible)
return state_set;
}
static void
gtk_color_swatch_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject *atk_obj = gtk_widget_get_accessible (widget);
if (strcmp (pspec->name, "selectable") == 0)
{
if (gtk_color_swatch_get_selectable (GTK_COLOR_SWATCH (widget)))
atk_object_set_role (atk_obj, ATK_ROLE_RADIO_BUTTON);
else
atk_object_set_role (atk_obj, ATK_ROLE_PUSH_BUTTON);
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_color_swatch_accessible_parent_class)->notify_gtk (obj, pspec);
}
static void
_gtk_color_swatch_accessible_class_init (GtkColorSwatchAccessibleClass *klass)
{
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass *)klass;
atk_class->initialize = gtk_color_swatch_accessible_initialize;
atk_class->ref_state_set = gtk_color_swatch_accessible_ref_state_set;
widget_class->notify_gtk = gtk_color_swatch_accessible_notify_gtk;
}
static void
_gtk_color_swatch_accessible_init (GtkColorSwatchAccessible *scale)
_gtk_color_swatch_accessible_init (GtkColorSwatchAccessible *self)
{
ATK_OBJECT (self)->role = ATK_ROLE_RADIO_BUTTON;
}
static gint

View File

@@ -17,20 +17,21 @@
#include "config.h"
#include "gtkentryaccessible.h"
#include "gtkcomboboxaccessible.h"
#include "gtkentryprivate.h"
#include "gtklabel.h"
#include "gtkpango.h"
#include "gtkstylecontextprivate.h"
#include "gtktextprivate.h"
#include "gtkwidgetprivate.h"
#include "gdk/gdkeventsprivate.h"
#include <glib/gi18n-lib.h>
#include <string.h>
#include <gtk/gtk.h>
#include "gtkpango.h"
#include "gtkentryaccessible.h"
#include "gtkentryprivate.h"
#include "gtksearchentryprivate.h"
#include "gtkpasswordentry.h"
#include "gtktextprivate.h"
#include "gtkcomboboxaccessible.h"
#include "gtkstylecontextprivate.h"
#include "gtkwidgetprivate.h"
#define GTK_TYPE_ENTRY_ICON_ACCESSIBLE (gtk_entry_icon_accessible_get_type ())
#define GTK_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE, GtkEntryIconAccessible))
@@ -157,7 +158,7 @@ gtk_entry_icon_accessible_ref_state_set (AtkObject *accessible)
if (!entry_set || atk_state_set_contains_state (entry_set, ATK_STATE_DEFUNCT))
{
atk_state_set_add_state (set, ATK_STATE_DEFUNCT);
g_clear_object (&entry_set);
g_clear_object (&entry_set);
return set;
}
@@ -356,15 +357,6 @@ icon_atk_component_interface_init (AtkComponentIface *iface)
}
/* Callbacks */
static void insert_text_cb (GtkEditable *editable,
gchar *new_text,
gint new_text_length,
gint *position);
static void delete_text_cb (GtkEditable *editable,
gint start,
gint end);
static gboolean check_for_selection_change (GtkEntryAccessible *entry,
GtkEditable *editable);
@@ -380,6 +372,277 @@ G_DEFINE_TYPE_WITH_CODE (GtkEntryAccessible, gtk_entry_accessible, GTK_TYPE_WIDG
G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
static GtkText *
get_text (AtkText *atk_text)
{
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
if (widget == NULL)
return NULL;
return gtk_entry_get_text_widget (GTK_ENTRY (widget));
}
static gboolean
check_for_selection_change (GtkEntryAccessible *accessible,
GtkEditable *editable)
{
gboolean ret_val = FALSE;
gint start, end;
if (gtk_editable_get_selection_bounds (editable, &start, &end))
{
if (end != accessible->priv->cursor_position ||
start != accessible->priv->selection_bound)
/*
* This check is here as this function can be called
* for notification of selection_bound and current_pos.
* The values of current_pos and selection_bound may be the same
* for both notifications and we only want to generate one
* text_selection_changed signal.
*/
ret_val = TRUE;
}
else
{
/* We had a selection */
ret_val = (accessible->priv->cursor_position != accessible->priv->selection_bound);
}
accessible->priv->cursor_position = end;
accessible->priv->selection_bound = start;
return ret_val;
}
static void
insert_text_cb (GtkEditable *editable,
gchar *new_text,
gint new_text_length,
gint *position,
GtkEntryAccessible *self)
{
int length;
if (new_text_length == 0)
return;
length = g_utf8_strlen (new_text, new_text_length);
g_signal_emit_by_name (self,
"text-changed::insert",
*position - length,
length);
}
/* We connect to GtkEditable::delete-text, since it carries
* the information we need. But we delay emitting our own
* text_changed::delete signal until the entry has update
* all its internal state and emits GtkEntry::changed.
*/
static void
delete_text_cb (GtkEditable *editable,
gint start,
gint end,
GtkEntryAccessible *self)
{
GtkText *textw;
textw = get_text (ATK_TEXT (self));
if (textw == NULL)
return;
if (end < 0)
{
gchar *text;
text = gtk_text_get_display_text (textw, 0, -1);
end = g_utf8_strlen (text, -1);
g_free (text);
}
if (end == start)
return;
g_signal_emit_by_name (self,
"text-changed::delete",
start,
end - start);
}
static void
on_notify (GObject *gobject,
GParamSpec *pspec,
GtkEntryAccessible *self)
{
GtkWidget *widget;
AtkObject* atk_obj;
GtkEntryAccessiblePrivate *priv;
widget = GTK_WIDGET (gobject);
atk_obj = gtk_widget_get_accessible (widget);
priv = gtk_entry_accessible_get_instance_private (self);
if (g_strcmp0 (pspec->name, "cursor-position") == 0)
{
if (check_for_selection_change (self, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
/*
* The entry cursor position has moved so generate the signal.
*/
g_signal_emit_by_name (atk_obj, "text-caret-moved",
gtk_editable_get_position (GTK_EDITABLE (widget)));
}
else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
{
if (check_for_selection_change (self, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
}
else if (g_strcmp0 (pspec->name, "editable") == 0)
{
gboolean value;
g_object_get (gobject, "editable", &value, NULL);
atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, value);
}
else if (g_strcmp0 (pspec->name, "visibility") == 0)
{
gboolean visibility;
AtkRole new_role;
visibility = gtk_entry_get_visibility (GTK_ENTRY (widget));
new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
atk_object_set_role (atk_obj, new_role);
}
else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
{
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY &&
!priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (self, GTK_ENTRY_ICON_PRIMARY);
g_signal_emit_by_name (self, "children-changed::add", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY &&
priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY]));
g_signal_emit_by_name (self, "children-changed::remove", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
{
gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0);
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY &&
!priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (self, GTK_ENTRY_ICON_SECONDARY);
g_signal_emit_by_name (self, "children-changed::add", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY &&
priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY]));
g_signal_emit_by_name (self, "children-changed::remove", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], "");
}
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], "");
}
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_ENABLED, on);
}
}
else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_SENSITIVE, on);
}
}
else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_SENSITIVE, on);
}
}
}
static AtkStateSet *
gtk_entry_accessible_ref_state_set (AtkObject *accessible)
@@ -423,9 +686,7 @@ gtk_entry_accessible_get_attributes (AtkObject *accessible)
if (widget == NULL)
return attributes;
if (GTK_IS_ENTRY (widget) || GTK_IS_SEARCH_ENTRY (widget))
g_object_get (widget, "placeholder-text", &text, NULL);
g_object_get (widget, "placeholder-text", &text, NULL);
if (text == NULL)
return attributes;
@@ -456,197 +717,9 @@ gtk_entry_accessible_initialize (AtkObject *obj,
gtk_entry_accessible->priv->selection_bound = start_pos;
/* Set up signal callbacks */
g_signal_connect_after (widget, "insert-text", G_CALLBACK (insert_text_cb), NULL);
g_signal_connect (widget, "delete-text", G_CALLBACK (delete_text_cb), NULL);
if (GTK_IS_PASSWORD_ENTRY (widget))
obj->role = ATK_ROLE_PASSWORD_TEXT;
else
obj->role = ATK_ROLE_TEXT;
}
static void
gtk_entry_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
{
GtkWidget *widget;
AtkObject* atk_obj;
GtkEntryAccessible* entry;
GtkEntryAccessiblePrivate *priv;
widget = GTK_WIDGET (obj);
atk_obj = gtk_widget_get_accessible (widget);
entry = GTK_ENTRY_ACCESSIBLE (atk_obj);
priv = entry->priv;
if (g_strcmp0 (pspec->name, "cursor-position") == 0)
{
if (check_for_selection_change (entry, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
/*
* The entry cursor position has moved so generate the signal.
*/
g_signal_emit_by_name (atk_obj, "text-caret-moved",
gtk_editable_get_position (GTK_EDITABLE (widget)));
}
else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
{
if (check_for_selection_change (entry, GTK_EDITABLE (widget)))
g_signal_emit_by_name (atk_obj, "text-selection-changed");
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "editable") == 0)
{
gboolean value;
g_object_get (obj, "editable", &value, NULL);
atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, value);
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "visibility") == 0)
{
gboolean visibility;
AtkRole new_role;
visibility = gtk_entry_get_visibility (GTK_ENTRY (widget));
new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
atk_object_set_role (atk_obj, new_role);
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0)
{
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_PRIMARY);
g_signal_emit_by_name (entry, "children-changed::add", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY]));
g_signal_emit_by_name (entry, "children-changed::remove", 0,
priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0)
{
gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0);
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_SECONDARY);
g_signal_emit_by_name (entry, "children-changed::add", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
}
else if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY]));
g_signal_emit_by_name (entry, "children-changed::remove", index,
priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL);
g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-name") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
const gchar *name;
name = gtk_entry_get_icon_name (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (name)
atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], "");
}
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gchar *text;
text = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
if (text)
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], text);
g_free (text);
}
else
{
atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], "");
}
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_ENABLED, on);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_activatable (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_ENABLED, on);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY],
ATK_STATE_SENSITIVE, on);
}
}
else if (GTK_IS_ENTRY (widget) &&
g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0)
{
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gboolean on = gtk_entry_get_icon_sensitive (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY);
atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY],
ATK_STATE_SENSITIVE, on);
}
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec);
g_signal_connect_after (widget, "insert-text", G_CALLBACK (insert_text_cb), obj);
g_signal_connect (widget, "delete-text", G_CALLBACK (delete_text_cb), obj);
g_signal_connect (widget, "notify", G_CALLBACK (on_notify), obj);
}
static gint
@@ -673,13 +746,10 @@ gtk_entry_accessible_get_n_children (AtkObject* obj)
if (widget == NULL)
return 0;
if (GTK_IS_ENTRY (widget))
{
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
count++;
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
count++;
}
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
count++;
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
count++;
return count;
}
@@ -697,9 +767,6 @@ gtk_entry_accessible_ref_child (AtkObject *obj,
if (widget == NULL)
return NULL;
if (!GTK_IS_ENTRY (widget))
return NULL;
switch (i)
{
case 0:
@@ -741,8 +808,7 @@ gtk_entry_accessible_finalize (GObject *object)
static void
gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
class->ref_state_set = gtk_entry_accessible_ref_state_set;
@@ -752,8 +818,6 @@ gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass)
class->get_n_children = gtk_entry_accessible_get_n_children;
class->ref_child = gtk_entry_accessible_ref_child;
widget_class->notify_gtk = gtk_entry_accessible_notify_gtk;
gobject_class->finalize = gtk_entry_accessible_finalize;
}
@@ -763,23 +827,8 @@ gtk_entry_accessible_init (GtkEntryAccessible *entry)
entry->priv = gtk_entry_accessible_get_instance_private (entry);
entry->priv->cursor_position = 0;
entry->priv->selection_bound = 0;
}
static GtkText *
get_text (AtkText *atk_text)
{
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
if (widget == NULL)
return NULL;
if (GTK_IS_ENTRY (widget))
return gtk_entry_get_text_widget (GTK_ENTRY (widget));
else if (GTK_IS_SEARCH_ENTRY (widget))
return gtk_search_entry_get_text_widget (GTK_SEARCH_ENTRY (widget));
else
return NULL; // FIXME;
ATK_OBJECT (entry)->role = ATK_ROLE_TEXT;
}
static gchar *
@@ -1377,96 +1426,6 @@ atk_editable_text_interface_init (AtkEditableTextIface *iface)
iface->set_run_attributes = NULL;
}
static void
insert_text_cb (GtkEditable *editable,
gchar *new_text,
gint new_text_length,
gint *position)
{
GtkEntryAccessible *accessible;
gint length;
if (new_text_length == 0)
return;
accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
length = g_utf8_strlen (new_text, new_text_length);
g_signal_emit_by_name (accessible,
"text-changed::insert",
*position - length,
length);
}
/* We connect to GtkEditable::delete-text, since it carries
* the information we need. But we delay emitting our own
* text_changed::delete signal until the entry has update
* all its internal state and emits GtkEntry::changed.
*/
static void
delete_text_cb (GtkEditable *editable,
gint start,
gint end)
{
GtkEntryAccessible *accessible;
GtkText *textw;
accessible = GTK_ENTRY_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (editable)));
textw = get_text (ATK_TEXT (accessible));
if (textw == NULL)
return;
if (end < 0)
{
gchar *text;
text = gtk_text_get_display_text (textw, 0, -1);
end = g_utf8_strlen (text, -1);
g_free (text);
}
if (end == start)
return;
g_signal_emit_by_name (accessible,
"text-changed::delete",
start,
end - start);
}
static gboolean
check_for_selection_change (GtkEntryAccessible *accessible,
GtkEditable *editable)
{
gboolean ret_val = FALSE;
gint start, end;
if (gtk_editable_get_selection_bounds (editable, &start, &end))
{
if (end != accessible->priv->cursor_position ||
start != accessible->priv->selection_bound)
/*
* This check is here as this function can be called
* for notification of selection_bound and current_pos.
* The values of current_pos and selection_bound may be the same
* for both notifications and we only want to generate one
* text_selection_changed signal.
*/
ret_val = TRUE;
}
else
{
/* We had a selection */
ret_val = (accessible->priv->cursor_position != accessible->priv->selection_bound);
}
accessible->priv->cursor_position = end;
accessible->priv->selection_bound = start;
return ret_val;
}
static gboolean
gtk_entry_accessible_do_action (AtkAction *action,
gint i)

View File

@@ -17,9 +17,10 @@
#include "config.h"
#include "gtkexpanderaccessibleprivate.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "gtkexpanderaccessible.h"
static void atk_action_interface_init (AtkActionIface *iface);
@@ -91,41 +92,27 @@ gtk_expander_accessible_ref_child (AtkObject *obj,
return accessible;
}
static void
gtk_expander_accessible_initialize (AtkObject *obj,
gpointer data)
void
gtk_expander_accessible_update_label (GtkExpanderAccessible *self)
{
ATK_OBJECT_CLASS (gtk_expander_accessible_parent_class)->initialize (obj, data);
AtkObject *atk_obj = ATK_OBJECT (self);
obj->role = ATK_ROLE_TOGGLE_BUTTON;
if (atk_obj->name == NULL)
g_object_notify (G_OBJECT (atk_obj), "accessible-name");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
static void
gtk_expander_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
void
gtk_expander_accessible_update_state (GtkExpanderAccessible *self,
gboolean expanded)
{
AtkObject* atk_obj;
GtkExpander *expander;
AtkObject *atk_obj = ATK_OBJECT (self);
expander = GTK_EXPANDER (obj);
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (expander));
;
if (g_strcmp0 (pspec->name, "label") == 0)
{
if (atk_obj->name == NULL)
g_object_notify (G_OBJECT (atk_obj), "accessible-name");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
else if (g_strcmp0 (pspec->name, "expanded") == 0)
{
atk_object_notify_state_change (atk_obj, ATK_STATE_CHECKED,
gtk_expander_get_expanded (expander));
atk_object_notify_state_change (atk_obj, ATK_STATE_EXPANDED,
gtk_expander_get_expanded (expander));
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_expander_accessible_parent_class)->notify_gtk (obj, pspec);
atk_object_notify_state_change (atk_obj, ATK_STATE_CHECKED, expanded);
atk_object_notify_state_change (atk_obj, ATK_STATE_EXPANDED, expanded);
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
static AtkStateSet *
@@ -158,21 +145,17 @@ static void
gtk_expander_accessible_class_init (GtkExpanderAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
widget_class->notify_gtk = gtk_expander_accessible_notify_gtk;
class->get_name = gtk_expander_accessible_get_name;
class->get_n_children = gtk_expander_accessible_get_n_children;
class->ref_child = gtk_expander_accessible_ref_child;
class->ref_state_set = gtk_expander_accessible_ref_state_set;
class->initialize = gtk_expander_accessible_initialize;
}
static void
gtk_expander_accessible_init (GtkExpanderAccessible *expander)
gtk_expander_accessible_init (GtkExpanderAccessible *self)
{
ATK_OBJECT (self)->role = ATK_ROLE_TOGGLE_BUTTON;
}
static gboolean

View File

@@ -0,0 +1,31 @@
/* gtkexpanderaccessibleprivate.h: GtkExpanderAccessible private API
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#include "gtkexpanderaccessible.h"
G_BEGIN_DECLS
void gtk_expander_accessible_update_label (GtkExpanderAccessible *self);
void gtk_expander_accessible_update_state (GtkExpanderAccessible *self,
gboolean expanded);
G_END_DECLS

View File

@@ -32,11 +32,11 @@
#define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
#define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
struct _GtkIconViewAccessiblePrivate
typedef struct
{
GList *items;
GtkTreeModel *model;
};
} GtkIconViewAccessiblePrivate;
typedef struct
{
@@ -265,7 +265,8 @@ get_text (GtkIconView *icon_view,
_gtk_icon_view_set_cell_data (icon_view, item);
gtk_cell_area_foreach (icon_view->priv->cell_area,
(GtkCellCallback)get_text_foreach, &text);
(GtkCellCallback) get_text_foreach,
&text);
return text;
}
@@ -742,8 +743,9 @@ gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
static void
_gtk_icon_view_item_accessible_init (GtkIconViewItemAccessible *item)
{
item->state_set = atk_state_set_new ();
atk_object_set_role (ATK_OBJECT (item), ATK_ROLE_ICON);
item->state_set = atk_state_set_new ();
atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
@@ -860,25 +862,25 @@ G_DEFINE_TYPE_WITH_CODE (GtkIconViewAccessible, gtk_icon_view_accessible, GTK_TY
typedef struct
{
AtkObject *item;
gint index;
} GtkIconViewItemAccessibleInfo;
int index;
} ItemAccessibleInfo;
static void
gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
AtkObject *item,
gint index)
gtk_icon_view_item_accessible_info_new (GtkIconViewAccessible *self,
GtkIconViewItemAccessible *item,
int index)
{
GtkIconViewAccessible *view = (GtkIconViewAccessible *)accessible;
GtkIconViewItemAccessibleInfo *info;
GtkIconViewItemAccessibleInfo *tmp_info;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
ItemAccessibleInfo *info;
ItemAccessibleInfo *tmp_info;
GList *items;
info = g_new (GtkIconViewItemAccessibleInfo, 1);
info->item = item;
info = g_new (ItemAccessibleInfo, 1);
info->item = ATK_OBJECT (item);
info->index = index;
items = view->priv->items;
items = priv->items;
while (items)
{
tmp_info = items->data;
@@ -886,7 +888,8 @@ gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
break;
items = items->next;
}
view->priv->items = g_list_insert_before (view->priv->items, items, info);
priv->items = g_list_insert_before (priv->items, items, info);
}
static gint
@@ -904,22 +907,24 @@ gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
return g_list_length (icon_view->priv->items);
}
static AtkObject *
gtk_icon_view_accessible_find_child (AtkObject *accessible,
gint index)
static GtkIconViewItemAccessible *
gtk_icon_view_accessible_find_child (GtkIconViewAccessible *self,
gint index)
{
GtkIconViewAccessible *view = (GtkIconViewAccessible*)accessible;
GtkIconViewItemAccessibleInfo *info;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GList *items;
items = view->priv->items;
items = priv->items;
while (items)
{
info = items->data;
ItemAccessibleInfo *info = items->data;
GList *next = items->next;
if (info->index == index)
return info->item;
items = items->next;
return GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
items = next;
}
return NULL;
@@ -929,31 +934,28 @@ static AtkObject *
gtk_icon_view_accessible_ref_child (AtkObject *accessible,
gint index)
{
GtkIconViewAccessible *self = GTK_ICON_VIEW_ACCESSIBLE (accessible);
GtkIconViewItemAccessible *a11y_item;
GtkIconView *icon_view;
GtkWidget *widget;
GList *icons;
AtkObject *obj;
GtkIconViewItemAccessible *a11y_item;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
if (!widget)
if (widget == NULL)
return NULL;
icon_view = GTK_ICON_VIEW (widget);
icons = g_list_nth (icon_view->priv->items, index);
obj = NULL;
if (icons)
{
GtkIconViewItem *item = icons->data;
g_return_val_if_fail (item->index == index, NULL);
obj = gtk_icon_view_accessible_find_child (accessible, index);
if (!obj)
a11y_item = gtk_icon_view_accessible_find_child (self, index);
if (a11y_item == NULL)
{
obj = g_object_new (GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, NULL);
gtk_icon_view_item_accessible_info_new (accessible, obj, index);
obj->role = ATK_ROLE_ICON;
a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
a11y_item = g_object_new (GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, NULL);
a11y_item->item = item;
a11y_item->widget = widget;
@@ -962,60 +964,62 @@ gtk_icon_view_accessible_ref_child (AtkObject *accessible,
gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
gtk_icon_view_item_accessible_info_new (self, a11y_item, index);
}
g_object_ref (obj);
g_object_ref (a11y_item);
return ATK_OBJECT (a11y_item);
}
else
{
return NULL;
}
return obj;
}
static void
gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *self,
GList *list)
{
GtkIconViewItemAccessibleInfo *info;
GtkIconViewItemAccessible *item;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GtkWidget *widget;
gboolean act_on_item;
GList *items;
if (view->priv->items)
if (priv->items == NULL)
return;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self));
if (widget == NULL)
return;
items = priv->items;
act_on_item = (list == NULL);
while (items)
{
GtkWidget *widget;
gboolean act_on_item;
ItemAccessibleInfo *info = items->data;
GtkIconViewItemAccessible *item;
GList *next = items->next;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
if (widget == NULL)
return;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
items = view->priv->items;
if (act_on_item == FALSE && list == items)
act_on_item = TRUE;
act_on_item = (list == NULL);
if (act_on_item)
gtk_icon_view_item_accessible_set_visibility (item, TRUE);
while (items)
{
info = (GtkIconViewItemAccessibleInfo *)items->data;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
if (act_on_item == FALSE && list == items)
act_on_item = TRUE;
if (act_on_item)
gtk_icon_view_item_accessible_set_visibility (item, TRUE);
items = items->next;
}
items = next;
}
}
void
_gtk_icon_view_accessible_adjustment_changed (GtkIconView *icon_view)
gtk_icon_view_accessible_adjustment_changed (GtkIconViewAccessible *self)
{
GtkIconViewAccessible *view;
view = GTK_ICON_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (icon_view)));
if (view == NULL)
return;
gtk_icon_view_accessible_traverse_items (view, NULL);
gtk_icon_view_accessible_traverse_items (self, NULL);
}
static void
@@ -1024,36 +1028,26 @@ gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer user_data)
{
AtkObject *atk_obj;
gint index;
GtkWidget *widget;
GtkIconView *icon_view;
GtkIconViewItem *item;
GtkIconViewAccessible *self = user_data;
GtkIconViewItemAccessible *a11y_item;
const gchar *name;
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
index = gtk_tree_path_get_indices(path)[0];
a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
gtk_icon_view_accessible_find_child (atk_obj, index));
int index;
index = gtk_tree_path_get_indices (path)[0];
a11y_item = gtk_icon_view_accessible_find_child (self, index);
if (a11y_item)
{
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
icon_view = GTK_ICON_VIEW (widget);
item = a11y_item->item;
GtkIconViewItem *item = a11y_item->item;
GtkIconView *icon_view = GTK_ICON_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (self)));
name = atk_object_get_name (ATK_OBJECT (a11y_item));
if (!name || strcmp (name, "") == 0)
const char *name = atk_object_get_name (ATK_OBJECT (a11y_item));
if (name == NULL || *name == '\0')
{
g_free (a11y_item->text);
a11y_item->text = get_text (icon_view, item);
}
}
g_signal_emit_by_name (atk_obj, "visible-data-changed");
return;
g_signal_emit_by_name (self, "visible-data-changed");
}
static void
@@ -1062,24 +1056,22 @@ gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer user_data)
{
GtkIconViewItemAccessibleInfo *info;
GtkIconViewAccessible *view;
GtkIconViewItemAccessible *item;
GtkIconViewAccessible *self = user_data;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GList *items;
GList *tmp_list;
AtkObject *atk_obj;
gint index;
int index;
index = gtk_tree_path_get_indices(path)[0];
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
index = gtk_tree_path_get_indices (path)[0];
items = view->priv->items;
items = priv->items;
tmp_list = NULL;
while (items)
{
info = items->data;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
ItemAccessibleInfo *info = items->data;
GtkIconViewItemAccessible *item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
GList *next = items->next;
if (info->index != item->item->index)
{
if (info->index < index)
@@ -1091,40 +1083,36 @@ gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
info->index = item->item->index;
}
items = items->next;
items = next;
}
gtk_icon_view_accessible_traverse_items (view, tmp_list);
g_signal_emit_by_name (atk_obj, "children-changed::add",
gtk_icon_view_accessible_traverse_items (self, tmp_list);
g_signal_emit_by_name (self,
"children-changed::add",
index, NULL, NULL);
return;
}
static void
gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
GtkTreePath *path,
gpointer user_data)
gpointer user_data)
{
GtkIconViewItemAccessibleInfo *info;
GtkIconViewAccessible *view;
GtkIconViewItemAccessible *item;
GtkIconViewAccessible *self = user_data;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GList *items;
GList *tmp_list;
GList *deleted_item;
AtkObject *atk_obj;
gint index;
GList *tmp_list = NULL;
GList *deleted_item = NULL;
int index;
index = gtk_tree_path_get_indices(path)[0];
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
index = gtk_tree_path_get_indices (path)[0];
items = view->priv->items;
tmp_list = NULL;
deleted_item = NULL;
info = NULL;
items = priv->items;
while (items)
{
info = items->data;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
ItemAccessibleInfo *info = items->data;
GtkIconViewItemAccessible *item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
GList *next = items->next;
if (info->index == index)
{
deleted_item = items;
@@ -1137,26 +1125,32 @@ gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
info->index = item->item->index;
}
items = items->next;
items = next;
}
if (deleted_item)
{
info = deleted_item->data;
gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
g_signal_emit_by_name (atk_obj, "children-changed::remove",
ItemAccessibleInfo *info = deleted_item->data;
gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item),
ATK_STATE_DEFUNCT,
TRUE);
g_signal_emit_by_name (self,
"children-changed::remove",
index, NULL, NULL);
view->priv->items = g_list_delete_link (view->priv->items, deleted_item);
priv->items = g_list_delete_link (priv->items, deleted_item);
g_object_unref (info->item);
g_free (info);
}
gtk_icon_view_accessible_traverse_items (view, tmp_list);
return;
gtk_icon_view_accessible_traverse_items (self, tmp_list);
}
static gint
gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
GtkIconViewItemAccessibleInfo *i2)
gtk_icon_view_accessible_item_compare (ItemAccessibleInfo *i1,
ItemAccessibleInfo *i2)
{
return i1->index - i2->index;
}
@@ -1166,151 +1160,138 @@ gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter,
gint *new_order,
gpointer user_data)
gpointer user_data)
{
GtkIconViewAccessible *view;
GtkIconViewItemAccessibleInfo *info;
GtkIconViewAccessible *self = user_data;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GtkIconView *icon_view;
GtkIconViewItemAccessible *item;
GList *items;
AtkObject *atk_obj;
gint *order;
gint length, i;
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
icon_view = GTK_ICON_VIEW (user_data);
view = (GtkIconViewAccessible*)atk_obj;
int *order;
int length, i;
icon_view = GTK_ICON_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (self)));
length = gtk_tree_model_iter_n_children (tree_model, NULL);
order = g_new (gint, length);
order = g_new (int, length);
for (i = 0; i < length; i++)
order [new_order[i]] = i;
items = view->priv->items;
items = priv->items;
while (items)
{
info = items->data;
item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
ItemAccessibleInfo *info = items->data;
GtkIconViewItemAccessible *item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
GList *next = items->next;
info->index = order[info->index];
item->item = g_list_nth_data (icon_view->priv->items, info->index);
items = items->next;
items = next;
}
g_free (order);
view->priv->items = g_list_sort (view->priv->items,
(GCompareFunc)gtk_icon_view_accessible_item_compare);
return;
priv->items = g_list_sort (priv->items, (GCompareFunc) gtk_icon_view_accessible_item_compare);
}
static void
gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
GtkWidget *widget)
gtk_icon_view_accessible_disconnect_model_signals (GtkIconViewAccessible *self)
{
GObject *obj;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
obj = G_OBJECT (model);
g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
g_signal_handlers_disconnect_by_func (priv->model, gtk_icon_view_accessible_model_row_changed, self);
g_signal_handlers_disconnect_by_func (priv->model, gtk_icon_view_accessible_model_row_inserted, self);
g_signal_handlers_disconnect_by_func (priv->model, gtk_icon_view_accessible_model_row_deleted, self);
g_signal_handlers_disconnect_by_func (priv->model, gtk_icon_view_accessible_model_rows_reordered, self);
}
static void
gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
gtk_icon_view_accessible_connect_model_signals (GtkIconViewAccessible *self)
{
GObject *obj;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
obj = G_OBJECT (icon_view->priv->model);
g_signal_connect_object (obj, "row-changed",
g_signal_connect_object (priv->model, "row-changed",
G_CALLBACK (gtk_icon_view_accessible_model_row_changed),
icon_view, 0);
g_signal_connect_object (obj, "row-inserted",
self, 0);
g_signal_connect_object (priv->model, "row-inserted",
G_CALLBACK (gtk_icon_view_accessible_model_row_inserted),
icon_view, G_CONNECT_AFTER);
g_signal_connect_object (obj, "row-deleted",
self, G_CONNECT_AFTER);
g_signal_connect_object (priv->model, "row-deleted",
G_CALLBACK (gtk_icon_view_accessible_model_row_deleted),
icon_view, G_CONNECT_AFTER);
g_signal_connect_object (obj, "rows-reordered",
self, G_CONNECT_AFTER);
g_signal_connect_object (priv->model, "rows-reordered",
G_CALLBACK (gtk_icon_view_accessible_model_rows_reordered),
icon_view, G_CONNECT_AFTER);
self, G_CONNECT_AFTER);
}
static void
gtk_icon_view_accessible_clear_cache (GtkIconViewAccessible *view)
gtk_icon_view_accessible_clear_cache (GtkIconViewAccessible *self)
{
GtkIconViewItemAccessibleInfo *info;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GList *items;
items = view->priv->items;
while (items)
if (priv->items == NULL)
return;
items = priv->items;
while (items != NULL)
{
info = (GtkIconViewItemAccessibleInfo *) items->data;
gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
ItemAccessibleInfo *info = items->data;
GList *next = items->next;
gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item),
ATK_STATE_DEFUNCT,
TRUE);
g_object_unref (info->item);
g_free (items->data);
items = items->next;
g_free (info);
items = next;
}
g_list_free (view->priv->items);
view->priv->items = NULL;
g_clear_pointer (&priv->items, g_list_free);
}
static void
gtk_icon_view_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
void
gtk_icon_view_accessible_update_model (GtkIconViewAccessible *self,
GtkTreeModel *model)
{
GtkIconView *icon_view;
GtkWidget *widget;
AtkObject *atk_obj;
GtkIconViewAccessible *view;
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
if (strcmp (pspec->name, "model") == 0)
if (priv->model != NULL)
{
widget = GTK_WIDGET (obj);
atk_obj = gtk_widget_get_accessible (widget);
view = (GtkIconViewAccessible*)atk_obj;
if (view->priv->model)
{
g_object_remove_weak_pointer (G_OBJECT (view->priv->model),
(gpointer *)&view->priv->model);
gtk_icon_view_accessible_disconnect_model_signals (view->priv->model, widget);
}
gtk_icon_view_accessible_clear_cache (view);
icon_view = GTK_ICON_VIEW (obj);
view->priv->model = icon_view->priv->model;
/* If there is no model the GtkIconView is probably being destroyed */
if (view->priv->model)
{
g_object_add_weak_pointer (G_OBJECT (view->priv->model), (gpointer *)&view->priv->model);
gtk_icon_view_accessible_connect_model_signals (icon_view);
}
g_object_remove_weak_pointer (G_OBJECT (priv->model),
(gpointer *) &priv->model);
gtk_icon_view_accessible_disconnect_model_signals (self);
}
return;
gtk_icon_view_accessible_clear_cache (self);
priv->model = model;
/* If there is no model the GtkIconView is probably being destroyed */
if (priv->model != NULL)
{
g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *) &priv->model);
gtk_icon_view_accessible_connect_model_signals (self);
}
}
static void
gtk_icon_view_accessible_initialize (AtkObject *accessible,
gpointer data)
{
GtkIconViewAccessible *view;
GtkIconView *icon_view;
GtkIconViewAccessible *self = GTK_ICON_VIEW_ACCESSIBLE (accessible);
GtkIconViewAccessiblePrivate *priv = gtk_icon_view_accessible_get_instance_private (self);
GtkIconView *icon_view = data;
if (ATK_OBJECT_CLASS (gtk_icon_view_accessible_parent_class)->initialize)
ATK_OBJECT_CLASS (gtk_icon_view_accessible_parent_class)->initialize (accessible, data);
icon_view = (GtkIconView*)data;
view = (GtkIconViewAccessible*)accessible;
g_signal_connect (data, "notify",
G_CALLBACK (gtk_icon_view_accessible_notify_gtk), NULL);
view->priv->model = icon_view->priv->model;
if (view->priv->model)
priv->model = icon_view->priv->model;
if (priv->model)
{
g_object_add_weak_pointer (G_OBJECT (view->priv->model), (gpointer *)&view->priv->model);
gtk_icon_view_accessible_connect_model_signals (icon_view);
g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *) &priv->model);
gtk_icon_view_accessible_connect_model_signals (self);
}
accessible->role = ATK_ROLE_LAYERED_PANE;
@@ -1319,7 +1300,7 @@ gtk_icon_view_accessible_initialize (AtkObject *accessible,
static void
gtk_icon_view_accessible_finalize (GObject *object)
{
GtkIconViewAccessible *view = (GtkIconViewAccessible*)object;
GtkIconViewAccessible *view = GTK_ICON_VIEW_ACCESSIBLE (object);
gtk_icon_view_accessible_clear_cache (view);
@@ -1329,11 +1310,8 @@ gtk_icon_view_accessible_finalize (GObject *object)
static void
gtk_icon_view_accessible_class_init (GtkIconViewAccessibleClass *klass)
{
GObjectClass *gobject_class;
AtkObjectClass *atk_class;
gobject_class = (GObjectClass *)klass;
atk_class = (AtkObjectClass *)klass;
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
gobject_class->finalize = gtk_icon_view_accessible_finalize;
@@ -1345,7 +1323,6 @@ gtk_icon_view_accessible_class_init (GtkIconViewAccessibleClass *klass)
static void
gtk_icon_view_accessible_init (GtkIconViewAccessible *accessible)
{
accessible->priv = gtk_icon_view_accessible_get_instance_private (accessible);
}
static AtkObject*

View File

@@ -35,13 +35,10 @@ G_BEGIN_DECLS
typedef struct _GtkIconViewAccessible GtkIconViewAccessible;
typedef struct _GtkIconViewAccessibleClass GtkIconViewAccessibleClass;
typedef struct _GtkIconViewAccessiblePrivate GtkIconViewAccessiblePrivate;
struct _GtkIconViewAccessible
{
GtkWidgetAccessible parent;
GtkIconViewAccessiblePrivate *priv;
};
struct _GtkIconViewAccessibleClass

View File

@@ -19,12 +19,14 @@
#define __GTK_ICON_VIEW_ACCESSIBLE_PRIVATE_H__
#include <gtk/a11y/gtkiconviewaccessible.h>
#include <gtk/gtkiconview.h>
G_BEGIN_DECLS
void _gtk_icon_view_accessible_adjustment_changed (GtkIconView *icon_view);
void gtk_icon_view_accessible_adjustment_changed (GtkIconViewAccessible *self);
void gtk_icon_view_accessible_update_model (GtkIconViewAccessible *self,
GtkTreeModel *model);
G_END_DECLS

View File

@@ -18,10 +18,11 @@
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "gtklevelbaraccessible.h"
#include "gtklevelbar.h"
#include <string.h>
static void atk_value_interface_init (AtkValueIface *iface);
@@ -29,45 +30,36 @@ G_DEFINE_TYPE_WITH_CODE (GtkLevelBarAccessible, gtk_level_bar_accessible, GTK_TY
G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init))
static void
gtk_level_bar_accessible_initialize (AtkObject *obj,
gpointer data)
on_value_changed (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
ATK_OBJECT_CLASS (gtk_level_bar_accessible_parent_class)->initialize (obj, data);
GtkLevelBarAccessible *self = user_data;
obj->role = ATK_ROLE_LEVEL_BAR;
g_object_notify (G_OBJECT (self), "accessible-value");
}
static void
gtk_level_bar_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
gtk_level_bar_accessible_initialize (AtkObject *object,
gpointer data)
{
GtkWidget *widget = GTK_WIDGET (obj);
GtkLevelBarAccessible *level_bar = GTK_LEVEL_BAR_ACCESSIBLE (gtk_widget_get_accessible (widget));
GtkLevelBar *level_bar = data;
if (strcmp (pspec->name, "value") == 0)
{
g_object_notify (G_OBJECT (level_bar), "accessible-value");
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_level_bar_accessible_parent_class)->notify_gtk (obj, pspec);
g_signal_connect (level_bar, "notify::value", G_CALLBACK (on_value_changed), object);
}
static void
gtk_level_bar_accessible_class_init (GtkLevelBarAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
AtkObjectClass *object_class = ATK_OBJECT_CLASS (klass);
widget_class->notify_gtk = gtk_level_bar_accessible_notify_gtk;
class->initialize = gtk_level_bar_accessible_initialize;
object_class->initialize = gtk_level_bar_accessible_initialize;
}
static void
gtk_level_bar_accessible_init (GtkLevelBarAccessible *button)
gtk_level_bar_accessible_init (GtkLevelBarAccessible *self)
{
ATK_OBJECT (self)->role = ATK_ROLE_LEVEL_BAR;
}
static void

View File

@@ -17,10 +17,12 @@
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "gtknotebookaccessible.h"
#include "gtknotebookaccessibleprivate.h"
#include "gtknotebookpageaccessible.h"
#include "gtknotebook.h"
#include <string.h>
struct _GtkNotebookAccessiblePrivate
{
@@ -153,55 +155,41 @@ gtk_notebook_accessible_ref_child (AtkObject *obj,
return child;
}
static void
gtk_notebook_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
void
gtk_notebook_accessible_update_page (GtkNotebookAccessible *self,
int page_num)
{
GtkWidget *widget;
AtkObject* atk_obj;
GtkNotebookAccessiblePrivate *priv = gtk_notebook_accessible_get_instance_private (self);
AtkObject *atk_obj = ATK_OBJECT (self);
int old_page_num = priv->selected_page;
widget = GTK_WIDGET (obj);
atk_obj = gtk_widget_get_accessible (widget);
priv->selected_page = page_num;
if (strcmp (pspec->name, "page") == 0)
/* Notify SELECTED state change for old and new page */
if (page_num != old_page_num)
{
gint page_num, old_page_num;
GtkNotebookAccessible *accessible;
GtkNotebook *notebook;
AtkObject *child;
accessible = GTK_NOTEBOOK_ACCESSIBLE (atk_obj);
notebook = GTK_NOTEBOOK (widget);
/* Notify SELECTED state change for old and new page */
old_page_num = accessible->priv->selected_page;
page_num = gtk_notebook_get_current_page (notebook);
accessible->priv->selected_page = page_num;
if (page_num != old_page_num)
if (old_page_num != -1)
{
AtkObject *child;
if (old_page_num != -1)
child = gtk_notebook_accessible_ref_child (atk_obj, old_page_num);
if (child != NULL)
{
child = gtk_notebook_accessible_ref_child (atk_obj, old_page_num);
if (child)
{
atk_object_notify_state_change (child, ATK_STATE_SELECTED, FALSE);
g_object_unref (child);
}
}
child = gtk_notebook_accessible_ref_child (atk_obj, page_num);
if (child)
{
atk_object_notify_state_change (child, ATK_STATE_SELECTED, TRUE);
atk_object_notify_state_change (child, ATK_STATE_SELECTED, FALSE);
g_object_unref (child);
}
g_signal_emit_by_name (atk_obj, "selection-changed");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
child = gtk_notebook_accessible_ref_child (atk_obj, page_num);
if (child != NULL)
{
atk_object_notify_state_change (child, ATK_STATE_SELECTED, TRUE);
g_object_unref (child);
}
g_signal_emit_by_name (atk_obj, "selection-changed");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_notebook_accessible_parent_class)->notify_gtk (obj, pspec);
}
/*
@@ -230,14 +218,11 @@ gtk_notebook_accessible_class_init (GtkNotebookAccessibleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
gobject_class->finalize = gtk_notebook_accessible_finalize;
class->ref_child = gtk_notebook_accessible_ref_child;
class->initialize = gtk_notebook_accessible_initialize;
widget_class->notify_gtk = gtk_notebook_accessible_notify_gtk;
}
static void

View File

@@ -0,0 +1,30 @@
/* gtknotebookaccessibleprivate.h: GtkNotebookAccessible private API
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#include "gtknotebookaccessible.h"
G_BEGIN_DECLS
void gtk_notebook_accessible_update_page (GtkNotebookAccessible *self,
int page_num);
G_END_DECLS

View File

@@ -0,0 +1,654 @@
/* gtkpasswordentryaccessible.c: A GtkWidgetAccessible for GtkPasswordEntry
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#include "config.h"
#include "gtkpasswordentryaccessibleprivate.h"
#include "gtkeditable.h"
#include "gtkimage.h"
#include "gtkintl.h"
#include "gtklabel.h"
#include "gtkpango.h"
#include "gtkpasswordentryprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtktextprivate.h"
struct _GtkPasswordEntryAccessible
{
GtkWidgetAccessible parent_instance;
int cursor_position;
int selection_bound;
};
static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
static void atk_text_interface_init (AtkTextIface *iface);
static void atk_action_interface_init (AtkActionIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkPasswordEntryAccessible, gtk_password_entry_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
static inline GtkText *
get_text_widget (GtkAccessible *accessible)
{
GtkWidget *widget = gtk_accessible_get_widget (accessible);
if (widget == NULL)
return NULL;
GtkPasswordEntry *entry = GTK_PASSWORD_ENTRY (widget);
return gtk_password_entry_get_text_widget (entry);
}
static gunichar
gtk_password_entry_accessible_get_character_at_offset (AtkText *atk_text,
gint offset)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
char *contents, *index;
gunichar result;
result = '\0';
text = get_text_widget (GTK_ACCESSIBLE (atk_text));
if (text == NULL)
return 0;
if (!gtk_text_get_visibility (text))
return result;
contents = gtk_text_get_display_text (text, 0, -1);
if (offset < g_utf8_strlen (contents, -1))
{
index = g_utf8_offset_to_pointer (contents, offset);
result = g_utf8_get_char (index);
g_free (contents);
}
return result;
}
static gint
gtk_password_entry_accessible_get_caret_offset (AtkText *atk_text)
{
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
if (widget == NULL)
return -1;
int cursor_position = 0;
gboolean result = gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), NULL, &cursor_position);
if (!result)
return -1;
return cursor_position;
}
static gboolean
gtk_password_entry_accessible_set_caret_offset (AtkText *atk_text,
gint offset)
{
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
if (widget == NULL)
return FALSE;
gtk_editable_set_position (GTK_EDITABLE (widget), offset);
return TRUE;
}
static gint
gtk_password_entry_accessible_get_character_count (AtkText *atk_text)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
if (text == NULL)
return 0;
char *display_text = gtk_text_get_display_text (text, 0, -1);
int char_count = 0;
if (display_text)
{
char_count = g_utf8_strlen (display_text, -1);
g_free (display_text);
}
return char_count;
}
static gint
gtk_password_entry_accessible_get_offset_at_point (AtkText *atk_text,
gint x,
gint y,
AtkCoordType coords)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
int index, x_layout, y_layout;
int x_local, y_local;
glong offset;
if (text == NULL)
return 1;
gtk_text_get_layout_offsets (text, &x_layout, &y_layout);
x_local = x - x_layout;
y_local = y - y_layout;
if (!pango_layout_xy_to_index (gtk_text_get_layout (text),
x_local * PANGO_SCALE,
y_local * PANGO_SCALE,
&index, NULL))
{
if (x_local < 0 || y_local < 0)
index = 0;
else
index = -1;
}
offset = -1;
if (index != -1)
{
char *entry_text = gtk_text_get_display_text (text, 0, -1);
offset = g_utf8_pointer_to_offset (entry_text, entry_text + index);
g_free (entry_text);
}
return offset;
}
static void
atk_text_interface_init (AtkTextIface *iface)
{
iface->get_character_at_offset = gtk_password_entry_accessible_get_character_at_offset;
iface->get_caret_offset = gtk_password_entry_accessible_get_caret_offset;
iface->set_caret_offset = gtk_password_entry_accessible_set_caret_offset;
iface->get_character_count = gtk_password_entry_accessible_get_character_count;
iface->get_offset_at_point = gtk_password_entry_accessible_get_offset_at_point;
}
static void
gtk_password_entry_accessible_set_text_contents (AtkEditableText *text,
const gchar *string)
{
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
if (widget == NULL)
return;
if (!gtk_editable_get_editable (GTK_EDITABLE (widget)))
return;
gtk_editable_set_text (GTK_EDITABLE (widget), string);
}
static void
gtk_password_entry_accessible_insert_text (AtkEditableText *text,
const gchar *string,
gint length,
gint *position)
{
GtkWidget *widget;
GtkEditable *editable;
int pos = 0;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
if (widget == NULL)
return;
editable = GTK_EDITABLE (widget);
if (!gtk_editable_get_editable (editable))
return;
if (position != NULL)
pos = *position;
gtk_editable_insert_text (editable, string, length, &pos);
gtk_editable_set_position (editable, pos);
if (position != NULL)
*position = pos;
}
static void
gtk_password_entry_accessible_delete_text (AtkEditableText *text,
gint start_pos,
gint end_pos)
{
GtkWidget *widget;
GtkEditable *editable;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
if (widget == NULL)
return;
editable = GTK_EDITABLE (widget);
if (!gtk_editable_get_editable (editable))
return;
gtk_editable_delete_text (editable, start_pos, end_pos);
}
typedef struct
{
GtkEditable *entry;
int position;
} PasteData;
static void
paste_received_cb (GObject *clipboard,
GAsyncResult *result,
gpointer data)
{
PasteData *paste = data;
char *text;
text = gdk_clipboard_read_text_finish (GDK_CLIPBOARD (clipboard), result, NULL);
if (text != NULL)
gtk_editable_insert_text (paste->entry,
text, -1,
&(paste->position));
g_object_unref (paste->entry);
g_free (paste);
g_free (text);
}
static void
gtk_password_entry_accessible_paste_text (AtkEditableText *text,
gint position)
{
GtkWidget *widget;
GtkEditable *editable;
PasteData *paste;
GdkClipboard *clipboard;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
if (widget == NULL)
return;
editable = GTK_EDITABLE (widget);
if (!gtk_editable_get_editable (editable))
return;
paste = g_new0 (PasteData, 1);
paste->entry = GTK_EDITABLE (widget);
paste->position = position;
g_object_ref (paste->entry);
clipboard = gtk_widget_get_clipboard (widget);
gdk_clipboard_read_text_async (clipboard, NULL, paste_received_cb, paste);
}
static void
atk_editable_text_interface_init (AtkEditableTextIface *iface)
{
iface->set_text_contents = gtk_password_entry_accessible_set_text_contents;
iface->insert_text = gtk_password_entry_accessible_insert_text;
iface->copy_text = NULL;
iface->cut_text = NULL;
iface->delete_text = gtk_password_entry_accessible_delete_text;
iface->paste_text = gtk_password_entry_accessible_paste_text;
iface->set_run_attributes = NULL;
}
static gboolean
gtk_password_entry_accessible_do_action (AtkAction *action,
gint i)
{
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
if (widget == NULL)
return FALSE;
if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
return FALSE;
if (i == 0)
{
gtk_widget_activate (widget);
return TRUE;
}
if (i == 1)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (action));
gboolean visibility = gtk_text_get_visibility (text);
gtk_text_set_visibility (text, !visibility);
return TRUE;
}
return FALSE;
}
static gint
gtk_password_entry_accessible_get_n_actions (AtkAction *action)
{
GtkAccessible *accessible = GTK_ACCESSIBLE (action);
GtkWidget *widget = gtk_accessible_get_widget (accessible);
if (widget == NULL)
return 0;
int n_actions = 1;
if (gtk_password_entry_get_show_peek_icon (GTK_PASSWORD_ENTRY (widget)))
n_actions += 1;
return n_actions;
}
static const gchar *
gtk_password_entry_accessible_get_keybinding (AtkAction *action,
gint i)
{
GtkWidget *widget;
GtkWidget *label;
AtkRelationSet *set;
AtkRelation *relation;
GPtrArray *target;
gpointer target_object;
guint key_val;
if (i != 0)
return NULL;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
if (widget == NULL)
return NULL;
set = atk_object_ref_relation_set (ATK_OBJECT (action));
if (!set)
return NULL;
label = NULL;
relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
if (relation)
{
target = atk_relation_get_target (relation);
target_object = g_ptr_array_index (target, 0);
label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
}
g_object_unref (set);
if (GTK_IS_LABEL (label))
{
key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
if (key_val != GDK_KEY_VoidSymbol)
return gtk_accelerator_name (key_val, GDK_ALT_MASK);
}
return NULL;
}
static const gchar *
gtk_password_entry_accessible_action_get_name (AtkAction *action,
gint i)
{
switch (i)
{
case 0:
return "activate";
case 1:
return "peek";
default:
break;
}
return NULL;
}
static const gchar*
gtk_password_entry_accessible_action_get_localized_name (AtkAction *action,
gint i)
{
if (i == 0)
return C_("Action name", "Activate");
if (i == 1)
return C_("Action name", "Peek");
return NULL;
}
static const gchar *
gtk_password_entry_accessible_action_get_description (AtkAction *action,
gint i)
{
if (i == 0)
return C_("Action description", "Activates the entry");
if (i == 1)
return C_("Action description", "Reveals the contents the entry");
return NULL;
}
static void
atk_action_interface_init (AtkActionIface *iface)
{
iface->do_action = gtk_password_entry_accessible_do_action;
iface->get_n_actions = gtk_password_entry_accessible_get_n_actions;
iface->get_keybinding = gtk_password_entry_accessible_get_keybinding;
iface->get_name = gtk_password_entry_accessible_action_get_name;
iface->get_localized_name = gtk_password_entry_accessible_action_get_localized_name;
iface->get_description = gtk_password_entry_accessible_action_get_description;
}
static AtkAttributeSet *
gtk_password_entry_accessible_get_attributes (AtkObject *accessible)
{
GtkWidget *widget;
AtkAttributeSet *attributes;
AtkAttribute *placeholder_text;
char *text = NULL;
attributes = ATK_OBJECT_CLASS (gtk_password_entry_accessible_parent_class)->get_attributes (accessible);
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
if (widget == NULL)
return attributes;
g_object_get (widget, "placeholder-text", &text, NULL);
if (text == NULL)
return attributes;
placeholder_text = g_malloc (sizeof (AtkAttribute));
placeholder_text->name = g_strdup ("placeholder-text");
placeholder_text->value = text;
attributes = g_slist_append (attributes, placeholder_text);
return attributes;
}
static gboolean
check_for_selection_change (GtkPasswordEntryAccessible *self,
GtkEditable *editable)
{
gboolean ret_val = FALSE;
gint start, end;
if (gtk_editable_get_selection_bounds (editable, &start, &end))
{
if (end != self->cursor_position ||
start != self->selection_bound)
/*
* This check is here as this function can be called
* for notification of selection_bound and current_pos.
* The values of current_pos and selection_bound may be the same
* for both notifications and we only want to generate one
* text_selection_changed signal.
*/
ret_val = TRUE;
}
else
{
/* We had a selection */
ret_val = (self->cursor_position != self->selection_bound);
}
self->cursor_position = end;
self->selection_bound = start;
return ret_val;
}
static void
on_cursor_position_changed (GObject *gobject,
GParamSpec *pspec,
gpointer data)
{
GtkPasswordEntryAccessible *self = data;
GtkEditable *editable = GTK_EDITABLE (gobject);
if (check_for_selection_change (self, editable))
g_signal_emit_by_name (self, "text-selection-changed");
// The entry cursor position has moved so generate the signal
g_signal_emit_by_name (self, "text-caret-moved",
gtk_editable_get_position (editable));
}
static void
on_selection_bound_changed (GObject *gobject,
GParamSpec *pspec,
gpointer data)
{
GtkPasswordEntryAccessible *self = data;
GtkEditable *editable = GTK_EDITABLE (gobject);
if (check_for_selection_change (self, editable))
g_signal_emit_by_name (self, "text-selection-changed");
}
static void
insert_text_cb (GtkEditable *editable,
gchar *new_text,
gint new_text_length,
gint *position,
GtkPasswordEntryAccessible *self)
{
int length;
if (new_text_length == 0)
return;
length = g_utf8_strlen (new_text, new_text_length);
g_signal_emit_by_name (self,
"text-changed::insert",
*position - length,
length);
}
static void
delete_text_cb (GtkEditable *editable,
gint start,
gint end,
GtkPasswordEntryAccessible *self)
{
GtkText *text;
text = get_text_widget (GTK_ACCESSIBLE (self));
if (text == NULL)
return;
if (end < 0)
{
char *contents;
contents = gtk_text_get_display_text (text, 0, -1);
end = g_utf8_strlen (contents, -1);
g_free (contents);
}
if (end == start)
return;
g_signal_emit_by_name (self,
"text-changed::delete",
start,
end - start);
}
static void
gtk_password_entry_accessible_initialize (AtkObject *atk_object,
gpointer data)
{
GtkPasswordEntryAccessible *self = GTK_PASSWORD_ENTRY_ACCESSIBLE (atk_object);
GtkEditable *editable = data;
GtkWidget *widget = data;
int start_pos, end_pos;
gtk_editable_get_selection_bounds (editable, &start_pos, &end_pos);
self->cursor_position = end_pos;
self->selection_bound = start_pos;
/* Set up signal callbacks */
g_signal_connect_after (widget, "insert-text", G_CALLBACK (insert_text_cb), self);
g_signal_connect (widget, "delete-text", G_CALLBACK (delete_text_cb), self);
g_signal_connect (widget, "notify::cursor-position",
G_CALLBACK (on_cursor_position_changed), self);
g_signal_connect (widget, "notify::selection-bound",
G_CALLBACK (on_selection_bound_changed), self);
}
static void
gtk_password_entry_accessible_class_init (GtkPasswordEntryAccessibleClass *klass)
{
AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
atk_object_class->initialize = gtk_password_entry_accessible_initialize;
atk_object_class->get_attributes = gtk_password_entry_accessible_get_attributes;
}
static void
gtk_password_entry_accessible_init (GtkPasswordEntryAccessible *self)
{
AtkObject *atk_obj = ATK_OBJECT (self);
atk_obj->role = ATK_ROLE_PASSWORD_TEXT;
atk_object_set_name (atk_obj, _("Password"));
}
void
gtk_password_entry_accessible_update_visibility (GtkPasswordEntryAccessible *self)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (self));
if (text == NULL)
return;
gboolean visibility = gtk_text_get_visibility (text);
AtkRole role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
atk_object_set_role (ATK_OBJECT (self), role);
}

View File

@@ -0,0 +1,48 @@
/* gtkpasswordentryaccessible.h: A GtkWidgetAccessible for GtkPasswordEntry
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#if !defined (__GTK_A11Y_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk-a11y.h> can be included directly."
#endif
#include <gtk/a11y/gtkentryaccessible.h>
G_BEGIN_DECLS
#define GTK_TYPE_PASSWORD_ENTRY_ACCESSIBLE (gtk_password_entry_accessible_get_type())
#define GTK_PASSWORD_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PASSWORD_ENTRY_ACCESSIBLE, GtkPasswordEntryAccessible))
#define GTK_IS_PASSWORD_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PASSWORD_ENTRY_ACCESSIBLE))
typedef struct _GtkPasswordEntryAccessible GtkPasswordEntryAccessible;
typedef struct _GtkPasswordEntryAccessibleClass GtkPasswordEntryAccessibleClass;
struct _GtkPasswordEntryAccessibleClass
{
GtkWidgetAccessibleClass parent_class;
};
GDK_AVAILABLE_IN_ALL
GType gtk_password_entry_accessible_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkPasswordEntryAccessible, g_object_unref)
G_END_DECLS

View File

@@ -0,0 +1,29 @@
/* gtkpasswordentryaccessibleprivate.h: Private API for GtkPasswordEntryAccessible
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#include "gtkpasswordentryaccessible.h"
G_BEGIN_DECLS
void gtk_password_entry_accessible_update_visibility (GtkPasswordEntryAccessible *self);
G_END_DECLS

View File

@@ -21,52 +21,28 @@
#include <gtk/gtk.h>
#include "gtkprogressbaraccessible.h"
#include "gtkprogressbaraccessibleprivate.h"
static void atk_value_interface_init (AtkValueIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkProgressBarAccessible, gtk_progress_bar_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init))
static void
gtk_progress_bar_accessible_initialize (AtkObject *obj,
gpointer data)
void
gtk_progress_bar_accessible_update_value (GtkProgressBarAccessible *self)
{
ATK_OBJECT_CLASS (gtk_progress_bar_accessible_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_PROGRESS_BAR;
}
static void
gtk_progress_bar_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject *accessible;
accessible = gtk_widget_get_accessible (widget);
if (strcmp (pspec->name, "fraction") == 0)
g_object_notify (G_OBJECT (accessible), "accessible-value");
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_progress_bar_accessible_parent_class)->notify_gtk (obj, pspec);
g_object_notify (G_OBJECT (self), "accessible-value");
}
static void
gtk_progress_bar_accessible_class_init (GtkProgressBarAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
widget_class->notify_gtk = gtk_progress_bar_accessible_notify_gtk;
class->initialize = gtk_progress_bar_accessible_initialize;
}
static void
gtk_progress_bar_accessible_init (GtkProgressBarAccessible *bar)
gtk_progress_bar_accessible_init (GtkProgressBarAccessible *self)
{
ATK_OBJECT (self)->role = ATK_ROLE_PROGRESS_BAR;
}
static void

View File

@@ -1,10 +1,13 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Red Hat, Inc.
/* gtkprogressbaraccessibleprivate.h: Private GtkProgressBarAccessible API
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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.
* 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
@@ -12,18 +15,15 @@
* 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/>.
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_ORIENTABLE_PRIVATE_H__
#define __GTK_ORIENTABLE_PRIVATE_H__
#pragma once
#include "gtkorientable.h"
#include "gtkprogressbaraccessible.h"
G_BEGIN_DECLS
void _gtk_orientable_set_style_classes (GtkOrientable *orientable);
void gtk_progress_bar_accessible_update_value (GtkProgressBarAccessible *self);
G_END_DECLS
#endif /* __GTK_ORIENTABLE_H__ */

View File

@@ -21,10 +21,12 @@
#include <gtk/gtk.h>
#include "gtkrangeaccessible.h"
struct _GtkRangeAccessiblePrivate
typedef struct
{
GtkAdjustment *adjustment;
};
gulong value_changed_id;
} GtkRangeAccessiblePrivate;
static void atk_value_interface_init (AtkValueIface *iface);
@@ -42,35 +44,44 @@ gtk_range_accessible_value_changed (GtkAdjustment *adjustment,
static void
gtk_range_accessible_widget_set (GtkAccessible *accessible)
{
GtkRangeAccessiblePrivate *priv = GTK_RANGE_ACCESSIBLE (accessible)->priv;
GtkRangeAccessible *self = GTK_RANGE_ACCESSIBLE (accessible);
GtkRangeAccessiblePrivate *priv = gtk_range_accessible_get_instance_private (self);
GtkWidget *range;
GtkAdjustment *adj;
range = gtk_accessible_get_widget (accessible);
adj = gtk_range_get_adjustment (GTK_RANGE (range));
if (adj)
if (adj != NULL)
{
priv->adjustment = adj;
g_object_ref (priv->adjustment);
g_signal_connect (priv->adjustment, "value-changed",
G_CALLBACK (gtk_range_accessible_value_changed),
accessible);
priv->adjustment = g_object_ref (adj);
priv->value_changed_id =
g_signal_connect (priv->adjustment, "value-changed",
G_CALLBACK (gtk_range_accessible_value_changed),
self);
}
}
static void
gtk_range_accessible_widget_unset (GtkAccessible *accessible)
{
GtkRangeAccessiblePrivate *priv = GTK_RANGE_ACCESSIBLE (accessible)->priv;
GtkRangeAccessible *self = GTK_RANGE_ACCESSIBLE (accessible);
GtkRangeAccessiblePrivate *priv = gtk_range_accessible_get_instance_private (self);
if (priv->adjustment)
if (priv->adjustment != NULL &&
priv->value_changed_id != 0)
{
g_signal_handlers_disconnect_by_func (priv->adjustment,
G_CALLBACK (gtk_range_accessible_value_changed),
accessible);
g_object_unref (priv->adjustment);
priv->adjustment = NULL;
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
g_clear_object (&priv->adjustment);
}
void
gtk_range_accessible_update_adjustment (GtkRangeAccessible *self)
{
gtk_range_accessible_widget_unset (GTK_ACCESSIBLE (self));
gtk_range_accessible_widget_set (GTK_ACCESSIBLE (self));
}
static void
@@ -82,42 +93,40 @@ gtk_range_accessible_initialize (AtkObject *obj,
}
static void
gtk_range_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
gtk_range_accessible_dispose (GObject *gobject)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject *range;
GtkRangeAccessible *self = GTK_RANGE_ACCESSIBLE (gobject);
GtkRangeAccessiblePrivate *priv = gtk_range_accessible_get_instance_private (self);
if (strcmp (pspec->name, "adjustment") == 0)
if (priv->adjustment != NULL && priv->value_changed_id != 0)
{
range = gtk_widget_get_accessible (widget);
gtk_range_accessible_widget_unset (GTK_ACCESSIBLE (range));
gtk_range_accessible_widget_set (GTK_ACCESSIBLE (range));
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_range_accessible_parent_class)->notify_gtk (obj, pspec);
}
g_clear_object (&priv->adjustment);
G_OBJECT_CLASS (gtk_range_accessible_parent_class)->dispose (gobject);
}
static void
gtk_range_accessible_class_init (GtkRangeAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
AtkObjectClass *atkobject_class = ATK_OBJECT_CLASS (klass);
GtkAccessibleClass *accessible_class = (GtkAccessibleClass*)klass;
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
class->initialize = gtk_range_accessible_initialize;
gobject_class->dispose = gtk_range_accessible_dispose;
atkobject_class->initialize = gtk_range_accessible_initialize;
accessible_class->widget_set = gtk_range_accessible_widget_set;
accessible_class->widget_unset = gtk_range_accessible_widget_unset;
widget_class->notify_gtk = gtk_range_accessible_notify_gtk;
}
static void
gtk_range_accessible_init (GtkRangeAccessible *range)
{
range->priv = gtk_range_accessible_get_instance_private (range);
}
static void

View File

@@ -35,13 +35,10 @@ G_BEGIN_DECLS
typedef struct _GtkRangeAccessible GtkRangeAccessible;
typedef struct _GtkRangeAccessibleClass GtkRangeAccessibleClass;
typedef struct _GtkRangeAccessiblePrivate GtkRangeAccessiblePrivate;
struct _GtkRangeAccessible
{
GtkWidgetAccessible parent;
GtkRangeAccessiblePrivate *priv;
};
struct _GtkRangeAccessibleClass
@@ -52,6 +49,9 @@ struct _GtkRangeAccessibleClass
GDK_AVAILABLE_IN_ALL
GType gtk_range_accessible_get_type (void);
/*< private >*/
void gtk_range_accessible_update_adjustment (GtkRangeAccessible *self);
G_END_DECLS
#endif /* __GTK_RANGE_ACCESSIBLE_H__ */

View File

@@ -23,79 +23,107 @@
#include <string.h>
typedef struct {
GtkAdjustment *adjustment;
gulong value_changed_id;
} GtkScaleButtonAccessiblePrivate;
static void atk_action_interface_init (AtkActionIface *iface);
static void atk_value_interface_init (AtkValueIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkScaleButtonAccessible, gtk_scale_button_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
G_ADD_PRIVATE (GtkScaleButtonAccessible)
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init));
static void
gtk_scale_button_accessible_value_changed (GtkAdjustment *adjustment,
gpointer data)
on_value_changed (GtkAdjustment *adjustment,
gpointer data)
{
g_object_notify (G_OBJECT (data), "accessible-value");
GtkScaleButtonAccessible *self = data;
g_object_notify (G_OBJECT (self), "accessible-value");
}
static void
on_adjustment_changed (GObject *gobject,
GParamSpec *pspec,
gpointer data)
{
GtkScaleButton *scale_button = GTK_SCALE_BUTTON (gobject);
GtkScaleButtonAccessible *self = data;
GtkScaleButtonAccessiblePrivate *priv =
gtk_scale_button_accessible_get_instance_private (self);
GtkAdjustment *adjustment =
gtk_scale_button_get_adjustment (scale_button);
if (priv->adjustment == adjustment)
return;
if (priv->adjustment != NULL && priv->value_changed_id != 0)
{
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
g_clear_object (&priv->adjustment);
if (adjustment != NULL)
{
priv->adjustment = g_object_ref (adjustment);
priv->value_changed_id =
g_signal_connect (priv->adjustment, "notify::value-changed",
G_CALLBACK (on_value_changed),
self);
}
}
static void
gtk_scale_button_accessible_initialize (AtkObject *obj,
gpointer data)
{
GtkAdjustment *adjustment;
GtkScaleButton *scale_button = data;
ATK_OBJECT_CLASS (gtk_scale_button_accessible_parent_class)->initialize (obj, data);
adjustment = gtk_scale_button_get_adjustment (GTK_SCALE_BUTTON (data));
if (adjustment)
g_signal_connect (adjustment,
"value-changed",
G_CALLBACK (gtk_scale_button_accessible_value_changed),
obj);
obj->role = ATK_ROLE_SLIDER;
g_signal_connect (scale_button, "notify::adjustment",
G_CALLBACK (on_adjustment_changed),
obj);
}
static void
gtk_scale_button_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
gtk_scale_button_accessible_dispose (GObject *gobject)
{
GtkScaleButton *scale_button;
GtkScaleButtonAccessible *accessible;
GtkScaleButtonAccessible *self = GTK_SCALE_BUTTON_ACCESSIBLE (gobject);
GtkScaleButtonAccessiblePrivate *priv =
gtk_scale_button_accessible_get_instance_private (self);
scale_button = GTK_SCALE_BUTTON (obj);
accessible = GTK_SCALE_BUTTON_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (scale_button)));
if (strcmp (pspec->name, "adjustment") == 0)
if (priv->adjustment != NULL && priv->value_changed_id != 0)
{
GtkAdjustment* adjustment;
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
adjustment = gtk_scale_button_get_adjustment (scale_button);
g_signal_connect (adjustment,
"value-changed",
G_CALLBACK (gtk_scale_button_accessible_value_changed),
accessible);
}
else
{
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_scale_button_accessible_parent_class)->notify_gtk (obj, pspec);
}
g_clear_object (&priv->adjustment);
G_OBJECT_CLASS (gtk_scale_button_accessible_parent_class)->dispose (gobject);
}
static void
gtk_scale_button_accessible_class_init (GtkScaleButtonAccessibleClass *klass)
{
AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
GtkWidgetAccessibleClass *widget_class = GTK_WIDGET_ACCESSIBLE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gtk_scale_button_accessible_dispose;
atk_object_class->initialize = gtk_scale_button_accessible_initialize;
widget_class->notify_gtk = gtk_scale_button_accessible_notify_gtk;
}
static void
gtk_scale_button_accessible_init (GtkScaleButtonAccessible *button)
gtk_scale_button_accessible_init (GtkScaleButtonAccessible *self)
{
ATK_OBJECT (self)->role = ATK_ROLE_SLIDER;
}
static gboolean

View File

@@ -35,13 +35,10 @@ G_BEGIN_DECLS
typedef struct _GtkScaleButtonAccessible GtkScaleButtonAccessible;
typedef struct _GtkScaleButtonAccessibleClass GtkScaleButtonAccessibleClass;
typedef struct _GtkScaleButtonAccessiblePrivate GtkScaleButtonAccessiblePrivate;
struct _GtkScaleButtonAccessible
{
GtkWidgetAccessible parent;
GtkScaleButtonAccessiblePrivate *priv;
};
struct _GtkScaleButtonAccessibleClass

View File

@@ -21,10 +21,11 @@
#include <gtk/gtk.h>
#include "gtkscrollbaraccessible.h"
struct _GtkScrollbarAccessiblePrivate
typedef struct
{
GtkAdjustment *adjustment;
};
gulong value_changed_id;
} GtkScrollbarAccessiblePrivate;
static void atk_value_interface_init (AtkValueIface *iface);
@@ -33,91 +34,93 @@ G_DEFINE_TYPE_WITH_CODE (GtkScrollbarAccessible, gtk_scrollbar_accessible, GTK_T
G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init))
static void
gtk_scrollbar_accessible_value_changed (GtkAdjustment *adjustment,
gpointer data)
on_value_changed (GtkAdjustment *adjustment,
gpointer data)
{
g_object_notify (G_OBJECT (data), "accessible-value");
GtkScrollbarAccessible *self = data;
g_object_notify (G_OBJECT (self), "accessible-value");
}
static void
gtk_scrollbar_accessible_widget_set (GtkAccessible *accessible)
on_adjustment_changed (GObject *gobject,
GParamSpec *pspec,
gpointer data)
{
GtkScrollbarAccessiblePrivate *priv = GTK_SCROLLBAR_ACCESSIBLE (accessible)->priv;
GtkWidget *scrollbar;
GtkAdjustment *adj;
GtkScrollbar *scrollbar = GTK_SCROLLBAR (gobject);
GtkScrollbarAccessible *self = data;
GtkScrollbarAccessiblePrivate *priv =
gtk_scrollbar_accessible_get_instance_private (self);
GtkAdjustment *adjustment =
gtk_scrollbar_get_adjustment (scrollbar);
scrollbar = gtk_accessible_get_widget (accessible);
adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (scrollbar));
if (adj)
if (priv->adjustment == adjustment)
return;
if (priv->adjustment != NULL && priv->value_changed_id != 0)
{
priv->adjustment = adj;
g_object_ref (priv->adjustment);
g_signal_connect (priv->adjustment, "value-changed",
G_CALLBACK (gtk_scrollbar_accessible_value_changed),
accessible);
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
g_clear_object (&priv->adjustment);
if (adjustment != NULL)
{
priv->adjustment = g_object_ref (adjustment);
priv->value_changed_id =
g_signal_connect (priv->adjustment, "value-changed",
G_CALLBACK (on_value_changed),
self);
}
}
static void
gtk_scrollbar_accessible_widget_unset (GtkAccessible *accessible)
gtk_scrollbar_accessible_dispose (GObject *gobject)
{
GtkScrollbarAccessiblePrivate *priv = GTK_SCROLLBAR_ACCESSIBLE (accessible)->priv;
GtkScrollbarAccessible *self = GTK_SCROLLBAR_ACCESSIBLE (gobject);
GtkScrollbarAccessiblePrivate *priv =
gtk_scrollbar_accessible_get_instance_private (self);
if (priv->adjustment)
if (priv->adjustment != NULL && priv->value_changed_id != 0)
{
g_signal_handlers_disconnect_by_func (priv->adjustment,
G_CALLBACK (gtk_scrollbar_accessible_value_changed),
accessible);
g_object_unref (priv->adjustment);
priv->adjustment = NULL;
g_signal_handler_disconnect (priv->adjustment, priv->value_changed_id);
priv->value_changed_id = 0;
}
g_clear_object (&priv->adjustment);
G_OBJECT_CLASS (gtk_scrollbar_accessible_parent_class)->dispose (gobject);
}
static void
gtk_scrollbar_accessible_initialize (AtkObject *obj,
gpointer data)
{
GtkScrollbar *scrollbar = data;
ATK_OBJECT_CLASS (gtk_scrollbar_accessible_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_SCROLL_BAR;
g_signal_connect (scrollbar, "notify::adjustment",
G_CALLBACK (on_adjustment_changed),
obj);
}
static void
gtk_scrollbar_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject *scrollbar;
if (strcmp (pspec->name, "adjustment") == 0)
{
scrollbar = gtk_widget_get_accessible (widget);
gtk_scrollbar_accessible_widget_unset (GTK_ACCESSIBLE (scrollbar));
gtk_scrollbar_accessible_widget_set (GTK_ACCESSIBLE (scrollbar));
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_scrollbar_accessible_parent_class)->notify_gtk (obj, pspec);
}
static void
gtk_scrollbar_accessible_class_init (GtkScrollbarAccessibleClass *klass)
{
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
GtkAccessibleClass *accessible_class = (GtkAccessibleClass*)klass;
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
class->initialize = gtk_scrollbar_accessible_initialize;
atk_object_class->initialize = gtk_scrollbar_accessible_initialize;
accessible_class->widget_set = gtk_scrollbar_accessible_widget_set;
accessible_class->widget_unset = gtk_scrollbar_accessible_widget_unset;
widget_class->notify_gtk = gtk_scrollbar_accessible_notify_gtk;
gobject_class->dispose = gtk_scrollbar_accessible_dispose;
}
static void
gtk_scrollbar_accessible_init (GtkScrollbarAccessible *scrollbar)
gtk_scrollbar_accessible_init (GtkScrollbarAccessible *self)
{
scrollbar->priv = gtk_scrollbar_accessible_get_instance_private (scrollbar);
ATK_OBJECT (self)->role = ATK_ROLE_SCROLL_BAR;
}
static void

View File

@@ -35,13 +35,10 @@ G_BEGIN_DECLS
typedef struct _GtkScrollbarAccessible GtkScrollbarAccessible;
typedef struct _GtkScrollbarAccessibleClass GtkScrollbarAccessibleClass;
typedef struct _GtkScrollbarAccessiblePrivate GtkScrollbarAccessiblePrivate;
struct _GtkScrollbarAccessible
{
GtkWidgetAccessible parent;
GtkScrollbarAccessiblePrivate *priv;
};
struct _GtkScrollbarAccessibleClass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
/* gtksearchentryaccessible.h: A GtkWidgetAccessible for GtkSearchEntry
*
* Copyright 2020 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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/>.
*/
#pragma once
#if !defined (__GTK_A11Y_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk-a11y.h> can be included directly."
#endif
#include <gtk/a11y/gtkentryaccessible.h>
G_BEGIN_DECLS
#define GTK_TYPE_SEARCH_ENTRY_ACCESSIBLE (gtk_search_entry_accessible_get_type())
#define GTK_SEARCH_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEARCH_ENTRY_ACCESSIBLE, GtkSearchEntryAccessible))
#define GTK_IS_SEARCH_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEARCH_ENTRY_ACCESSIBLE))
typedef struct _GtkSearchEntryAccessible GtkSearchEntryAccessible;
typedef struct _GtkSearchEntryAccessibleClass GtkSearchEntryAccessibleClass;
struct _GtkSearchEntryAccessibleClass
{
GtkWidgetAccessibleClass parent_class;
};
GDK_AVAILABLE_IN_ALL
GType gtk_search_entry_accessible_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkSearchEntryAccessible, g_object_unref)
G_END_DECLS

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