In order to properly accumulate scroll velocities, we need to keep
the kinetic scroll helpers after we have possibly stopped them
in the process of initiating a further scroll flick.
So, instead of stopping (and destroying) those helpers on scroll-begin,
keep them until the next scroll-end if a scroll was initiated before
kinetic scroll finished. This way we can fetch the last velocity when
calculating the extra kick.
In order to ensure the helpers don't live beyond what it is expected,
we now also remove them after a finished hold event.
Fixes the accumulation of scrolling velocity on consecutive scroll
sequences.
Do not depend on the kinetic scroll helpers existing or not before
exiting the animation, as we may want to keep those a little bit
longer after stopped.
On the "scroll" signal, the widget uses
gtk_event_controller_scroll_get_unit() to get the
scroll unit.
When the unit is GDK_SCROLL_UNIT_WHEEL, the
behavior is unchanged: the widget scrolls a
certain number of pixels at each wheel detent
click. This number of pixels is determined by the
window dimensions in get_wheel_detent_scroll_step().
When the delta unit is GDK_SCROLL_UNIT_SURFACE, the
widget directly adds the delta to the number of
scrolled pixels no matter the window dimensions.
This may come from different sources at around the same time, e.g.
a hold gesture while on overshoot. Avoid doing that if an
animation is already set.
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/4730
Previously we had issues on macos where the overshoot would keep showing.
To fix this we need to actually use discrete events instead of the
generated deltas from macOS in the scroll wheel case. Additionally, we need
to drop the kinetic momentum events from macOS and rely on the gtk kinetic
events which are already happening anyway. We also need to submit the
is_stop event for the GDK_SCROLL_SMOOTH case when we detect it.
To keep the discrete scroll events correct, we need to alter the hack in
gtkscrolledwindow.c to use the same path as other platforms except for
when a smooth scroll event is in place. In the future, I would imagine that
this falls into the boundary of high-precision scrolling and would share
the same code paths as other platforms.
With all of these in place, kinetic scrolling with overshoot appears the
same on macOS as other platforms.
We used to override cursor to use all-scroll while the
content is being scrolled. Unfortunately, there is several
problems with this:
- It is really only expected certain devices, and we don't
have the device information on Wayland
- With the way cursor setting works in GTK4, non-NULL cursors
of the content (eg the text views ibeam) win, making the
scroll cursor not show up
- Under X11, we seem to miss scroll end events and then
the scroll cursor gets stuck
Therefore, just remove this feature.
If we scroll down in a list that's still being filled, we hit the edge and
initiate overshoot, and then the adjustment's upper value increases. This
leads to an unwanted bounce back.
Additionally, if in a similar situation the upper value decreases, the
overscroll glow gets stuck.
Update kinetic scrolling upper and lower value on changes, and immediately
cancel it if dimensions on that side change.
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3752
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.
In order to do this, leverage smooth scroll handling into the capture
phase scroll controller, controlled by ::scroll-begin in the propagation
phase controller.
There's 2 cases here:
- A child widget handles scroll. The scrolled window does not get
::scroll-begin, the child widget handles the full scroll sequence.
- No child handles scroll, the scrolled window gets ::scroll-begin,
and transfers control of scrolling to the capture phase controller.
As scrolling is performed, the pointer may fall into scrollable children,
but the scrolled window will be capturing the scroll events, so these
won't be seen by the child widgets.
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/593
Using GList is a bit lame, and makes the API more complicated to use
than necessary in the common case.
The only real use case for a GList is gtk_widget_add_mnemonic_label(),
and for that we can use the GValue-based API instead.
Fixes: #3343
For the various uses of GDK_WINDOWING_QUARTZ, we need to use
alternatives from GDK_WINDOWING_MACOS.
Some minor loss of functionality is here, such as icons sent with
application menus. That can certainly be added back at a future
point.
Claiming early makes the contents unable to react to the touch press
event. Do this on GtkGestureDrag::update past a threshold, so the
child widget(s) can claim before the scrolledwindow does.
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3125
This API is kinda stuck in the GdkEvent days, we now negotiate ownership
of the input sequence via GtkGestures. Remove it as it reflects a way to
work that was not exactly accurate and it will turn plainly wrong soon.
Make GdkEvents hold a single GdkDevice. This device is closer to
the logical device conceptually, although it must be sufficient for
device checks (i.e. GdkInputSource), which makes it similar to the
physical devices.
Make the logical devices have a more accurate GdkInputSource where
needed, and conflate the event devices altogether.
To build a better world sometimes means having to tear the old one down.
-- Alexander Pierce, "Captain America: The Winter Soldier"
ATK served us well for nearly 20 years, but the world has changed, and
GTK has changed with it. Now ATK is mostly a hindrance towards improving
the accessibility stack:
- it maps to a very specific implementation, AT-SPI, which is Linux and
Unix specific
- it requires implementing the same functionality in three different
layers of the stack: AT-SPI, ATK, and GTK
- only GTK uses it; every other Linux and Unix toolkit and application
talks to AT-SPI directly, including assistive technologies
Sadly, we cannot incrementally port GTK to a new accessibility stack;
since ATK insulates us entirely from the underlying implementation, we
cannot replace it piecemeal. Instead, we're going to remove everything
and then incrementally build on a clean slate:
- add an "accessible" interface, implemented by GTK objects directly,
which describe the accessible role and state changes for every UI
element
- add an "assistive technology context" to proxy a native accessibility
API, and assign it to every widget
- implement the AT context depending on the platform
For more information, see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2833
Check correctly that the captured motion events are emitted towards the
content or one of the scrollbars, in order to have it set the expected
"over" state depending on whether the drag begins from the scrolledwindow
content or one of the scrollbars.
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2879
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 was not working in the case that the existing child
is not a scrollable. It showed up as crashes of the
scrolling benchmark in gtk4-demo when switching examples.
Add back a property that determines whether an individual
widget will accept focus or not. :can-focus prevents the
focus from ever entering the entire widget hierarchy
below a widget, and :focusable just determines if grabbing
the focus to the widget itself will succeed.
See #2686