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>
`clutter_actor_iter_destroy` will try to match up the iterator's `age`
with that of the parent ("root") actor:
```
g_return_if_fail (ri->age == ri->root->priv->age);
```
In a simple actor graph that's completely reasonable but somewhere in the
more complex graph of gnome-shell the parent's `age` was skipping ahead
faster than that of the iterator. This could happen in theory if the
destroy indirectly leads to more children being destroyed than the
iterator has visited.
So there's no evidence of actual corruption, only the age check might
fail in a `clutter_actor_iter_destroy` loop because the age check itself
can't handle all possible valid scenarios.
Since our only mandate is to destroy all children, we can do that reliably
without an iterator and thus without assuming anything about the parent's
`age` counter.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4747
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2074>
ClutterColorState, that is a GObject. each ClutterActor would own
such an object, and it'd be set via a GObject property.
It would have an API to get the colorspace, whether the actor
content is in pq or not, and things like that.
if it is NULL, it will default to color state with sRGB colorspace.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2443>
There are no 'features' left, the last one, GLSL shader support, was
moved to Cogl.
This also move the Cogl context creation to a more sensible place, as it
was hidden away in the feature initialization.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2015>
The Cogl feature was removed a while back, while Clutter just hard coded
it to TRUE. Lets remove the confusion that GLSL isn't supported and just
remove the (dead) fallback paths.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2015>
Cleanup all the boilerplate, and port the function to use the auto
generated private helper. Remove the manual autocleanup declaration
since this is now done in the clutter-image.h header.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2355>
A slightly annoying "feature" of Clutters debug messages is that it also
logs the filename and line of the current debug message. If you don't
have an ultrawide monitor, this can be very annoying and cause lots of
linebreaks in the debug logs.
So remove that debugging feature and no longer log the filename and
line number with debugging messages.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2378>
This is a signal that will be emitted between the 'before-update' and
'before-paint'. It can be used to handle things when you know whether
there is an update, and you know whether a paint or not will happen, by
looking at the current damage.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2393>
Mutters event filter can prevent events from getting processed by
Clutter, this can also happen for TOUCH_END/CANCEL events. Processing
these events in Clutter is crucial for proper tracking of touch
sequences though, that's because Clutter adds a PointerDeviceEntry to
the stage on a TOUCH_BEGIN *before* going through the event filter, but
removes that entry on a TOUCH_END *after* going through the filter. So
Clutter really needs to see those TOUCH_END events, or else there will
be a stale PointerDeviceEntry on the ClutterStage.
Make sure those TOUCH_END/CANCEL events always get seen by Clutter by
removing the device entry immediately when those get filtered out.
Because there might still be events belonging to this sequence in the
event queue of the stage, we need to flush the queue before removing the
entry, too.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2350>
Unfortunately we cannot do this generically since the target of the
button/touch press does matter, e.g. tapping on the OSK, or clicking
the IBus candidates window. These situations should not trigger a
reset.
So be more selective about the situations where button/touch presses
trigger an IM reset, in the case of ClutterText these are still clicks
inside the actor, for Wayland's text-input it is when clicking the
surface that has text_input focus.
For all other situations where clicking anywhere else might make
sense to trigger an IM reset are covered by the focus changing paths,
that also ensure a reset before changing focus between surfaces/actors.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1961
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2384>
Focus changes should trigger an IM reset, as some engines do want
to maybe commit the preedit buffer before changing focus. Since
the preedit string is also cleared on reset(), we can do without
that explicit call.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2384>
Right now we have a bit of a mixed bag between an active model where
input foci set the surrounding text without being asked for (e.g.
wayland's text_input), and a passive model where the IM engines ask
for content.
Make ClutterText take the same side than text_input, so that dealing
with those is at least consistent.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2384>
The clutter_text_delete_text() function used underneath expects character
offsets for both start/end position. Fix the end position passed an offset
instead of that, and compesnate for the cursor position being always -1
when the caret is at the end of the string.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2384>
I've overseen quite an important case in commit
98a5cb37d9: Repicking only when actors get
destroyed is not enough, we actually need to repick when actors go
hidden/unmapped.
While we could also listen to notify::mapped just like we listen to
notify::reactive, it seems better to avoid using property notifications
here due to the usage of g_object_freeze/thaw_notify() in ClutterActor.
It can lead to the stage receiving a notify::mapped with mapped = true
for a pointer actor, which really shouldn't happen (just like
notify::reactive with reactive = true shouldn't happen).
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5124
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2333>
We want all pointer events to be passed through the pointer a11y
processing before going through event filters: Once we go through event
filters, events might be dispatched to Wayland and get filtered out.
With the changes to immediately dispatch events to wayland, this changed
and the pointer a11y is now no longer seeing any events going to wayland
clients. Fix it by shuffling things around a bit and letting pointer
a11y take a peek at events earlier.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5192
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2332>
There's a bunch of crashes right now where the assertions in
clutter_actor_set_mapped() after calling the map/unmap() vfuncs are
failing. The only way this can happen is by re-entering
clutter_actor_set_mapped() during the map/unmap recursion.
The reason for those crashes is that the shell hides/shows some actors
in response to crossing events and key-focus changes. These in turn get
triggered by the newly introduced ungrabbing of ClutterGrabs when an
actor gets unmapped, which triggers GRAB_NOTIFY crossing events and
key-focus changes.
Since these situations are hardly avoidable (it's a valid use-case to
hide/show something in response to a crossing/key-focus event), catch
the set_mapped() call early while we reenter the mapping machinery and
log a warning instead of crashing.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3165
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2299>
With the introduction of untrottled event delivery to wayland clients,
we moved the _clutter_event_process_filters() call outside of
_clutter_process_event(). This also moved the processing of event
filters outside of the timespan where the event is added to Clutters
current_event stack, making Clutter.get_current_event() no longer
available to anything happening inside mutters event filter.
One thing that happens in mutters event filter is detecting and
triggering keybindings like the alt-tab switcher. Now the alt-tab
switcher has a special case where it finishes and activates a window
right when the keybinding gets activated, relying on the current event
time as the timestamp to activate the window.
Now since the current event time is no longer available from inside
mutters event filter, we'd pass 0 to meta_window_activate(), causing
mutter to send a notification instead of actually activating the window.
To fix this, also set a current_event for the ClutterContext when going
through event filters, this makes sure Clutter.get_current_event_time()
works when called inside keybinding handlers.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2327>
In the right combination of circumstances, and given 2 actors (parent
actor P with an offscreen effect and child actor C), we may have the
following situation happening:
- A redraw is queued on the actor C, actors C and P are marked as
priv->is_dirty and priv->propagated_one_redraw.
- During paint() handling we paint actor P, priv->propagated_one_redraw
is turned off.
- We recurse into child actor C, priv->propagated_one_redraw is turned
off.
- A new redraw is queued on actor C, actors C and P are marked as
priv->is_dirty and priv->propagated_one_redraw.
- The paint() method recurses back, actors C and P get priv->is_dirty
disabled, priv->propagated_one_redraw remains set.
- At this point queueing up more redraws on actor C will not propagate
up, because actor C has priv->propagated_one_redraw set, but the
parent actor P has priv->is_dirty unset, so the offscreen effect will
not get CLUTTER_EFFECT_PAINT_ACTOR_DIRTY and will avoid repainting
actor C.
The end result is that actor C does not redraw again, despite requesting
redraws. This situation eventually resolves itself through e.g. relayouts
on actor P, but may take some time to happen.
In order to fix this, consider actors that did get a further redraw
request still dirty after paint().
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2188
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2353>
Simplify the function arguments (the origin is just the actor that
the function is originally called from), and make it also handle
marking as dirty the actor that got the redraw queued up explicitly.
This makes it a single place where priv->is_dirty is being enabled.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2353>
We not just have X11 devices, but also virtual devices on both backends.
In the mean time, keep these working on top of a ClutterInputDeviceType,
but transform that into capabilities on device construction so users can
rely on the new flagset.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2331>
This fixes instances of:
```
*** BUG ***
In pixman_region32_init_rect: Invalid rectangle passed
Set a breakpoint on '_pixman_log_error' to debug
```
seen when navigating the overview and launching apps.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2349>
The ClutterGestureAction base code would correctly try to cancel a
gesture if it would receive GRAB_NOTIFY leave events (that would indicate
other portions of the actor tree stole input away from the gesture actor),
but it would mistakenly do so only if the gesture was already initiated,
possibly leaving stale point information if the gesture collected input
but didn't initiate yet.
This could be indirectly seen clicking with the mouse on OSK keys with
no motions in between, clicks would accumulate on the swipeTracker
gestures until the trigger point, so the third click could drag the
workspaces.
We do always want to unregister the related device/sequence here, do that
while still cancelling any already initiated gesture.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1907
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4987
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2334>
We'll need the additional context of which actor the event will be
emitted to in mutters event filter (see next commit), so pass that
target actor to the event filters that are installed.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2321>
It does not make sense that the event "source" (aka the target) is
both content and recipient of a message. Not doing so, events become
largely independent of the actor that is receiving/handling an
event. This is small step toward making events opaque and immutable.
Every user of these API calls in our code have ported away from
them, but other users may remain in extensions, so make these
functions work on top of the alternative API without accessing the
soon to be removed event field.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2311>
This is just "necessary" for --nested stages, since the pointer is
allowed to leave the stage in that case. Since the only side effect
is that there is still a pointer focus somewhere inside the stage,
simply drop this.
This is a small leftover of commit b8f92a6ce4, since we stopped
handling the double ENTER event there.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2311>
In addition to the presented callback time, it shows the time to the
reported presentation time (which can be earlier or later than the
presented callback), as well as the GPU rendering duration.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1928>
The distribute_natural_allocation() function was copied over from Gtk to
Clutter 11 years ago with commit e636a0bbce.
Gtk only supports integers sizes in its layout machinery, while Clutter
does everything using floats.
Since this function sets the minimum_size (the size we allocate the
children in the end) to an integer, this means we're implicitly
typecasting floats to integers here, effectively floor()'ing all sizes
that we allocate the box children.
A bug this caused in gnome-shell was that a scrollView (like the one in
the endSessionDialog) was showing scrollbars even though the content
perfectly fit inside the view: Say the content and its scrollView parent
request a size of 63.9 px, but get allocated a size of 63 px by a box
layout. Now the scrollView notices that its allocated size is smaller
than the requested size and thus shows a scrollbar.
So fix that and use floats in distribute_natural_allocation() instead of
integers, as we do everywhere else in the layout machinery.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2284>
Without input device grabs in play, all functions that emit
pointer/key/crossing/touch events are pretty much the same. Remove this
duplication and use a common emit_event() function.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2100>
In case of misuse (e.g. passing NULL stage) this might result in crashes
before the precondition checks managed to kick in. Move this priv variable
initialization after these checks.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
Wayland event processing and WM operations are themselves outside the
ClutterGrab loop so far. Until this is sorted out, these pieces of
event handling have got to learn to stay aside while there is a
ClutterGrab going on.
So, synchronize foci and other state when grabs come in or out, and
make it sure that Wayland event processing does not happen while
grabs happen.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
Since we want these accessed from bindings this must be a boxed
type. This has the side effect of making ClutterGrab a refcounted
object, since we want to avoid JS from pointing to freed memory
and maybe causing crashes if misusing the object after dismiss.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
Toggling the click action on when leaving the actor/action sounds weird,
this was presumably meant to toggle it off on leave, and back to in_held
on enter. This way, the CLUTTER_LEAVE handling also matches what we want
to do in case of grabs.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
The lack of handling of regular crossing events here is dubious, perhaps
to be fixed later on. So far, ensure gestures are cancelled whenever
a grab-inducted crossing event would leave this action in the blue.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
This is (luckily!) unused, and it's inconvenient to have a toggle to
break the input model we are striving towards. Drop this function
and stick to the default behavior.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2099>
This looks like a relic of glReadPixels-based picking, the pointer
might well be outside redrawn areas, yet still require a device
update (e.g. in order to reflect the actor layout changes in the
"clear area" info).
Instead, always update all devices that are inside the view after
relayouts, the tracking on the need for that update is now done
on each ClutterStageView, instead of globally in the ClutterStage.
This theoretically fixes situations where pointers might miss
updating their "clear area" after the actor tree changed.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2117
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2257>
The stage window is an interface, that added properties, that were only
then actually managed by MetaStageImpl. Shuffle things slightly, and let
the MetaStageImpl object deal with these things itself.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2014>
As ClutterGrab is a stack, the backend only cares about some grab
existing currently or not. Make it sure that we grab whenever we
go to >=1 grabs, and ungrab whenever we go to <1.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
Dissociate clutter_stage_set_key_focus() from the actors focused
state, so that it obeys stage grabs. The key focus actor state may
also change due to grab changes, add the code to notify about this.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
Emit crossing events whenever a grab coming or going would cause a
pointer/touchpoint to become inactive on their position. Depending
on whether the pointer lies inside the old or new grab widgets,
enter or leave events would be generated.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
We will want to be more specific about the portions of the actor
hierarchy that receive this event, separate creation and emission
so each place does what is relevant.
However, this commit brings no functional changes.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
These events are not meant to be ever silenced away, every actor
that is meant to receive one should do so. Make it sure that those
events cannot be stopped, despite the event signal handlers return
values.
This opens the debate about whether crossing events should be
ClutterEvents, since they are more and more uncommon at being one,
maybe this notification mechanism should be taken away from the
event machinery, but that's something for future refactors.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
Hopefully, the one to make them all converge. This new ClutterGrab
represents a handle on a created grab. These are stacked, so grabs
can be overridden and remain inactive until there is a time that
they become active again, although undoing these early is optional.
These grabs are global, they do apply to all pointer, touchpoint
and keyboard foci.
At the moment, only the API to create and stack those is added,
the actual functionality is added in future commits.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2068>
A property for reversing the visible order of children is a bit odd.
It has also been unused by actual gnome-shell code since 2010, and the
somewhat related pack_start()/pack_end() API in GtkBox(Layout) is gone
in GTK4.
With that in mind, turn the property into a no-op and deprecate it,
so that it can be dropped next cycle.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2206>
This ensures they remain perfectly smooth regardless of how the
dispatch time has been adjusted/optimized/delayed/jittered.
Idea by Ivan Molodetskikh <yalterz@gmail.com>
For example, dragging a window on a 60Hz monitor:
BEFORE
delta(time_us) = 17014μs
delta(time_us) = 15998μs
delta(time_us) = 17006μs
delta(time_us) = 16975μs
delta(time_us) = 16001μs
delta(time_us) = 17002μs
delta(time_us) = 17006μs
delta(time_us) = 16004μs
AFTER
delta(time_us) = 16667μs
delta(time_us) = 16667μs
delta(time_us) = 16670μs
delta(time_us) = 16667μs
delta(time_us) = 16669μs
delta(time_us) = 16668μs
delta(time_us) = 16664μs
delta(time_us) = 16674μs
Caveat 1: Because we don't know a "next presentation time" on the first
frame, the interval between the first and second frame will usually be
different to the subsequent steady interval. So this change increases the
jitter of just frame 2, but eliminates jitter thereafter.
Caveat 2: `clutter_frame_clock_schedule_update_now` schedules updates
earlier than `clutter_frame_clock_schedule_update`. This means potentially
you could get multiple frames targeting the same "next presentation time".
That doesn't really change here though - we're dispatching at the same
times as we used to and just giving timelines a better vsync-aligned
timestamp now.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/25
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2161>
This won't change anything for 60Hz displays but higher refresh rate
users will benefit.
Using Nvidia EGLStreams on a 240Hz monitor for example (refresh interval
~4.1ms), the maximum render time allowed before dropping to 120Hz is now
3.6ms whereas it was previously 2.1ms.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2158>
This is notably necessary with transformations, since these don't
trigger allocation machinery, but may affect the actor under the
pointer.
Visible e.g. with GNOME Shell's "Application does not respond"
dialogs.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
With Wayland handling all events as they come, this code now just
performs motion compression for events that will be handled by Clutter
widgetry.
The intent to opt tablets and styli out of motion compression was
early and fast client handling, since that is now covered in a generic
manner, this code is superfluous. We don't really need the extra events
for these devices in compositor widgetry either.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
We essentially create those at the time they need to be handled, and
use shortcuts that avoid the event from being queued up. It's too much
of a short cut though, these events are also of interest to the Wayland
event handlers, e.g. to handle pointer state changes (e.g. repicks due
to the pick actor being destroyed) immediately, instead of at the next
event.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
If we are still under the "clear area" of the pick actor, we forget
to update the coordinates. This is usually not needed, unless we
need to repick again for non-event circumstances (e.g. pick actor
is destroyed). This will ensure the right pointer coordinates are
used afterwards in those situations.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
Traditionally, the next repaint would also involve picking, which
would correct the actor under the pointer. This now does not happen
out of the box, so we really are waiting for the next pointer event
here.
To avoid the pointer/cursor to lag behind, trigger an immediate
repick here, that will look up the new actor under the pointer
coordinates.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
And resort to it first, unless we are told to ignore the cache
(e.g. after relayouts). This avoids further pick context operations
while the pointer is on the current actor.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
This safe area is the region (in stage coordinates) where the pointer
is ensured to stay within the current actor. This is not used yet, but
will be used for optimizations in pointer picking.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
These may be used for optimizations once we find the pick actor,
so picking can be avoided in areas we know didn't cross into
other actors. Nothing makes use of it yet though, just log these
so far.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
Add a clutter_stage_pick_and_update_device() method that is the only
single entry point for updating a device position as seen by the
stage.
Also, update all callers to use it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
The clutter_stage_get_actor_at_pos() calls it almost 1:1 underneath
and is public API, we can have all callers use this, and stop using
this function outside of clutter-stage.c.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
As event handling goes:
1) Events get generated and queued by the seat (from another thread in
native, in the same thread in X11)
2) The MetaBackend gets those events and forwards them to Clutter
via clutter_do_event()
3) The events get queued in the ClutterStage
4) At the time of processing a frame, the input events are processed,
5) Motion events are throttled, only the last is effectively handled
6) Events are filtered, wayland and WM handling happens here
7) Events maybe reach to clutter
This commit moves 6 to happen between 2 and 3. The end result is that:
- Throttling only applies to Clutter event handling, The wayland event
forwarding bits will handle the event stream as soon as it comes, as
timely as possible.
- WM event handling is also unthrottled, but that's more of a side
effect.
- This all still happens on the main thread, so there's the possibility
that other busy areas (e.g. relayout) temporarily block this event
forwarding.
- Sending events unthrottled inherently means more CPU, probably
dependent on input devices' frequency. The impact is not measured.
This should bring the best of both worlds with e.g. 1000Hz mice, wayland
clients get unthrottled events, while GNOME Shell UI still behaves like
it used to do.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
If we wait till finalize, dispose will destroy the actor hierarchy
and cause untimely repicks. Ensure to free the pointer/touch info
first, so the hooked signal callbacks are gone when destroying the
actors.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1915>
In the case a11y is required, the screen reader is very much
interested in getting an uninterrupted flow of key events. It attempts
so by setting a ::captured-event callback on the ClutterStage, but
that falls short with our MetaDisplay event handler, as clutter events
can be stopped before a11y gets a chance to see them.
This kind of selective amnesia wrt key events is not new, in X11 those
go unheard of by the WM as long as a client is focused and no grabs hold,
so it is clients' responsibility to talk with AT bridge.
This commit doesn't yet change that for X11, but we can do this right
away from the compositor on Wayland, and without any chance to be
tampered by clients.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1328>
If one would end up with an actor attached to mapped actor, where the
attached actor doesn't itself have an up to date stage view list while
listening on the stage for updating, when clearing the stage views of
the list, anything that would query the stage views list at this time
would end up accessing freed memory.
This could happen if
1) An actor was added to a newly created container actor attached to
the stage
2) The actor got a timeline attached to it
3) The actor was moved to a container that already was mapped
4) A hotplug happened
After (1) both the container and actor would not have any stage views.
After (2) the timeline would listen on the stage for stage views
updates. After (3) the actor would still listen on the stage for stage
views updates. When (4) happened, the actor would be signalled when the
stage got its stage view cleared, at which point it would traverse up
its actor's tree finding an appropriate stage view to base its animation
on. The problem here would be that it'd query the already mapped
container and its yet-to-be-cleared stage view list, resulting in
use-after free, resulting in for example the following backtrace:
0) g_type_check_instance_cast ()
1) CLUTTER_STAGE_VIEW ()
2) clutter_actor_pick_frame_clock ()
3) clutter_actor_pick_frame_clock ()
4) update_frame_clock ()
5) on_frame_clock_actor_stage_views_changed ()
6) g_closure_invoke ()
7) signal_emit_unlocked_R ()
8) g_signal_emit_valist ()
9) g_signal_emit ()
10) clear_stage_views_cb ()
11) _clutter_actor_traverse_depth ()
12) _clutter_actor_traverse ()
13) clutter_actor_clear_stage_views_recursive ()
14) clutter_stage_clear_stage_views ()
...
Avoid this issue by making sure that we don't emit 'stage-views-changed'
signals while the actor tree is in an invalid state. While we now end up
traversing tree twice, it doesn't change the Big-O notation. It has not
been measured whether this has any noticible performance impact.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1950
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2025>
This does two things to frown upon:
- Modifies ClutterEvent structs, while the effort is to have those
completely opaque, and readonly after creation from the input
thread side.
- Stores state in the ClutterInputDevice struct, event though those
are also considered static after creation, managed by the input
thread, etc.
Stop doing that. This makes all events just forwarded as-is in
the ClutterStage/clutter-main.c code.
Handling of click count sounds like material for a ClutterGestureAction
(or perhaps ClutterClickAction), all of both callers now do it in place
at the moment, while gestures lack a better state tracking and management.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2024>
This will not try the captured-event shenanigans to emulate grab
behavior, instead relying on event delivery being influenced by
other grab mechanisms.
While at it, improve handling of additional touchpoints by
cancelling the click action right away, as the differences in
event handling make this unwanted behavior surface.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2024>
By default, the pan action performs matrix translations on the
child widget. Nobody wants that (or, nobody wants *just* that).
It's cleaner not to mix mechanism and effect in ClutterGestureAction
subclasses, so drop this base implementation, and change the signal
accumulator so it's more similar to event signals (not that it's
used any longer, anyway).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2024>
This warning is actually dead code, since should_be_mapped and
must_be_realized are always set to the same value, so it does not
make sense to check for "a && !b".
Turn this into an assert so we avoid the dead branch, but do not
remove the variable duplication so the more aptly named variable
is used where it belongs, for clarity.
CID: #1506254
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2061>
It was a feature relevant for when Clutter was an application toolkit
that wanted the application window to communicate a minimum size to the
windowing system.
Now, clutter is part of the windowing system component, so this feature
doesn't make any sense, so remove it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
This feature was configured depending on whether the Cogl backend
reported COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN or not. All cogl backends
do report this, so any code handled the 'static' case were never used.
While we only ever use one stage, it's arguable more correct to
consilidate on the single stage case, but multiple stages is something
that might be desirable for e.g. a remote lock screen, so lets keep this
logic intact.
This has the side effect of completely removing backend features, as
this was the only left-over feature detection that they handled.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
This changes the setup phase of clutter to not be result of calling an
init function that sets up a few global singletons, via global singleton
setup vfuncs.
The way it worked was that mutter first did some initial setup
(connecting to the X11 server), then set a "custom backend" setup vfunc
global, before calling clutter_init().
During the clutter_init() call, the context and backend was setup by
calling the global singleton getters, which implicitly created the
backend and context on-demand.
This has now changed to mutter explicitly creating a `ClutterContext`
(which is actually a `ClutterMainContext`, but with the name shortened to
be consistent with `CoglContext` and `MetaContext`), calling it with a
backend constructor vfunc and user data pointer.
This function now explicitly creates the backend, without having to go
via the previously set global vfunc.
This changes the behavior of some "get_default()" like functions, which
will now fail if called after mutter has shut down, as when it does so,
it now destroys the backends and contexts, not only its own, but the
clutter ones too.
The "ownership" of the clutter backend is also moved to
`ClutterContext`, and MetaBackend is changed to fetch it via the clutter
context.
This also removed the unused option parsing that existed in clutter.
In some places, NULL checks for fetching the clutter context, or
backend, and fetching the cogl context from the clutter backend, had to
be added.
The reason for this is that some code that handles EGL contexts attempts
to restore the cogl EGL context tracking so that the right EGL context
is used by cogl the next time. This makes no sense to do before Cogl and
Clutter are even initialized, which was the case. It wasn't noticed
because the relevant singletons were initialized on demand via their
"getters".
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
This one is a trivial wrapper around clutter_actor_get_children(), so just
use that in the two places where clutter_container_get_children() is used,
and remove clutter_container_get_children().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2057>
Right now we damage the stage even if an actor is not mapped, for
example in the overview.
Stop doing so, reducing over-paint significantly in some situations.
Clones will still do stage damage on their own.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2035>
ClutterText implements its own get_paint_volume() with its own cache,
but was not invalidating the actor paint volume when when it has
changed. This sometimes could result in labels, especially quickly
changing ones, using the old paint volume which either would cut off the
label or leave parts of the old label on screen.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1943
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2006>
This mode is passed along by the ClutterInputMethod, the
ClutterInputFocus will preserve it and ensure it is honored
whenever the IM is being reset.
This mode is immediate. The ClutterInputFocus commits the
text directly without queueing a CLUTTER_IM_COMMIT event.
This is important so events are serialized in the right order
in the wayland implementations (i.e. commit before wl_pointer.press).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1940>
In line with GTK, the input method context should be reset when clicks
are handled by the ClutterInputFocus user. The reset action can then
either clear or commit the preedit text, as configured by the IM module.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1940>
Make sure that when we've recreated views that we'll actually paint a
new frame for it. This was very rarely a problem, as views tend to
result in getting damage etc being queued as side effects of various
things, like layout, but e.g. when running certain tests, this might not
happen. There is no situation where we want to create a new view that
should remain unpainted, so just make sure we initialize it to become up
to date.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1947>
This code sneaked unconditionally, even though we can disable
tracing code with -Dprofiler=false. Add some COGL_HAS_TRACING
checks so that this code is also optionally built.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1951>
Will be used to trace a lot more, and with more details, and thus may
have a larger impact on what is actually measured. This potential impact
is the reason for enabling only when needed.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1700>
The failure to allocate was not properly handled, causing crashes later
on due to the offscreen being NULL.
#0 cogl_gl_framebuffer_bind (target=36160, gl_framebuffer=0x0)
#1 _cogl_driver_gl_flush_framebuffer_state (...)
#2 cogl_context_flush_framebuffer_state (read_buffer=0x55f48f386780, draw_buffer=0x55f48f386780, ...)
#3 cogl_framebuffer_clear4f (framebuffer=0x55f48f386780, ...)
#4 clutter_layer_node_pre_draw (...)
#5 clutter_paint_node_paint (...)
...
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1942>
We only listen to it for 2 settings (drag threshold, double click
time), and we already have the stock ClutterSettings object tracking
the source of these. This code is redundant.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1862>
Not sure how to update the damage or redraw clip or something; at least
this works properly when under a constantly-redrawing window, which is
ok for debugging purposes.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1762>
Max render time shows how early the frame clock needs to be dispatched
to make it to the predicted next presentation time. Before this commit
it was set to refresh interval minus 2 ms. This means Mutter would
always start compositing 14.7 ms before a display refresh on a 60 Hz
screen or 4.9 ms before a display refresh on a 144 Hz screen. However,
Mutter frequently does not need as much time to finish compositing and
submit buffer to KMS:
max render time
/------------\
---|---------------|---------------|---> presentations
D----S D--S
D - frame clock dispatch
S - buffer submission
This commit aims to automatically compute a shorter max render time to
make Mutter start compositing as late as possible (but still making it
in time for the presentation):
max render time
/-----\
---|---------------|---------------|---> presentations
D----S D--S
Why is this better? First of all, Mutter gets application contents to
draw at the time when compositing starts. If new application buffer
arrives after the compositing has started, but before the next
presentation, it won't make it on screen:
---|---------------|---------------|---> presentations
D----S D--S
A-------------X----------->
^ doesn't make it for this presentation
A - application buffer commit
X - application buffer sampled by Mutter
Here the application committed just a few ms too late and didn't make on
screen until the next presentation. If compositing starts later in the
frame cycle, applications can commit buffers closer to the presentation.
These buffers will be more up-to-date thereby reducing input latency.
---|---------------|---------------|---> presentations
D----S D--S
A----X---->
^ made it!
Moreover, applications are recommended to render their frames on frame
callbacks, which Mutter sends right after compositing is done. Since
this commit delays the compositing, it also reduces the latency for
applications drawing on frame callbacks. Compare:
---|---------------|---------------|---> presentations
D----S D--S
F--A-------X----------->
\____________________/
latency
---|---------------|---------------|---> presentations
D----S D--S
F--A-------X---->
\_____________/
less latency
F - frame callback received, application starts rendering
So how do we actually estimate max render time? We want it to be as low
as possible, but still large enough so as not to miss any frames by
accident:
max render time
/-----\
---|---------------|---------------|---> presentations
D------S------------->
oops, took a little too long
For a successful presentation, the frame needs to be submitted to KMS
and the GPU work must be completed before the vblank. This deadline can
be computed by subtracting the vblank duration (calculated from display
mode) from the predicted next presentation time.
We don't know how long compositing will take, and we also don't know how
long the GPU work will take, since clients can submit buffers with
unfinished GPU work. So we measure and estimate these values.
The frame clock dispatch can be split into two phases:
1. From start of the dispatch to all GPU commands being submitted (but
not finished)—until the call to eglSwapBuffers().
2. From eglSwapBuffers() to submitting the buffer to KMS and to GPU
work completing. These happen in parallel, and we want the latest of
the two to be done before the vblank.
We measure these three durations and store them for the last 16 frames.
The estimate for each duration is a maximum of these last 16 durations.
Usually even taking just the last frame's durations as the estimates
works well enough, but I found that screen-capturing with OBS Studio
increases duration variability enough to cause frequent missed frames
when using that method. Taking a maximum of the last 16 frames smoothes
out this variability.
The durations are naturally quite variable and the estimates aren't
perfect. To take this into account, an additional constant 2 ms is added
to the max render time.
How does it perform in practice? On my desktop with 144 Hz monitors I
get a max render time of 4–5 ms instead of the default 4.9 ms (I had
1 ms manually configured in sway) and on my laptop with a 60 Hz screen I
get a max render time of 4.8–5.5 ms instead of the default 14.7 ms (I
had 5–6 ms manually configured in sway). Weston [1] went with a 7 ms
default.
The main downside is that if there's a sudden heavy batch of work in the
compositing, which would've made it in default 14.7 ms, but doesn't make
it in reduced 6 ms, there is a delayed frame which would otherwise not
be there. Arguably, this happens rarely enough to be a good trade-off
for reduced latency. One possible solution is a "next frame is expected
to be heavy" function which manually increases max render time for the
next frame. This would avoid this single dropped frame at the start of
complex animations.
[1]: https://www.collabora.com/about-us/blog/2015/02/12/weston-repaint-scheduling/
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1762>
This fixes a warning/error:
In function 'parse_settings',
inlined from 'read_settings' at ../clutter/clutter/x11/xsettings/xsettings-client.c:398:25:
../clutter/clutter/x11/xsettings/xsettings-client.c:202:13: error: 'buffer.byte_order' may be used uninitialized [-Werror=maybe-uninitialized]
202 | if (buffer.byte_order != MSBFirst &&
| ~~~~~~^~~~~~~~~~~
This is needed to bump the CI image from F33 to F34, which includes a
upgraded compiler.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1865>
A simply wrapper around `CoglTexture`, making it easy to reuse
content without roundtrip from GPU to CPU memory and back.
It optionally takes a clip rectangle which is implemented by
creating a `CoglSubTexture`. A limitation here is that floating
point clips are not supported.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1888>
When using `CLUTTER_PAINT=damage-region` highlighting was conspicuously
absent during fullscreen animations like entering or leaving the
overview. That was because `queued_redraw_clip` was empty, because it
had been initialized from `redraw_clip == NULL` (full stage redraw).
Now we paint the damage region as the full view (which it is) instead
of nothing at all.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1890>
This commit adds scaling support to clutter_stage_capture_into, which
is currently used when screencasting monitors. This is supposed to
fix graphical issues that arise when using fractional scaling.
Fixes#1131
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1855>
All pointer a11y is a fabrication of Clutter backend-independent
code, with the help of a ClutterVirtualInputDevice and with some
UI on top.
On the other hand, MetaInputSettings is a backend implementation
detail, this has 2 gotchas:
- In the native backend, the MetaInputSettings (and pointer a11y
with it) are initialized early, before the ClutterSeat core
pointer is set up.
- Doing this from the MetaInputSettings also means another dubious
access from the input thread into main thread territory.
Move the pointer a11y into ClutterSettings, making this effectively
backend-independent business, invariably done from the main thread
and ensured to happen after seat initialization.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1765
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1849>