Compare commits

...

17 commits

Author SHA1 Message Date
Simon Ser
9b42c1901d build: bump version to 0.19.1 2025-09-21 23:03:29 +02:00
Kenny Levinsen
7a52788929 render/vulkan: Handle multi-descriptor sets
A combined image sampler may need several descriptors in a descriptor
set. We are not currently checking how many descriptors are required,
nor is it presumably guaranteed that such multi-descriptor allocation
will not fail due to fragmentation.

If the pool free counter is not zero, try to allocate but continue with
the next pool and fall back to creating a new pool if the allocation
failed.

Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4010
(cherry picked from commit dd7f543189)
2025-09-21 23:03:09 +02:00
Simon Ser
d4009183a1 cursor: use source buffer to signal release timeline point
Same as 128cd07e91 ("scene/surface: use source buffer to signal
release timeline point"), but for the cursor.

(cherry picked from commit 462046ffdc)
2025-09-11 09:13:42 -04:00
Simon Ser
d092e40dec scene/surface: fix NULL deref when source buffer is destroyed
Fixes the following crash, witnessed after a GPU reset:

    #0  0x00007fba9a32774c n/a (libc.so.6 + 0x9774c)
    #1  0x00007fba9a2cddc0 raise (libc.so.6 + 0x3ddc0)
    #2  0x00007fba9a2b557a abort (libc.so.6 + 0x2557a)
    #3  0x00007fba9a2b54e3 n/a (libc.so.6 + 0x254e3)
    #4  0x00007fba9a53fb78 wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer (libwlroots-0.20.so + 0x26b78)
    #5  0x00007fba9a590846 surface_reconfigure (libwlroots-0.20.so + 0x77846)
    #6  0x00007fba9a590cbb scene_surface_set_clip (libwlroots-0.20.so + 0x77cbb)
    #7  0x00007fba9a590efa subsurface_tree_set_clip (libwlroots-0.20.so + 0x77efa)
    #8  0x00007fba9a590f1f subsurface_tree_set_clip (libwlroots-0.20.so + 0x77f1f)
    #9  0x00007fba9a590f1f subsurface_tree_set_clip (libwlroots-0.20.so + 0x77f1f)
    #10 0x00007fba9a590f8d wlr_scene_subsurface_tree_set_clip (libwlroots-0.20.so + 0x77f8d)

Reported-by: Hubert Hirtz <hubert@hirtz.pm>
(cherry picked from commit bd566225ea)
2025-09-11 09:13:35 -04:00
Simon Ser
bb5180ce9e scene/surface: simplify single-pixel-buffer check in surface_reconfigure()
No need to call wlr_client_buffer_get() on wlr_client_buffer.base:
we're already manipulating a wlr_client_buffer.

(cherry picked from commit b62c6878e1)
2025-09-11 09:13:29 -04:00
Simon Ser
73aa61686f output/cursor: fix missing second cursor
When attaching more than one cursor to wlr_output, the first one
will pick the output's hardware cursor, then for the second one
output_set_hardware_cursor() would fail (since the hardware cursor
was already taken), but we still ended up resetting the current
hardware cursor (by calling output_disable_hardware_cursor() below).
As a result only the second cursor would be displayed.

To fix this, move the current hardware cursor check to the caller.

Fixes: 510664e79b ("output: disable hardware cursor when falling back to software")
(cherry picked from commit fd069ad4f2)
2025-09-11 09:13:11 -04:00
liupeng
9079380498 drm_lease_v1: initialize device resource link during abnormal exit
Signed-off-by: liupeng <liupeng01@kylinos.cn>
(cherry picked from commit 5e5842cb1a)
2025-09-11 09:13:01 -04:00
Simon Zeni
3118ca5c3e drm-lease-v1: remove connector active_lease & lease connectors
Upon leasing, the wlr_drm_lease_connector_v1 will be automatically clean up by the wlr_output
destroy handler. There is no need for the wlr_drm_lease_manager to keep track of leased connectors.

(cherry picked from commit 0166fd9eb7)
2025-09-11 09:12:49 -04:00
liupeng
c1938f79c3 cursor: update output cursor even if output is disabled
During suspend, we first disable output and then remove the input device.
This causes cursor->state->surface released while cursor->texture leaves.
Which leads to use-after-free after resume.

(cherry picked from commit be5e266211)
2025-08-27 13:44:35 -04:00
Jesper Jensen
aa904ccf06 output/cursor: Fix double cursor bug
When we fail to render the cursor (in my case because the cursor is too
large) we bail out of the output_cursor_attempt_hardware function. This
causes output_cursor_set_texture to clean up after us, but we've already
cleared the hardware_cursor, and so output_disable_hardware_cursor
thinks we don't have a hardware cursor to disable.

We shouldn't modify the hardware_cursor variable before we've
successfully changed the hardware cursor, this way the caller can clean
up after us like it expect to.

This was brought up by an actual bug when playing the game Kaizen. Which
uses oddly sized cursors, that fell back to software cursors for me, and
left the hardware cursor hanging around. This change has been tested to
fix that.

During the testing of this change, I have noticed that the previous code
worked fine the first time the cursor was switch to software. It only
failed on subsequent attempts. I haven't figured out why that is.

(cherry picked from commit 07e92fb868)
2025-08-27 13:44:22 -04:00
Andri Yngvason
52e1ad01e3 ext-image-capture-source: output: Apply transform to cursor
The cursor can be expected to also be transformed if the output is
transformed.

(cherry picked from commit 80c7e0f772)
2025-08-27 13:44:11 -04:00
Consolatis
30c0602457 transient_seat: initialize seat destroy listener
This fixes a `wl_list_remove()` from an uninitialized listener
when using `wlr_transient_seat_v1_deny()` in a `create_seat`
handler.

(cherry picked from commit c39b3ce7a3)
2025-08-27 13:43:58 -04:00
tokyo4j
b7205866c0 backend/libinput: don't leak udev_device
(cherry picked from commit 170f7e0706)
2025-07-10 09:45:17 -04:00
DreamMaoMao
f935404e68 render/pass: Ensure the precision is consistent during comparison
(cherry picked from commit a08acfcee0)
2025-07-10 09:44:47 -04:00
David Turner
5aa8c192a5 scene: Block damage on single-pixel buffer textures
We cache whether buffers are single-pixel buffers (and if so what color
they are) to allow rendering optimizations.  But this breaks if the
client changes out the single-pixel buffer for one with a different
color, because this updates the texture in-place instead of actually
changing the buffer.

We can fix this by blocking in-place texture updates for single pixel
buffers.

Original bug: https://codeberg.org/ifreund/waylock/issues/121
See also: !5092

(cherry picked from commit 58c3680d96)
2025-07-10 09:44:28 -04:00
Simon Ser
68dea55970 render/egl: fix software rendering check
Commit b4ce0d8b39 ("render/egl: accept negative DRM FD to select
software rendering") added an EXT_device_drm check to figure out
whether the user selected a device with a DRM FD or without one.
However, for KMS-only devices, Mesa will never advertise the
selected KMS node:
3f1d40d230/src/egl/main/egldevice.c (L109)

Instead, pass down a parameter to indicate whether a DRM FD was
passed in.

Fixes: b4ce0d8b39 ("render/egl: accept negative DRM FD to select software rendering")
(cherry picked from commit 48bd1831fe)
2025-07-10 09:44:10 -04:00
Isaac Freund
f3fe6b9a43 util/box: set dest to empty if boxes don't intersect
Currently if both box_a and box_b are non-empty but do not intersect,
this function does not set dest to an empty box. This contradicts the
doc comments and is surprising for users.

(cherry picked from commit f5e7caf599)
2025-06-23 10:53:22 -04:00
14 changed files with 121 additions and 129 deletions

View file

@ -104,6 +104,7 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
struct udev_device *udev = libinput_device_get_udev_device(handle);
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
udev_device_unref(udev);
int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
for (int i = 0; i < groups; ++i) {

View file

@ -37,6 +37,7 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) {
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
udev_device_unref(udev);
wl_list_init(&dev->tablet_tools);
}

View file

@ -62,8 +62,6 @@ struct wlr_drm_lease_connector_v1 {
struct wlr_output *output;
struct wlr_drm_lease_device_v1 *device;
/** NULL if no client is currently leasing this connector */
struct wlr_drm_lease_v1 *active_lease;
struct wl_list link; // wlr_drm_lease_device_v1.connectors
@ -93,9 +91,6 @@ struct wlr_drm_lease_v1 {
struct wlr_drm_lease_device_v1 *device;
struct wlr_drm_lease_connector_v1 **connectors;
size_t n_connectors;
struct wl_list link; // wlr_drm_lease_device_v1.leases
void *data;

View file

@ -1,7 +1,7 @@
project(
'wlroots',
'c',
version: '0.19.0',
version: '0.19.1',
license: 'MIT',
meson_version: '>=1.3',
default_options: [

View file

@ -260,7 +260,8 @@ static struct wlr_egl *egl_create(void) {
return egl;
}
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display,
bool allow_software) {
egl->display = display;
EGLint major, minor;
@ -326,9 +327,8 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
// The only way a non-DRM device is selected is when the user
// explicitly picks software rendering
if (check_egl_ext(device_exts_str, "EGL_MESA_device_software") &&
egl->exts.EXT_device_drm) {
if (env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
if (check_egl_ext(device_exts_str, "EGL_MESA_device_software")) {
if (allow_software || env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
wlr_log(WLR_INFO, "Using software rendering");
} else {
wlr_log(WLR_ERROR, "Software rendering detected, please use "
@ -382,7 +382,7 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
}
static bool egl_init(struct wlr_egl *egl, EGLenum platform,
void *remote_display) {
void *remote_display, bool allow_software) {
EGLint display_attribs[3] = {0};
size_t display_attribs_len = 0;
@ -401,7 +401,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform,
return false;
}
if (!egl_init_display(egl, display)) {
if (!egl_init_display(egl, display, allow_software)) {
if (egl->exts.KHR_display_reference) {
eglTerminate(display);
}
@ -556,6 +556,8 @@ static int open_render_node(int drm_fd) {
}
struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
bool allow_software = drm_fd < 0;
struct wlr_egl *egl = egl_create();
if (egl == NULL) {
wlr_log(WLR_ERROR, "Failed to create EGL context");
@ -569,7 +571,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
*/
EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
if (egl_device != EGL_NO_DEVICE_EXT) {
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device, allow_software)) {
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT");
return egl;
}
@ -594,7 +596,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
goto error;
}
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) {
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device, allow_software)) {
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR");
return egl;
}
@ -633,7 +635,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
return NULL;
}
if (!egl_init_display(egl, display)) {
if (!egl_init_display(egl, display, true)) {
free(egl);
return NULL;
}

View file

@ -21,8 +21,8 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass,
if (!wlr_fbox_empty(&options->src_box)) {
const struct wlr_fbox *box = &options->src_box;
assert(box->x >= 0 && box->y >= 0 &&
box->x + box->width <= options->texture->width &&
box->y + box->height <= options->texture->height);
(uint32_t)(box->x + box->width) <= options->texture->width &&
(uint32_t)(box->y + box->height) <= options->texture->height);
}
render_pass->impl->add_texture(render_pass, options);

View file

@ -66,59 +66,72 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
struct wl_list *pool_list, size_t *last_pool_size) {
VkResult res;
bool found = false;
struct wlr_vk_descriptor_pool *pool;
wl_list_for_each(pool, pool_list, link) {
if (pool->free > 0) {
found = true;
break;
}
}
if (!found) { // create new pool
pool = calloc(1, sizeof(*pool));
if (!pool) {
wlr_log_errno(WLR_ERROR, "allocation failed");
return NULL;
}
size_t count = 2 * (*last_pool_size);
if (!count) {
count = start_descriptor_pool_size;
}
pool->free = count;
VkDescriptorPoolSize pool_size = {
.descriptorCount = count,
.type = type,
};
VkDescriptorPoolCreateInfo dpool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = count,
.poolSizeCount = 1,
.pPoolSizes = &pool_size,
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
};
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
&pool->pool);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateDescriptorPool", res);
free(pool);
return NULL;
}
*last_pool_size = count;
wl_list_insert(pool_list, &pool->link);
}
VkDescriptorSetAllocateInfo ds_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorSetCount = 1,
.pSetLayouts = layout,
.descriptorPool = pool->pool,
};
struct wlr_vk_descriptor_pool *pool;
wl_list_for_each(pool, pool_list, link) {
if (pool->free > 0) {
ds_info.descriptorPool = pool->pool;
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
switch (res) {
case VK_ERROR_FRAGMENTED_POOL:
case VK_ERROR_OUT_OF_POOL_MEMORY:
// Descriptor sets with more than one descriptor can cause us
// to run out of pool memory early or lead to fragmentation
// that makes the pool unable to service our allocation
// request. Try the next pool or allocate a new one.
continue;
case VK_SUCCESS:
--pool->free;
return pool;
default:
wlr_vk_error("vkAllocateDescriptorSets", res);
return NULL;
}
}
}
pool = calloc(1, sizeof(*pool));
if (!pool) {
wlr_log_errno(WLR_ERROR, "allocation failed");
return NULL;
}
size_t count = 2 * (*last_pool_size);
if (!count) {
count = start_descriptor_pool_size;
}
pool->free = count;
VkDescriptorPoolSize pool_size = {
.descriptorCount = count,
.type = type,
};
VkDescriptorPoolCreateInfo dpool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = count,
.poolSizeCount = 1,
.pPoolSizes = &pool_size,
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
};
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
&pool->pool);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateDescriptorPool", res);
free(pool);
return NULL;
}
*last_pool_size = count;
wl_list_insert(pool_list, &pool->link);
ds_info.descriptorPool = pool->pool;
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
if (res != VK_SUCCESS) {
wlr_vk_error("vkAllocateDescriptorSets", res);

View file

@ -283,7 +283,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_ext_image_copy_capture_frame_v1_ready(frame, WL_OUTPUT_TRANSFORM_NORMAL, &now);
wlr_ext_image_copy_capture_frame_v1_ready(frame,
cursor_source->output->transform, &now);
}
static const struct wlr_ext_image_capture_source_v1_interface output_cursor_source_impl = {

View file

@ -288,18 +288,10 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
struct wlr_output *output = cursor->output;
if (!output->impl->set_cursor ||
output->software_cursor_locks > 0) {
if (!output->impl->set_cursor || output->software_cursor_locks > 0) {
return false;
}
struct wlr_output_cursor *hwcur = output->hardware_cursor;
if (hwcur != NULL && hwcur != cursor) {
return false;
}
output->hardware_cursor = NULL;
struct wlr_texture *texture = cursor->texture;
// If the cursor was hidden or was a software cursor, the hardware
@ -424,12 +416,15 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
wl_list_init(&cursor->renderer_destroy.link);
}
if (output_cursor_attempt_hardware(cursor)) {
return true;
if (output->hardware_cursor == NULL || output->hardware_cursor == cursor) {
if (output_cursor_attempt_hardware(cursor)) {
return true;
}
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
output_disable_hardware_cursor(output);
}
wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
output_disable_hardware_cursor(output);
output_cursor_damage_whole(cursor);
return true;
}

View file

@ -96,8 +96,11 @@ static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buf
return;
}
assert(buffer->n_ignore_locks > 0);
buffer->n_ignore_locks--;
// If the buffer was a single-pixel buffer where we cached its color
// then it won't have been marked as damage-allowed.
if (buffer->n_ignore_locks > 0) {
buffer->n_ignore_locks--;
}
}
static int min(int a, int b) {
@ -165,7 +168,21 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
scene_buffer_unmark_client_buffer(scene_buffer);
if (surface->buffer) {
client_buffer_mark_next_can_damage(surface->buffer);
// If we've cached the buffer's single-pixel buffer color
// then any in-place updates to the texture wouldn't be
// reflected in rendering. So only allow in-place texture
// updates if it's not a single pixel buffer. Note that we
// can't use the cached scene_buffer->is_single_pixel_buffer
// because that's only set later on.
bool is_single_pixel_buffer = false;
if (surface->buffer->source != NULL) {
struct wlr_single_pixel_buffer_v1 *spb =
wlr_single_pixel_buffer_v1_try_from_buffer(surface->buffer->source);
is_single_pixel_buffer = spb != NULL;
}
if (!is_single_pixel_buffer) {
client_buffer_mark_next_can_damage(surface->buffer);
}
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
@ -186,7 +203,8 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
&surface->buffer->base, &options);
if (syncobj_surface_state != NULL &&
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
surface->buffer->source != NULL) {
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
surface->buffer->source);
}

