The EI protocol is needed for the xdg-desktop-portal `RemoteDesktop`
portal to emulate input devices, as well as by the `InputCapture` portal
for Synergy-like uses (input-leap supports Wayland with this portal).
This exposes a relatively simple API for a compositor to create EI seats
and devices, mirroring the `Seat` API. It also provides an
`InputBackend`
that converts emulated input to Smithay input events.
Receiver contexts for the `InputCapture` portal are also a bit more
complicated to implement. Those involve capturing input once the cursor
crosses outside the display. That isn't implemented at all here yet.
We may want to change things in the future to accommodate receiver
contexts, etc. But this API is fairly minimal to use, so future breaking
changes shouldn't be too challenging for a compositor to adapt to.
This will be needed for winit 0.31.
In the future, we may want to change the API to more naturally fit
winit. That will be needed if we want to work on Android, and we could
also make things more flexible, like supporting multiple winit windows.
`DrmCompositor::commit_frame()` would pass `None` for the `user_data`
arg to `DrmCompositor::handle_flip()`. When `handle_flip()` sees no
user-data, it dropped the prepared_frame entirely. The swapchain would
still hold a reference to the frame, but if `reset_buffers()` is called
after `commit_frame()` but before the page flip actually occurs, the
swapchain would drop anything in all of its slots, and frame would be
fully dropped.
On the legacy DRM path, this would cause `EINVAL` to be returned on page
flip, because dropping the frames would also cause all framebuffers to
be deleted, and the driver would have nothing to flip to.
This modifies `handle_flip()` to no longer take the `user_data`
parameter; instead, callers (there are only two of them) are expected to
store the pending frame in the appropriate place. `commit_frame()` now
stores the pending frame in `self.current_frame`, which will keep it
alive in the case where all data in the swapchain is dropped.
after suspend/resume we might end up with
a broken mode blob, rendering the surface
dead.
prevent this by always re-initializing the mode
blob on reset_state, which is typically called
after resume.
This break the state after a VT switch as it initializes
the pending state to the current state, making commit_pending
always return false and also looses the configured mode.
This reverts commit 13f07dd1f1.
When drmSetMaster() fails in activate(), the error was only logged and
execution continued unconditionally, setting active=true. This causes
every subsequent atomic page flip commit to return EPERM because the
compositor holds no DRM master on the device.
Fix: return Err(Error::DrmMasterFailed) on acquisition failure so the
device stays inactive (active=false). Callers that check the return
value will correctly skip rendering until the next ActivateSession event
grants master via the seat manager.
Also map DrmMasterFailed to SwapBuffersError::TemporaryFailure in the
From<Error> impl, since master loss during a VT switch is transient —
the seat manager will re-grant master on the next VT resume.
Reproducer: hybrid GPU system (Intel render + NVIDIA display), VT switch
while cosmic-comp is running. Without this fix, every frame after VT
resume floods journald with EPERM from DRM_MODE_ATOMIC on the NVIDIA
device.
Fixes: pop-os/cosmic-comp#2331, pop-os/cosmic-comp#2302
This also:
* Renames pending_geometry() to pending_configure().
* Renames buffered_geometry() to buffered_configure().
* Renames SharedSurfaceState members to reflect the new names.
* Adds a new bbox() function that returns the size of the last buffer
committed (falling back to the last configure
* Adds geometry() back, but now it is the bbox minus the frame extents.
In addition, now the SpaceElement ::geometry and ::bbox impls now just
delegate to the new functions on X11Surface.
On X11, clients can set _GTK_FRAME_EXTENTS to describe non-user-visible
areas at the edges of the surface. This is usually used for drop
shadows.
This is, in a way, the inverse of xdg_toplevel.set_window_geometry.
This change SpaceElement's ::geometry impl for X11Surface to return the
bounding box minus the frame extents.
Related to #2031
The synchronous `set_input_focus(NONE, NONE)` in `X11Surface::leave`
breaks focus transitions between same-client windows. Defer the
focus-out decision to the next event-loop iteration so it can be
cancelled out.
This demos the usage of X11Surface::send_sync_request() in Anvil,
allowing Anvil to throttle X11 ConfigureNotify events sent to the client
when it is unable to repaint fast enough during resizes.
This handles the protocol details around _NET_WM_SYNC_REQUEST, and
exposes API so the compositor can coordinate configure events and
frame/decoration resize with app repaints.
Additionally, we set _XWAYLAND_ALLOW_COMMITS to 0 on the X11 window
while a sync request is in flight, which instructs the XWayland server
to not commit to the underlying wl_surface. This avoids black bars
along the edge of the window when resizing.
See https://specifications.freedesktop.org/wm/1.5/ar01s06.html#id-1.7.3
and https://fishsoup.net/misc/wm-spec-synchronization.html for details.
(Note that this does not implement `_NET_WM_FRAME_DRAWN` or
`_NET_WM_FRAME_TIMINGS`; this only implements the core
`_NET_WM_SYNC_REQUEST`.)
X11Surface::bbox() returns the geometry stored internally by
X11Surface, which is based on the last committed configure attempted by
the compositor (via configure()). The problem here is that the client
is free to reject that size (size increments, min size, max size, etc.).
In these cases, we can mis-render the window (placement or size) if the
last configured rect is not the same as the actual committed buffer.
Instead, use the surface/buffer size, and only fall back to X11Surface's
geometry if that's not available.
This is a convenience wrapper on top of ShellClient::send_ping() and
X11Surface::send_ping() that semi-unifies the ping protocols of both
surface types.
Callers still need to implement the surface-type-specific pong/ack
handler to receive replies.
This adds `X11Surface::ping()`, which, if supported by the client, sends
a `_NET_WM_PING` message to the window. When the client responds,
`XwmHandler::ping_acked()` is called.
to make it easier to identify windows.
Example use case:
in a custom compositor to be able to implement a custom IPC to
list and controls current windows
Signed-off-by: Hichem, Ben Fekih <hichem.f@live.de>
During resize, a client with _NET_WM_OPAQUE_REGION set will send a flood
of changes to this property as the window changes size and the opaque
regions move and change size. Profiling shows that processing all of
these updates can take 10-15ms, causing missed vblanks.
Not only does it take a while to process the flood of updates, fetching
the updated property value from the XWayland server can be very slow
during this period (I've observed a median of 3ms and P90 of 12ms, with
a P99 of 27ms!). My theory is that x11rb's socket processing
architecture appears to be working against us here: in this flood of
updates during a resize, a lot of other things are also going on:
configure requests, configure notify events, etc. This causes x11rb's
incoming event processing to back up, and with the property fetch reply
far down the queue of events to process, it takes a while for it to get
there.
Instead, when receiving a PropertyNotify event for
_NET_WM_OPAQUE_REGION, simply None-out the stored value and mark it as
dirty. In the pre-commit hook, if the value is dirty, re-fetch the
property. This avoids several tens of slow property fetches per frame,
coalescing it down to one per frame at most.
I've also taken pains to avoid holding the mutex on SharedSurfaceState
across the XWayland server round-trip; since that call can take several
milliseconds when there's a flood of events, a multi-threaded compositor
might experience lock contention if it's trying to do anything else with
the X11Surface.
This doesn't fully fix the problem: the property fetch in the pre-commit
handler can still be slow to the tune of several milliseconds (and
sometimes worse) during resize. But this change does eliminate most of
the missed vblanks and skipped frames. (If x11rb were to expose
poll_for_reply(), we could do this in a non-blocking manner, and
completely eliminate this issue, but it's a private function.)
In normal non-resize situations, the opaque region will change only
rarely (if ever), and even when it does, it should presumably be at a
time when there isn't a flood of traffic with the XWayland server, so
the lazy re-fetch in the pre-commit handler should complete in
microseconds.
A single `delegate_dispatch2!` replaces all other delegate macros.
When wayland-rs updates the definition of `Dispatch`, this macro will be
unnecessary, and `Dispatch` type bounds should become inferable by the
type system.
`Dispatch` is now implemented for the user-data type, so `smithay` is
able to provide blanket implementations as long as the user data is a
type owned by `smithay`. Therefore, `GlobalData` replaces `()` as a user
data (`smithay-client-toolkit` already did this), and udata that is
simply a type like `Weak<WlSurface>` is wrapped.
This makes the documentation more consistent with other protocols, and
means there's a test for the protocol that doesn't otherwise exists
since `anvil` doesn't use it.
This adds a setter and getter for the root window property, and also
adds XwmHandler trait items for the root window client message to enable
or disable the mode.
In a compositor that restarts XWayland on a crash, the new XWayland
instance will start off with a fresh serial counter. As new X11 windows
are created, they can have the same serial as a window created on the
previous XWayland instance. Without this cleanup, the lookup in
surface_for_serial() will return a stale/dead wl_surface, and the
xwayland machinery will be unable to properly associate new windows with
a surface.
The XWayland root window uses a 24bpp visual, so when we copy the depth
and visual from the parent for the frame window, we end up with a 24bpp
frame window. When XWayland creates the wl_buffer for a client, it ends
up using the frame window as a template for the buffer format, which
will never have an alpha channel. So if the client wants to do partial
transparency, such as for CSD drop shadows, they'll end up drawing as
opaque rectangles around the window.
Instead, match the client window's visual and colormap when creating the
frame window. This also caches the colormap that goes along with the
selected visual so we avoid creating a new one with each window (and
then need to free it later). In practice, clients will likely use one
of a small number of possible visuals, so it'll mostly be cache hits,
and the cache will only have a few entries.