It should be considered a bug if a compositor sets a non-finite
cursor position, so fail loudly (in debug builds) if that happens.
The existing check in wlr_cursor_warp_closest() is now redundant,
and would silently hide such bugs, so remove it.
In wlr_output_attach_render(), stop setting
wlr_output.pending.buffer. This removes one footgun: using the
wlr_buffer at that stage is invalid, because rendering operations
haven't been flushed to the GPU yet. We need to wait until
output_clear_back_buffer() for the wlr_buffer to be used safely.
Instead, set wlr_output.pending.buffer in wlr_output_test() and
wlr_output_commit().
Additionally, move the output_clear_back_buffer() from
wlr_output_commit_state() to wlr_output_commit(). This reduces the
number of calls in the failure path.
We can just use pending.buffer instead. It's completely fine to
call wlr_swapchain_set_buffer_submitted() with a buffer which
doesn't come from the swapchain, in which case it's a no-op.
This is documented to reset the gamma LUT, but we don't handle this
properly.
While at it, make sure we leave wlr_output.pending in a good state
on allocation failure.
wlr_buffer.c is difficult to read because it contains a mixed bag
of unrelated things: base buffer type, buffer implementations,
buffer resource factory, and client buffer.
Split each of these into their own file.
valgrind said (on exit from labwc):
Invalid write of size 8
at 0x487DEAF: wl_list_remove (wayland-util.c:56)
by 0x487DF80: wl_signal_emit_mutable (wayland-server.c:2182)
by 0x48CD6B7: backend_destroy.part.0.lto_priv.0 (backend.c:41)
by 0x48DC19D: multi_backend_destroy (backend.c:58)
by 0x4880286: UnknownInlinedFun (wayland-server.c:2315)
by 0x4880286: wl_display_destroy (wayland-server.c:1170)
by 0x112491: UnknownInlinedFun (server.c:485)
by 0x112491: main (main.c:110)
Address 0x1f9d0210 is 112 bytes inside a block of size 136 free'd
at 0x484426F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x487DF6D: wl_signal_emit_mutable (wayland-server.c:2179)
by 0x48CD6B7: backend_destroy.part.0.lto_priv.0 (backend.c:41)
by 0x48DC19D: multi_backend_destroy (backend.c:58)
by 0x4880286: UnknownInlinedFun (wayland-server.c:2315)
by 0x4880286: wl_display_destroy (wayland-server.c:1170)
by 0x112491: UnknownInlinedFun (server.c:485)
by 0x112491: main (main.c:110)
Block was alloc'd at
at 0x4846A73: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x4918D4E: drm_lease_device_v1_create (wlr_drm_lease_v1.c:639)
by 0x48D3B00: wlr_multi_for_each_backend (backend.c:249)
by 0x49191D2: wlr_drm_lease_v1_manager_create (wlr_drm_lease_v1.c:706)
by 0x111EE9: UnknownInlinedFun (server.c:384)
by 0x111EE9: main (main.c:92)
dac040f87f mistakenly renamed
xdg_surface_destroy listener, which was listening to *unmap* events, to
xdg_surface_unmap. The actual fix, however, is to listen to destroy
events. This fixes various crashes.
If the first test in output_ensure_buffer() fails with modifiers we
replace the swapchain with a modifierless swapchain and try again.
However if that fails as well the output is currently stuck without
modifiers until the next modeset.
To fix this, destroy the modifierless swapchain if the test using it
fails. The next output_attach_back_buffer() call will create a swapchain
that allows modifiers when needed.
Originally, I thought that we could safely subtract opaque regions
from the background even if the black rect optimization was kicking in.
This is wrong because a scene node that isn't fully occluded will still
appear in the render list even if its partially under a black rect. We
need to make sure that while culling the background, we only consider
opaque regions that are also visible. This will fix the black rect
optimization with the background.
We don't need to worry about the black rect optimization here (that
always assumes that there will be a black background) because the
background is culled based on the render list. That means if a black rect
is removed, the visibility will reach all the way to the bottom forcing
the renderer to clear the area not breaking the assumption.
If culling is not enabled, there is no longer any guarantee that the
elements behind the rect won't be rendered. We must render the black rect
in all circumstances to cover up anything rendered.
This fixes the WLR_SCENE_DISABLE_VISIBILTY option.
If the client binds to version 3 of zxdg_output_v1 and version 1 of
wl_output no wl_output.done or zxdg_output_v1.done event is
emitted [1].
Also no wl_output.done event is emitted when version 2 or lower of
zxdg_output_v1 is bound to.
Add a version check to output_manager_handle_get_xdg_output so that no
wl_output.done event is emitted when using version 1 of wl_output and
version 2 or lower of zxdg_output_v1.
[1]: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/81
This has a few benefits one of them crucial for proper operation:
- The primary output will be based on the largest area that is actually
visible to the user. Presentation and frame done events are based on
this state. This is important to do since we cull frame done events.
If we happen to be in a situation where a surface sits mostly on output
A and some on output B but is completely obstructed by for instance a
fullscreen surface on output A we will erroneously send frame_done
events based on output A. If we base things as they are in reality
(visibility) the primary output will instead be output B and things will
work properly.
- The primary output will be NULL if the surface is completely hidden.
Due to quirks with wayland, on a surface commit, frame done events are
required to be sent. Therefore, a new frame will be submitted for rendering
on the primary output. We can improve adaptive sync on completely hidden
but enabled surfaces if we null out the primary output in this state.
- The client will be more likely to choose better metadata to use
for rendering to an output's optimal rendering characteristics.
We can also get rid of the intersection checks in the rendering functions
because we are guaranteed to already be in the node do to the prior
intersection checking of the node visibility.
Simplify damage handling by using our cached visibility state.
Damaging can happen in one step because since we can use the old visibility
state which represent what portions of the screen the scene node was. This
way we can damage everything in one step after the fact.
Will query the scene for all nodes that appear in the given wlr_box.
The nodes will be sent to the iterator from closest to farthest from the
eye.
Refactor wlr_scene_node_at to use this new function.
This lets the renderer handle the wlr_buffer directly, just like it
does in texture_from_buffer. This also allows the renderer to batch
the rectangle updates, and update more than the damage region if
desirable (e.g. too many rects), so can be more efficient.
Only the exclusion zone for mapped layer shell surfaces should be respected. In
particular, a layer shell surface that was mapped with an exclusion zone but is
now unmapped should not adjust the usable area.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3471
This allows whatever the user calls from the signal handlers to react to observe
the new state rather than the old, e.g. that a surface is no longer mapped in
the unmap handler.
This results in the following warning, which in release mode causes an
error due to -Werror:
../types/seat/wlr_seat_pointer.c: In function ‘wlr_seat_pointer_send_axis’:
../types/seat/wlr_seat_pointer.c:344:25: error: ‘low_res_value_discrete’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
343 | if (version < WL_POINTER_AXIS_VALUE120_SINCE_VERSION &&
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
344 | value_discrete != 0 && low_res_value_discrete == 0) {
| ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
This commit fixes:
- sending discrete scrolling events to multiple pointer resources
- sending events to clients which don't support wl_pointer.axis_discrete
When the client doesn't support high-resolution scroll, accumulate
deltas until we can notify a discrete event.
Some mice have a free spinning wheel, making possible to lock the wheel
when the accumulator value is not 0. To avoid synchronization issues
between the mouse wheel and the accumulators, store the last delta and
when the scroll direction changes, reset the accumulator.
Upgrade the seat protocol to version 8 and handle clients that support
high-resolution scroll wheel events.
Since the backend already sends discrete values in the 120 range,
forwarding them is enough.
Currently, the "wlr_event_pointer_axis" event stores low-resolution
values in its "delta_discrete" field. Low-resolution values are always
multiples of one, i.e., 1 for one wheel detent, 2 for two wheel
detents, etc.
In order to simplify internal handling of events, always transform in
the backend from the low-resolution value into the high-resolution
value.
The transformation is performed by multiplying by 120. The 120 magic
number is used by the kernel and it is exposed to clients in the
"WLR_POINTER_AXIS_DISCRETE_STEP" constant.
When using direct scanout back_buffer is NULL. We'd emit a commit
event with WLR_OUTPUT_STATE_BUFFER set but with a NULL buffer field,
which is non-sensical.
wl_subsurface description states:
A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and
the parent surface is mapped.
Note that this doesn't require an explicit commit, which means that a
newly created subsurface with a mapped parent and a buffer already
attached must be mapped immediately. This can happen with the following
sequence of events:
- subcompositor.get_subsurface(subsurface, surface, parent)
- surface.attach(buffer)
- surface.commit()
- subsurface.destroy()
- subcompositor.get_subsurface(subsurface, surface, parent)
Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3449
The previous wlr_output_cursor_set_image() allows setting a NULL buffer for the
cursor to hide it. This functionality was used by sway to hide the cursor,
restore the original semantics by allowing NULL buffers again by avoiding the
wlr_buffer allocation in case we have NULL pixels and handing a NULL wlr_buffer
to wlr_output_cursor_set_buffer().
Whether a texture is opaque or not doesn't depend on the renderer
at all, it just depends on the source buffer. Instead of forcing
all renderers to implement wlr_texture_impl.is_opaque, let's move
this in common code and use the wlr_buffer format to know whether
a texture will be opaque.
...in wlr_scene_layer_surface_v1_configure()
Reproduce bug with waybar by setting `"margin": 5,`
in ~/.config/waybar/config. It will result in the right edge of the panel
extending outside the edge of the output.
The bug can also be reproduced with gtk-layer-demo by anchoring
left/right/top/bottom and setting respective margins
Relates-to: https://github.com/labwc/labwc/issues/382
Before calling wlr_output_impl.{test,commit}, perform a cheap
comparison between the current and candidate state. Unset any
fields which didn't change.
This refactors output_ensure_buffer() to not mutate the state passed,
making the previous subtle behavior much more explicit.
Fixes: d483dd2f ("output: add wlr_output_commit_state")
Closes: #3442
Replace them with wlr_signal_emit_safe, which correctly handles
cases where a listener removes another listener.
Reported-by: Isaac Freund <ifreund@ifreund.xyz>
See the discussion at [1]: there's no easy way to fix libwayland-cursor
without a new API. Sending the error for other roles will prevent the
same client bug from appearing elsewhere.
[1]: https://gitlab.freedesktop.org/wayland/wayland/-/issues/194
This commit ensures that outputs that weren't created by the output
layout helper aren't destroyed on the output layout change.
Consider the following piece of logic:
// struct wlr_output *o1, *o2;
// struct wlr_scene *scene;
// struct wlr_output_layout *layout;
wlr_scene_attach_output_layout(scene, layout);
wlr_output_layout_add_auto(layout, o1);
struct wlr_scene_output *so2 = wlr_scene_output_create(scene, o2);
wlr_output_layout_move(layout, o1, 100, 200);
// so2 is invalid now
Since 5e0ef70cc0 ("seat: Create inert objects for missing capabilities")
wlroots can create inert seat objects when the capability is currently missing
for the client but it had the capablity before. The client hoever will happily
handover the wl_pointer resource to the relative_pointer implementation,
creating a NULL pointer dereference when trying to access the seat_client which
is set to NULL for inert objects.
Since the protocol does not contain an error for such requests, we hand out an
relative_pointer handle with the seat set to NULL.
We also need to check whether there is an associated seat in
send_relative_motion and need to tweak the destroy notifier in case no seat is
available.
This way we can hand out a valid relative_pointer resource and don't crash the
compositor when trying to access an inert seat pointer resource in
relative_pointer.
Relevant WAYLAND_DEBUG=1 when testing a client and switching VT every second:
[2619872.442] wl_seat@30.capabilities(3)
[2619872.460] -> wl_seat@30.get_pointer(new id wl_pointer@36)
[2619872.484] wl_data_device@25.selection(nil)
[2619872.504] zwp_primary_selection_device_v1@26.selection(nil)
[2619874.995] wl_seat@12.capabilities(3)
[2619875.035] -> wl_compositor@5.create_surface(new id wl_surface@37)
[2619875.088] -> wl_seat@12.get_pointer(new id wl_pointer@29)
[2619875.105] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@27, wl_pointer@29)
[2619875.127] -> wl_compositor@5.create_surface(new id wl_surface@35)
[2619875.139] -> wl_seat@12.get_pointer(new id wl_pointer@43)
[2619981.180] wl_seat@12.capabilities(2)
[2619981.214] -> zwp_relative_pointer_v1@27.destroy()
[2619981.226] -> wl_pointer@29.release()
[2619981.236] -> wl_surface@37.destroy()
[2619981.247] -> wl_pointer@43.release()
[2619981.254] -> wl_surface@35.destroy()
[2619981.262] wl_seat@12.capabilities(0)
[2619981.285] -> wl_keyboard@33.release()
[2619987.316] wl_seat@30.capabilities(2)
[2619987.336] -> wl_pointer@36.release()
[2619987.363] wl_seat@30.capabilities(0)
[2619987.371] -> wl_keyboard@34.release()
[2621932.880] wl_display@1.delete_id(41)
[2621932.903] wl_display@1.delete_id(40)
[2621932.910] wl_display@1.delete_id(27)
[2621932.917] wl_display@1.delete_id(29)
[2621932.924] wl_display@1.delete_id(37)
[2621932.930] wl_display@1.delete_id(43)
[2621932.944] wl_display@1.delete_id(35)
[2621932.950] wl_display@1.delete_id(33)
[2621932.959] wl_seat@12.capabilities(2)
[2621932.976] -> wl_seat@12.get_keyboard(new id wl_keyboard@33)
[2621936.875] wl_seat@12.capabilities(3)
[2621936.893] -> wl_compositor@5.create_surface(new id wl_surface@35)
[2621936.931] -> wl_seat@12.get_pointer(new id wl_pointer@43)
[2621936.945] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@37, wl_pointer@43)
[2621936.965] -> wl_compositor@5.create_surface(new id wl_surface@29)
[2621936.987] -> wl_seat@12.get_pointer(new id wl_pointer@27)
[2621942.796] wl_data_device@25.selection(nil)
[2621942.817] zwp_primary_selection_device_v1@26.selection(nil)
[2621942.823] wl_seat@30.capabilities(2)
[1] has changed wlr_drm_format to remove the assumption that
MOD_INVALID is always implicitly enabled. MOD_INVALID is now part
of the modifier list just like any other modifier.
The patch adding support for linux-dmabuf-v1 feedback has been
written a lot of time before [1], and hasn't been updated accordingly
when merged. This results in MOD_INVALID being advertised twice [2] and
other index bugs.
Fix these issues by removing special-casing for MOD_INVALID.
[1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3231
[2]: https://github.com/swaywm/sway/issues/7028
This allows the make/model/serial to be NULL when unset, and allows
them to be longer than the hardcoded array length.
This is a breaking change: compositors need to handle the new NULL
case, and we stop setting make/model to useless "headless" or
"wayland" strings.
This will display red translucent rectangles on the screen regions that
have been damaged. These rectangles will fade out over the span of 250
msecs. If the area is damaged again while the region is fading out,
the timer is reset.
Let's also disable direct scan out when this option is enabled, or else
we won't be able to render the highlight damage regions.
After cancelation we destroy the touch points associated with this
surface as the Wayland spec says:
No further events are sent to the clients from that particular gesture.
Touch cancellation applies to all touch points currently active on this
client's surface. The client is responsible for finalizing the touch
points, future touch points on this surface may re-use the touch point
ID.
Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/2999
This function sidesteps damage tracking and output awareness on
buffers/surfaces. This function isn't a great fit for the API.
Let's also inline the function and simplify it.
There were a couple places this was missing
- on mode change of an output. If the resolution changes for example
nodes may fall out of the view.
- on commits on an output for scale or transform changes
- when the transform of a buffer is changed. If the dest size is not
set, the buffer may have been rotated potentially changing its size
if the buffer width != height