View file

@ -530,10 +530,6 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
struct wlr_cursor *cur = output_cursor->cursor;
struct wlr_output *output = output_cursor->output_cursor->output;
if (!output->enabled) {
return;
}
cursor_output_cursor_reset_image(output_cursor);
if (cur->state->buffer != NULL) {
@ -589,10 +585,11 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
&src_box, dst_width, dst_height, surface->current.transform,
hotspot_x, hotspot_y, wait_timeline, wait_point);
if (syncobj_surface_state != NULL && surface->buffer != NULL &&
if (syncobj_surface_state != NULL &&
surface->buffer != NULL && surface->buffer->source != NULL &&
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
&surface->buffer->base);
surface->buffer->source);
}
if (output_cursor->output_cursor->visible) {

View file

@ -68,10 +68,6 @@ static void drm_lease_connector_v1_destroy(
wlr_log(WLR_DEBUG, "Destroying connector %s", connector->output->name);
if (connector->active_lease) {
wlr_drm_lease_terminate(connector->active_lease->drm_lease);
}
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &connector->resources) {
wp_drm_lease_connector_v1_send_withdrawn(resource);
@ -140,14 +136,9 @@ static void lease_handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&lease->destroy.link);
for (size_t i = 0; i < lease->n_connectors; ++i) {
lease->connectors[i]->active_lease = NULL;
}
wl_list_remove(&lease->link);
wl_resource_set_user_data(lease->resource, NULL);
free(lease->connectors);
free(lease);
}
@ -180,20 +171,6 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant(
return NULL;
}
lease->connectors = calloc(request->n_connectors, sizeof(*lease->connectors));
if (!lease->connectors) {
wlr_log(WLR_ERROR, "Failed to allocate lease connectors list");
close(fd);
wp_drm_lease_v1_send_finished(lease->resource);
free(lease);
return NULL;
}
lease->n_connectors = request->n_connectors;
for (size_t i = 0; i < request->n_connectors; ++i) {
lease->connectors[i] = request->connectors[i];
lease->connectors[i]->active_lease = lease;
}
lease->destroy.notify = lease_handle_destroy;
wl_signal_add(&lease->drm_lease->events.destroy, &lease->destroy);
@ -338,16 +315,6 @@ static void drm_lease_request_v1_handle_submit(
return;
}
for (size_t i = 0; i < request->n_connectors; ++i) {
struct wlr_drm_lease_connector_v1 *conn = request->connectors[i];
if (conn->active_lease) {
wlr_log(WLR_ERROR, "Failed to create lease, connector %s has "
"already been leased", conn->output->name);
wp_drm_lease_v1_send_finished(lease_resource);
return;
}
}
request->lease_resource = lease_resource;
wl_signal_emit_mutable(&request->device->manager->events.request,
@ -440,10 +407,6 @@ static struct wp_drm_lease_connector_v1_interface lease_connector_impl = {
static void drm_lease_connector_v1_send_to_client(
struct wlr_drm_lease_connector_v1 *connector,
struct wl_resource *resource) {
if (connector->active_lease) {
return;
}
struct wl_client *client = wl_resource_get_client(resource);
uint32_t version = wl_resource_get_version(resource);
@ -490,10 +453,12 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
if (!device) {
wlr_log(WLR_DEBUG, "Failed to bind lease device, "
"the wlr_drm_lease_device_v1 has been destroyed");
wl_list_init(wl_resource_get_link(device_resource));
return;
}
wl_resource_set_user_data(device_resource, device);
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
int fd = wlr_drm_backend_get_non_master_fd(device->backend);
if (fd < 0) {
@ -505,8 +470,6 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
wp_drm_lease_device_v1_send_drm_fd(device_resource, fd);
close(fd);
wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
struct wlr_drm_lease_connector_v1 *connector;
wl_list_for_each(connector, &device->connectors, link) {
drm_lease_connector_v1_send_to_client(connector, device_resource);

View file

@ -64,6 +64,7 @@ static void manager_create_transient_seat(struct wl_client *client,
wl_resource_set_implementation(seat->resource, &transient_seat_impl,
seat, transient_seat_handle_resource_destroy);
wl_list_init(&seat->seat_destroy.link);
wl_signal_emit_mutable(&manager->events.create_seat, seat);
return;

View file

@ -67,7 +67,12 @@ bool wlr_box_intersection(struct wlr_box *dest, const struct wlr_box *box_a,
dest->width = x2 - x1;
dest->height = y2 - y1;
return !wlr_box_empty(dest);
if (wlr_box_empty(dest)) {
*dest = (struct wlr_box){0};
return false;
}
return true;
}
bool wlr_box_contains_point(const struct wlr_box *box, double x, double y) {