This is not yet used, but next commits will need to assign a frame
to the paint context whenever painting onscreens.
Assigning a frame to the paint context is a one-way operation, and
treats multiple assignments strictly as a programming error.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2804>
Both Clutter and Cogl use g_return(_val)_if_fail() to safeguard
introspected API. Release builds were dropping these checks, which could
result in a much more crashy experience, especially when considering
extensions, but also due to bugs in the shell code itself.
This won't affect any major distro, because they all use "plain" builds.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2930>
Stage view users can schedule updates at ease with
clutter_stage_view_schedule_update(), but couldn't schedule update
"now". Make that easy too by adding
clutter_stage_view_schedule_update_now().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2854>
If we call schedule(), which will schedule an update some time in the
future, and then schedule_now(), we should reschedule the frame clock to
update immediately, and not some time in the future.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2854>
For motion-induced crossing events, this will be the device that generated
the motion. For code-induced crossing events (e.g. grabs or actors disappearing)
this will be none.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2828>
Since the last commit, ClutterStage automatically cancels an implicit
grab (including all its ClutterActions) when a conflicting ClutterGrab
appears.
This means we no longer have to look out for GRAB_NOTIFY crossings in
ClutterGestureAction and can instead depend on the sequence_cancelled()
vfunc for this.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
A ClutterGrab takes precedence over implicit grabs, so when one happens,
let's check which part of the implicit grab tree is inside the new
ClutterGrab. Cancel and remove the parts which aren't, and if nothing
is in there anymore, cancel the whole implicit grab.
Emitting crossing events correctly here is getting quite tricky:
- When the implicit grab didn't get cancelled by the ClutterGrab, we
simply want to emit all GRAB_NOTIFY crossings to the implicit grab, as
we do with all other crossings.
- When the implicit grab did get cancelled and the new ClutterGrab wants
to emit ENTER crossings, we want those to be emitted to the actual
targets, so cancel the implicit grab before emission.
- In the last case where the implicit grab did get cancelled and the new
ClutterGrab wants to emit LEAVE crossings, those should be emitted to
the implicit grab again, so we cancel the grab only after the emission
of those.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
Now that we have two kinds of grabs, the intricacies of event delivery
got slightly more complicated. So this seems like a good point to
introduce a new GRABS debug flag that gives an overview of which grabs
are currently in effect.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
We're almost there, everything is in place to notify ClutterActions
about a sequence getting pulled away under its feet.
The only thing that's missing is the actual notification to actions now,
so let's do that.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
Another baby step just like the last commit: This commit takes care of
the opposite case: An action handling a sequence event stops further
emission of events to actors.
Since sequences remain around for longer than the context of just a
single event, it makes sense to provide a way to "claim" those sequences
even when outside of event handling context, so introduce API for that.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
As soon as any event of a sequence is handles/stopped during emission,
all actors and actions that would have gotten to see it afterwards have
a big problem: If that event was a TOUCH_END event, the actor/action is
forever going to think that this touch is still active.
For ClutterActions, we're going to handle this by introducing a way to
send them a notification when stuff like this happens.
As a baby step towards all that, make event emission exclusive to actors
as soon as any actor stopped an event.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
We'll soon introduce a new gesture tracking framework which heavily
depends on ClutterActions seeing all events of a sequence. For this to
work, a larger change to event delivery is needed: Implicit grabbing of
all events for button and touch press->motion->release sequences to
ensure ClutterActions continue receiving events for the whole sequence.
This commit takes care of that: At the start of an event sequence we
collect all the event-handling actors and actions to a GArray that lives
in the PointerDeviceEntry, and then deliver all events belonging to
that sequence to the same actors/actions until the sequence ends.
To avoid events getting pulled from under our feet when mutters event
filter returns CLUTTER_EVENT_STOP, this also introduces private API
(maybe_lost_implicit_grab()) on ClutterStage so that we can't end up
with stale sequences.
Note that this also slightly changes behavior when it comes to event
delivery to actions: Because we now store actions separated from their
actors, any action returning CLUTTER_EVENT_STOP now stops event
propagation immediately. That was different before, where we'd emit
events to all actions of the actor and only then stop propagation.
Note that this isn't handling ClutterGrabs correctly right now,
this will be a little tricky, so we'll take care of that in a future
commit.
To handle actors getting destroyed or unmapped during a grab, listen to
notify::grab on the deepmost actor in the implicit grab tree. This gives
us a notification when any actor inside the tree goes unmapped.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
A fairly small refactor, move the emission of events to actions from
clutter_actor_event() to stage level.
We do this because in the future we'll need to know on stage level
whether events were handled by an actor or by an action.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
_clutter_actor_handle_event() currently allocates a new GPtrArray on the
heap for every single event emission, let's avoid this by keeping an
array around in ClutterStage and reusing that.
This is moving the last few bits of event emission into ClutterStage,
which will be useful when we introduce implicit grabbing in subsequent
commits.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
There's no real reason to keep those events exclusive to the stage, some
actors or actions might want to get notified about proximity events too,
so propagate them like any other event.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
Right now and due to loads of refactorings lately, the event emission
paths are a bit cluttered (ha ha ha) around in Clutter. For example the
event target actor gets set in clutter-main.c, but event emission is
actually managed by ClutterStage these days.
Since we'll introduce implicit grabbing of touch/button-press sequences
soon, let's shuffle things around a bit to make that easier:
Move event emission to the stage, it now gets a ClutterEvent without any
extra context like the target actor from clutter-main. The stage then
looks up the target actor itself and emits the event to the appropriate
actors in the scenegraph. A special path is introduced for emitting
crossing events, because here the event-receiving actors don't follow
the "capture+bubble from pointer actor to grab actor" rule.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
Crossing events should never be stopped during event emission. We
already have a check that enforces this in clutter_actor_event(), but
ClutterActions still sometimes try to stop crossing events from
propagating.
Improve that situation and return CLUTTER_EVENT_PROPAGATE when handling
crossings in ClutterActions, too.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
There's still a possibility that some events remain within the
`ClutterMainContext` when it's being unref-ed for the last time (as seen
on asan logs). Make sure they get freed by using
`g_async_queue_new_full()` and specifying the appropriate destroy
function.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2817>
Calculating a timestamp from the past distorts the dispatch lateness
calculation, leading to an inflated max_render_time, which again
increases the likelyhood of next_update_time being in the past.
Fixes 99850f4645
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2819>
That means before-update, prepare-paint, before-paint, paint-view, after-paint,
after-update. While yet to be used, it will be used as a transient frame
book keeping object, to maintain object and state that is only valid
during a frame dispatch.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2795>
Fix a silly copy-paste mistake. Since `GObject` is the parent class,
chaining up to `dispose()` from within your `finalize()`
implementation just leads to a little memory leak and nothing worse.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2799>
Clutter has an API to get the text direction but used to depend
on gtk3's translation domain. In order to avoid broken i18n
in case gtk3 is not installed, move the transtalable string to
clutter itself.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2407>
Now that dynamic max render time uses a new algorithm and takes dispatch
lateness into account, this seems worth a shot. We'll see how it works
out in the wild.
The net result compared to before these changes is still slightly higher
(by ~0.5 ms) minimum latency for me, as measured by
weston-presentation-shm. It should be less vulnerable to frame drops
though.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2500>
Store only two values per kind of duration: The short term and long term
maximum.
The short term maximum is updated in each frame clock dispatch. The long
term maximum is updated at most once per second: If the short term
maximum is higher, the long term maximum is updated to match it.
Otherwise, a fraction of the delta between the two maxima is subtracted
from the long term maximum.
Compared to the previous algorithm:
* The calculcations are simpler.
* The calculated max render time has a slow exponential drop-off (by at
most a few milliseconds every second) instead of potentially abruptly
dropping after as few as 16 frames.
This should fix https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4830
since the short term maximum should always include a sample from the
clock's second tick.
v2:
* Use divisor 2 instead of 4.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2500>
Dispatch lateness is the difference between when we wanted frame clock
dispatch to run and when it actually started running. This can be up to
1ms even under normal circumstances due to process scheduling
granularity, or even higher under load.
This keeps track of dispatch lateness of the last 16 frame clock
dispatches, and incorporates the maximum into the dynamic render time
estimate.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2500>
When we remove a child, we stop its transitions (animations), but we
didn't stop animations on grand children. What we did, however, was to
clear the stage views of the grand children, and this caused a bunch of
orphaned transitions (ClutterTimeline) and accompanied warnings.
Make it so that if we stop transitions, and clear stage views, also stop
transitions for the grand children. Detached children don't have a way
to continue animating anyway, since they have no stage view (thus frame
clock) to be driven by.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2716>
When a badly behaving ClutterActor implementation manages to invalidate
the allocation after the layout phase and before painting, we have no
idea where the actor should be painted without running the whole layout
machinery again.
For paint volumes in this case we pretend the actor covers the whole
stage and queue full-stage redraws. When updating stage-views, we're
also handling this case, but not in the most graceful way. Just like
with paint volumes, we should assume an actor without a valid allocation
is simply everywhere, so set priv->stage_views to all available stage
views in that case.
Related: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6054
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2694>
We've been sending all events to clients immediately for quite some time
now, so this is only really impacting the Clutter scene graph, not
clients anymore.
That makes this behavior a somewhat unnecessary optimization (it was
useful at the time it was added, but it's not anymore), which will only
make our lives harder when we actually expect an event to be queued
(eg. in tests), so remove it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2697>
As suggested by Carlos in a review of this MR, refactor the logic of
clutter_do_event() to have both adding and removing of devices from the
devices list in a single place.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2696>
Having the stage device list be responsible for delivering the
same events twice (first immediately to clients, then later to Clutter)
was expected to be tricky, a sneaky problem with it right now is the
following case:
While collecting events for a stage update cycle, we get three touch
events from the backend: TOUCH_BEGIN(seq=1) -> TOUCH_END(seq=1) ->
TOUCH_BEGIN(seq=1)
What we do right now when we see a TOUCH_BEGIN event is adding a device
to the stage right when it comes in from the backend. And when we see
a TOUCH_END, we remove the device from the stage not immediately but
only after it went through the queue.
In the case of the three events mentioned above, with the current
behavior, this will happen when they come in from the backend:
- TOUCH_BEGIN(seq=1): device gets added to the stage with seq 1, event
gets queued
- TOUCH_END(seq=1): Nothing happens, event gets queued
- TOUCH_BEGIN(seq=1): we try to add device to the stage, but seq 1 is
already there, event gets queued
Now when we go through the queue and see the TOUCH_END, the device with
seq 1 gets removed, but on the subsequent TOUCH_BEGIN, we won't add a
new device, so this event (and all events with seq=1 that are still in
the queue) is now ignored by Clutter because it has no device.
What we want to do here is to cut short once the TOUCH_END event comes
in: Process queued events immediately and make sure the device is
removed from the stage list before a new device can be added. Same goes
for any other events that will lead to devices getting removed.
Small note: Since this leads to clutter_stage_get_device_actor()
returning NULL, I was wondering why we never crash because of this:
Turns out _clutter_actor_handle_event() handles self = NULL just fine
without crashing...
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2696>
With commit 6c17aa66c6 we made sure no
stale device entries might land in the stage device list. The same can
happen for pointer devices too in theory, in practice we never really
filter them out, but it's good to handle them here anyway.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2696>
We'll call this function from a few more places for the
CLUTTER_DEVICE_REMOVED case, so move the check for which devices are
valid into the function itself to avoid having to check everywhere.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2696>
Updating of the paint volume used for culling these days happens
during the finish-layout stage, not while painting. Also we have
geometry-based, not paint-based picking anymore.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
Rename the `last_paint_volume` to `visible_paint_volume`: That avoids
confusion with the `had_effects_on_last_paint_volume_update` flag and
also makes it clear that this paint volume is the currently visible one.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
Rename the paint_volume_valid flag to has_paint_volume in order to
better reflect what it's for.
The name "paint_volume_valid" implies that the paint volume can be
invalidated and thus sounds like it's involved with some kind of
caching. The flag that's actually involved with caching is
"needs_paint_volume_update", while "paint_volume_valid" is only meant to
store whether the actor has a paint volume to work with.
So rename paint_volume_valid to has_paint_volume to avoid confusion
about which flag is used for caching.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
For clarity and for further improvements, introduce a separate function
to update the paint volume instead of doing that inside
_clutter_actor_get_paint_volume_mutable().
Also add a FIXME comment for a possible bug I noticed while working on
it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
Since ClutterActor now properly caches its paint volume and ClutterText
tries hard to invalidate its own cached paint volume on every redraw
anyway (that's more often than ClutterActor invalidates its own paint
volume), we can simply rely on the caching of the paint volume done by
ClutterActor and invalidate that on every redraw.
So remove the private cached paint volume from ClutterText and all its
invalidation machinery.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
The function _clutter_paint_volume_get_stage_paint_box() actually
doesn't modify the paint volume that's passed to it, so make that a bit
more clear by passing a const paint volume as the argument.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
These days it's possible to chain up into the default get_paint_volume()
implementation again, which renders
clutter_actor_get_default_paint_volume() unnecessary. So remove that
function and move clutter_actor_update_default_paint_volume() back into
real_get_paint_volume() where it belongs.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1492>
We traverse the whole screnegraph anyway these days in finish_layout(),
so no need for the whole "set the flag on parents even though we don't
need it" dance anymore.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2667>
There do indeed seem to be places in our own code that trigger grabs on
actors before they are realized. It was not the intention to change the
practical preconditions for GNOME 43, so make it an even lower minimum
that every caller ought to match: That the actor is attached to the stage.
Further constraining of these preconditions will have to wait until
branching for new development.
Fixes: 9c79c7234 (clutter: Only allow grabs to be created on realized actors)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2670>
The bare minimum that we can ask to an actor before creating a grab
on it is that it is realized (and thus, attached to the stage). Bail
out if that is not the case when creating a grab.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2669>
If an actor is being unrealized or otherwise unparented, it's a good
indication that its grabs are now stale and possibly harmful. Ensure
these are dropped when the actor is unparented.
This is now an unlikely event, since there is code to also dismiss
grabs when a visible grabbed actor goes unmapped. But that may be
prevented from happening, or the ordering of circumstances allow a
grab to be created and an actor destroyed without going unmapped
first. This grab dismission on unmap stays as it matches the UI-level
expectatives that an actor must be visible to be grabbed.
Related: https://gitlab.gnome.org/GNOME/mutter/-/issues/2475
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2669>
The stage view list does not get updated when an actor gets hidden in
order to avoid unnecessary work, such as scale changes. However, we
still want `is_effectively_on_stage_view` to report `FALSE` in this
case.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2662>
The :input-purpose and :input-hints properties were added without
actually handling the get/set operations, whoops.
All code uses the (working) methods, so this only fixes expectations,
not an actual bug :-)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2659>
If we have a window that match the size (i.e. will pass the "fits
framebuffer" low level check), that doesn't mean it matches the
position. For example, if we have two monitors 2K monitors, with two 2K
sized windows, one on monitor A, and one on monitor both monitor A and
B, overlapping both, if the latter window is above the former, it'll end
up bing scanned out on both if it ends up fitting all the other
requirements.
Fix this by checking that the paint box matches the stage view layout,
as that makes sure the actor we're painting isn't just partially on the
right view.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2387
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2624>
A few calculations and assignments are done unnecessarily when the
last next presentation time is invalid. This increases the cognitive
complexity of the function for no reason.
No change in behavior.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2486>
I don't see how this makes sense at all, ClutterClickAction really
shouldn't mess with BUTTON_RELEASE events that are not part of a
gesture.
So propagate those events instead of stopping them.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2552>
The source field was removed from ClutterEvent with commit
b644ea1bce because the preferred way of
getting the event actor is now to use the device/sequence actor from the
stage directly.
With crossing events it's not that easy though, as crossing events
explicitly have a source and related actor that doesn't have to be the
same actor as the device actor. Since we kept around the "related" field
there anyway, let's also introduce a "source" field in
ClutterCrossingEvent and return that actor when get_source() is called
on a crossing event.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2551>
Just like we did with the ::captured-event signal, add detail to the
::event signal too. At the first glance this might not seem necessary
since there are individual signals like scroll-event or touch-event that
get emitted at the same time, but these don't exist for touchpad gesture
events and others.
As an easy solution for that, just make it possible to use detail on the
event signal as we did with the caputured-event signal.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2431>
In some hardware configurations, presentation timestamps could be
missing from some page flip events, leading to a temporary loss of
vblank synchronization.
This occurs at least with AMD GPUs for atomic commits that only update
the cursor plane. [0]
In those cases, it's better to calculate the next update time
according to the last valid presentation timestamp instead of relying
on the dispatch lateness.
[0] https://gitlab.freedesktop.org/drm/amd/-/issues/2030
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2481>
When taking the scanout path we still want to clear the
redraw-clip from the stage-view in order to ensure we skip
frames in `handle_frame_clock_frame()` if no new redraw-clip
was recorded.
This was not done previously as the accumulated redraw-clip was
needed for the next repaint, likely under the assumption that
scheduling a scanout repeatedly would be computationally cost-free.
This assumption does not hold in a VRR world.
In order to archive both, an accumulated redraw-clip for the next
paint and frame-skipping during scanout, introduce new API to defer
and accumulate redraw-clips until the next repaint.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2480>
Similar to the clutter commits
- Drop all the private structs documentations
- Make use of gi-docgen items linking as much as possible
- Use markdown formatting for code snippets
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2441>
This can happen with the native backend if the previous frame clock
dispatch didn't result in any KMS update, e.g. because it was triggered
by an input event, but the HW cursor didn't need updating on the stage
view. (This is likely to happen on some out of multiple stage views,
but might be possible even with a single stage view if the cursor isn't
visible)
We would previously delay next_presentation_time_us by one refresh
interval in this case, which could result in spuriously leaving one
refresh cycle unused.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2498>
Somewhat long overdue... We've been supporting more than a single
pointer for quite a long time now, let's make sure things don't break if
two pointer devices enter the same ClutterActor: Count the number of
pointers an actor has instead of using a simple boolean value.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2348>
In certain edge cases it's currently possible that an actor never
gets a valid allocation and paint volume.
One such case is adding an unmapped, hidden child to an unmapped
cloned parent and then showing the child. This happens currently
e.g. if a Wayland subsurface is added to a already mapped window
while the user is in the overview.
Ensure relayouts in two more such cases.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2530>
The notification list in the GNOME Shell calendar popup triggers some
interesting interactions when closing a notification:
- Close button is clicked
- The notification animates to be hidden
- The next notification ends up hovered as a result of the animation
- The notification being hovered sets its close button as non-transparent
and reactive
- The pointer is now again over a close button
At this point the reactiveness change should trigger a repick, so that
the new notification's close button is picked, and future button presses
are directed to it, but we do not handle this situation.
To fix this, handle actors becoming reactive so that if the closest
reactive parent has a pointer, it will be repicked again just in case
the pointer is over the newly reactive actor.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2364
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2532>
The function that currently invalidates pointers over an specific actor
also asserts for the situations where this invalidation makes sense to
happen (i.e. the actor became unmapped, or non-reactive).
We want to have a function that is more forgiving, and that doesn't
enforce any guarantees about the pointer focus actually changing.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2532>