Escape XML tags in gi-docgen oriented comment e.g. from <child> to
`<child>`, so that they don't become HTML tag on the final webpage.
This fix includes everything from commit ff46ea64 and #5312.
Fixes#5312
If the drag events are claimed by another gesture (e.g. a GtkDragSource
in an item widget), list base still commits a rubberband selection, for
a rubberband which wasn't even visible yet. This is a problem for the
GNOME Files application which needs both rubberbanding and drag-n-drop.
My previous fix[0] was enough for the case where the event sequence is
claimed right before the first GtkDragGesture::drag-update emission,
but it's useless if the event is claimed later (e.g. after the drag
treashold), because a rubberband already exists by that time.
Therefore, the complete solution requres checking whether the event
sequence is no longer being handled by our gesture, and commit the
selection changes only if it is, but otherwise cleanup the rubberband.
This is what GtkFlowBox does already, so let's do the same here.
[0] commit dc4540fae9
The EventControllerFocus on the list item, updates the list base focus
tracker and scrolled to position any time the list item enters focus.
This works when interacting within a single window, but has unexpected
results when changing focus between multiple windows.
Instead of using the focus controller workaround, just make
gtk_list_base_update_focus_tracker the set_focus_child vfunc
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5433
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5432
The container view itself being focusable makes keyboard navigation
slower by adding a useless focus step.
It also means if an item gets removed, the focus jumps back to the view,
instead of jumping to the next item, as seen in nautilus bug report:
https://gitlab.gnome.org/GNOME/nautilus/-/issues/2489
Instead of making the GtkListBase container itself focusable, override
the .grab_focus() vfunc. This way, calling gtk_widget_grab_focus() on
the view container keeps working sucessfully, but focuses the focus
item directly instead.
This is particularly useful to have because applicaiton authors do
not have direct acess to this class's children, so they can't call
gtk_widget_grab_focus() on them directly.
Use set_child_visible(FALSE) on those widgets and don't allocate them.
This should usually be the majority of items, so it's quite a worthwhile
addition.
Idea by Ivan Molodetskikh.
Related: #3334
GtkGestrureDrag::drag-end can be emitted when the pointer has just
crossed the drag threshold and we have not started the rubberband yet.
This happens if another gesture has claimed the event sequence earlier
in the current event propagation chain.
In such situation, our ::drag-end calls gtk_list_base_drag_update(),
which proceeds to start the rubberband. That's obviously wrong.
Additionally, it also tries to get modifiers from an event it we are
already denied, which obviously fails with criticals:
`gdk_event_get_modifier_state: assertion 'GDK_IS_EVENT (event)' failed`
Thus, if there is no rubberband when we receive ::drag-end, do nothing.
Those property features don't seem to be in use anywhere.
They are redundant since the docs cover the same information
and more. They also created unnecessary translation work.
Closes#4904
If multiple nested widgets have drag sources on them, both using bubble
phase, we need to reliably pick the inner one. Both of them will try to
start dragging, and we need to make sure there are no situations where the
outer widget starts drag earlier and cancels the inner one.
Currently, this can easily happen via integer rounding: start and current
coordinates passed into gtk_drag_check_threshold() are initially doubles
(other than in GtkNotebook and GtkIconView), and are casted to ints. Then
those rounded values are used to calculate deltas to compare to the drag
threshold, losing quite a lot of precision along the way, and often
resulting in the outer widget getting larger deltas.
To avoid it, just don't round it. Introduce a variant of the function that
operates on doubles: gtk_drag_check_threshold_double() and use it instead
of the original everywhere.
Change the apis in GtkListView, GtkColumnView and
GtkGridView to be explicitly about GtkSelectionModel,
to make it obvious that the widgets handle selection.
Update all users.
... and do the right things:
nothing: selection = rubberband
ctrl: selection = selection OR rubberband
shift: selection = selection AND (NOT rubberband)
ctrl+shift: selection = selection XOR rubberband
(not sure this one makes sense, but toggling is fun)
Instead of storing the active items as we go, compute the affected items
whenever the rubberband changes and in particular when the rubberband
ends.
That way, the rubberband is guaranteed to select a rectangle even
after scrolling very far.
This is achieved by having a get_items_in_rect() vfunc that selects all
the items in the rubberbanded rectangle and returns them as a bitset.
The rubberband is now handled on the list coordinate system.
When starting the rubberband, we track the item under the pointer and
follow it when it is moving.
This may lead to the rubberband start position changing position and
while this may be confusing, it alerts users to the fact that something
crazy is going on.
Break out an update_autoscroll() function that can
be used for other things than rubberbanding. It will
be used for autoscroll during DND in the future.
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.
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.
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.
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.