There's two meanings of "frame" there! Since SSD frames are now
rendered by an external client, and there are no actual mechanism
that ensures the frame did already get painted when the client did
respond to its NET_WM_FRAME_SYNC_REQUEST request, there may be
artifacts when resizing windows.
In order to get always the best visual result, we should actually
synchronize rendering with both the client window and the window
frame window.
This commit adds these mechanisms, so a sync alarm update is
expected on both windows until further resizes are allowed, this
ensures window and frame stay in sync, even after moving rendering
elsewhere.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
It will become necessary to track properties and changes from frame windows,
and it will be more convenient to have this managed by the common property
tracking mechanisms.
Add this source_xwindow parameter so property handler functions can check
whether the property belonged to the client Window or the frame Window.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
Store the alarms in a different hashtable, and look up the MetaSyncCounter
right away. It so far avoids the MetaWindow middle man, but will also be
simpler when each window can possibly have more than one active alarms.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
This small X11 client takes care of creating frames for client
windows, Mutter will use this client to delegate window frame
rendering and event handling.
The MetaWindowTracker object will keep track of windows created
from other clients, and will await for _MUTTER_NEEDS_FRAME property
updates on those (coming from Mutter), indicating the need for a
frame window.
This process is resilient to restarts of the frames client, existing
windows will be queried during start, and the existence of relevant
properties checked. Mutter will be able to just hide/show
SSD-decorated windows while the frames client restarts.
The frames are created through GTK4 widgets, the MetaWindowContent
widget acts as a replacement prop for the actual client window,
and the MetaFrameHeader wraps GtkHeaderBar so that windows can be
overshrunk, but otherwise a MetaFrame is a 100% true GTK4 GtkWindow.
After a frame window is created for a client window, the
_MUTTER_FRAME_FOR property will be set on the frame window,
indicating to mutter the correspondence between both Windows.
Additionally, the pixel sizes of the visible left/right/top/bottom
borders of the frame will be set through the _MUTTER_FRAME_EXTENTS
property, set on the frame window.
In order to make the frame window behave as the frame for the
client window, a number of properties will be tracked from the
client window to update the relevant frame behavior (window title,
resizability, availability of actions...), and also some forwarding
of events happening in the frame will be forwarded to the client
window (mainly, WM_DELETE_WINDOW when the close button is clicked).
Other than that, the frames are pretty much CSD GTK4 windows, so
window drags and resizes, and window context menus are forwarded for
the WM to handle.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
This check dates all the way back to commit ac2aa5337d. At the time, the
window switcher was an actual X window, that could generate crossing events
if popped up under the pointer. Checking for this kind of crossing events
made sense back at the time in order not to break focus-follows-mouse as
it's been behaving for long.
But now, this UI is all Clutter widgetry, which in the worst case (X11
sessions, of course) it will update the stage window shape to make these
parts clickable. This happens in other places of code that do already
check for ignoring crossing events.
Underneath, this looked up for a Mutter-local GdkWindow of type
GDK_WINDOW_TEMP, only the main MetaFrames window matches those characteristics
nowadays, notably no window switcher popups. Since the remaining window is
never unmapped (until perhaps shutdown), the paths were functionally dead.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
If the window is not managed, it's weird that it asks for _NET_FRAME_EXTENTS,
it's even weirder that mutter replies with a frame border that would only
apply if the window were managed. Stop doing the latter, and drop the
MetaUI call that calculates borders from the theme settings.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
Put the helper to use, in order to lift MetaWindow itself from this
accounting. As a bonus, the data itself now moved to the MetaWindowX11
private struct, since this may only happen with X11 windows (or its
Xwayland subclass).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
This helper struct takes care of the handling of requests and alarms
in order to satisfy NET_WM_SYNC_REQUEST. It will be necessary to
decouple rendering of windows and frames in future commits, so each
window may need its own synchronization and accounting.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
This may result in a view of the stack in MetaStackManager that does not correspond
to reality, since the window is already being unmanaged, there is no point either in
notifying the stack manager about it.
This slight divergence with reality in the MetaStackManager may produce a non-accurate
view if querying its state has to go through the predicted branches. Later synchronization
with the X11 stack may even this out, but the result really depends on when it is asked.
Fixes some intermittent failures in the stacking/closed-transient-only-take-focus-parents
unit test.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
The meta_window_show() method internally relies on window->mapped being
up-to-date, or attempting to focus it may fail since the window is not
mapped yet, resulting on the window being mapped, but not focused as
it would be expected.
This is moot so far, since windows with frames are created sort-of
synchronously and showing them will result in the focus attempt happening
when the window is already mapped, but things will break when this
becomes an asynchronous step.
Ensure to synchronize client state before showing, so any attempts to
focus the window are able to succeed despite the initial state when
calling meta_window_update_visibility().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
The test does simply "wait" which apparently is not enough to ensure the
client window did resize to the expected dimensions. Use "wait_reconfigure"
and assert that the size after resize is the expected, before going further
at testing its behavior after maximize/unmaximize; it might end up with the
unexpected size after the whole operation.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
Move the use count from a separate MetaWaylandBufferRef struct to the
MetaWaylandBuffer class, and remove the former.
The buffer use count is now incremented already in
meta_wayland_surface_commit, since the Wayland protocol defines the
buffer to be in use by the compositor at that point. If the buffer
attachment ends up being dropped again before it is applied to the
surface state (e.g. because another buffer is committed to a
synchronized sub-surface before the parent surface is committed),
the use count is now decremented, and a buffer release event is sent if
the use count drops to 0.
Buffer release events were previously incorrectly not sent under these
circumstances. Test case: Run the weston-subsurfaces demo with the -r1
and/or -t1 command line parameter. Resize the window. Before this
change, weston-subsurfaces would freeze or abort after a few resize
operations, because mutter failed to send release events and the
client ran out of usable buffers.
v2:
* Handle NULL priv->buffer_ref in
meta_wayland_cursor_surface_apply_state.
v3:
* Remove MetaWaylandBufferRef altogether, move the use count tracking
to MetaWaylandBuffer itself. Much simpler, and doesn't run into
lifetime issues when mutter shuts down.
v4:
* Warn if use count isn't 0 in meta_wayland_buffer_finalize.
* Keep pending_buffer_resource_destroyed for attached but not yet
committed buffers. If the client attaches a buffer and then destroys
it before commit, we ignore the buffer attachement, same as before
this MR.
v5:
* Rebase on top of new commit which splits up surface->texture.
* MetaWaylandSurfaceState::buffer can only be non-NULL if
::newly_attached is TRUE, simplify accordingly.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Until all dma-buf file descriptors for all buffers in the transaction
are readable, which corresponds to when the client drawing to the
buffers has finished.
This fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1162 if the
GPU & drivers support high priority contexts which can preempt lower
priority contexts.
v2:
* Also remove dma-buf fds from transaction and try applying it from
pending_buffer_resource_destroyed. Avoids freeze due to leaving a
GSource based on a closed fd attached if a client destroys a wl_buffer
which is part of a transaction which was committed but not applied
yet. (Robert Mader)
* Tweak transaction cleanup logic in wl_surface_destructor.
v3:
* Adapt to meta_wayland_dma_buf_get_source.
v4:
* Adapt to new commits using transactions for (sub-)surface destruction,
drop code to remove destroyed surfaces from pending transactions.
v5:
* Use g_clear_pointer in meta_wayland_transaction_destroy.
(Georges Basile Stavracas Neto)
* Add spaces between type casts and values. (Carlos Garnacho)
* Use (gpointer *) instead of (void**). (Carlos Garnacho)
* Use gpointer instead of void * in
meta_wayland_transaction_dma_buf_dispatch.
v6:
* Use g_hash_table_remove in meta_wayland_transaction_dma_buf_dispatch.
(Carlos Garnacho)
v7: (Jonas Ådahl)
* Move include of glib-unix.h below that of meta-wayland-transaction.h.
* Split up g_hash_table_iter_next call to multiple lines in
meta_wayland_transaction_commit.
* Call g_source_destroy as well as g_source_unref when freeing a
committed but not yet applied transaction (during mutter shutdown).
v8:
* Drop dma_buf_source_destroy, can use g_source_destroy directly.
(Jonas Ådahl)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
From xdg_surface_constructor_get_popup / xdg_popup_reposition (called
during Wayland protocol processing) to finish_popup_setup /
meta_wayland_xdg_popup_apply_state (called when the popup state is
applied).
This makes sure that the parent window frame rectangle is up to date in
meta_wayland_xdg_positioner_to_placement.
v2:
* Use meta_wayland_surface_state_new () in
meta_wayland_transaction_add_xdg_popup_reposition.
v3:
* Move xdg_popup_repositioned handling to
meta_wayland_xdg_popup_apply_state.
v4:
* Do not steal pending->xdg_positioner in
meta_wayland_xdg_popup_apply_state, fixes leaking the corresponding
memory.
* Drop MetaWaylandSurfaceState::xdg_popup_repositioned, just use
::xdg_positioner.
v5:
* Reformat meta_wayland_xdg_positioner_to_placement calls to stay within
80 columns. (Jonas Ådahl)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
This makes sure that finish_popup_setup is called after any previous
transactions for the parent surface have been applied, so the parent
window geometry is up to date.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Preparation for potentially calling meta_wayland_transaction_apply some
time after surface commit, in which case doing it in the former would be
too late: The client may legally destroy the attached wl_buffer
immediately after commit, in which case meta_wayland_buffer_attach would
spuriously fail and disconnect the client (or possibly even crash mutter
due to NULL error).
Requires splitting up the surface texture between protocol and output
state, and propagating from the former to the latter via
MetaWaylandSurfaceState.
v2: (Jonas Ådahl)
* Move meta_wayland_surface_get_texture call to separate line.
* Use g_autoptr for GError.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
And keep track of the hierarchy separately for the Wayland protocol and
for output. Protocol state is updated immediately as protocol requests
are processed, output state only when the corresponding transaction is
applied (which may be deferred until the next commit of the parent
surface).
v2:
* Directly add placement ops to a transaction, instead of going via
pending_state.
* Use transaction entry for the sub-surface instead of that for its
parent surface.
v3:
* Use transaction entry for the parent surface again, to ensure proper
ordering of placement ops, and call
meta_wayland_surface_notify_subsurface_state_changed only once per
parent surface.
* Drop all use of wl_resource_add_destroy_listener, transactions are
keeping surfaces alive as long as needed.
v4:
* Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501
* Drop ClutterActor code from meta_wayland_surface_apply_placement_ops.
(Robert Mader)
v5:
* Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since
the next commit adds not sub-surface specific state to it.
v6:
* Move include of meta-wayland-subsurface.h from
meta-wayland-transaction.c to .h, since the latter references
MetaWaylandSubsurfacePlacementOp.
v7:
* Drop superfluous !entry check from meta_wayland_transaction_apply.
v8:
* Rename output/protocol fields to output/protocol_state. (Jonas Ådahl)
v9:
* Use meta_wayland_surface_state_new in
meta_wayland_transaction_add_placement_op.
v10:
* Fix a few style issues per check-style.py.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Destroy Wayland protocol related state immediately when the Wayland
resource is destroyed, but keep the rest alive by any transaction which
references the surface.
This makes it easier and cleaner to deal with a surface getting
destroyed while it's still referenced by transactions.
v2:
* No more need to keep references for surfaces in the entries hash
table.
v3:
* Do not use surface->sub.transaction in wl_surface_destructor, just
destroy it.
v4:
* No need for wl_surface_destructor to use its own transaction.
v5:
* Use g_steal_pointer & (more) g_clear_pointer in wl_surface_destructor.
v6:
* Leave SURFACE_DESTROY signal emission in wl_surface_destructor.
v7:
* Use finalize instead of dispose callback.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
This keeps all surfaces referenced by a transaction alive until the
transaction is destroyed, and makes sure transactions are applied in
the same order as they were committed with respect to all surfaces
they reference.
v2:
* Guard against NULL entry in meta_wayland_transaction_apply.
v3:
* Keep single entries hash table.
v4:
* Unref the surface in the meta_wayland_transaction_merge_into while
loop only if the "to" transaction didn't already have an entry for it,
to prevent premature finalization of the surface (likely followed by a
crash).
v5:
* Unref the surface (implicitly via g_hash_table_iter_remove) in the
meta_wayland_transaction_merge_into while loop even if the "to"
transaction already had an entry for it, or we leak a reference.
* Use g_clear_object & g_steal_pointer to not leave behind a dangling
from->state pointer in meta_wayland_transaction_entry_merge_into.
v6:
* Add curly braces around
meta_wayland_transaction_add_placement_surfaces calls. (Jonas Ådahl)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Instead of cached_state.
surface_commit for a synchronized sub-surface either commits the
transaction or merges it into the parent surface's transaction (if
the parent is a synchronized sub-surface itself).
This should fix or at least improve the behaviour of nested synchronized
sub-surfaces.
Also change wl_subsurface_set_desync:
* Commit sub-surface transactions separately. This may allow some of
them to be applied earlier in some cases.
* Commit transaction only for descendant sub-surfaces which become
newly de-synchronized themselves.
v2:
* Drop unused function prototypes
v3:
* Use g_clear_pointer for surface->sub.transaction.
v4:
* Use g_steal_pointer instead of g_clear_pointer. (Sebastian Wick, Jonas
Ådahl)
v5: (Carlos Garnacho)
* Add spaces between type casts and values.
* Use (gpointer *) instead of (void**).
v6: (Jonas Ådahl)
* Use g_clear_object in meta_wayland_transaction_entry_merge_into.
* Use meta_wayland_transaction_entry_free in
meta_wayland_transaction_merge_into.
* Fix alignment of meta_wayland_transaction_merge_pending_state
parameters.
* Remove unused meta_wayland_transaction_add_state declaration.
v7:
* Use meta_wayland_surface_state_new in
meta_wayland_transaction_merge_pending_state.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
A transaction contains the committed state for a surface, plus any
cached state for synchronized subsurfaces.
v2:
* Handle sub-surface positions separately from surface states.
v3:
* Sync child states only for surfaces with state in the transaction.
v4: (Jonas Ådahl)
* Drop unnecessary g_object_new call from wl_subsurface_set_desync. (me)
* Fix indentation & formatting in meta_wayland_surface_commit.
* Add meta_wayland_surface_state_new helper function.
* Fix alignment of meta_wayland_transaction_apply_subsurface_position
parameters.
* Add curly braces around meta_wayland_transaction_sync_child_states
call in meta_wayland_transaction_apply.
v5:
* Make meta_wayland_surface_state_new an inline function.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
If multiple transactions have entries for the same surface, they are
applied in the same order as they were committed. Otherwise, they can
be applied in any order.
This is preparation for following changes, transactions are still
applied as soon as they're committed.
v2:
* Move GQueue for transactions to MetaWaylandCompositor (Jonas Ådahl)
v3
* Say "entry for" instead of "state for", since there can be transaction
entries with no state (for surfaces which are getting destroyed).
v4:
* Use a hash table to keep track of all candidate transactions which
might be newly ready to be applied.
* Use clearer function / variable names.
v5:
* Use custom single-linked list instead of hash table for candidate
transactions, ordered by the transaction commit sequence number, so
that they're attempted to be applied in the same order as they were
committed.
* Rename transaction->queue to transaction->committed_queue, and
simplify its handling.
v6: (Carlos Garnacho)
* Add spaces between type casts and values.
* Use (gpointer *) instead of (void**).
v7: (Jonas Ådahl)
* Use G_MAXSIZE instead of ULONG_MAX.
* Fix indentation of meta_wayland_transaction_apply &
meta_wayland_transaction_maybe_apply_one parameters.
* Refactor find_next_transaction_for_surface & ensure_next_candidate
helper functions out of meta_wayland_transaction_apply.
* Refactor has_unapplied_dependencies helper function out of
meta_wayland_transaction_maybe_apply_one.
* Make while (TRUE) loop in meta_wayland_transaction_maybe_apply
consistent with general usage.
* Drop unused value local from meta_wayland_transaction_commit.
* Store pointer to compositor object in transactions, instead of
pointer to the queue of committed transactions.
* Drop tautological g_assert from meta_wayland_transaction_apply. (me)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
v2:
* Use single hash table with struct which will contain all kinds of
state handled by a transaction.
v3:
* Add meta_wayland_transaction_destroy.
v4 (Georges Basile Stavracas Neto)
* Fix struct _MetaWaylandTransaction(Entry) formatting.
* Explicitly test against NULL.
* Use gpointer insteadof void * for
meta_wayland_transaction_entry_destroy.
v5: (Robert Mader)
* Use for loop in is_ancestor.
* Include meta-wayland-transaction.h first in
meta-wayland-transaction.c.
v6:
* Use g_autofree & g_clear_object.
v7: (Jonas Ådahl)
* Rename meta_wayland_transaction_entry_destroy to
meta_wayland_transaction_entry_free.
* Drop g_autofree use from meta_wayland_transaction_entry_free again.
* Make meta_wayland_transaction_entry_free take a
MetaWaylandTransactionEntry pointer.
* Rename meta_wayland_transaction_destroy to
meta_wayland_transaction_free.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Need to deal with surface->resource == NULL and
surface->pending_state == NULL in some places.
v2:
* Avoid expanding conditions to multiple lines.
(Georges Basile Stavracas Neto)
v3:
* Use a single bailout condition in meta_wayland_client_owns_window as
well.
v4:
* Remove spare empty line in meta_wayland_surface_apply_state.
(Robert Mader)
* Add wl_resource_post_error calls in xdg-shell request handlers.
(Robert Mader)
* Drop checks in functions which can only be called if there's a valid
resource.
* Drop more checks which are unnecessary due to leaving the
SURFACE_DESTROY signal emission in wl_surface_destructor later.
v5:
* Move resource = surface->resource assignments to if (!resource) tests.
(Jonas Ådahl)
v6:
* Fix style issue per check-style.py.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Creates a GSource which will call the specified dispatch callback when
all dma-buf file descriptors for the buffer have become readable.
v2:
* Hold a reference to the buffer in the source, to prevent the buffer
from getting destroyed before the source.
v3:
* Do not use check callback, handle everything in dispatch callback.
(Dor Askayo)
v4: (Georges Basile Stavracas Neto)
* Define and use MetaWaylandDmaBufSource & MetaWaylandDmaBufSourceDispatch
types.
* Fix meta_wayland_dma_buf_source_dispatch &
meta_wayland_dma_buf_source_funcs formatting.
* Use gpointer instead of void*.
* Rename meta_wayland_dma_buf_get_source to
meta_wayland_dma_buf_create_source. (Carlos Garnacho)
v5:
* Explicitly handle NULL return value. (Jonas Ådahl)
v6:
* Fix style issue per check-style.py.
v7:
* Fix code style harder. (Jonas Ådahl)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
And call it from meta_wayland_buffer_realize. This makes dma-buf fds
available for EGL image type buffers as well.
v2:
* Move buffer->dma_buf.dma_buf assignment value to next line.
(Jonas Ådahl)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
Add internal state (starting, running, stopping), and use this instead
of MetaDisplay struct fields to determine whether to start animations.
This fixes issues when we try to animate things when shutting down.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2716>
On hotplug, the events we receive from the kernel are async, and
connectors in the kernel come and go as they please. In practice, this
means that calling drmModeGetConnector() twice more or less directly
after each other, there is no guarantee that the latter call will return
anything if the former did.
When updating the connector in response to hotplugs, we'd first update
the list of existing connectors, and following that, query each and
every one again for their current state, to update our internal
representation; only the former handled drmModeGetConnector() returning
NULL, meaning if unlucky, we'd end up doing a null pointer dereference
when trying to update the state.
Handle this by querying the kernel for the current connector state only
once per connector, updating the list of connectors and their
corresponding state at the same time.
Fixes the following crash:
#0 meta_kms_connector_read_state at ../src/backends/native/meta-kms-connector.c:684
#1 meta_kms_connector_update_state at ../src/backends/native/meta-kms-connector.c:767
#2 meta_kms_impl_device_update_states at ../src/backends/native/meta-kms-impl-device.c:916
#3 meta_kms_device_update_states_in_impl at ../src/backends/native/meta-kms-device.c:267
#4 meta_kms_update_states_in_impl at ../src/backends/native/meta-kms.c:604
#5 update_states_in_impl at ../src/backends/native/meta-kms.c:620
#6 meta_kms_run_impl_task_sync at ../src/backends/native/meta-kms.c:435
#7 meta_kms_update_states_sync at ../src/backends/native/meta-kms.c:641
#8 handle_hotplug_event at ../src/backends/native/meta-kms.c:651
#9 on_udev_hotplug at ../src/backends/native/meta-kms.c:668
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2131269
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2709>