Instead of one item keeping the item + its position and sorting that
list, keep the items in 1 array and put the positions into a 2nd array.
This is generally slower while sorting, but allows multiple improvements:
1. We can replace items with keys
This allows avoiding multiple slow lookups when using complex
comparisons
2. We can keep multiple position arrays
This allows doing a sorting in the background without actually
emitting items-changed() until the array is completely sorted.
3. The main list tracks the items in the original model
So only a single memmove() is necessary there, while the old version
had to upgrade the position in every item.
Benchmarks:
sorting a model of simple strings
old new
256,000 items 256ms 268ms
512,000 items 569ms 638ms
sorting a model of file trees, directories first, by size
old new
64,000 items 350ms 364ms
128,000 items 667ms 691ms
removing half the model
old new
512,000 items 24ms 15ms
1,024,000 items 49ms 25ms
This was preventing any sort of building on macOS, even though the quartz
backend is currently non-functional. Fixing this is a pre-requisite to
getting a new macOS backend compiling.
This is a scary idea where you #define a bunch of preprocessor values
and then #include "gdkarrayimpl.c" and end up with a dynamic array for
that data type.
See https://en.wikipedia.org/wiki/X_Macro for what's going on.
What are the advantages over using GArray or GPtrArray?
* It's typesafe
Because it works like C++ templates, we can use the actual type of
the object instead of having to use gpointer.
* It's one less indirection
instead of 2 indirections via self->array->data, this array is
embedded, so self->array is the actual data, and just one indirection
away. This is pretty irrelevant in general, but can be very noticable
in tight loops.
* It's all inline
Because the whole API is defined as static inline functions, the
compiler has full access to everything and can (and does) optimize
out unnecessary calls, thereby speeding up some operations quite
significantly, when full optimizations are enabled.
* It has more features
In particular preallocation allows for avoiding malloc() calls, which
can again speed up tight loops a lot.
But there's also splice(), which is very useful when used with
listmodels.
Instead of an array of arrays, let's use an array of dictionaries; it's
easier to add optional keys without requiring to remember where to put
empty arrays.
char ** arrays are null-terminated everywhere, so make sure they are in
splice(), too.
Also fix the argument to be a const char * const * like in the
constructor.
Simplify all view model APIs and always return G_TYPE_OBJECT as the
item-type for every model.
It turns out nobody uses item-type anyway.
So instead of adding lots of APIs, forcing people to think about it and
trying to figure out how to handle filter or map models that modify item
types, just having an easy life is a better approach.
All the models need to be able to deal with any type of object going
through anyway.
Verify that the selection filter changes mirror
the selection changes of the underlying model,
as expected. These tests verify the fixes in
the previous commit.
One of the widget-factory focus tests is flaky in ci,
perhaps due to font changes causing size computations
to go slightly differently.
Drop this for now.
Always keep the order:
- [value]
- [marks.top]
- [marks.bottom]
- trough
Which makes sense given the rendering order. Slider should be drawn
after the marks.
Makes it possible to simply remove the custom snapshot implementations
in scale and range. And Adwaita does not depend on the node order
anyway.
In particular, track which items remain in ::items-changed
signal emissions.
But the main use case is sorting, which causes items-changed(0, n, n)
to be emitted.
In 99.9% of all cases, these are just NULL, NULL.
So just do away with these arguments, people can
use the setters for the rare cases where they want
the scrolled window to use a different adjustment.
This is a list model holding strings, initialized
from a char **. String lists are buildable as well,
and that replaces the buildable support in GktDropDowns.
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.
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
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.
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.
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.
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.
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.
This is a somewhat large commit that:
- Adds GtkColumnViewSorter
This is a special-purpose, private sorter implementation which sorts
according to multiple sorters, allowing each individual sorter to be
inverted. This will be used with clickable column view headers.
- Adds a read-only GtkColumnView::sorter property
The GtkColumnView creates a GtkColumnViewSorter at startup that it uses
for this property.
- Adds a writable GtkColumnViewColumn::sorter property
This allows defining per-column sorters. Whenever an application sets a
sorter for a column, the header becomes clickable and whenever
a header is clicked, that column's sorter is prepended to the list of
sorters, unless it is already the first sorter, in which case we invert
its order. No column can be in the list more than once.
Actually inhibit snapshotting of frames from reftest_inhibit_snapshot.
We were not ignoring the case where inhibit_count > 0, and then disconnected
the callback meaning we only ever got the first snapshot.
When displaying accelerators, differentiate keypad
symbols with a 'KP' prefix. Fixing a 17 year old bug.
Update expected output in accelerator tests.
Fixes: #227
If we don't destroy the surface, it leaks.
GDK backends keep an extra reference on the
surface for the external resources associated
with it, and only drop it in destroy().
Add test setups that set the GDK_BACKEND and
TEST_OUTPUT_SUBDIR environment variables.
This lets use run
meson test --setup x11 --suite reftest
meson test --setup wayland --suite reftest
and the output will be nicely separated.
We still need to do compositor / display server
setup from the outside.
meson seems somewhat weak when it comes to handling
test output. We need to get the output from different
test runs into different locations, and the only
way to communicate from a test setup with the actual
test code seems the environment, so use that.
Make all tests that produce output in files respect
a TEST_OUTPUT_SUBDIR environment variable which specifies
the name of a subdirectory to use. This is combined
with the existing --output argument, which specifies
a per-test location.
Affected tests are reftests, css performance tests
and gsk compare tests.
If you run weston with the headless backend, you get a Wayland
display with no seat, which is just fine by the protocol.
gdk_display_get_default_seat() returns NULL in this case. Various
widgets assume that we always have a seat with a keyboard and a
pointer, since that is what X guarantees. Make things survive
without that, so we can run the testsuite under a headless
Wayland compositor.
If the inner clip intersects with the corners of the outer clip, we
potentially need a texture. We should add more fine-grained checks for
this in the future though.
Test case included.
When moving from gtk_container_forall to the widget dom
api, we are now iterating over all children of the listbox,
including headers, separators, etc. So, skip everything
that is not a listboxrow, to make the tests work again.
This test was relying on gtk_container_forall returning
the visual (ie sorted) order of children, while iterating
with the widget dom api gives the insertion order.
Instead of using gtk_container_forall, use
gtk_list_box_row_get_index to reconstruct the visual
order.
This commit is porting GtkPaned to be derived
from GtkWidget instead of GtkContainer, while adding
start-child and end-child properties. The existing
properties are renamed to follow the start/end naming
scheme, and we add proper getters and setters.
Update all users.
See #2719
One of the treeview tests was calling gtk_widget_destroy
on a child instead of the toplevel, which leaks the toplevel
unnecessarily. Plus, we're moving towards allowing destroy
only on toplevels.
Add template tests that show the complex dialogs before
destroying them. This reveals that we are leaking in
several of them. These leaks don't show up if the
dialogs are destroyed right away, as the existing
tests do.
Disable the two failing tests for now:
/template/GtkFileChooserDialog/show
/template/GtkPrintUnixDialog/show
It turns out that we have a ref leak at the very
core of our dom model :( gtk_widget_insert_before/after
leak a reference if the widget was already under
the same parent. This is something that GtkBox
frequently does. It shows up e.g. when packing
widgets at the end in a headerbar.
This was testing something that shouldn't be possible
anyway: Adding more than one child to a bin. With the
bin removal, this now just overrides the child so
only one child is left in the end.
Just remove the test.
Use window title, or custom title widget if it's set. Remove 'title'
property.
Update demos and tests to set the title on the window instead of
headerbar.
Despite the name, the test was not in fact showing
contents on map anymore, since widgets are visible
by default. Setting visible to FALSE makes the test
work as expected again.
We are comparing a transparent label to a transparent
text view, so need to make sure the caret does not show
up in the text view to ruin the comparison.
GdkEvent has been a "I-can't-believe-this-is-not-OOP" type for ages,
using a union of sub-types. This has always been problematic when it
comes to implementing accessor functions: either you get generic API
that takes a GdkEvent and uses a massive switch() to determine which
event types have the data you're looking for; or you create namespaced
accessors, but break language bindings horribly, as boxed types cannot
have derived types.
The recent conversion of GskRenderNode (which had similar issues) to
GTypeInstance, and the fact that GdkEvent is now a completely opaque
type, provide us with the chance of moving GdkEvent to GTypeInstance,
and have sub-types for GdkEvent.
The change from boxed type to GTypeInstance is pretty small, all things
considered, but ends up cascading to a larger commit, as we still have
backends and code in GTK trying to access GdkEvent structures directly.
Additionally, the naming of the public getter functions requires
renaming all the data structures to conform to the namespace/type-name
pattern.
In the hope of making ci-only failures less of a black hole,
add a backtrace to the messsage for criticals.
This could eventually go into GLib (pass backtrace symbols along
as a log field for criticals), but for now this will do.
Make GtkScaleButton a widget that has a toggle button
as a child, just like all the other button widgets now.
The immediate benefit of this arrangement is to avoid
the "double focus" problem when we pop up the popup.
Update accessible, demos and tests to match.
The color editor shows a color picker button only if it
finds a suitable implementation, which it does not in ci.
So disable the focus-chain test for page 3.
This test was expecting to make existing widgets like
GtkBox focusable by setting :can-focus. That just doesn't
work anymore.
The focus chain testing that is done here is already
better covered by test-focus-chain, so lets just remove this.
The notebook grab_focus change in the previous commit made
backwards tabbing work as expected, and thereby changed the
output of one of the focus-chain tests.
Reviewing the existing settings, the only backend with
some differences in the modifier intent settings is OS X,
and we would rather have that implemented by interpreting
the existing modifiers in the appropriate way.
X11 Wayland Win32 OS X
primary ctrl ctrl ctrl mod2
mnemonic alt alt alt alt
context menu - - - ctrl
extend sel shift shift shift shift
modify sel ctrl ctrl ctrl mod2
no text alt|ctrl alt|ctrl alt|ctrl mod2|ctrl
shift group varies - - alt
GTK now uses the following modifiers:
primary ctrl
mnemonic alt
extend sel shift
modify sel ctrl
no text alt|ctrl
The context menu and shift group intents were not used
in GTK at all.
Update tests to no longer expect <Primary> to roundtrip
through the accelerator parsing and formatting code.
Add all of the keyboard translation results in the key event,
so we can translate the keyboard state at the time the event
is created, and avoid doing state translation at match time.
We actually need to carry two sets of translation results,
since we ignore CapsLock when matching accelerators, in
gdk_event_matches().
At the same time, drop the scancode field - it is only ever
set on win32, and is basically unused in GTK.
Update all callers.
The colorbutton contains a button which contains a colorswatch.
We want the focus to go straight to the button, nowhere else,
so mark the swatch as !can-focus.
Adapt tests to match.