From 4a8e681a5fa82d59544fbdb8026f1606c41504e2 Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Thu, 11 Nov 2021 17:26:27 +0100 Subject: [PATCH 001/190] util/token: don't leak /dev/urandom fd to children Closes #3324. --- util/token.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/util/token.c b/util/token.c index cf6034a32..1b839aaa6 100644 --- a/util/token.c +++ b/util/token.c @@ -1,20 +1,31 @@ +#define _POSIX_C_SOURCE 200809L #include "util/token.h" #include "wlr/util/log.h" +#include #include #include #include #include +#include +#include +#include bool generate_token(char out[static TOKEN_STRLEN]) { static FILE *urandom = NULL; uint64_t data[2]; if (!urandom) { - if (!(urandom = fopen("/dev/urandom", "r"))) { + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd < 0) { wlr_log_errno(WLR_ERROR, "Failed to open random device"); return false; } + if (!(urandom = fdopen(fd, "r"))) { + wlr_log_errno(WLR_ERROR, "fdopen failed"); + close(fd); + return false; + } } if (fread(data, sizeof(data), 1, urandom) != 1) { wlr_log_errno(WLR_ERROR, "Failed to read from random device"); From 8274c85d21df4c790b46666f4383731c89352480 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Sun, 14 Nov 2021 18:37:36 +0100 Subject: [PATCH 002/190] backend/headless: unlink input device on destroy Removing an input device requires unlinking it from the list of all headless input devices. For that implement a destroy function. --- backend/headless/input_device.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/headless/input_device.c b/backend/headless/input_device.c index 76e69c523..1d91f8d12 100644 --- a/backend/headless/input_device.c +++ b/backend/headless/input_device.c @@ -11,7 +11,14 @@ #include "backend/headless.h" #include "util/signal.h" -static const struct wlr_input_device_impl input_device_impl = { 0 }; +static void input_device_destroy(struct wlr_input_device *wlr_dev) { + wl_list_remove(&wlr_dev->link); + free(wlr_dev); +} + +static const struct wlr_input_device_impl input_device_impl = { + .destroy = input_device_destroy, +}; bool wlr_input_device_is_headless(struct wlr_input_device *wlr_dev) { return wlr_dev->impl == &input_device_impl; From 9a4e1095cad154b7f8ce41cedbfb1e9a7e137d66 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 16 Nov 2021 22:55:54 +0100 Subject: [PATCH 003/190] linux-dmabuf-v1: properly validate flags We were send a protocol error if INTERLACED or BOTTOM_FIRST was set. This is incorrect for the zwp_linux_dmabuf_params.create code-path because this kills the client without allowing it to gracefully handle the error. We should only send a protocol error if the client provides a bit not listed in the protocol definition. --- types/wlr_linux_dmabuf_v1.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 7b08b350c..b111a721c 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -204,6 +204,17 @@ static void params_create_common(struct wl_resource *params_resource, goto err_out; } + /* reject unknown flags */ + uint32_t all_flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT | + ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED | + ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST; + if (flags & ~all_flags) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, + "Unknown dmabuf flags %"PRIu32, flags); + goto err_out; + } + attribs.width = width; attribs.height = height; attribs.format = format; @@ -265,14 +276,6 @@ static void params_create_common(struct wl_resource *params_resource, } } - /* reject unknown flags */ - if (attribs.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) { - wl_resource_post_error(params_resource, - ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, - "Unknown dmabuf flags %"PRIu32, attribs.flags); - goto err_out; - } - /* Check if dmabuf is usable */ if (!check_import_dmabuf(linux_dmabuf, &attribs)) { goto err_failed; From a04cfca4da42d1cc01047c1cd9e60ef504beae98 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 16 Nov 2021 22:51:06 +0100 Subject: [PATCH 004/190] Remove support for DMA-BUF flags They are never used in practice, which makes all of our flag handling effectively dead code. Also, APIs such as KMS don't provide a good way to deal with the flags. Let's just fail the DMA-BUF import when clients provide flags. --- backend/drm/renderer.c | 6 ------ backend/wayland/output.c | 12 +----------- backend/x11/output.c | 4 ---- include/render/gles2.h | 2 -- include/render/vulkan.h | 1 - include/wlr/render/dmabuf.h | 7 ------- include/wlr/render/gles2.h | 1 - render/gles2/renderer.c | 4 ---- render/gles2/shaders.c | 7 +------ render/gles2/texture.c | 3 --- render/vulkan/renderer.c | 14 -------------- render/vulkan/texture.c | 13 ------------- types/wlr_export_dmabuf_v1.c | 2 +- types/wlr_linux_dmabuf_v1.c | 6 +++++- types/wlr_screencopy_v1.c | 13 ++++--------- 15 files changed, 12 insertions(+), 83 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 40e068cd8..6c26558f9 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -282,12 +282,6 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, goto error_get_dmabuf; } - if (attribs.flags != 0) { - wlr_log(WLR_DEBUG, "Buffer with DMA-BUF flags 0x%"PRIX32" cannot be " - "scanned out", attribs.flags); - goto error_get_dmabuf; - } - if (formats && !wlr_drm_format_set_has(formats, attribs.format, attribs.modifier)) { // The format isn't supported by the plane. Try stripping the alpha diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 8d8f036c8..3fa86a3cf 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -166,18 +166,8 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl, dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo); } - uint32_t flags = 0; - if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; - } - if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED; - } - if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST; - } struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed( - params, dmabuf->width, dmabuf->height, dmabuf->format, flags); + params, dmabuf->width, dmabuf->height, dmabuf->format, 0); // TODO: handle create() errors return wl_buffer; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 3ad7b4a40..76172582f 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -140,10 +140,6 @@ static xcb_pixmap_t import_dmabuf(struct wlr_x11_output *output, return XCB_PIXMAP_NONE; } - if (dmabuf->flags != 0) { - return XCB_PIXMAP_NONE; - } - // xcb closes the FDs after sending them, so we need to dup them here struct wlr_dmabuf_attributes dup_attrs = {0}; if (!wlr_dmabuf_attributes_copy(&dup_attrs, dmabuf)) { diff --git a/include/render/gles2.h b/include/render/gles2.h index fb2de1ab1..245b2804e 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -24,7 +24,6 @@ struct wlr_gles2_pixel_format { struct wlr_gles2_tex_shader { GLuint program; GLint proj; - GLint invert_y; GLint tex; GLint alpha; GLint pos_attrib; @@ -101,7 +100,6 @@ struct wlr_gles2_texture { EGLImageKHR image; - bool inverted_y; bool has_alpha; // Only affects target == GL_TEXTURE_2D diff --git a/include/render/vulkan.h b/include/render/vulkan.h index aa40198ce..1cba5a192 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -246,7 +246,6 @@ struct wlr_vk_texture { bool dmabuf_imported; bool owned; // if dmabuf_imported: whether we have ownership of the image bool transitioned; // if dma_imported: whether we transitioned it away from preinit - bool invert_y; // if dma_imported: whether we must flip y struct wl_list foreign_link; struct wl_list destroy_link; struct wl_list link; // wlr_gles2_renderer.textures diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 75892d30f..76aad6295 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -14,16 +14,9 @@ #define WLR_DMABUF_MAX_PLANES 4 -enum wlr_dmabuf_attributes_flags { - WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0, - WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1, - WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2, -}; - struct wlr_dmabuf_attributes { int32_t width, height; uint32_t format; - uint32_t flags; // enum wlr_dmabuf_attributes_flags uint64_t modifier; int n_planes; diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index dabe49dde..e6844ce9d 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -30,7 +30,6 @@ struct wlr_gles2_texture_attribs { GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */ GLuint tex; - bool inverted_y; bool has_alpha; }; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 01efaf1de..527d85bfa 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -309,7 +309,6 @@ static bool gles2_render_subtexture_with_matrix( glUseProgram(shader->program); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix); - glUniform1i(shader->invert_y, texture->inverted_y); glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, alpha); @@ -810,7 +809,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { goto error; } renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgba.invert_y = glGetUniformLocation(prog, "invert_y"); renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); @@ -822,7 +820,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { goto error; } renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgbx.invert_y = glGetUniformLocation(prog, "invert_y"); renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); @@ -835,7 +832,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { goto error; } renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_ext.invert_y = glGetUniformLocation(prog, "invert_y"); renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index d854b270c..7898059ed 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -28,18 +28,13 @@ const GLchar quad_fragment_src[] = // Textured quads const GLchar tex_vertex_src[] = "uniform mat3 proj;\n" -"uniform bool invert_y;\n" "attribute vec2 pos;\n" "attribute vec2 texcoord;\n" "varying vec2 v_texcoord;\n" "\n" "void main() {\n" " gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" -" if (invert_y) {\n" -" v_texcoord = vec2(texcoord.x, 1.0 - texcoord.y);\n" -" } else {\n" -" v_texcoord = texcoord;\n" -" }\n" +" v_texcoord = texcoord;\n" "}\n"; const GLchar tex_fragment_src_rgba[] = diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 293b7a19b..8d6f3fc24 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -250,8 +250,6 @@ static struct wlr_texture *gles2_texture_from_dmabuf( return NULL; } texture->drm_format = DRM_FORMAT_INVALID; // texture can't be written anyways - texture->inverted_y = - (attribs->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) != 0; const struct wlr_pixel_format_info *drm_fmt = drm_get_pixel_format_info(attribs->format); @@ -363,6 +361,5 @@ void wlr_gles2_texture_get_attribs(struct wlr_texture *wlr_texture, memset(attribs, 0, sizeof(*attribs)); attribs->target = texture->target; attribs->tex = texture->tex; - attribs->inverted_y = texture->inverted_y; attribs->has_alpha = texture->has_alpha; } diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 31ce0b76c..a1d8d41ef 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -433,15 +433,6 @@ static struct wlr_vk_render_buffer *create_render_buffer( wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d", (const char*) &dmabuf.format, dmabuf.width, dmabuf.height); - // NOTE: we could at least support WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT - // if it is needed by anyone. Can be implemented using negative viewport - // height or flipping matrix. - if (dmabuf.flags != 0) { - wlr_log(WLR_ERROR, "dmabuf flags %x not supported/implemented on vulkan", - dmabuf.flags); - goto error_buffer; - } - buffer->image = vulkan_import_dmabuf(renderer, &dmabuf, buffer->memories, &buffer->mem_count, true); if (!buffer->image) { @@ -789,11 +780,6 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render vert_pcr_data.uv_size[0] = box->width / wlr_texture->width; vert_pcr_data.uv_size[1] = box->height / wlr_texture->height; - if (texture->invert_y) { - vert_pcr_data.uv_off[1] += vert_pcr_data.uv_size[1]; - vert_pcr_data.uv_size[1] = -vert_pcr_data.uv_size[1]; - } - vkCmdPushConstants(cb, renderer->pipe_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); vkCmdPushConstants(cb, renderer->pipe_layout, diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index f6fbec5a9..76c370113 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -605,19 +605,6 @@ static struct wlr_texture *vulkan_texture_from_dmabuf(struct wlr_renderer *wlr_r goto error; } - uint32_t flags = attribs->flags; - if (flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) { - texture->invert_y = true; - flags &= ~WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT; - } - - if (flags != 0) { - wlr_log(WLR_ERROR, "dmabuf flags %x not supported/implemented on vulkan", - attribs->flags); - // NOTE: should probably make this a critical error in future - // return VK_NULL_HANDLE; - } - const struct wlr_pixel_format_info *format_info = drm_get_pixel_format_info(attribs->format); assert(format_info); diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index 954a3270b..d26a9a450 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -77,7 +77,7 @@ static void frame_output_handle_commit(struct wl_listener *listener, uint32_t mod_high = attribs.modifier >> 32; uint32_t mod_low = attribs.modifier & 0xFFFFFFFF; zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, - attribs.width, attribs.height, 0, 0, attribs.flags, frame_flags, + attribs.width, attribs.height, 0, 0, 0, frame_flags, attribs.format, mod_high, mod_low, attribs.n_planes); for (int i = 0; i < attribs.n_planes; ++i) { diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index b111a721c..9b4cdd445 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -215,10 +215,14 @@ static void params_create_common(struct wl_resource *params_resource, goto err_out; } + if (flags != 0) { + wlr_log(WLR_ERROR, "dmabuf flags aren't supported"); + goto err_failed; + } + attribs.width = width; attribs.height = height; attribs.format = format; - attribs.flags = flags; if (width < 1 || height < 1) { wl_resource_post_error(params_resource, diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 7c7d7e95e..3f3d3bc5a 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -254,8 +254,7 @@ error_src_tex: return false; } -static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame, - uint32_t *flags) { +static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame) { struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); @@ -268,11 +267,7 @@ static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame, return false; } - bool ok = blit_dmabuf(renderer, dma_buffer, output->front_buffer); - *flags = dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ? - ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; - - return ok; + return blit_dmabuf(renderer, dma_buffer, output->front_buffer); } static void frame_handle_output_commit(struct wl_listener *listener, @@ -282,7 +277,6 @@ static void frame_handle_output_commit(struct wl_listener *listener, struct wlr_output_event_commit *event = data; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); - uint32_t flags; assert(renderer); if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { @@ -304,8 +298,9 @@ static void frame_handle_output_commit(struct wl_listener *listener, wl_list_remove(&frame->output_commit.link); wl_list_init(&frame->output_commit.link); + uint32_t flags = 0; bool ok = frame->shm_buffer ? - frame_shm_copy(frame, &flags) : frame_dma_copy(frame, &flags); + frame_shm_copy(frame, &flags) : frame_dma_copy(frame); if (!ok) { zwlr_screencopy_frame_v1_send_failed(frame->resource); frame_destroy(frame); From b5d4bc3c62886f3e089165bd4d82bae781a6bda3 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Mon, 15 Nov 2021 09:44:12 -0500 Subject: [PATCH 005/190] Improve wlr_drm_format documentation A wlroots user can easily get confused and think that `cap` refers to wlroots buffer capabilities, not array capacity. --- include/wlr/render/drm_format_set.h | 23 ++++++++++++++++++++-- render/drm_format_set.c | 30 ++++++++++++++--------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h index 15d4eea3f..cb367a632 100644 --- a/include/wlr/render/drm_format_set.h +++ b/include/wlr/render/drm_format_set.h @@ -5,19 +5,38 @@ #include #include +/** A single DRM format */ struct wlr_drm_format { + // The actual DRM format, from `drm_fourcc.h` uint32_t format; - size_t len, cap; + // The number of modifiers + size_t len; + // The capacity of the array; do not use. + size_t capacity; + // The actual modifiers uint64_t modifiers[]; }; +/** A set of DRM formats */ struct wlr_drm_format_set { - size_t len, cap; + // The number of formats + size_t len; + // The capacity of the array; private to wlroots + size_t capacity; + // A pointer to an array of `struct wlr_drm_format *` of length `len`. struct wlr_drm_format **formats; }; +/** + * Free all of the DRM formats in the set, making the set empty. Does not + * free the set itself. + */ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set); +/** + * Return a pointer to a member of this `wlr_drm_format_set` of format + * `format`, or NULL if none exists. + */ const struct wlr_drm_format *wlr_drm_format_set_get( const struct wlr_drm_format_set *set, uint32_t format); diff --git a/render/drm_format_set.c b/render/drm_format_set.c index bd8f0cb75..3edc1925b 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -15,7 +15,7 @@ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set) { free(set->formats); set->len = 0; - set->cap = 0; + set->capacity = 0; set->formats = NULL; } @@ -74,8 +74,8 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, return false; } - if (set->len == set->cap) { - size_t new = set->cap ? set->cap * 2 : 4; + if (set->len == set->capacity) { + size_t new = set->capacity ? set->capacity * 2 : 4; struct wlr_drm_format **tmp = realloc(set->formats, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * new); @@ -85,7 +85,7 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, return false; } - set->cap = new; + set->capacity = new; set->formats = tmp; } @@ -94,15 +94,15 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, } struct wlr_drm_format *wlr_drm_format_create(uint32_t format) { - size_t cap = 4; + size_t capacity = 4; struct wlr_drm_format *fmt = - calloc(1, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + calloc(1, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * capacity); if (!fmt) { wlr_log_errno(WLR_ERROR, "Allocation failed"); return NULL; } fmt->format = format; - fmt->cap = cap; + fmt->capacity = capacity; return fmt; } @@ -119,16 +119,16 @@ bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { } } - if (fmt->len == fmt->cap) { - size_t cap = fmt->cap ? fmt->cap * 2 : 4; + if (fmt->len == fmt->capacity) { + size_t capacity = fmt->capacity ? fmt->capacity * 2 : 4; - fmt = realloc(fmt, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + fmt = realloc(fmt, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * capacity); if (!fmt) { wlr_log_errno(WLR_ERROR, "Allocation failed"); return false; } - fmt->cap = cap; + fmt->capacity = capacity; *fmt_ptr = fmt; } @@ -137,9 +137,9 @@ bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { } struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { - assert(format->len <= format->cap); + assert(format->len <= format->capacity); size_t format_size = sizeof(struct wlr_drm_format) + - format->cap * sizeof(format->modifiers[0]); + format->capacity * sizeof(format->modifiers[0]); struct wlr_drm_format *duped_format = malloc(format_size); if (duped_format == NULL) { return NULL; @@ -171,12 +171,12 @@ struct wlr_drm_format *wlr_drm_format_intersect( return NULL; } format->format = a->format; - format->cap = format_cap; + format->capacity = format_cap; for (size_t i = 0; i < a->len; i++) { for (size_t j = 0; j < b->len; j++) { if (a->modifiers[i] == b->modifiers[j]) { - assert(format->len < format->cap); + assert(format->len < format->capacity); format->modifiers[format->len] = a->modifiers[i]; format->len++; break; From 142d10e591c0f349843f718d87b44c8ba2b33476 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 5 Nov 2021 12:26:38 +0100 Subject: [PATCH 006/190] output: add wlr_output_init_render Co-authored-by: Simon Zeni --- include/wlr/types/wlr_output.h | 14 +++++++++++ types/output/cursor.c | 25 ++++++------------- types/output/render.c | 45 +++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 29 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 17f48311e..9d3dc3cbf 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -182,6 +182,8 @@ struct wlr_output { struct wlr_buffer *cursor_front_buffer; int software_cursor_locks; // number of locks forcing software cursors + struct wlr_allocator *allocator; + struct wlr_renderer *renderer; struct wlr_swapchain *swapchain; struct wlr_buffer *back_buffer, *front_buffer; @@ -256,6 +258,18 @@ struct wlr_surface; void wlr_output_enable(struct wlr_output *output, bool enable); void wlr_output_create_global(struct wlr_output *output); void wlr_output_destroy_global(struct wlr_output *output); +/** + * Initialize the output's rendering subsystem with the provided allocator and + * renderer. Can only be called once. + * + * Call this function prior to any call to wlr_output_attach_render, + * wlr_output_commit or wlr_output_cursor_create. + * + * The buffer capabilities of the provided must match the capabilities of the + * output's backend. Returns false otherwise. + */ +bool wlr_output_init_render(struct wlr_output *output, + struct wlr_allocator *allocator, struct wlr_renderer *renderer); /** * Returns the preferred mode for this output. If the output doesn't support * modes, returns NULL. diff --git a/types/output/cursor.c b/types/output/cursor.c index 0a6cbb757..f1e6aee5e 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -6,7 +6,6 @@ #include #include #include -#include "backend/backend.h" #include "render/allocator/allocator.h" #include "render/swapchain.h" #include "types/wlr_output.h" @@ -38,7 +37,7 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) { } static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); struct wlr_box box = { @@ -71,8 +70,7 @@ static void output_cursor_get_box(struct wlr_output_cursor *cursor, static void output_cursor_render(struct wlr_output_cursor *cursor, pixman_region32_t *damage) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(cursor->output->backend); + struct wlr_renderer *renderer = cursor->output->renderer; assert(renderer); struct wlr_texture *texture = cursor->texture; @@ -195,7 +193,7 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { } static struct wlr_drm_format *output_pick_cursor_format(struct wlr_output *output) { - struct wlr_allocator *allocator = backend_get_allocator(output->backend); + struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); const struct wlr_drm_format_set *display_formats = NULL; @@ -226,17 +224,9 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor) return NULL; } - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); - if (renderer == NULL) { - wlr_log(WLR_ERROR, "Failed to get backend renderer"); - return NULL; - } - - struct wlr_allocator *allocator = backend_get_allocator(output->backend); - if (allocator == NULL) { - wlr_log(WLR_ERROR, "Failed to get backend allocator"); - return NULL; - } + struct wlr_allocator *allocator = output->allocator; + struct wlr_renderer *renderer = output->renderer; + assert(allocator != NULL && renderer != NULL); int width = texture->width; int height = texture->height; @@ -370,8 +360,7 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(cursor->output->backend); + struct wlr_renderer *renderer = cursor->output->renderer; if (!renderer) { // if the backend has no renderer, we can't draw a cursor, but this is // actually okay, for ex. with the noop backend diff --git a/types/output/render.c b/types/output/render.c index b37b8ea12..2f6fe2600 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -11,6 +11,30 @@ #include "render/wlr_renderer.h" #include "types/wlr_output.h" +bool wlr_output_init_render(struct wlr_output *output, + struct wlr_allocator *allocator, struct wlr_renderer *renderer) { + assert(output->allocator == NULL && allocator != NULL); + assert(output->renderer == NULL && renderer != NULL); + + uint32_t backend_caps = backend_get_buffer_caps(output->backend); + uint32_t renderer_caps = renderer_get_render_buffer_caps(renderer); + + if (!(backend_caps & allocator->buffer_caps)) { + wlr_log(WLR_ERROR, "output backend and allocator buffer capabilities " + "don't match"); + return false; + } else if (!(backend_caps & renderer_caps)) { + wlr_log(WLR_ERROR, "output backend and renderer buffer capabilities " + "don't match"); + return false; + } + + output->allocator = allocator; + output->renderer = renderer; + + return true; +} + /** * Ensure the output has a suitable swapchain. The swapchain is re-created if * necessary. @@ -29,11 +53,8 @@ static bool output_create_swapchain(struct wlr_output *output, return true; } - struct wlr_allocator *allocator = backend_get_allocator(output->backend); - if (allocator == NULL) { - wlr_log(WLR_ERROR, "Failed to get backend allocator"); - return false; - } + struct wlr_allocator *allocator = output->allocator; + assert(allocator != NULL); const struct wlr_drm_format_set *display_formats = NULL; if (output->impl->get_primary_formats) { @@ -80,7 +101,7 @@ static bool output_attach_back_buffer(struct wlr_output *output, return false; } - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); struct wlr_buffer *buffer = @@ -103,7 +124,7 @@ void output_clear_back_buffer(struct wlr_output *output) { return; } - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); renderer_bind_buffer(renderer, NULL); @@ -130,7 +151,7 @@ static bool output_attach_empty_buffer(struct wlr_output *output) { int width, height; output_pending_resolution(output, &width, &height); - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; wlr_renderer_begin(renderer, width, height); wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); wlr_renderer_end(renderer); @@ -211,8 +232,8 @@ void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) { struct wlr_drm_format *output_pick_format(struct wlr_output *output, const struct wlr_drm_format_set *display_formats) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); - struct wlr_allocator *allocator = backend_get_allocator(output->backend); + struct wlr_renderer *renderer = output->renderer; + struct wlr_allocator *allocator = output->allocator; assert(renderer != NULL && allocator != NULL); const struct wlr_drm_format_set *render_formats = @@ -264,7 +285,9 @@ struct wlr_drm_format *output_pick_format(struct wlr_output *output, } uint32_t wlr_output_preferred_read_format(struct wlr_output *output) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; + assert(renderer != NULL); + if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) { return DRM_FORMAT_INVALID; } From 6d6e70b9e0e40b6d38ba9276127b869bae893d43 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 24 Sep 2021 09:34:51 -0400 Subject: [PATCH 007/190] examples: init wlr_output with allocator and renderer --- examples/fullscreen-shell.c | 8 +++++++- examples/multi-pointer.c | 12 +++++++++++- examples/output-layout.c | 9 ++++++++- examples/pointer.c | 12 +++++++++++- examples/quads.c | 9 ++++++++- examples/rotation.c | 9 ++++++++- examples/scene-graph.c | 14 +++++++++++--- examples/simple.c | 13 +++++++++++-- examples/tablet.c | 10 +++++++++- examples/touch.c | 12 +++++++++--- 10 files changed, 93 insertions(+), 15 deletions(-) diff --git a/examples/fullscreen-shell.c b/examples/fullscreen-shell.c index 07320045c..5a9d4c926 100644 --- a/examples/fullscreen-shell.c +++ b/examples/fullscreen-shell.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ struct fullscreen_server { struct wl_display *wl_display; struct wlr_backend *backend; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_fullscreen_shell_v1 *fullscreen_shell; struct wl_listener present_surface; @@ -146,6 +148,8 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; + wlr_output_init_render(wlr_output, server->allocator, server->renderer); + struct fullscreen_output *output = calloc(1, sizeof(struct fullscreen_output)); output->wlr_output = wlr_output; @@ -203,8 +207,10 @@ int main(int argc, char *argv[]) { struct fullscreen_server server = {0}; server.wl_display = wl_display_create(); server.backend = wlr_backend_autocreate(server.wl_display); - server.renderer = wlr_backend_get_renderer(server.backend); + server.renderer = wlr_renderer_autocreate(server.backend); wlr_renderer_init_wl_display(server.renderer, server.wl_display); + server.allocator = wlr_allocator_autocreate(server.backend, + server.renderer); wlr_compositor_create(server.wl_display, server.renderer); diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 495562802..5095cb729 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,8 @@ struct sample_state { struct wl_display *display; struct wlr_xcursor *xcursor; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; float default_color[4]; float clear_color[4]; struct wlr_output_layout *layout; @@ -90,7 +93,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct sample_output *output = wl_container_of(listener, output, frame); struct sample_state *sample = output->sample; struct wlr_output *wlr_output = output->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = sample->renderer; wlr_output_attach_render(wlr_output, NULL); @@ -144,6 +147,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->output = output; sample_output->sample = sample; @@ -269,6 +275,10 @@ int main(int argc, char *argv[]) { if (!wlr) { exit(1); } + + state.renderer = wlr_renderer_autocreate(wlr); + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + wl_list_init(&state.cursors); wl_list_init(&state.pointers); wl_list_init(&state.outputs); diff --git a/examples/output-layout.c b/examples/output-layout.c index 356d5d56d..bc5cb7e90 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ struct sample_state { struct wl_listener new_output; struct wl_listener new_input; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_texture *cat_texture; struct wlr_output_layout *layout; float x_offs, y_offs; @@ -158,6 +160,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); wlr_output_layout_add_auto(sample->layout, output); sample_output->output = output; @@ -273,11 +278,13 @@ int main(int argc, char *argv[]) { wl_signal_add(&wlr->events.new_input, &state.new_input); state.new_input.notify = new_input_notify; - state.renderer = wlr_backend_get_renderer(wlr); + state.renderer = wlr_renderer_autocreate(wlr); state.cat_texture = wlr_texture_from_pixels(state.renderer, DRM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height, cat_tex.pixel_data); + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + if (!wlr_backend_start(wlr)) { wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(wlr); diff --git a/examples/pointer.c b/examples/pointer.c index 1abdf1cfe..bf3701a45 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,8 @@ struct sample_state { struct wl_display *display; struct compositor_state *compositor; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_xcursor_manager *xcursor_manager; struct wlr_cursor *cursor; double cur_x, cur_y; @@ -95,7 +98,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); struct sample_state *state = sample_output->state; struct wlr_output *wlr_output = sample_output->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = state->renderer; assert(renderer); wlr_output_attach_render(wlr_output, NULL); @@ -250,6 +253,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->output = output; sample_output->state = sample; @@ -331,6 +337,10 @@ int main(int argc, char *argv[]) { if (!wlr) { exit(1); } + + state.renderer = wlr_renderer_autocreate(wlr); + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + state.cursor = wlr_cursor_create(); state.layout = wlr_output_layout_create(); wlr_cursor_attach_output_layout(state.cursor, state.layout); diff --git a/examples/quads.c b/examples/quads.c index 6696ef7ce..d74ef25e6 100644 --- a/examples/quads.c +++ b/examples/quads.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ struct sample_state { struct wl_listener new_input; struct timespec last_frame; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wl_list outputs; }; @@ -103,6 +105,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); struct wlr_output_mode *mode = wlr_output_preferred_mode(output); @@ -195,13 +200,15 @@ int main(int argc, char *argv[]) { state.new_input.notify = new_input_notify; clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - state.renderer = wlr_backend_get_renderer(wlr); + state.renderer = wlr_renderer_autocreate(wlr); if (!state.renderer) { wlr_log(WLR_ERROR, "Could not start compositor, OOM"); wlr_backend_destroy(wlr); exit(EXIT_FAILURE); } + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + if (!wlr_backend_start(wlr)) { wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(wlr); diff --git a/examples/rotation.c b/examples/rotation.c index ff34630ea..cc1cfbb5b 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ struct sample_state { struct wl_listener new_input; struct timespec last_frame; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_texture *cat_texture; struct wl_list outputs; enum wl_output_transform transform; @@ -105,6 +107,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->x_offs = sample_output->y_offs = 0; sample_output->x_vel = sample_output->y_vel = 128; @@ -245,7 +250,7 @@ int main(int argc, char *argv[]) { state.new_input.notify = new_input_notify; clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - state.renderer = wlr_backend_get_renderer(wlr); + state.renderer = wlr_renderer_autocreate(wlr); if (!state.renderer) { wlr_log(WLR_ERROR, "Could not start compositor, OOM"); wlr_backend_destroy(wlr); @@ -259,6 +264,8 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + if (!wlr_backend_start(wlr)) { wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(wlr); diff --git a/examples/scene-graph.c b/examples/scene-graph.c index d5c23a16b..bd2003f53 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,8 @@ static const int border_width = 3; struct server { struct wl_display *display; struct wlr_backend *backend; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_scene *scene; struct wl_list outputs; @@ -73,6 +76,8 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { struct server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; + wlr_output_init_render(wlr_output, server->allocator, server->renderer); + struct output *output = calloc(1, sizeof(struct output)); output->wlr = wlr_output; @@ -161,11 +166,14 @@ int main(int argc, char *argv[]) { server.backend = wlr_backend_autocreate(server.display); server.scene = wlr_scene_create(); - struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend); - wlr_renderer_init_wl_display(renderer, server.display); + server.renderer = wlr_renderer_autocreate(server.backend); + wlr_renderer_init_wl_display(server.renderer, server.display); + + server.allocator = wlr_allocator_autocreate(server.backend, + server.renderer); struct wlr_compositor *compositor = - wlr_compositor_create(server.display, renderer); + wlr_compositor_create(server.display, server.renderer); wlr_xdg_shell_create(server.display); diff --git a/examples/simple.c b/examples/simple.c index 9135d163b..94f3abe0e 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,8 @@ struct sample_state { struct wl_display *display; struct wl_listener new_output; struct wl_listener new_input; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct timespec last_frame; float color[4]; int dec; @@ -61,8 +64,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_attach_render(wlr_output, NULL); - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = sample->renderer; wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(renderer, sample->color); wlr_renderer_end(renderer); @@ -84,6 +86,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->output = output; @@ -171,6 +176,10 @@ int main(void) { if (!backend) { exit(1); } + + state.renderer = wlr_renderer_autocreate(backend); + state.allocator = wlr_allocator_autocreate(backend, state.renderer); + wl_signal_add(&backend->events.new_output, &state.new_output); state.new_output.notify = new_output_notify; wl_signal_add(&backend->events.new_input, &state.new_input); diff --git a/examples/tablet.c b/examples/tablet.c index 5d0e8dcc3..234bfb991 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ struct sample_state { struct wl_display *display; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; bool proximity, tap, button; double distance; double pressure; @@ -237,6 +239,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->output = output; sample_output->sample = sample; @@ -361,11 +366,14 @@ int main(int argc, char *argv[]) { state.new_input.notify = new_input_notify; clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - state.renderer = wlr_backend_get_renderer(wlr); + state.renderer = wlr_renderer_autocreate(wlr); if (!state.renderer) { wlr_log(WLR_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); } + + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + if (!wlr_backend_start(wlr)) { wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(wlr); diff --git a/examples/touch.c b/examples/touch.c index 0c9cd2b40..ae2dcf8fc 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -10,8 +10,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -23,6 +24,7 @@ struct sample_state { struct wl_display *display; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_texture *cat_texture; struct wl_list touch_points; struct timespec last_frame; @@ -148,6 +150,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) { static void new_output_notify(struct wl_listener *listener, void *data) { struct wlr_output *output = data; struct sample_state *sample = wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); sample_output->output = output; sample_output->sample = sample; @@ -254,8 +259,7 @@ int main(int argc, char *argv[]) { state.new_input.notify = new_input_notify; clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - - state.renderer = wlr_backend_get_renderer(wlr); + state.renderer = wlr_renderer_autocreate(wlr); if (!state.renderer) { wlr_log(WLR_ERROR, "Could not start compositor, OOM"); exit(EXIT_FAILURE); @@ -268,6 +272,8 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } + state.allocator = wlr_allocator_autocreate(wlr, state.renderer); + if (!wlr_backend_start(wlr)) { wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(wlr); From a6538ced35872a86d37d6ca32b1d9ddb5fe2c4b7 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:42:06 -0500 Subject: [PATCH 008/190] tinywl: autocreate allocator and init output --- tinywl/tinywl.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index b11549bea..82f0977a2 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ struct tinywl_server { struct wl_display *wl_display; struct wlr_backend *backend; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_xdg_shell *xdg_shell; struct wl_listener new_xdg_surface; @@ -676,6 +678,10 @@ static void server_new_output(struct wl_listener *listener, void *data) { } } + /* Configures the output created by the backend to use our allocator + * and our renderer */ + wlr_output_init_render(wlr_output, server->allocator, server->renderer); + /* Allocates and configures our state for this output */ struct tinywl_output *output = calloc(1, sizeof(struct tinywl_output)); @@ -841,12 +847,20 @@ int main(int argc, char *argv[]) { * if an X11 server is running. */ server.backend = wlr_backend_autocreate(server.wl_display); - /* If we don't provide a renderer, autocreate makes a GLES2 renderer for us. + /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user + * can also specify a renderer using the WLR_RENDERER env var. * The renderer is responsible for defining the various pixel formats it * supports for shared memory, this configures that for clients. */ - server.renderer = wlr_backend_get_renderer(server.backend); + server.renderer = wlr_renderer_autocreate(server.backend); wlr_renderer_init_wl_display(server.renderer, server.wl_display); + /* Autocreates an allocator for us. + * The allocator is the bridge between the renderer and the backend. It + * handles the buffer creation, allowing wlroots to render onto the + * screen */ + server.allocator = wlr_allocator_autocreate(server.backend, + server.renderer); + /* This creates some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device manager * handles the clipboard. Each of these wlroots interfaces has room for you From 0c76aef2022525e9346b59596b5fa6e08b462998 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 12:10:57 -0500 Subject: [PATCH 009/190] backend: remove backend ensure renderer and allocator check --- backend/backend.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index f8fa45c4a..16ad309f4 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -208,21 +208,6 @@ static size_t parse_outputs_env(const char *name) { return outputs; } -static struct wlr_backend *ensure_backend_renderer_and_allocator( - struct wlr_backend *backend) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(backend); - if (renderer == NULL) { - wlr_backend_destroy(backend); - return NULL; - } - struct wlr_allocator *allocator = backend_get_allocator(backend); - if (allocator == NULL) { - wlr_backend_destroy(backend); - return NULL; - } - return backend; -} - static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { struct wlr_backend *backend = wlr_wl_backend_create(display, NULL); if (backend == NULL) { @@ -234,7 +219,7 @@ static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { wlr_wl_output_create(backend); } - return ensure_backend_renderer_and_allocator(backend); + return backend; } #if WLR_HAS_X11_BACKEND @@ -250,7 +235,7 @@ static struct wlr_backend *attempt_x11_backend(struct wl_display *display, wlr_x11_output_create(backend); } - return ensure_backend_renderer_and_allocator(backend); + return backend; } #endif @@ -266,7 +251,7 @@ static struct wlr_backend *attempt_headless_backend( wlr_headless_add_output(backend, 1280, 720); } - return ensure_backend_renderer_and_allocator(backend); + return backend; } static struct wlr_backend *attempt_noop_backend(struct wl_display *display) { @@ -320,7 +305,7 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, return NULL; } - return ensure_backend_renderer_and_allocator(primary_drm); + return backend; } #endif From 6dc6af1534534394e62761bda7c7dbf01aaa3144 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 16 Nov 2021 09:26:44 -0500 Subject: [PATCH 010/190] backend: remove backend_get_allocator --- backend/backend.c | 18 ------------------ include/backend/backend.h | 6 ------ include/wlr/backend.h | 1 - 3 files changed, 25 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index 16ad309f4..634e53b69 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -45,7 +45,6 @@ void wlr_backend_init(struct wlr_backend *backend, void wlr_backend_finish(struct wlr_backend *backend) { wlr_signal_emit_safe(&backend->events.destroy, backend); - wlr_allocator_destroy(backend->allocator); if (backend->has_own_renderer) { wlr_renderer_destroy(backend->renderer); } @@ -175,23 +174,6 @@ uint32_t backend_get_buffer_caps(struct wlr_backend *backend) { return backend->impl->get_buffer_caps(backend); } -struct wlr_allocator *backend_get_allocator(struct wlr_backend *backend) { - if (backend->allocator != NULL) { - return backend->allocator; - } - - struct wlr_renderer *renderer = wlr_backend_get_renderer(backend); - if (renderer == NULL) { - return NULL; - } - - backend->allocator = wlr_allocator_autocreate(backend, renderer); - if (backend->allocator == NULL) { - wlr_log(WLR_ERROR, "Failed to create backend allocator"); - } - return backend->allocator; -} - static size_t parse_outputs_env(const char *name) { const char *outputs_str = getenv(name); if (outputs_str == NULL) { diff --git a/include/backend/backend.h b/include/backend/backend.h index 7d88cd79d..8c7440c3d 100644 --- a/include/backend/backend.h +++ b/include/backend/backend.h @@ -10,10 +10,4 @@ */ uint32_t backend_get_buffer_caps(struct wlr_backend *backend); -/** - * Get the backend's allocator. Automatically creates the allocator if - * necessary. - */ -struct wlr_allocator *backend_get_allocator(struct wlr_backend *backend); - #endif diff --git a/include/wlr/backend.h b/include/wlr/backend.h index d616fa1db..9da840394 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -30,7 +30,6 @@ struct wlr_backend { bool has_own_renderer; struct wlr_renderer *renderer; - struct wlr_allocator *allocator; }; /** From d07c87f668877c570a3de4ca5a34b05fd3ba3661 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 12:41:57 -0500 Subject: [PATCH 011/190] types/wlr_screencopy_v1: use renderer from output --- types/wlr_screencopy_v1.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 3f3d3bc5a..e0e7916ba 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -192,7 +192,7 @@ static bool frame_shm_copy(struct wlr_screencopy_frame_v1 *frame, uint32_t *flags) { struct wl_shm_buffer *shm_buffer = frame->shm_buffer; struct wlr_output *output = frame->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); int x = frame->box.x; @@ -257,7 +257,7 @@ error_src_tex: static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame) { struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; struct wlr_output *output = frame->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); // TODO: add support for copying regions with DMA-BUFs @@ -276,7 +276,7 @@ static void frame_handle_output_commit(struct wl_listener *listener, wl_container_of(listener, frame, output_commit); struct wlr_output_event_commit *event = data; struct wlr_output *output = frame->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { @@ -538,7 +538,7 @@ static void capture_output(struct wl_client *wl_client, goto error; } - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); uint32_t drm_format = wlr_output_preferred_read_format(frame->output); From 5a98eae0dce0cf4d64406a48beefaff70b5074bd Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 12:50:37 -0500 Subject: [PATCH 012/190] types/wlr_scene: use renderer from wlr_output --- types/scene/wlr_scene.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 5a2528d1b..b6eed4177 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -605,7 +605,7 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, } static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); struct wlr_box box = { @@ -628,7 +628,7 @@ static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { static void render_rect(struct wlr_output *output, pixman_region32_t *output_damage, const float color[static 4], const struct wlr_box *box, const float matrix[static 9]) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); pixman_region32_t damage; @@ -650,7 +650,7 @@ static void render_texture(struct wlr_output *output, pixman_region32_t *output_damage, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); struct wlr_fbox default_src_box = {0}; @@ -726,7 +726,7 @@ static void render_node_iterator(struct wlr_scene_node *node, case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); if (texture == NULL) { return; @@ -768,8 +768,7 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, damage = &full_region; } - struct wlr_renderer *renderer = - wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); if (output->enabled && pixman_region32_not_empty(damage)) { @@ -919,7 +918,7 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); bool scanout = scene_output_scanout(scene_output); From 5f111986056ff398e72d819481b6270c2b6dcbf6 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 12:53:03 -0500 Subject: [PATCH 013/190] backend/x11: get renderer from wlr_x11_output --- backend/x11/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/x11/output.c b/backend/x11/output.c index 76172582f..9081769e3 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -376,7 +376,7 @@ static void update_x11_output_cursor(struct wlr_x11_output *output, static bool output_cursor_to_picture(struct wlr_x11_output *output, struct wlr_buffer *buffer) { struct wlr_x11_backend *x11 = output->x11; - struct wlr_renderer *renderer = wlr_backend_get_renderer(&x11->backend); + struct wlr_renderer *renderer = output->wlr_output.renderer; if (output->cursor.pic != XCB_NONE) { xcb_render_free_picture(x11->xcb, output->cursor.pic); From a1430933392aabc25040cb22e6e4a0d6517b39b5 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:24:55 -0500 Subject: [PATCH 014/190] backend/headless: don't store the parent renderer --- backend/headless/backend.c | 39 +++----------------------------------- include/backend/headless.h | 2 -- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 49c2c8bac..886be2761 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -51,7 +51,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { } wl_list_remove(&backend->display_destroy.link); - wl_list_remove(&backend->parent_renderer_destroy.link); struct wlr_headless_output *output, *output_tmp; wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) { @@ -70,17 +69,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { free(backend); } -static struct wlr_renderer *backend_get_renderer( - struct wlr_backend *wlr_backend) { - struct wlr_headless_backend *backend = - headless_backend_from_backend(wlr_backend); - if (backend->parent_renderer != NULL) { - return backend->parent_renderer; - } else { - return wlr_backend->renderer; - } -} - static int backend_get_drm_fd(struct wlr_backend *wlr_backend) { struct wlr_headless_backend *backend = headless_backend_from_backend(wlr_backend); @@ -96,7 +84,6 @@ static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) { static const struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, - .get_renderer = backend_get_renderer, .get_drm_fd = backend_get_drm_fd, .get_buffer_caps = get_buffer_caps, }; @@ -107,33 +94,13 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { backend_destroy(&backend->backend); } -static void handle_renderer_destroy(struct wl_listener *listener, void *data) { - struct wlr_headless_backend *backend = - wl_container_of(listener, backend, parent_renderer_destroy); - backend_destroy(&backend->backend); -} - static bool backend_init(struct wlr_headless_backend *backend, - struct wl_display *display, struct wlr_renderer *renderer) { + struct wl_display *display) { wlr_backend_init(&backend->backend, &backend_impl); backend->display = display; wl_list_init(&backend->outputs); wl_list_init(&backend->input_devices); - wl_list_init(&backend->parent_renderer_destroy.link); - - if (renderer == NULL) { - renderer = wlr_renderer_autocreate(&backend->backend); - if (!renderer) { - wlr_log(WLR_ERROR, "Failed to create renderer"); - return false; - } - backend->backend.renderer = renderer; - } else { - backend->parent_renderer = renderer; - backend->parent_renderer_destroy.notify = handle_renderer_destroy; - wl_signal_add(&renderer->events.destroy, &backend->parent_renderer_destroy); - } backend->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &backend->display_destroy); @@ -202,7 +169,7 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { wlr_log(WLR_ERROR, "Failed to open DRM render node"); } - if (!backend_init(backend, display, NULL)) { + if (!backend_init(backend, display)) { goto error_init; } @@ -236,7 +203,7 @@ struct wlr_backend *wlr_headless_backend_create_with_renderer( } } - if (!backend_init(backend, display, renderer)) { + if (!backend_init(backend, display)) { goto error_init; } diff --git a/include/backend/headless.h b/include/backend/headless.h index 42a07db8d..09d5856b2 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -14,8 +14,6 @@ struct wlr_headless_backend { size_t last_output_num; struct wl_list input_devices; struct wl_listener display_destroy; - struct wlr_renderer *parent_renderer; - struct wl_listener parent_renderer_destroy; bool started; }; From 42549a1c9a43ed4ed313d84a5252a8e3fc34c55c Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:28:43 -0500 Subject: [PATCH 015/190] backend/drm: stop initializing backend renderer --- backend/drm/backend.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index cd5b8ee0e..ca91be15b 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -232,10 +232,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, } if (drm->parent) { - // Ensure we use the same renderer as the parent backend - drm->backend.renderer = wlr_backend_get_renderer(&drm->parent->backend); - assert(drm->backend.renderer != NULL); - if (!init_drm_renderer(drm, &drm->mgpu_renderer)) { wlr_log(WLR_ERROR, "Failed to initialize renderer"); goto error_resources; From d1ebd52ab28a4758d1760e2f50181474e7f49e2f Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:29:59 -0500 Subject: [PATCH 016/190] backend/multi: remove backend_get_renderer --- backend/multi/backend.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/backend/multi/backend.c b/backend/multi/backend.c index ffe794762..2309691d4 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -64,20 +64,6 @@ static void multi_backend_destroy(struct wlr_backend *wlr_backend) { free(backend); } -static struct wlr_renderer *multi_backend_get_renderer( - struct wlr_backend *backend) { - struct wlr_multi_backend *multi = multi_backend_from_backend(backend); - - struct subbackend_state *sub; - wl_list_for_each(sub, &multi->backends, link) { - struct wlr_renderer *rend = wlr_backend_get_renderer(sub->backend); - if (rend != NULL) { - return rend; - } - } - return NULL; -} - static struct wlr_session *multi_backend_get_session( struct wlr_backend *_backend) { struct wlr_multi_backend *backend = multi_backend_from_backend(_backend); @@ -136,7 +122,6 @@ static uint32_t multi_backend_get_buffer_caps(struct wlr_backend *backend) { static const struct wlr_backend_impl backend_impl = { .start = multi_backend_start, .destroy = multi_backend_destroy, - .get_renderer = multi_backend_get_renderer, .get_session = multi_backend_get_session, .get_presentation_clock = multi_backend_get_presentation_clock, .get_drm_fd = multi_backend_get_drm_fd, @@ -211,15 +196,6 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi, return true; } - struct wlr_renderer *multi_renderer = - multi_backend_get_renderer(&multi->backend); - struct wlr_renderer *backend_renderer = wlr_backend_get_renderer(backend); - if (multi_renderer != NULL && backend_renderer != NULL && multi_renderer != backend_renderer) { - wlr_log(WLR_ERROR, "Could not add backend: multiple renderers at the " - "same time aren't supported"); - return false; - } - struct subbackend_state *sub = calloc(1, sizeof(struct subbackend_state)); if (sub == NULL) { wlr_log(WLR_ERROR, "Could not add backend: allocation failed"); From fdf3169b4185dad34b01b62762a0218f1412897f Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:30:38 -0500 Subject: [PATCH 017/190] backend: remove wlr_backend_get_renderer --- backend/backend.c | 33 --------------------------------- include/wlr/backend.h | 9 --------- include/wlr/backend/interface.h | 1 - 3 files changed, 43 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index 634e53b69..cd96377b4 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -45,9 +45,6 @@ void wlr_backend_init(struct wlr_backend *backend, void wlr_backend_finish(struct wlr_backend *backend) { wlr_signal_emit_safe(&backend->events.destroy, backend); - if (backend->has_own_renderer) { - wlr_renderer_destroy(backend->renderer); - } } bool wlr_backend_start(struct wlr_backend *backend) { @@ -69,36 +66,6 @@ void wlr_backend_destroy(struct wlr_backend *backend) { } } -static bool backend_create_renderer(struct wlr_backend *backend) { - if (backend->renderer != NULL) { - return true; - } - - backend->renderer = wlr_renderer_autocreate(backend); - if (backend->renderer == NULL) { - return false; - } - - backend->has_own_renderer = true; - return true; -} - -struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend) { - if (backend->impl->get_renderer) { - return backend->impl->get_renderer(backend); - } - if (backend_get_buffer_caps(backend) != 0) { - // If the backend is capable of presenting buffers, automatically create - // the renderer if necessary. - if (!backend_create_renderer(backend)) { - wlr_log(WLR_ERROR, "Failed to create backend renderer"); - return NULL; - } - return backend->renderer; - } - return NULL; -} - struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) { if (backend->impl->get_session) { return backend->impl->get_session(backend); diff --git a/include/wlr/backend.h b/include/wlr/backend.h index 9da840394..d781f74de 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -25,11 +25,6 @@ struct wlr_backend { /** Raised when new outputs are added, passed the wlr_output */ struct wl_signal new_output; } events; - - // Private state - - bool has_own_renderer; - struct wlr_renderer *renderer; }; /** @@ -49,10 +44,6 @@ bool wlr_backend_start(struct wlr_backend *backend); * automatically when the wl_display is destroyed. */ void wlr_backend_destroy(struct wlr_backend *backend); -/** - * Obtains the wlr_renderer reference this backend is using. - */ -struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend); /** * Obtains the wlr_session reference from this backend if there is any. * Might return NULL for backends that don't use a session. diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index 529f8f87a..f0cafb015 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -16,7 +16,6 @@ struct wlr_backend_impl { bool (*start)(struct wlr_backend *backend); void (*destroy)(struct wlr_backend *backend); - struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend); struct wlr_session *(*get_session)(struct wlr_backend *backend); clockid_t (*get_presentation_clock)(struct wlr_backend *backend); int (*get_drm_fd)(struct wlr_backend *backend); From e736ebc63cfdf5fb1e8a0b082cf15086875d9a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Thu, 18 Nov 2021 23:06:13 -0300 Subject: [PATCH 018/190] docs: mention WLR_RENDERER=vulkan. This option was added with commit 8e346922508aa3eaccd6e12f2917f6574f349843. --- docs/env_vars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/env_vars.md b/docs/env_vars.md index 1d39a6249..2959ab581 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -10,7 +10,7 @@ wlroots reads these environment variables * *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead of following shell search semantics for "Xwayland") * *WLR_RENDERER*: forces the creation of a specified renderer (available - renderers: gles2, pixman) + renderers: gles2, pixman, vulkan) ## DRM backend From 33eba9080c5fb54484bd6f39a9f38d48b31a2dd4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 19 Nov 2021 15:24:07 +0100 Subject: [PATCH 019/190] output: fix renderer buffer cap sanity check in wlr_output_init_render The backend and renderer don't directly interact together, so there's no point in checking that their buffer caps intersect. What we want to check is that: - The backend and allocator buffer caps are compatible, because the backend consumes buffers to display them. - The renderer and allocator buffer caps are compatible, because the renderer imports buffers to sample them or render to them. For instance, when running with the DRM backend and the Pixman renderer, the (backend & renderer) check will fail because backend = DMABUF and renderer = DATA_PTR. --- types/output/render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/output/render.c b/types/output/render.c index 2f6fe2600..5bf5530e7 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -23,8 +23,8 @@ bool wlr_output_init_render(struct wlr_output *output, wlr_log(WLR_ERROR, "output backend and allocator buffer capabilities " "don't match"); return false; - } else if (!(backend_caps & renderer_caps)) { - wlr_log(WLR_ERROR, "output backend and renderer buffer capabilities " + } else if (!(renderer_caps & allocator->buffer_caps)) { + wlr_log(WLR_ERROR, "renderer and allocator buffer capabilities " "don't match"); return false; } From 25bb92faeec27fa67340eb417d427ce721dc3218 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 19 Nov 2021 10:44:45 -0500 Subject: [PATCH 020/190] backend/multi: add asserts in wlr_multi_backend_add --- backend/multi/backend.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 2309691d4..b06bc4865 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -189,6 +189,9 @@ static struct subbackend_state *multi_backend_get_subbackend(struct wlr_multi_ba bool wlr_multi_backend_add(struct wlr_backend *_multi, struct wlr_backend *backend) { + assert(_multi && backend); + assert(_multi != backend); + struct wlr_multi_backend *multi = multi_backend_from_backend(_multi); if (multi_backend_get_subbackend(multi, backend)) { From c0fd60be633945fd7381a5b995572e4f2350a31e Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 19 Nov 2021 10:41:52 -0500 Subject: [PATCH 021/190] backend: fix attempt_backend_by_name multi backend self insertion --- backend/backend.c | 50 +++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index cd96377b4..7f0de3c2c 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -258,46 +258,46 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, } #endif -static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, - struct wlr_backend *backend, struct wlr_session **session, - const char *name) { +static bool attempt_backend_by_name(struct wl_display *display, + struct wlr_multi_backend *multi, char *name) { + struct wlr_backend *backend = NULL; if (strcmp(name, "wayland") == 0) { - return attempt_wl_backend(display); + backend = attempt_wl_backend(display); #if WLR_HAS_X11_BACKEND } else if (strcmp(name, "x11") == 0) { - return attempt_x11_backend(display, NULL); + backend = attempt_x11_backend(display, NULL); #endif } else if (strcmp(name, "headless") == 0) { - return attempt_headless_backend(display); + backend = attempt_headless_backend(display); } else if (strcmp(name, "noop") == 0) { - return attempt_noop_backend(display); + backend = attempt_noop_backend(display); } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { // DRM and libinput need a session - if (!*session) { - *session = session_create_and_wait(display); - if (!*session) { + if (multi->session == NULL) { + multi->session = session_create_and_wait(display); + if (multi->session == NULL) { wlr_log(WLR_ERROR, "failed to start a session"); - return NULL; + return false; } } if (strcmp(name, "libinput") == 0) { #if WLR_HAS_LIBINPUT_BACKEND - return wlr_libinput_backend_create(display, *session); -#else - return NULL; + backend = wlr_libinput_backend_create(display, multi->session); #endif } else { #if WLR_HAS_DRM_BACKEND - return attempt_drm_backend(display, backend, *session); -#else - return NULL; + // attempt_drm_backend adds the multi drm backends itself + return attempt_drm_backend(display, &multi->backend, + multi->session) != NULL; #endif } + } else { + wlr_log(WLR_ERROR, "unrecognized backend '%s'", name); + return false; } - wlr_log(WLR_ERROR, "unrecognized backend '%s'", name); - return NULL; + return wlr_multi_backend_add(&multi->backend, backend); } struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { @@ -323,17 +323,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { char *saveptr; char *name = strtok_r(names, ",", &saveptr); while (name != NULL) { - struct wlr_backend *subbackend = attempt_backend_by_name(display, - backend, &multi->session, name); - if (subbackend == NULL) { - wlr_log(WLR_ERROR, "failed to start backend '%s'", name); - wlr_session_destroy(multi->session); - wlr_backend_destroy(backend); - free(names); - return NULL; - } - - if (!wlr_multi_backend_add(backend, subbackend)) { + if (!attempt_backend_by_name(display, multi, name)) { wlr_log(WLR_ERROR, "failed to add backend '%s'", name); wlr_session_destroy(multi->session); wlr_backend_destroy(backend); From ee210758fca4182e1ba3a37051fb3d7eec099da4 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 19 Nov 2021 10:17:04 -0500 Subject: [PATCH 022/190] tinywl: init output render before commit --- tinywl/tinywl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 82f0977a2..ab5ed7ce4 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -664,6 +664,10 @@ static void server_new_output(struct wl_listener *listener, void *data) { wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; + /* Configures the output created by the backend to use our allocator + * and our renderer. Must be done once, before commiting the output */ + wlr_output_init_render(wlr_output, server->allocator, server->renderer); + /* Some backends don't have modes. DRM+KMS does, and we need to set a mode * before we can use the output. The mode is a tuple of (width, height, * refresh rate), and each monitor supports only a specific set of modes. We @@ -678,10 +682,6 @@ static void server_new_output(struct wl_listener *listener, void *data) { } } - /* Configures the output created by the backend to use our allocator - * and our renderer */ - wlr_output_init_render(wlr_output, server->allocator, server->renderer); - /* Allocates and configures our state for this output */ struct tinywl_output *output = calloc(1, sizeof(struct tinywl_output)); From 7508f87fcbfa8c9feb72fcd38f323113059c1b83 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Wed, 10 Nov 2021 22:54:04 -0500 Subject: [PATCH 023/190] output: lift up output format fallback logic This makes it possible for the two functions using output_pick_format (output_pick_cursor_format and output_create_swapchain) to select different buffer formats. --- include/types/wlr_output.h | 2 +- types/output/cursor.c | 8 ++++- types/output/render.c | 66 ++++++++++++++++++-------------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index cde64e3ac..1159d00a1 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -8,7 +8,7 @@ void output_pending_resolution(struct wlr_output *output, int *width, int *height); struct wlr_drm_format *output_pick_format(struct wlr_output *output, - const struct wlr_drm_format_set *display_formats); + const struct wlr_drm_format_set *display_formats, uint32_t format); void output_clear_back_buffer(struct wlr_output *output); bool output_ensure_buffer(struct wlr_output *output); diff --git a/types/output/cursor.c b/types/output/cursor.c index f1e6aee5e..e14142017 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -206,7 +206,13 @@ static struct wlr_drm_format *output_pick_cursor_format(struct wlr_output *outpu } } - return output_pick_format(output, display_formats); + struct wlr_drm_format *format = output_pick_format(output, display_formats, + DRM_FORMAT_ARGB8888); + if (format == NULL) { + format = output_pick_format(output, display_formats, + DRM_FORMAT_XRGB8888); + } + return format; } static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor) { diff --git a/types/output/render.c b/types/output/render.c index 5bf5530e7..8b35355d9 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -66,7 +66,12 @@ static bool output_create_swapchain(struct wlr_output *output, } } - struct wlr_drm_format *format = output_pick_format(output, display_formats); + struct wlr_drm_format *format = output_pick_format(output, display_formats, + DRM_FORMAT_ARGB8888); + if (format == NULL) { + format = output_pick_format(output, display_formats, + DRM_FORMAT_XRGB8888); + } if (format == NULL) { wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'", output->name); @@ -231,7 +236,8 @@ void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) { } struct wlr_drm_format *output_pick_format(struct wlr_output *output, - const struct wlr_drm_format_set *display_formats) { + const struct wlr_drm_format_set *display_formats, + uint32_t fmt) { struct wlr_renderer *renderer = output->renderer; struct wlr_allocator *allocator = output->allocator; assert(renderer != NULL && allocator != NULL); @@ -243,41 +249,31 @@ struct wlr_drm_format *output_pick_format(struct wlr_output *output, return NULL; } - struct wlr_drm_format *format = NULL; - const uint32_t candidates[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 }; - for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); i++) { - uint32_t fmt = candidates[i]; - - const struct wlr_drm_format *render_format = - wlr_drm_format_set_get(render_formats, fmt); - if (render_format == NULL) { - wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt); - continue; - } - - if (display_formats != NULL) { - const struct wlr_drm_format *display_format = - wlr_drm_format_set_get(display_formats, fmt); - if (display_format == NULL) { - wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt); - continue; - } - format = wlr_drm_format_intersect(display_format, render_format); - } else { - // The output can display any format - format = wlr_drm_format_dup(render_format); - } - - if (format == NULL) { - wlr_log(WLR_DEBUG, "Failed to intersect display and render " - "modifiers for format 0x%"PRIX32, fmt); - } else { - break; - } + const struct wlr_drm_format *render_format = + wlr_drm_format_set_get(render_formats, fmt); + if (render_format == NULL) { + wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt); + return NULL; } + + struct wlr_drm_format *format = NULL; + if (display_formats != NULL) { + const struct wlr_drm_format *display_format = + wlr_drm_format_set_get(display_formats, fmt); + if (display_format == NULL) { + wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt); + return NULL; + } + format = wlr_drm_format_intersect(display_format, render_format); + } else { + // The output can display any format + format = wlr_drm_format_dup(render_format); + } + if (format == NULL) { - wlr_log(WLR_ERROR, "Failed to choose a format for output '%s'", - output->name); + wlr_log(WLR_DEBUG, "Failed to intersect display and render " + "modifiers for format 0x%"PRIX32 " on output '%s", + fmt, output->name); return NULL; } From 3d7d6ec06ff519e4b28198fd514d511c6d670b0b Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Wed, 10 Nov 2021 22:59:31 -0500 Subject: [PATCH 024/190] output: use XRGB8888 format instead of ARGB8888 Most (and possibly all) compositors using wlroots only ever render fully opaque content. To provide better performance, this change switches the default format used by wlr_output buffers from ARGB8888 to the opaque XRGB8888. Compositors like mutter, kwin, and weston already default to XRGB8888, so this change is unlikely to expose any new bugs in underlying drivers and hardware. This does not affect the hardware cursor's buffer format, which is still ARGB8888 by default. As part of this change, the X11 backend (which does not support changing format at runtime) now picks a true color, 24 bit depth visual (i.e. XRGB8888) instead of a 32 bit depth (ARGB8888) one. --- backend/x11/backend.c | 4 ++-- types/output/render.c | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 9eaf56644..6db9aa6c9 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -572,9 +572,9 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, goto error_event; } - x11->depth = get_depth(x11->screen, 32); + x11->depth = get_depth(x11->screen, 24); if (!x11->depth) { - wlr_log(WLR_ERROR, "Failed to get 32-bit depth for X11 screen"); + wlr_log(WLR_ERROR, "Failed to get 24-bit depth for X11 screen"); goto error_event; } diff --git a/types/output/render.c b/types/output/render.c index 8b35355d9..adce1ee33 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -67,11 +67,7 @@ static bool output_create_swapchain(struct wlr_output *output, } struct wlr_drm_format *format = output_pick_format(output, display_formats, - DRM_FORMAT_ARGB8888); - if (format == NULL) { - format = output_pick_format(output, display_formats, - DRM_FORMAT_XRGB8888); - } + DRM_FORMAT_XRGB8888); if (format == NULL) { wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'", output->name); From e879d566bb5e0140036170b73757a613de51e4ca Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Wed, 10 Nov 2021 23:20:10 -0500 Subject: [PATCH 025/190] output: Add function to set preferred render format This change introduces new double buffered state to the wlr_output, corresponding to the buffer format to render to. The format being rendered to does not control the bit depth of colors being sent to the display; it does generally determine the format with which screenshot data is provided. The DRM backend _may_ sent higher bit depths if the render format depth is increased, but hardware and other limitations may apply. --- include/wlr/interfaces/wlr_output.h | 1 + include/wlr/types/wlr_output.h | 19 ++++++++++++ types/output/output.c | 46 +++++++++++++++++++++++++++++ types/output/render.c | 22 +++++++++----- 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 100754f68..5ae1ab56f 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -21,6 +21,7 @@ (WLR_OUTPUT_STATE_DAMAGE | \ WLR_OUTPUT_STATE_SCALE | \ WLR_OUTPUT_STATE_TRANSFORM | \ + WLR_OUTPUT_STATE_RENDER_FORMAT | \ WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) /** diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 9d3dc3cbf..7d7fbaad8 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -61,6 +61,7 @@ enum wlr_output_state_field { WLR_OUTPUT_STATE_TRANSFORM = 1 << 5, WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED = 1 << 6, WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7, + WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 8, }; enum wlr_output_state_mode_type { @@ -78,6 +79,7 @@ struct wlr_output_state { float scale; enum wl_output_transform transform; bool adaptive_sync_enabled; + uint32_t render_format; // only valid if WLR_OUTPUT_STATE_BUFFER struct wlr_buffer *buffer; @@ -134,6 +136,7 @@ struct wlr_output { enum wl_output_subpixel subpixel; enum wl_output_transform transform; enum wlr_output_adaptive_sync_status adaptive_sync_status; + uint32_t render_format; bool needs_frame; // damage for cursors and fullscreen surface, in output-local coordinates @@ -308,6 +311,22 @@ void wlr_output_set_transform(struct wlr_output *output, * Adaptive sync is double-buffered state, see `wlr_output_commit`. */ void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled); +/** + * Set the output buffer render format. Default value: DRM_FORMAT_XRGB8888 + * + * While high bit depth render formats are necessary for a monitor to receive + * useful high bit data, they do not guarantee it; a DRM_FORMAT_XBGR2101010 + * buffer will only lead to sending 10-bpc image data to the monitor if + * hardware and software permit this. + * + * This only affects the format of the output buffer used when rendering, + * as with `wlr_output_attach_render`. It has no impact on the cursor buffer + * format, or on the formats supported for direct scan-out (see also + * `wlr_output_attach_buffer`). + * + * This format is double-buffered state, see `wlr_output_commit`. + */ +void wlr_output_set_render_format(struct wlr_output *output, uint32_t format); /** * Sets a scale for the output. * diff --git a/types/output/output.c b/types/output/output.c index 4e3f403ff..76c9ed9e9 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -1,10 +1,13 @@ #define _POSIX_C_SOURCE 200809L #include +#include +#include #include #include #include #include #include +#include "render/allocator/allocator.h" #include "render/swapchain.h" #include "types/wlr_output.h" #include "util/global.h" @@ -296,6 +299,16 @@ void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled) { output->pending.adaptive_sync_enabled = enabled; } +void wlr_output_set_render_format(struct wlr_output *output, uint32_t format) { + if (output->render_format == format) { + output->pending.committed &= ~WLR_OUTPUT_STATE_RENDER_FORMAT; + return; + } + + output->pending.committed |= WLR_OUTPUT_STATE_RENDER_FORMAT; + output->pending.render_format = format; +} + void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel subpixel) { if (output->subpixel == subpixel) { @@ -343,6 +356,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->impl = impl; output->display = display; wl_list_init(&output->modes); + output->render_format = DRM_FORMAT_XRGB8888; output->transform = WL_OUTPUT_TRANSFORM_NORMAL; output->scale = 1; output->commit_seq = 0; @@ -542,6 +556,30 @@ static bool output_basic_test(struct wlr_output *output) { } } + if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + struct wlr_allocator *allocator = output->allocator; + assert(allocator != NULL); + + const struct wlr_drm_format_set *display_formats = NULL; + if (output->impl->get_primary_formats) { + display_formats = + output->impl->get_primary_formats(output, allocator->buffer_caps); + if (display_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get primary display formats"); + return false; + } + } + + struct wlr_drm_format *format = output_pick_format(output, display_formats, + output->pending.render_format); + if (format == NULL) { + wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output"); + return false; + } + + free(format); + } + bool enabled = output->enabled; if (output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { enabled = output->pending.enabled; @@ -569,6 +607,10 @@ static bool output_basic_test(struct wlr_output *output) { wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output"); return false; } + if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + wlr_log(WLR_DEBUG, "Tried to set format for a disabled output"); + return false; + } if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) { wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output"); return false; @@ -642,6 +684,10 @@ bool wlr_output_commit(struct wlr_output *output) { } } + if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + output->render_format = output->pending.render_format; + } + output->commit_seq++; bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE; diff --git a/types/output/render.c b/types/output/render.c index adce1ee33..f23d1a9a8 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -9,6 +9,7 @@ #include "render/drm_format_set.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" +#include "render/pixel_format.h" #include "types/wlr_output.h" bool wlr_output_init_render(struct wlr_output *output, @@ -47,12 +48,6 @@ static bool output_create_swapchain(struct wlr_output *output, int width, height; output_pending_resolution(output, &width, &height); - if (output->swapchain != NULL && output->swapchain->width == width && - output->swapchain->height == height && - (allow_modifiers || output->swapchain->format->len == 0)) { - return true; - } - struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); @@ -67,12 +62,22 @@ static bool output_create_swapchain(struct wlr_output *output, } struct wlr_drm_format *format = output_pick_format(output, display_formats, - DRM_FORMAT_XRGB8888); + output->render_format); if (format == NULL) { wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output '%s'", output->name); return false; } + + if (output->swapchain != NULL && output->swapchain->width == width && + output->swapchain->height == height && + output->swapchain->format->format == format->format && + (allow_modifiers || output->swapchain->format->len == 0)) { + // no change, keep existing swapchain + free(format); + return true; + } + wlr_log(WLR_DEBUG, "Choosing primary buffer format 0x%"PRIX32" for output '%s'", format->format, output->name); @@ -171,6 +176,9 @@ bool output_ensure_buffer(struct wlr_output *output) { if (output->pending.committed & WLR_OUTPUT_STATE_MODE) { needs_new_buffer = true; } + if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + needs_new_buffer = true; + } if (!needs_new_buffer || (output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { return true; From d0bb7df6303cbe919f5d6d456cd4a8d46904b115 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Thu, 18 Nov 2021 17:55:56 -0500 Subject: [PATCH 026/190] output: remove XRGB8888 cursor fallback format All graphics drivers supporting cursor planes support ARGB8888, the default cursor format, so this fallback is almost certainly unused. Essentially all cursor themes use alpha transparency to make it clearer where relative to the screen content the cursor hotspot is. It is better to fall back to a slightly slower software cursor than it is to fall back to the opaque square that is a hardware cursor without an alpha channel. --- types/output/cursor.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/types/output/cursor.c b/types/output/cursor.c index e14142017..8fa2cf010 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -206,13 +206,7 @@ static struct wlr_drm_format *output_pick_cursor_format(struct wlr_output *outpu } } - struct wlr_drm_format *format = output_pick_format(output, display_formats, - DRM_FORMAT_ARGB8888); - if (format == NULL) { - format = output_pick_format(output, display_formats, - DRM_FORMAT_XRGB8888); - } - return format; + return output_pick_format(output, display_formats, DRM_FORMAT_ARGB8888); } static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor) { From a37f538ca0cc6d504358eb797150751b60c4511b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Nov 2021 13:37:24 +0100 Subject: [PATCH 027/190] Introduce WLR_DEVICE_LEASE events This will allow the DRM backend to reload its lessee list. --- backend/session/session.c | 8 ++++++++ include/wlr/backend/session.h | 1 + 2 files changed, 9 insertions(+) diff --git a/backend/session/session.c b/backend/session/session.c index 382f3d60b..e83a8b4c1 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -157,6 +157,14 @@ static void read_udev_change_event(struct wlr_device_change_event *event, if (prop != NULL) { hotplug->prop_id = strtoul(prop, NULL, 10); } + + return; + } + + const char *lease = udev_device_get_property_value(udev_dev, "LEASE"); + if (lease != NULL && strcmp(lease, "1") == 0) { + event->type = WLR_DEVICE_LEASE; + return; } } diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 7d34bfebe..c8461ff7c 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -59,6 +59,7 @@ struct wlr_session_add_event { enum wlr_device_change_type { WLR_DEVICE_HOTPLUG = 1, + WLR_DEVICE_LEASE, }; struct wlr_device_hotplug_event { From 86f5ecf46867236d4b96a3ce1ad664a8963d6ae4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Nov 2021 14:03:59 +0100 Subject: [PATCH 028/190] backend/drm: introduce wlr_drm_lease Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3183 --- backend/drm/drm.c | 79 ++++++++++++++++------------ include/backend/drm/drm.h | 5 +- include/wlr/backend/drm.h | 32 ++++++++--- include/wlr/types/wlr_drm_lease_v1.h | 3 +- types/wlr_drm_lease_v1.c | 17 +++--- 5 files changed, 80 insertions(+), 56 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 3031d09b2..64db81f5c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1554,17 +1554,13 @@ int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend) { return fd; } -/* TODO: make the function return a `wlr_drm_lease` to provide a destroy event - * that can be fired when the kernel notifies us through uevent that the lease - * has been destroyed - */ -int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, - uint32_t *lessee_id) { +struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, + size_t n_outputs, int *lease_fd_ptr) { assert(outputs); if (n_outputs == 0) { wlr_log(WLR_ERROR, "Can't lease 0 outputs"); - return -1; + return NULL; } struct wlr_drm_backend *drm = @@ -1575,11 +1571,11 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, for (size_t i = 0; i < n_outputs; ++i) { struct wlr_drm_connector *conn = get_drm_connector_from_output(outputs[i]); - assert(conn->lessee_id == 0); + assert(conn->lease == NULL); if (conn->backend != drm) { wlr_log(WLR_ERROR, "Can't lease output from different backends"); - return -1; + return NULL; } objects[n_objects++] = conn->id; @@ -1587,7 +1583,7 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, if (!conn->crtc) { wlr_log(WLR_ERROR, "Connector has no CRTC"); - return -1; + return NULL; } objects[n_objects++] = conn->crtc->id; @@ -1604,50 +1600,63 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, assert(n_objects != 0); - wlr_log(WLR_DEBUG, "Issuing DRM lease with the %d objects", n_objects); - int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0, - lessee_id); - if (lease_fd < 0) { - return lease_fd; + struct wlr_drm_lease *lease = calloc(1, sizeof(*lease)); + if (lease == NULL) { + return NULL; } - wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, *lessee_id); + lease->backend = drm; + wl_signal_init(&lease->events.destroy); + + wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects); + int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0, + &lease->lessee_id); + if (lease_fd < 0) { + free(lease); + return NULL; + } + *lease_fd_ptr = lease_fd; + + wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, lease->lessee_id); for (size_t i = 0; i < n_outputs; ++i) { struct wlr_drm_connector *conn = get_drm_connector_from_output(outputs[i]); - conn->lessee_id = *lessee_id; - conn->crtc->lessee_id = *lessee_id; + conn->lease = lease; + conn->crtc->lease = lease; } - return lease_fd; + return lease; } -bool wlr_drm_backend_terminate_lease(struct wlr_backend *backend, - uint32_t lessee_id) { - wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lessee_id); +void wlr_drm_lease_terminate(struct wlr_drm_lease *lease) { + struct wlr_drm_backend *drm = lease->backend; - assert(backend); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); - - int r = drmModeRevokeLease(drm->fd, lessee_id); - if (r < 0) { - wlr_log_errno(WLR_DEBUG, "Failed to terminate lease"); + wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lease->lessee_id); + int ret = drmModeRevokeLease(drm->fd, lease->lessee_id); + if (ret < 0) { + wlr_log_errno(WLR_ERROR, "Failed to terminate lease"); } + drm_lease_destroy(lease); +} + +void drm_lease_destroy(struct wlr_drm_lease *lease) { + struct wlr_drm_backend *drm = lease->backend; + + wlr_signal_emit_safe(&lease->events.destroy, NULL); + struct wlr_drm_connector *conn; wl_list_for_each(conn, &drm->outputs, link) { - if (conn->lessee_id == lessee_id) { - conn->lessee_id = 0; - /* Will be re-initialized in scan_drm_connectors */ + if (conn->lease == lease) { + conn->lease = NULL; } } for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (drm->crtcs[i].lessee_id == lessee_id) { - drm->crtcs[i].lessee_id = 0; + if (drm->crtcs[i].lease == lease) { + drm->crtcs[i].lease = NULL; } } - return r >= 0; + free(lease); } - diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index e045a72ee..d3640afb8 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -36,7 +36,7 @@ struct wlr_drm_plane { struct wlr_drm_crtc { uint32_t id; - uint32_t lessee_id; + struct wlr_drm_lease *lease; // Atomic modesetting only uint32_t mode_id; @@ -118,7 +118,7 @@ struct wlr_drm_connector { enum wlr_drm_connector_status status; bool desired_enabled; uint32_t id; - uint32_t lessee_id; + struct wlr_drm_lease *lease; struct wlr_drm_crtc *crtc; uint32_t possible_crtcs; @@ -157,6 +157,7 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn); bool drm_connector_supports_vrr(struct wlr_drm_connector *conn); size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc); +void drm_lease_destroy(struct wlr_drm_lease *lease); struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 0e9f61081..800bc585f 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -14,6 +14,20 @@ #include #include +struct wlr_drm_backend; + +struct wlr_drm_lease { + int fd; + uint32_t lessee_id; + struct wlr_drm_backend *backend; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + /** * Creates a DRM backend using the specified GPU file descriptor (typically from * a device node in /dev/dri). @@ -41,18 +55,20 @@ uint32_t wlr_drm_connector_get_id(struct wlr_output *output); int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend); /** - * Leases a given output to the caller. The output must be from the associated - * DRM backend. - * Returns a valid opened DRM FD or -1 on error. + * Leases the given outputs to the caller. The outputs must be from the + * associated DRM backend. + * + * Returns NULL on error. */ -int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, - uint32_t *lessee_id); +struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, + size_t n_outputs, int *lease_fd); /** - * Terminates a given lease. The output will be owned again by the backend + * Terminates and destroys a given lease. + * + * The outputs will be owned again by the backend. */ -bool wlr_drm_backend_terminate_lease(struct wlr_backend *backend, - uint32_t lessee_id); +void wlr_drm_lease_terminate(struct wlr_drm_lease *lease); /** * Add mode to the list of available modes diff --git a/include/wlr/types/wlr_drm_lease_v1.h b/include/wlr/types/wlr_drm_lease_v1.h index bf625235d..5b4137c5b 100644 --- a/include/wlr/types/wlr_drm_lease_v1.h +++ b/include/wlr/types/wlr_drm_lease_v1.h @@ -81,14 +81,13 @@ struct wlr_drm_lease_request_v1 { struct wlr_drm_lease_v1 { struct wl_resource *resource; + struct wlr_drm_lease *drm_lease; struct wlr_drm_lease_device_v1 *device; struct wlr_drm_lease_connector_v1 **connectors; size_t n_connectors; - uint32_t lessee_id; - struct wl_list link; // wlr_drm_lease_device_v1::leases void *data; diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index a917930ef..eaca8f170 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -52,13 +52,11 @@ static void drm_lease_v1_destroy(struct wlr_drm_lease_v1 *lease) { return; } - wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->lessee_id); + wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->drm_lease->lessee_id); wp_drm_lease_v1_send_finished(lease->resource); - struct wlr_drm_lease_device_v1 *device = lease->device; - wlr_drm_backend_terminate_lease(device->backend, lease->lessee_id); - lease->lessee_id = 0; + wlr_drm_lease_terminate(lease->drm_lease); for (size_t i = 0; i < lease->n_connectors; ++i) { lease->connectors[i]->active_lease = NULL; @@ -171,10 +169,10 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( outputs[i] = request->connectors[i]->output; } - int fd = wlr_drm_create_lease(outputs, request->n_connectors, - &lease->lessee_id); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "drm_create_lease failed"); + int fd; + lease->drm_lease = wlr_drm_create_lease(outputs, request->n_connectors, &fd); + if (!lease->drm_lease) { + wlr_log(WLR_ERROR, "wlr_drm_create_lease failed"); wp_drm_lease_v1_send_finished(lease->resource); return NULL; } @@ -183,6 +181,7 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( sizeof(struct wlr_drm_lease_connector_v1 *)); if (!lease->connectors) { wlr_log(WLR_ERROR, "Failed to allocate lease connectors list"); + close(fd); wp_drm_lease_v1_send_finished(lease->resource); return NULL; } @@ -212,7 +211,7 @@ void wlr_drm_lease_request_v1_reject( void wlr_drm_lease_v1_revoke(struct wlr_drm_lease_v1 *lease) { assert(lease); - wlr_log(WLR_DEBUG, "Revoking lease %"PRIu32, lease->lessee_id); + wlr_log(WLR_DEBUG, "Revoking lease %"PRIu32, lease->drm_lease->lessee_id); drm_lease_v1_destroy(lease); } From 6bb897330980f65194b75547c3f909e614bdcd49 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Nov 2021 14:22:35 +0100 Subject: [PATCH 029/190] drm-lease-v1: listen to lease destroy event --- include/wlr/types/wlr_drm_lease_v1.h | 2 ++ types/wlr_drm_lease_v1.c | 54 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/include/wlr/types/wlr_drm_lease_v1.h b/include/wlr/types/wlr_drm_lease_v1.h index 5b4137c5b..5a7827ea3 100644 --- a/include/wlr/types/wlr_drm_lease_v1.h +++ b/include/wlr/types/wlr_drm_lease_v1.h @@ -90,6 +90,8 @@ struct wlr_drm_lease_v1 { struct wl_list link; // wlr_drm_lease_device_v1::leases + struct wl_listener destroy; + void *data; }; diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index eaca8f170..7da40686e 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -47,28 +47,6 @@ static struct wlr_drm_lease_v1 *drm_lease_v1_from_resource( return wl_resource_get_user_data(resource); } -static void drm_lease_v1_destroy(struct wlr_drm_lease_v1 *lease) { - if (!lease) { - return; - } - - wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->drm_lease->lessee_id); - - wp_drm_lease_v1_send_finished(lease->resource); - - wlr_drm_lease_terminate(lease->drm_lease); - - 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); -} - static void drm_lease_request_v1_destroy( struct wlr_drm_lease_request_v1 *request) { if (!request) { @@ -93,7 +71,7 @@ static void drm_lease_connector_v1_destroy( wlr_log(WLR_DEBUG, "Destroying connector %s", connector->output->name); if (connector->active_lease) { - drm_lease_v1_destroy(connector->active_lease); + wlr_drm_lease_terminate(connector->active_lease->drm_lease); } struct wl_resource *resource, *tmp; @@ -140,7 +118,7 @@ static void drm_lease_device_v1_destroy( struct wlr_drm_lease_v1 *lease, *tmp_lease; wl_list_for_each_safe(lease, tmp_lease, &device->leases, link) { - drm_lease_v1_destroy(lease); + wlr_drm_lease_terminate(lease->drm_lease); } struct wlr_drm_lease_connector_v1 *connector, *tmp_connector; @@ -154,6 +132,26 @@ static void drm_lease_device_v1_destroy( free(device); } +static void lease_handle_destroy(struct wl_listener *listener, void *data) { + struct wlr_drm_lease_v1 *lease = wl_container_of(listener, lease, destroy); + + wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->drm_lease->lessee_id); + + wp_drm_lease_v1_send_finished(lease->resource); + + 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); +} + struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( struct wlr_drm_lease_request_v1 *request) { assert(request->lease); @@ -191,6 +189,9 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( lease->connectors[i]->active_lease = lease; } + lease->destroy.notify = lease_handle_destroy; + wl_signal_add(&lease->drm_lease->events.destroy, &lease->destroy); + wlr_log(WLR_DEBUG, "Granting request %p", request); wp_drm_lease_v1_send_lease_fd(lease->resource, fd); @@ -212,13 +213,12 @@ void wlr_drm_lease_request_v1_reject( void wlr_drm_lease_v1_revoke(struct wlr_drm_lease_v1 *lease) { assert(lease); wlr_log(WLR_DEBUG, "Revoking lease %"PRIu32, lease->drm_lease->lessee_id); - - drm_lease_v1_destroy(lease); + wlr_drm_lease_terminate(lease->drm_lease); } static void drm_lease_v1_handle_resource_destroy(struct wl_resource *resource) { struct wlr_drm_lease_v1 *lease = drm_lease_v1_from_resource(resource); - drm_lease_v1_destroy(lease); + wlr_drm_lease_terminate(lease->drm_lease); } static void drm_lease_v1_handle_destroy( From e656697a7d6ad851cf299276287665f2aaf80369 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Nov 2021 14:23:00 +0100 Subject: [PATCH 030/190] backend/drm: scan leases on uevent Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3181 --- backend/drm/backend.c | 7 +++++-- backend/drm/drm.c | 30 ++++++++++++++++++++++++++++++ include/backend/drm/drm.h | 1 + 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index ca91be15b..10f324a02 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -133,12 +133,15 @@ static void handle_dev_change(struct wl_listener *listener, void *data) { return; } - // TODO: add and handle lease uevents switch (change->type) { - case WLR_DEVICE_HOTPLUG:; + case WLR_DEVICE_HOTPLUG: wlr_log(WLR_DEBUG, "Received hotplug event for %s", drm->name); scan_drm_connectors(drm, &change->hotplug); break; + case WLR_DEVICE_LEASE: + wlr_log(WLR_DEBUG, "Received lease event for %s", drm->name); + scan_drm_leases(drm); + break; default: wlr_log(WLR_DEBUG, "Received unknown change event for %s", drm->name); } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 64db81f5c..40506cd46 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1425,6 +1425,36 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, } } +void scan_drm_leases(struct wlr_drm_backend *drm) { + drmModeLesseeListRes *list = drmModeListLessees(drm->fd); + if (list == NULL) { + wlr_log_errno(WLR_ERROR, "drmModeListLessees failed"); + return; + } + + struct wlr_drm_connector *conn; + wl_list_for_each(conn, &drm->outputs, link) { + if (conn->lease == NULL) { + continue; + } + + bool found = false; + for (size_t i = 0; i < list->count; i++) { + if (list->lessees[i] == conn->lease->lessee_id) { + found = true; + break; + } + } + if (!found) { + wlr_log(WLR_DEBUG, "DRM lease %"PRIu32" has been terminated", + conn->lease->lessee_id); + drm_lease_destroy(conn->lease); + } + } + + drmFree(list); +} + static int mhz_to_nsec(int mhz) { return 1000000000000LL / mhz; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index d3640afb8..c5d3358f9 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -149,6 +149,7 @@ bool init_drm_resources(struct wlr_drm_backend *drm); void finish_drm_resources(struct wlr_drm_backend *drm); void scan_drm_connectors(struct wlr_drm_backend *state, struct wlr_device_hotplug_event *event); +void scan_drm_leases(struct wlr_drm_backend *drm); int handle_drm_event(int fd, uint32_t mask, void *data); void destroy_drm_connector(struct wlr_drm_connector *conn); bool drm_connector_commit_state(struct wlr_drm_connector *conn, From 52c34e82539e1f09711046a3f1e1fdad100eb5c0 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Thu, 18 Nov 2021 16:29:05 -0500 Subject: [PATCH 031/190] tinywl: build with meson if examples option is enabled --- meson.build | 1 + tinywl/meson.build | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 tinywl/meson.build diff --git a/meson.build b/meson.build index c546b74d0..2f2969496 100644 --- a/meson.build +++ b/meson.build @@ -180,6 +180,7 @@ summary(features + internal_features, bool_yn: true) if get_option('examples') subdir('examples') + subdir('tinywl') endif pkgconfig = import('pkgconfig') diff --git a/tinywl/meson.build b/tinywl/meson.build new file mode 100644 index 000000000..82d31d22f --- /dev/null +++ b/tinywl/meson.build @@ -0,0 +1,5 @@ +executable( + 'tinywl', + ['tinywl.c', protocols_client_header['xdg-shell']], + dependencies: wlroots, +) From d70d74ad4f3069687ed7f98f9cbbe9f6551e05c6 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 19 Nov 2021 10:52:57 -0500 Subject: [PATCH 032/190] ci/archlinux: enable address and undefined sanitizers --- .builds/archlinux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 4d8e3767b..ec98563c9 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -23,14 +23,14 @@ sources: tasks: - setup: | cd wlroots - CC=gcc meson build-gcc --fatal-meson-warnings --default-library=both -Dauto_features=enabled --prefix /usr + CC=gcc meson build-gcc --fatal-meson-warnings --default-library=both -Dauto_features=enabled --prefix /usr -Db_sanitize=address,undefined CC=clang meson build-clang --fatal-meson-warnings -Dauto_features=enabled - gcc: | cd wlroots/build-gcc ninja sudo ninja install cd ../tinywl - make + CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" make - clang: | cd wlroots/build-clang ninja From 3d73b899ffdb6cdb45f69acfa5d7a914943dc592 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 22 Nov 2021 10:32:55 +0100 Subject: [PATCH 033/190] linux-dmabuf-v1: hide wlr_linux_buffer_params_v1 The parameters are used when the client is in the process of building a buffer. There's no reason why this internal implementation detail should be exposed in our public header. --- include/wlr/types/wlr_linux_dmabuf_v1.h | 11 ++++------- types/wlr_linux_dmabuf_v1.c | 7 +++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index a2db7fea3..b4eb8675d 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -20,6 +20,8 @@ struct wlr_dmabuf_v1_buffer { struct wl_resource *resource; // can be NULL if the client destroyed it struct wlr_dmabuf_attributes attributes; + // private state + struct wl_listener release; }; @@ -36,13 +38,6 @@ bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource); struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource( struct wl_resource *buffer_resource); -struct wlr_linux_buffer_params_v1 { - struct wl_resource *resource; - struct wlr_linux_dmabuf_v1 *linux_dmabuf; - struct wlr_dmabuf_attributes attributes; - bool has_modifier; -}; - /* the protocol interface */ struct wlr_linux_dmabuf_v1 { struct wl_global *global; @@ -52,6 +47,8 @@ struct wlr_linux_dmabuf_v1 { struct wl_signal destroy; } events; + // private state + struct wl_listener display_destroy; struct wl_listener renderer_destroy; }; diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 9b4cdd445..63b52023d 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -13,6 +13,13 @@ #define LINUX_DMABUF_VERSION 3 +struct wlr_linux_buffer_params_v1 { + struct wl_resource *resource; + struct wlr_linux_dmabuf_v1 *linux_dmabuf; + struct wlr_dmabuf_attributes attributes; + bool has_modifier; +}; + static void buffer_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); From 3b93da70a0b9419c56958c0095ce441dbc1282b1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 22 Nov 2021 19:29:30 +0100 Subject: [PATCH 034/190] backend/wayland: report parent presentation clock There's no guarantee that the parent Wayland compositor uses CLOCK_MONOTONIC for reporting presentation timestamps, they could be using e.g. CLOCK_MONOTONIC_RAW or another system-specific clock. Forward the value via wlr_backend_impl.get_presentation_clock. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3254#note_1143061 --- backend/wayland/backend.c | 19 +++++++++++++++++++ include/backend/wayland.h | 1 + 2 files changed, 20 insertions(+) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index ea216511c..3d962d4fe 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -75,6 +75,16 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { xdg_wm_base_handle_ping, }; +static void presentation_handle_clock_id(void *data, + struct wp_presentation *presentation, uint32_t clock) { + struct wlr_wl_backend *wl = data; + wl->presentation_clock = clock; +} + +static const struct wp_presentation_listener presentation_listener = { + .clock_id = presentation_handle_clock_id, +}; + static void linux_dmabuf_v1_handle_format(void *data, struct zwp_linux_dmabuf_v1 *linux_dmabuf_v1, uint32_t format) { // Note, this event is deprecated @@ -227,6 +237,8 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, wp_presentation_interface.name) == 0) { wl->presentation = wl_registry_bind(registry, name, &wp_presentation_interface, 1); + wp_presentation_add_listener(wl->presentation, + &presentation_listener, wl); } else if (strcmp(iface, zwp_tablet_manager_v2_interface.name) == 0) { wl->tablet_manager = wl_registry_bind(registry, name, &zwp_tablet_manager_v2_interface, 1); @@ -352,6 +364,11 @@ static void backend_destroy(struct wlr_backend *backend) { free(wl); } +static clockid_t backend_get_presentation_clock(struct wlr_backend *backend) { + struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend); + return wl->presentation_clock; +} + static int backend_get_drm_fd(struct wlr_backend *backend) { struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend); return wl->drm_fd; @@ -366,6 +383,7 @@ static uint32_t get_buffer_caps(struct wlr_backend *backend) { static const struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, + .get_presentation_clock = backend_get_presentation_clock, .get_drm_fd = backend_get_drm_fd, .get_buffer_caps = get_buffer_caps, }; @@ -397,6 +415,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wl_list_init(&wl->outputs); wl_list_init(&wl->seats); wl_list_init(&wl->buffers); + wl->presentation_clock = CLOCK_MONOTONIC; wl->remote_display = wl_display_connect(remote); if (!wl->remote_display) { diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 3235494df..32783597f 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -40,6 +40,7 @@ struct wlr_wl_backend { struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct wl_list seats; // wlr_wl_seat.link struct zwp_tablet_manager_v2 *tablet_manager; + clockid_t presentation_clock; struct wlr_drm_format_set shm_formats; struct wlr_drm_format_set linux_dmabuf_v1_formats; struct wl_drm *legacy_drm; From c9ba9e82b6a829d6e6d5acc65753b3ade46cefb9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 22 Nov 2021 22:43:39 +0100 Subject: [PATCH 035/190] wlr_drag: emit destroy after wl_data_device.leave --- types/data_device/wlr_drag.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 53bf4066a..1952dcb88 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -138,9 +138,6 @@ static void drag_destroy(struct wlr_drag *drag) { } } - // We issue destroy after ending the grab to allow focus changes. - wlr_signal_emit_safe(&drag->events.destroy, drag); - if (drag->started) { drag_set_focus(drag, NULL, 0, 0); @@ -148,6 +145,13 @@ static void drag_destroy(struct wlr_drag *drag) { drag->seat->drag = NULL; } + // We issue destroy after ending the grab to allow focus changes. + // Furthermore, we wait until after clearing the drag focus in order + // to ensure that the wl_data_device.leave is sent before emitting the + // signal. This allows e.g. wl_pointer.enter to be sent in the destroy + // signal handler. + wlr_signal_emit_safe(&drag->events.destroy, drag); + if (drag->source) { wl_list_remove(&drag->source_destroy.link); } From 1d9c1bcea6a223379af63b4d779d53663eaffcf8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 22 Nov 2021 22:30:40 +0100 Subject: [PATCH 036/190] input-device: remove wlr_input_device.link This field's ownership is unclear: it's in wlr_input_device, but it's not managed by the common code, it's up to each individual backend to use it and clean it up. Since this is a backend implementation detail, move it to the backend-specific structs. --- backend/headless/backend.c | 5 ++-- backend/headless/input_device.c | 8 +++--- backend/libinput/backend.c | 6 ++--- backend/libinput/events.c | 16 ++++++------ backend/wayland/backend.c | 4 +-- backend/wayland/seat.c | 38 ++++++++++++++-------------- backend/wayland/tablet_v2.c | 4 +-- include/backend/headless.h | 2 +- include/backend/libinput.h | 2 +- include/backend/wayland.h | 1 + include/wlr/types/wlr_input_device.h | 2 -- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 886be2761..ad0c4ebfe 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -33,8 +33,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) { } struct wlr_headless_input_device *input_device; - wl_list_for_each(input_device, &backend->input_devices, - wlr_input_device.link) { + wl_list_for_each(input_device, &backend->input_devices, link) { wlr_signal_emit_safe(&backend->backend.events.new_input, &input_device->wlr_input_device); } @@ -59,7 +58,7 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { struct wlr_headless_input_device *input_device, *input_device_tmp; wl_list_for_each_safe(input_device, input_device_tmp, - &backend->input_devices, wlr_input_device.link) { + &backend->input_devices, link) { wlr_input_device_destroy(&input_device->wlr_input_device); } diff --git a/backend/headless/input_device.c b/backend/headless/input_device.c index 1d91f8d12..4df01aff8 100644 --- a/backend/headless/input_device.c +++ b/backend/headless/input_device.c @@ -12,8 +12,10 @@ #include "util/signal.h" static void input_device_destroy(struct wlr_input_device *wlr_dev) { - wl_list_remove(&wlr_dev->link); - free(wlr_dev); + struct wlr_headless_input_device *dev = + wl_container_of(wlr_dev, dev, wlr_input_device); + wl_list_remove(&dev->link); + free(dev); } static const struct wlr_input_device_impl input_device_impl = { @@ -93,7 +95,7 @@ struct wlr_input_device *wlr_headless_add_input_device( wlr_switch_init(wlr_device->switch_device, NULL); } - wl_list_insert(&backend->input_devices, &wlr_device->link); + wl_list_insert(&backend->input_devices, &device->link); if (backend->started) { wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_device); diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 00145e419..4191f3507 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -143,9 +143,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { struct wl_list **wlr_devices_ptr; wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) { - struct wlr_input_device *wlr_dev, *next; - wl_list_for_each_safe(wlr_dev, next, *wlr_devices_ptr, link) { - wlr_input_device_destroy(wlr_dev); + struct wlr_libinput_input_device *dev, *tmp; + wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) { + wlr_input_device_destroy(&dev->wlr_input_device); } free(*wlr_devices_ptr); } diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 828837794..67598998b 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -23,10 +23,10 @@ struct wlr_input_device *get_appropriate_device( if (!wlr_devices) { return NULL; } - struct wlr_input_device *dev; + struct wlr_libinput_input_device *dev; wl_list_for_each(dev, wlr_devices, link) { - if (dev->type == desired_type) { - return dev; + if (dev->wlr_input_device.type == desired_type) { + return &dev->wlr_input_device; } } return NULL; @@ -36,7 +36,7 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) { struct wlr_libinput_input_device *dev = get_libinput_device_from_device(wlr_dev); libinput_device_unref(dev->handle); - wl_list_remove(&dev->wlr_input_device.link); + wl_list_remove(&dev->link); free(dev); } @@ -63,7 +63,7 @@ static struct wlr_input_device *allocate_device( if (output_name != NULL) { wlr_dev->output_name = strdup(output_name); } - wl_list_insert(wlr_devices, &wlr_dev->link); + wl_list_insert(wlr_devices, &dev->link); dev->handle = libinput_dev; libinput_device_ref(libinput_dev); wlr_input_device_init(wlr_dev, type, &input_device_impl, @@ -198,7 +198,7 @@ static void handle_device_added(struct wlr_libinput_backend *backend, fail: wlr_log(WLR_ERROR, "Could not allocate new device"); - struct wlr_input_device *dev, *tmp_dev; + struct wlr_libinput_input_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { free(dev); } @@ -215,9 +215,9 @@ static void handle_device_removed(struct wlr_libinput_backend *backend, if (!wlr_devices) { return; } - struct wlr_input_device *dev, *tmp_dev; + struct wlr_libinput_input_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { - wlr_input_device_destroy(dev); + wlr_input_device_destroy(&dev->wlr_input_device); } size_t i = 0; struct wl_list **ptr; diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 3d962d4fe..63d6a7df6 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -314,9 +314,9 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_output_destroy(&output->wlr_output); } - struct wlr_input_device *input_device, *tmp_input_device; + struct wlr_wl_input_device *input_device, *tmp_input_device; wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) { - wlr_input_device_destroy(input_device); + wlr_input_device_destroy(&input_device->wlr_input_device); } struct wlr_wl_buffer *buffer, *tmp_buffer; diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 508551a0f..7792d136e 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -25,12 +25,13 @@ static struct wlr_wl_pointer *output_get_pointer( struct wlr_wl_output *output, const struct wl_pointer *wl_pointer) { - struct wlr_input_device *wlr_dev; - wl_list_for_each(wlr_dev, &output->backend->devices, link) { - if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) { + struct wlr_wl_input_device *dev; + wl_list_for_each(dev, &output->backend->devices, link) { + if (dev->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) { continue; } - struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer); + struct wlr_wl_pointer *pointer = + pointer_get_wl(dev->wlr_input_device.pointer); if (pointer->output == output && pointer->wl_pointer == wl_pointer) { return pointer; } @@ -440,7 +441,7 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) { } // We can't destroy pointer here because we might have multiple devices // exposing it to compositor. - wl_list_remove(&dev->wlr_input_device.link); + wl_list_remove(&dev->link); free(dev); } @@ -473,7 +474,7 @@ struct wlr_wl_input_device *create_wl_input_device( wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, product); - wl_list_insert(&seat->backend->devices, &wlr_dev->link); + wl_list_insert(&seat->backend->devices, &dev->link); return dev; } @@ -822,19 +823,20 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, struct wl_pointer *wl_pointer = seat->pointer; - struct wlr_input_device *device, *tmp; + struct wlr_wl_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->type != WLR_INPUT_DEVICE_POINTER) { + if (device->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) { continue; } - struct wlr_wl_pointer *pointer = pointer_get_wl(device->pointer); + struct wlr_wl_pointer *pointer = + pointer_get_wl(device->wlr_input_device.pointer); if (pointer->wl_pointer != wl_pointer) { continue; } wlr_log(WLR_DEBUG, "dropping pointer %s", pointer->input_device->wlr_input_device.name); struct wlr_wl_output *output = pointer->output; - wlr_input_device_destroy(device); + wlr_input_device_destroy(&device->wlr_input_device); assert(seat->active_pointer != pointer); assert(output->cursor.pointer != pointer); } @@ -856,18 +858,16 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat); - struct wlr_input_device *device, *tmp; + struct wlr_wl_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + if (device->wlr_input_device.type != WLR_INPUT_DEVICE_KEYBOARD) { continue; } - struct wlr_wl_input_device *input_device = - get_wl_input_device_from_input_device(device); - if (input_device->seat != seat) { + if (device->seat != seat) { continue; } - wlr_input_device_destroy(device); + wlr_input_device_destroy(&device->wlr_input_device); } assert(seat->keyboard == NULL); // free'ed by input_device_destroy } @@ -883,10 +883,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); - struct wlr_input_device *device, *tmp; + struct wlr_wl_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->type == WLR_INPUT_DEVICE_TOUCH) { - wlr_input_device_destroy(device); + if (device->wlr_input_device.type == WLR_INPUT_DEVICE_TOUCH) { + wlr_input_device_destroy(&device->wlr_input_device); } } diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index 9f90a3696..cda651011 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -402,7 +402,7 @@ static void handle_tablet_pad_removed(void *data, /* This doesn't free anything, but emits the destroy signal */ wlr_input_device_destroy(&dev->wlr_input_device); /* This is a bit ugly, but we need to remove it from our list */ - wl_list_remove(&dev->wlr_input_device.link); + wl_list_remove(&dev->link); struct wlr_wl_tablet_pad_group *group, *it; wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) { @@ -873,7 +873,7 @@ static void handle_tablet_removed(void *data, /* This doesn't free anything, but emits the destroy signal */ wlr_input_device_destroy(&dev->wlr_input_device); /* This is a bit ugly, but we need to remove it from our list */ - wl_list_remove(&dev->wlr_input_device.link); + wl_list_remove(&dev->link); zwp_tablet_v2_destroy(dev->resource); free(dev); diff --git a/include/backend/headless.h b/include/backend/headless.h index 09d5856b2..f60d07e66 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -29,7 +29,7 @@ struct wlr_headless_output { struct wlr_headless_input_device { struct wlr_input_device wlr_input_device; - + struct wl_list link; struct wlr_headless_backend *backend; }; diff --git a/include/backend/libinput.h b/include/backend/libinput.h index e85ad2913..a6841d7e9 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -26,7 +26,7 @@ struct wlr_libinput_backend { struct wlr_libinput_input_device { struct wlr_input_device wlr_input_device; - + struct wl_list link; struct libinput_device *handle; }; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 32783597f..4e5d36361 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -87,6 +87,7 @@ struct wlr_wl_output { struct wlr_wl_input_device { struct wlr_input_device wlr_input_device; + struct wl_list link; uint32_t fingers; struct wlr_wl_backend *backend; diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index 8ed9b4659..cbc877df6 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -53,8 +53,6 @@ struct wlr_input_device { } events; void *data; - - struct wl_list link; }; #endif From 5332935afcdd519dd2dd9dbfeb50c6aa0f91e9c3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Nov 2021 13:22:14 +0100 Subject: [PATCH 037/190] render/vulkan: quiet glslangValidator This suppresses the output filename printed to stdout. Errors and warnings should still be printed to stderr as usual. --- render/vulkan/meson.build | 3 +++ render/vulkan/shaders/meson.build | 3 +++ 2 files changed, 6 insertions(+) diff --git a/render/vulkan/meson.build b/render/vulkan/meson.build index 6ae8df0c3..0c45a7136 100644 --- a/render/vulkan/meson.build +++ b/render/vulkan/meson.build @@ -33,6 +33,9 @@ if not glslang.found() endif endif +glslang_version_info = run_command(glslang, '--version', check: true).stdout() +glslang_version = glslang_version_info.split('\n')[0].split(':')[-1] + wlr_files += files( 'renderer.c', 'texture.c', diff --git a/render/vulkan/shaders/meson.build b/render/vulkan/shaders/meson.build index b183c46ca..906618c29 100644 --- a/render/vulkan/shaders/meson.build +++ b/render/vulkan/shaders/meson.build @@ -8,6 +8,9 @@ vulkan_shaders = [] foreach shader : vulkan_shaders_src name = shader.underscorify() + '_data' args = [glslang, '-V', '@INPUT@', '-o', '@OUTPUT@', '--vn', name] + if glslang_version.version_compare('>=11.0.0') + args += '--quiet' + endif header = custom_target( shader + '_spv', output: shader + '.h', From f132d66816263a509b46092e14755b5e3f0e258f Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 10 Nov 2021 11:41:39 +0000 Subject: [PATCH 038/190] render/vulkan: Optimize vertex shader This ends up being a horrible global load: s_getpc_b64 s[4:5] // 000000000000: BE841C80 v_add_u32 v0, s2, v0 // 000000000004: 68000002 v_sub_co_u32 v1, vcc, 0, v0 // 000000000008: 34020080 v_max_i32 v1, v0, v1 // 00000000000C: 1A020300 v_and_b32 v1, 3, v1 // 000000000010: 26020283 v_cmp_lt_i32 s[0:1], v0, 0 // 000000000014: D0C10000 00010100 v_sub_co_u32 v0, vcc, 0, v1 // 00000000001C: 34000280 v_cndmask_b32 v0, v1, v0, s[0:1] // 000000000020: D1000000 00020101 v_lshlrev_b32 v1, 3, v0 // 000000000028: 24020083 v_mad_u32_u24 v0, v0, 8, 4 // 00000000002C: D1C30000 02111100 v_min_u32 v1, 32, v1 // 000000000034: 1C0202A0 v_min_u32 v0, 32, v0 // 000000000038: 1C0000A0 s_getpc_b64 s[0:1] // 00000000003C: BE801C00 s_add_u32 s0, s0, 0x0000003c // 000000000040: 8000FF00 0000003C s_addc_u32 s1, s1, 0 // 000000000048: 82018001 global_load_dword v1, v[1:2], s[0:1] // 00000000004C: DC508000 01000001 global_load_dword v0, v[0:1], s[0:1] // 000000000054: DC508000 00000000 v_mov_b32 v2, 0 // 00000000005C: 7E040280 v_mov_b32 v3, 1.0 // 000000000060: 7E0602F2 s_waitcnt vmcnt(0) // 000000000064: BF8C0F70 exp pos0, v1, v0, v2, v3 done // 000000000068: C40008CF 03020001 exp param0, off, off, off, off // 000000000070: C4000200 00000000 s_endpgm // 000000000078: BF810000 v_cndmask_b32 v0, s0, v0, vcc // 00000000007C: 00000000 v_cndmask_b32 v0, s0, v0, vcc // 000000000080: 00000000 v_add_f16 v192, s0, v0 // 000000000084: 3F800000 v_cndmask_b32 v0, s0, v0, vcc // 000000000088: 00000000 v_add_f16 v192, s0, v0 // 00000000008C: 3F800000 v_add_f16 v192, s0, v0 // 000000000090: 3F800000 v_cndmask_b32 v0, s0, v0, vcc // 000000000094: 00000000 v_add_f16 v192, s0, v0 // 000000000098: 3F800000 v_cndmask_b32 v0, s0, v0, vcc // 00000000009C: 00000000 With some bit magic, we can get something much nicer: v_add_u32 v0, s2, v0 // 000000000000: 68000002 v_add_u32 v1, 1, v0 // 000000000004: 68020081 v_and_b32 v1, 2, v1 // 000000000008: 26020282 v_cvt_f32_i32 v1, v1 // 00000000000C: 7E020B01 v_mul_f32 v1, 0.5, v1 // 000000000010: 0A0202F0 v_and_b32 v0, 2, v0 // 000000000014: 26000082 v_cvt_f32_i32 v0, v0 // 000000000018: 7E000B00 v_mul_f32 v0, 0.5, v0 // 00000000001C: 0A0000F0 v_mov_b32 v2, 0 // 000000000020: 7E040280 v_mov_b32 v3, 1.0 // 000000000024: 7E0602F2 exp pos0, v1, v0, v2, v3 done // 000000000028: C40008CF 03020001 exp param0, off, off, off, off // 000000000030: C4000200 00000000 s_endpgm // 000000000038: BF810000 The above output was based on just shoving it in ShaderPlayground -- I was not able to use pipeline feedback as I was unable to get RenderDoc working due to the EXT_physical_device_drm requirement. I additionally considered using >> 1 instead of * 0.5, but AMD has dedicated modifiers to merge a * 0.5, * 2.0, etc in a single instruction. (Albeit, not taken advantage of in the code above, but might with ACO) Signed-off-by: Joshua Ashton --- render/vulkan/shaders/common.vert | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/render/vulkan/shaders/common.vert b/render/vulkan/shaders/common.vert index fa31d26c2..c6175d248 100644 --- a/render/vulkan/shaders/common.vert +++ b/render/vulkan/shaders/common.vert @@ -10,16 +10,9 @@ layout(push_constant, row_major) uniform UBO { layout(location = 0) out vec2 uv; -// 4 outlining points and uv coords -const vec2[] values = { - {0, 0}, - {1, 0}, - {1, 1}, - {0, 1}, -}; - void main() { - vec2 pos = values[gl_VertexIndex % 4]; + vec2 pos = vec2(float((gl_VertexIndex + 1) & 2) * 0.5f, + float(gl_VertexIndex & 2) * 0.5f); uv = data.uv_offset + pos * data.uv_size; gl_Position = data.proj * vec4(pos, 0.0, 1.0); } From bcefb71cf61b4d12465c8ba41c79ec6b651e045e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 10:57:53 +0100 Subject: [PATCH 039/190] docs/env_vars: drop WLR_DIRECT_TTY The direct session is gone, so this env var isn't looked up anymore. --- docs/env_vars.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/env_vars.md b/docs/env_vars.md index 2959ab581..66c6dcc6c 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -6,7 +6,6 @@ wlroots reads these environment variables libinput, drm, wayland, x11, headless, noop) * *WLR_NO_HARDWARE_CURSORS*: set to 1 to use software cursors instead of hardware cursors -* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty) * *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead of following shell search semantics for "Xwayland") * *WLR_RENDERER*: forces the creation of a specified renderer (available From bf578255606d2bcc9d283c3a5042deddf29c52b5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 10:35:30 +0100 Subject: [PATCH 040/190] render: pick DRM FD in autocreate If the backend hasn't picked a DRM FD but supports DMA-BUF, pick an arbitrary render node. This will allow removing the DRM device selection logic from the headless backend. --- render/wlr_renderer.c | 69 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 8a1f1e941..6667a8199 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,6 +1,9 @@ +#define _POSIX_C_SOURCE 200809L #include +#include #include #include +#include #include #include #include @@ -9,6 +12,7 @@ #include #include #include +#include #include @@ -21,6 +25,7 @@ #include #endif // WLR_HAS_VULKAN_RENDERER +#include "backend/backend.h" #include "util/signal.h" #include "render/pixel_format.h" #include "render/wlr_renderer.h" @@ -296,10 +301,72 @@ struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd) { return NULL; } +static int open_drm_render_node(void) { + uint32_t flags = 0; + int devices_len = drmGetDevices2(flags, NULL, 0); + if (devices_len < 0) { + wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); + return -1; + } + drmDevice **devices = calloc(devices_len, sizeof(drmDevice *)); + if (devices == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + devices_len = drmGetDevices2(flags, devices, devices_len); + if (devices_len < 0) { + free(devices); + wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); + return -1; + } + + int fd = -1; + for (int i = 0; i < devices_len; i++) { + drmDevice *dev = devices[i]; + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + const char *name = dev->nodes[DRM_NODE_RENDER]; + wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name); + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + goto out; + } + break; + } + } + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to find any DRM render node"); + } + +out: + for (int i = 0; i < devices_len; i++) { + drmFreeDevice(&devices[i]); + } + free(devices); + + return fd; +} + struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend) { // Note, drm_fd may be negative if unavailable int drm_fd = wlr_backend_get_drm_fd(backend); - return renderer_autocreate_with_drm_fd(drm_fd); + + // If the backend hasn't picked a DRM FD, but accepts DMA-BUFs, pick an + // arbitrary render node + int render_drm_fd = -1; + uint32_t backend_caps = backend_get_buffer_caps(backend); + if (drm_fd < 0 && (backend_caps & WLR_BUFFER_CAP_DMABUF) != 0) { + render_drm_fd = open_drm_render_node(); + drm_fd = render_drm_fd; + } + + struct wlr_renderer *renderer = renderer_autocreate_with_drm_fd(drm_fd); + + if (render_drm_fd >= 0) { + close(render_drm_fd); + } + + return renderer; } int wlr_renderer_get_drm_fd(struct wlr_renderer *r) { From e4f748c6e9d618eb2ee8f15aa22aae8dcde4cc4a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 10:33:13 +0100 Subject: [PATCH 041/190] render/allocator: fallback to renderer DRM FD in autocreate If the backend doesn't have a DRM FD, fallback to the renderer's. This accomodates for the situation where the headless backend hasn't picked a DRM FD in particular, but the renderer has picked one. --- render/allocator/allocator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c index 15d55a0de..5108ad043 100644 --- a/render/allocator/allocator.c +++ b/render/allocator/allocator.c @@ -139,6 +139,9 @@ struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, struct wlr_renderer *renderer) { // Note, drm_fd may be negative if unavailable int drm_fd = wlr_backend_get_drm_fd(backend); + if (drm_fd < 0) { + drm_fd = wlr_renderer_get_drm_fd(renderer); + } return allocator_autocreate_with_drm_fd(backend, renderer, drm_fd); } From f29abe4c777ba8293ab76334ef2ac83eaa0043f6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 10:36:39 +0100 Subject: [PATCH 042/190] backend/headless: stop picking a DRM FD Sometimes the headless backend is used standalone with the Pixman renderer, sometimes it's used together with another backend which has already picked a DRM FD. In both of these cases it doesn't make sense to pick a DRM FD. Broadly speaking the headless backend doesn't really care which DRM device is used for the buffers it receives. So it doesn't really make sense to tie it to a particular DRM device. Let the backend users (e.g. wlr_renderer_autocreate) open an arbitrary DRM FD as needed instead. --- backend/headless/backend.c | 93 ++------------------------------------ backend/headless/output.c | 1 - include/backend/headless.h | 1 - 3 files changed, 4 insertions(+), 91 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index ad0c4ebfe..8d74287d3 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -1,16 +1,9 @@ -#define _POSIX_C_SOURCE 200809L #include -#include -#include #include -#include #include #include -#include #include -#include #include "backend/headless.h" -#include "render/drm_format_set.h" #include "util/signal.h" struct wlr_headless_backend *headless_backend_from_backend( @@ -64,16 +57,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wlr_backend_finish(wlr_backend); - close(backend->drm_fd); free(backend); } -static int backend_get_drm_fd(struct wlr_backend *wlr_backend) { - struct wlr_headless_backend *backend = - headless_backend_from_backend(wlr_backend); - return backend->drm_fd; -} - static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) { return WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF @@ -83,7 +69,6 @@ static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) { static const struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, - .get_drm_fd = backend_get_drm_fd, .get_buffer_caps = get_buffer_caps, }; @@ -107,52 +92,6 @@ static bool backend_init(struct wlr_headless_backend *backend, return true; } -static int open_drm_render_node(void) { - uint32_t flags = 0; - int devices_len = drmGetDevices2(flags, NULL, 0); - if (devices_len < 0) { - wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); - return -1; - } - drmDevice **devices = calloc(devices_len, sizeof(drmDevice *)); - if (devices == NULL) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - return -1; - } - devices_len = drmGetDevices2(flags, devices, devices_len); - if (devices_len < 0) { - free(devices); - wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); - return -1; - } - - int fd = -1; - for (int i = 0; i < devices_len; i++) { - drmDevice *dev = devices[i]; - if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { - const char *name = dev->nodes[DRM_NODE_RENDER]; - wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name); - fd = open(name, O_RDWR | O_CLOEXEC); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); - goto out; - } - break; - } - } - if (fd < 0) { - wlr_log(WLR_ERROR, "Failed to find any DRM render node"); - } - -out: - for (int i = 0; i < devices_len; i++) { - drmFreeDevice(&devices[i]); - } - free(devices); - - return fd; -} - struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { wlr_log(WLR_INFO, "Creating headless backend"); @@ -163,21 +102,12 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { return NULL; } - backend->drm_fd = open_drm_render_node(); - if (backend->drm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to open DRM render node"); - } - if (!backend_init(backend, display)) { - goto error_init; + free(backend); + return NULL; } return &backend->backend; - -error_init: - close(backend->drm_fd); - free(backend); - return NULL; } struct wlr_backend *wlr_headless_backend_create_with_renderer( @@ -191,27 +121,12 @@ struct wlr_backend *wlr_headless_backend_create_with_renderer( return NULL; } - int drm_fd = wlr_renderer_get_drm_fd(renderer); - if (drm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM device FD from parent renderer"); - backend->drm_fd = -1; - } else { - backend->drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); - if (backend->drm_fd < 0) { - wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); - } - } - if (!backend_init(backend, display)) { - goto error_init; + free(backend); + return NULL; } return &backend->backend; - -error_init: - close(backend->drm_fd); - free(backend); - return NULL; } bool wlr_backend_is_headless(struct wlr_backend *backend) { diff --git a/backend/headless/output.c b/backend/headless/output.c index 43762b239..50d914e44 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "backend/headless.h" #include "util/signal.h" diff --git a/include/backend/headless.h b/include/backend/headless.h index f60d07e66..e126ac4ef 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -8,7 +8,6 @@ struct wlr_headless_backend { struct wlr_backend backend; - int drm_fd; struct wl_display *display; struct wl_list outputs; size_t last_output_num; From 2e33139ef732040c86e913ecb984c8eb0bf66cb2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 10:52:39 +0100 Subject: [PATCH 043/190] render: introduce WLR_RENDER_DRM_DEVICE This env var allows to override the DRM node used by the GLES2 and Vulkan renderers. It's especially useful to select a DRM node when running with the headless backend. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2656 --- docs/env_vars.md | 2 ++ render/wlr_renderer.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/env_vars.md b/docs/env_vars.md index 66c6dcc6c..a07b2f197 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -10,6 +10,8 @@ wlroots reads these environment variables of following shell search semantics for "Xwayland") * *WLR_RENDERER*: forces the creation of a specified renderer (available renderers: gles2, pixman, vulkan) +* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for + hardware-accelerated renderers. ## DRM backend diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 6667a8199..ff3159135 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -348,18 +348,41 @@ out: } struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend) { - // Note, drm_fd may be negative if unavailable - int drm_fd = wlr_backend_get_drm_fd(backend); + int drm_fd = -1; + int render_drm_fd = -1; + + // Allow the user to override the render node + const char *render_name = getenv("WLR_RENDER_DRM_DEVICE"); + if (render_name != NULL) { + wlr_log(WLR_INFO, + "Opening DRM render node '%s' from WLR_RENDER_DRM_DEVICE", + render_name); + render_drm_fd = open(render_name, O_RDWR | O_CLOEXEC); + if (render_drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", render_name); + return NULL; + } + if (drmGetNodeTypeFromFd(render_drm_fd) != DRM_NODE_RENDER) { + wlr_log(WLR_ERROR, "'%s' is not a DRM render node", render_name); + close(render_drm_fd); + return NULL; + } + drm_fd = render_drm_fd; + } + + if (drm_fd < 0) { + drm_fd = wlr_backend_get_drm_fd(backend); + } // If the backend hasn't picked a DRM FD, but accepts DMA-BUFs, pick an // arbitrary render node - int render_drm_fd = -1; uint32_t backend_caps = backend_get_buffer_caps(backend); if (drm_fd < 0 && (backend_caps & WLR_BUFFER_CAP_DMABUF) != 0) { render_drm_fd = open_drm_render_node(); drm_fd = render_drm_fd; } + // Note, drm_fd may be negative if unavailable struct wlr_renderer *renderer = renderer_autocreate_with_drm_fd(drm_fd); if (render_drm_fd >= 0) { From b234edcf58bbd73d64e8d5986aa5cc380d2f48d6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 25 Nov 2021 10:50:28 +0100 Subject: [PATCH 044/190] backend/headless: drop wlr_headless_backend_create_with_renderer The headless backend no longer needs a parent renderer: it no longer needs to return it in wlr_backend_impl.get_renderer, nor does it need to return its DRM FD in wlr_backend_impl.get_drm_fd. Drop this function altogether since it now behaves exactly like wlr_headless_backend_create. --- backend/headless/backend.c | 41 +++++----------------------------- include/wlr/backend/headless.h | 5 ----- 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 8d74287d3..b77881051 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -78,20 +78,6 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { backend_destroy(&backend->backend); } -static bool backend_init(struct wlr_headless_backend *backend, - struct wl_display *display) { - wlr_backend_init(&backend->backend, &backend_impl); - - backend->display = display; - wl_list_init(&backend->outputs); - wl_list_init(&backend->input_devices); - - backend->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &backend->display_destroy); - - return true; -} - struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { wlr_log(WLR_INFO, "Creating headless backend"); @@ -102,29 +88,14 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { return NULL; } - if (!backend_init(backend, display)) { - free(backend); - return NULL; - } + wlr_backend_init(&backend->backend, &backend_impl); - return &backend->backend; -} + backend->display = display; + wl_list_init(&backend->outputs); + wl_list_init(&backend->input_devices); -struct wlr_backend *wlr_headless_backend_create_with_renderer( - struct wl_display *display, struct wlr_renderer *renderer) { - wlr_log(WLR_INFO, "Creating headless backend with parent renderer"); - - struct wlr_headless_backend *backend = - calloc(1, sizeof(struct wlr_headless_backend)); - if (!backend) { - wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend"); - return NULL; - } - - if (!backend_init(backend, display)) { - free(backend); - return NULL; - } + backend->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &backend->display_destroy); return &backend->backend; } diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index 3eb1677d2..07dac9b84 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -18,11 +18,6 @@ * default. */ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); -/** - * Creates a headless backend with an existing renderer. - */ -struct wlr_backend *wlr_headless_backend_create_with_renderer( - struct wl_display *display, struct wlr_renderer *renderer); /** * Create a new headless output backed by an in-memory EGL framebuffer. You can * read pixels from this framebuffer via wlr_renderer_read_pixels but it is From 1d3dd7fc08f22f2e82cb812ced822369e984d845 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Thu, 30 Sep 2021 10:53:18 -0400 Subject: [PATCH 045/190] backend: remove noop backend --- backend/backend.c | 17 -------- backend/meson.build | 1 - backend/noop/backend.c | 79 ---------------------------------- backend/noop/meson.build | 4 -- backend/noop/output.c | 87 -------------------------------------- docs/env_vars.md | 2 +- include/backend/noop.h | 27 ------------ include/wlr/backend/noop.h | 31 -------------- 8 files changed, 1 insertion(+), 247 deletions(-) delete mode 100644 backend/noop/backend.c delete mode 100644 backend/noop/meson.build delete mode 100644 backend/noop/output.c delete mode 100644 include/backend/noop.h delete mode 100644 include/wlr/backend/noop.h diff --git a/backend/backend.c b/backend/backend.c index 7f0de3c2c..33a218518 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -203,20 +202,6 @@ static struct wlr_backend *attempt_headless_backend( return backend; } -static struct wlr_backend *attempt_noop_backend(struct wl_display *display) { - struct wlr_backend *backend = wlr_noop_backend_create(display); - if (backend == NULL) { - return NULL; - } - - size_t outputs = parse_outputs_env("WLR_NOOP_OUTPUTS"); - for (size_t i = 0; i < outputs; ++i) { - wlr_noop_add_output(backend); - } - - return backend; -} - #if WLR_HAS_DRM_BACKEND static struct wlr_backend *attempt_drm_backend(struct wl_display *display, struct wlr_backend *backend, struct wlr_session *session) { @@ -269,8 +254,6 @@ static bool attempt_backend_by_name(struct wl_display *display, #endif } else if (strcmp(name, "headless") == 0) { backend = attempt_headless_backend(display); - } else if (strcmp(name, "noop") == 0) { - backend = attempt_noop_backend(display); } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { // DRM and libinput need a session if (multi->session == NULL) { diff --git a/backend/meson.build b/backend/meson.build index 7fffc8395..71a00dc9b 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -16,7 +16,6 @@ endforeach subdir('multi') subdir('wayland') -subdir('noop') subdir('headless') subdir('session') diff --git a/backend/noop/backend.c b/backend/noop/backend.c deleted file mode 100644 index 7bdda051e..000000000 --- a/backend/noop/backend.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include -#include "backend/noop.h" -#include "util/signal.h" - -struct wlr_noop_backend *noop_backend_from_backend( - struct wlr_backend *wlr_backend) { - assert(wlr_backend_is_noop(wlr_backend)); - return (struct wlr_noop_backend *)wlr_backend; -} - -static bool backend_start(struct wlr_backend *wlr_backend) { - struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); - wlr_log(WLR_INFO, "Starting noop backend"); - - struct wlr_noop_output *output; - wl_list_for_each(output, &backend->outputs, link) { - wlr_output_update_enabled(&output->wlr_output, true); - wlr_signal_emit_safe(&backend->backend.events.new_output, - &output->wlr_output); - } - - backend->started = true; - return true; -} - -static void backend_destroy(struct wlr_backend *wlr_backend) { - struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); - if (!wlr_backend) { - return; - } - - struct wlr_noop_output *output, *output_tmp; - wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) { - wlr_output_destroy(&output->wlr_output); - } - - wlr_backend_finish(wlr_backend); - - wl_list_remove(&backend->display_destroy.link); - - free(backend); -} - -static const struct wlr_backend_impl backend_impl = { - .start = backend_start, - .destroy = backend_destroy, -}; - -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_noop_backend *noop = - wl_container_of(listener, noop, display_destroy); - backend_destroy(&noop->backend); -} - -struct wlr_backend *wlr_noop_backend_create(struct wl_display *display) { - wlr_log(WLR_INFO, "Creating noop backend"); - - struct wlr_noop_backend *backend = - calloc(1, sizeof(struct wlr_noop_backend)); - if (!backend) { - wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_backend"); - return NULL; - } - wlr_backend_init(&backend->backend, &backend_impl); - backend->display = display; - wl_list_init(&backend->outputs); - - backend->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &backend->display_destroy); - - return &backend->backend; -} - -bool wlr_backend_is_noop(struct wlr_backend *backend) { - return backend->impl == &backend_impl; -} diff --git a/backend/noop/meson.build b/backend/noop/meson.build deleted file mode 100644 index 950c07160..000000000 --- a/backend/noop/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -wlr_files += files( - 'backend.c', - 'output.c', -) diff --git a/backend/noop/output.c b/backend/noop/output.c deleted file mode 100644 index bde808208..000000000 --- a/backend/noop/output.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include -#include -#include "backend/noop.h" -#include "util/signal.h" - -static const uint32_t SUPPORTED_OUTPUT_STATE = - WLR_OUTPUT_STATE_BACKEND_OPTIONAL | - WLR_OUTPUT_STATE_MODE; - -static struct wlr_noop_output *noop_output_from_output( - struct wlr_output *wlr_output) { - assert(wlr_output_is_noop(wlr_output)); - return (struct wlr_noop_output *)wlr_output; -} - -static bool output_commit(struct wlr_output *wlr_output) { - uint32_t unsupported = - wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; - if (unsupported != 0) { - wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, - unsupported); - return false; - } - - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { - assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); - wlr_output_update_custom_mode(wlr_output, - wlr_output->pending.custom_mode.width, - wlr_output->pending.custom_mode.height, - wlr_output->pending.custom_mode.refresh); - } - - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - return false; - } - - return true; -} - -static void output_destroy(struct wlr_output *wlr_output) { - struct wlr_noop_output *output = - noop_output_from_output(wlr_output); - - wl_list_remove(&output->link); - - free(output); -} - -static const struct wlr_output_impl output_impl = { - .destroy = output_destroy, - .commit = output_commit, -}; - -bool wlr_output_is_noop(struct wlr_output *wlr_output) { - return wlr_output->impl == &output_impl; -} - -struct wlr_output *wlr_noop_add_output(struct wlr_backend *wlr_backend) { - struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); - - struct wlr_noop_output *output = calloc(1, sizeof(struct wlr_noop_output)); - if (output == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_output"); - return NULL; - } - output->backend = backend; - wlr_output_init(&output->wlr_output, &backend->backend, &output_impl, - backend->display); - struct wlr_output *wlr_output = &output->wlr_output; - - strncpy(wlr_output->make, "noop", sizeof(wlr_output->make)); - strncpy(wlr_output->model, "noop", sizeof(wlr_output->model)); - snprintf(wlr_output->name, sizeof(wlr_output->name), "NOOP-%zd", - ++backend->last_output_num); - - wl_list_insert(&backend->outputs, &output->link); - - if (backend->started) { - wlr_output_update_enabled(wlr_output, true); - wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); - } - - return wlr_output; -} diff --git a/docs/env_vars.md b/docs/env_vars.md index a07b2f197..609ca97bd 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -3,7 +3,7 @@ wlroots reads these environment variables # wlroots specific * *WLR_BACKENDS*: comma-separated list of backends to use (available backends: - libinput, drm, wayland, x11, headless, noop) + libinput, drm, wayland, x11, headless) * *WLR_NO_HARDWARE_CURSORS*: set to 1 to use software cursors instead of hardware cursors * *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead diff --git a/include/backend/noop.h b/include/backend/noop.h deleted file mode 100644 index 5a8ee6779..000000000 --- a/include/backend/noop.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef BACKEND_NOOP_H -#define BACKEND_NOOP_H - -#include -#include - -struct wlr_noop_backend { - struct wlr_backend backend; - struct wl_display *display; - struct wl_list outputs; - size_t last_output_num; - bool started; - - struct wl_listener display_destroy; -}; - -struct wlr_noop_output { - struct wlr_output wlr_output; - - struct wlr_noop_backend *backend; - struct wl_list link; -}; - -struct wlr_noop_backend *noop_backend_from_backend( - struct wlr_backend *wlr_backend); - -#endif diff --git a/include/wlr/backend/noop.h b/include/wlr/backend/noop.h deleted file mode 100644 index 592b8f35b..000000000 --- a/include/wlr/backend/noop.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_BACKEND_NOOP_H -#define WLR_BACKEND_NOOP_H - -#include -#include - -/** - * Creates a noop backend. Noop backends do not have a framebuffer and are not - * capable of rendering anything. They are useful for when there's no real - * outputs connected; you can stash your views on a noop output until an output - * is connected. - */ -struct wlr_backend *wlr_noop_backend_create(struct wl_display *display); - -/** - * Create a new noop output. - */ -struct wlr_output *wlr_noop_add_output(struct wlr_backend *backend); - -bool wlr_backend_is_noop(struct wlr_backend *backend); -bool wlr_output_is_noop(struct wlr_output *output); - -#endif From 585a908a014a49a718771375264ed284d4599d59 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 25 Oct 2021 18:29:24 +0200 Subject: [PATCH 046/190] scene: add wlr_scene_xdg_surface_create This allows compositors to easily add an xdg_surface to the scene-graph while retaining the ability to unconstraint popups and decide their final position. Compositors can handle new popups with the wlr_xdg_shell.new_surface event, get the parent scene-graph node via wlr_xdg_popup.parent.data, create a new scene-graph node via wlr_scene_xdg_surface_tree_create, and unconstraint the popup if they want to. --- include/wlr/types/wlr_scene.h | 11 +++ types/meson.build | 1 + types/scene/xdg_shell.c | 124 ++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 types/scene/xdg_shell.c diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 538b89412..622dbb280 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -25,6 +25,7 @@ struct wlr_output; struct wlr_output_layout; +struct wlr_xdg_surface; enum wlr_scene_node_type { WLR_SCENE_NODE_ROOT, @@ -298,4 +299,14 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, struct wlr_scene_node *wlr_scene_subsurface_tree_create( struct wlr_scene_node *parent, struct wlr_surface *surface); +/** + * Add a node displaying an xdg_surface and all of its sub-surfaces to the + * scene-graph. + * + * The origin of the returned scene-graph node will match the top-left corner + * of the xdg_surface window geometry. + */ +struct wlr_scene_node *wlr_scene_xdg_surface_create( + struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface); + #endif diff --git a/types/meson.build b/types/meson.build index 89e834cec..1694ac94a 100644 --- a/types/meson.build +++ b/types/meson.build @@ -10,6 +10,7 @@ wlr_files += files( 'scene/subsurface_tree.c', 'scene/wlr_scene.c', 'scene/output_layout.c', + 'scene/xdg_shell.c', 'seat/wlr_seat_keyboard.c', 'seat/wlr_seat_pointer.c', 'seat/wlr_seat_touch.c', diff --git a/types/scene/xdg_shell.c b/types/scene/xdg_shell.c new file mode 100644 index 000000000..9b3ad71c3 --- /dev/null +++ b/types/scene/xdg_shell.c @@ -0,0 +1,124 @@ +#include +#include +#include + +struct wlr_scene_xdg_surface { + struct wlr_scene_tree *tree; + struct wlr_xdg_surface *xdg_surface; + struct wlr_scene_node *surface_node; + + struct wl_listener tree_destroy; + struct wl_listener xdg_surface_destroy; + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_commit; +}; + +static void scene_xdg_surface_handle_tree_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, tree_destroy); + // tree and surface_node will be cleaned up by scene_node_finish + wl_list_remove(&scene_xdg_surface->tree_destroy.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_destroy.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_map.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_unmap.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_commit.link); + free(scene_xdg_surface); +} + +static void scene_xdg_surface_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_destroy); + wlr_scene_node_destroy(&scene_xdg_surface->tree->node); +} + +static void scene_xdg_surface_handle_xdg_surface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_map); + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, true); +} + +static void scene_xdg_surface_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_unmap); + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, false); +} + +static void scene_xdg_surface_update_position( + struct wlr_scene_xdg_surface *scene_xdg_surface) { + struct wlr_xdg_surface *xdg_surface = scene_xdg_surface->xdg_surface; + + struct wlr_box geo = {0}; + wlr_xdg_surface_get_geometry(xdg_surface, &geo); + wlr_scene_node_set_position(scene_xdg_surface->surface_node, + -geo.x, -geo.y); + + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_xdg_popup *popup = xdg_surface->popup; + wlr_scene_node_set_position(&scene_xdg_surface->tree->node, + popup->geometry.x, popup->geometry.y); + } +} + +static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_commit); + scene_xdg_surface_update_position(scene_xdg_surface); +} + +struct wlr_scene_node *wlr_scene_xdg_surface_create( + struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + calloc(1, sizeof(*scene_xdg_surface)); + if (scene_xdg_surface == NULL) { + return NULL; + } + + scene_xdg_surface->xdg_surface = xdg_surface; + + scene_xdg_surface->tree = wlr_scene_tree_create(parent); + if (scene_xdg_surface->tree == NULL) { + free(scene_xdg_surface); + return NULL; + } + + scene_xdg_surface->surface_node = wlr_scene_subsurface_tree_create( + &scene_xdg_surface->tree->node, xdg_surface->surface); + if (scene_xdg_surface->surface_node == NULL) { + wlr_scene_node_destroy(&scene_xdg_surface->tree->node); + free(scene_xdg_surface); + return NULL; + } + + scene_xdg_surface->tree_destroy.notify = + scene_xdg_surface_handle_tree_destroy; + wl_signal_add(&scene_xdg_surface->tree->node.events.destroy, + &scene_xdg_surface->tree_destroy); + + scene_xdg_surface->xdg_surface_destroy.notify = + scene_xdg_surface_handle_xdg_surface_destroy; + wl_signal_add(&xdg_surface->events.destroy, &scene_xdg_surface->xdg_surface_destroy); + + scene_xdg_surface->xdg_surface_map.notify = + scene_xdg_surface_handle_xdg_surface_map; + wl_signal_add(&xdg_surface->events.map, &scene_xdg_surface->xdg_surface_map); + + scene_xdg_surface->xdg_surface_unmap.notify = + scene_xdg_surface_handle_xdg_surface_unmap; + wl_signal_add(&xdg_surface->events.unmap, &scene_xdg_surface->xdg_surface_unmap); + + scene_xdg_surface->xdg_surface_commit.notify = + scene_xdg_surface_handle_xdg_surface_commit; + wl_signal_add(&xdg_surface->surface->events.commit, + &scene_xdg_surface->xdg_surface_commit); + + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, xdg_surface->mapped); + scene_xdg_surface_update_position(scene_xdg_surface); + + return &scene_xdg_surface->tree->node; +} From d78cb808b1b051eae443e368c0b88bc90258fd02 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 31 Mar 2021 16:50:17 +0200 Subject: [PATCH 047/190] render/drm_format_set: add wlr_drm_format_has --- include/render/drm_format_set.h | 1 + render/drm_format_set.c | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/render/drm_format_set.h b/include/render/drm_format_set.h index c438722bc..c94c2af29 100644 --- a/include/render/drm_format_set.h +++ b/include/render/drm_format_set.h @@ -4,6 +4,7 @@ #include struct wlr_drm_format *wlr_drm_format_create(uint32_t format); +bool wlr_drm_format_has(const struct wlr_drm_format *fmt, uint64_t modifier); bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier); struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format); /** diff --git a/render/drm_format_set.c b/render/drm_format_set.c index 3edc1925b..ef2929b75 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -48,13 +48,7 @@ bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, return true; } - for (size_t i = 0; i < fmt->len; ++i) { - if (fmt->modifiers[i] == modifier) { - return true; - } - } - - return false; + return wlr_drm_format_has(fmt, modifier); } bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, @@ -106,6 +100,15 @@ struct wlr_drm_format *wlr_drm_format_create(uint32_t format) { return fmt; } +bool wlr_drm_format_has(const struct wlr_drm_format *fmt, uint64_t modifier) { + for (size_t i = 0; i < fmt->len; ++i) { + if (fmt->modifiers[i] == modifier) { + return true; + } + } + return false; +} + bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { struct wlr_drm_format *fmt = *fmt_ptr; @@ -113,10 +116,8 @@ bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { return true; } - for (size_t i = 0; i < fmt->len; ++i) { - if (fmt->modifiers[i] == modifier) { - return true; - } + if (wlr_drm_format_has(fmt, modifier)) { + return true; } if (fmt->len == fmt->capacity) { From affe9eda5708a8368dd96870ddf2442c5b637202 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 31 Mar 2021 17:07:55 +0200 Subject: [PATCH 048/190] Require INVALID for implicit format modifiers See [1] for the motivation. [1]: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/75 --- backend/drm/drm.c | 18 ++++++++---------- backend/drm/renderer.c | 2 +- backend/x11/backend.c | 1 + render/allocator/gbm.c | 18 ++++++++++++------ render/drm_format_set.c | 31 ++++++++++++------------------- render/egl.c | 11 +++++------ types/wlr_linux_dmabuf_v1.c | 9 ++++----- 7 files changed, 43 insertions(+), 47 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 40506cd46..e22e06905 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -118,9 +118,14 @@ static bool add_plane(struct wlr_drm_backend *drm, p->id = drm_plane->plane_id; p->props = *props; - for (size_t j = 0; j < drm_plane->count_formats; ++j) { - wlr_drm_format_set_add(&p->formats, drm_plane->formats[j], - DRM_FORMAT_MOD_INVALID); + for (size_t i = 0; i < drm_plane->count_formats; ++i) { + // Force a LINEAR layout for the cursor if the driver doesn't support + // modifiers + uint64_t mod = DRM_FORMAT_MOD_INVALID; + if (type == DRM_PLANE_TYPE_CURSOR) { + mod = DRM_FORMAT_MOD_LINEAR; + } + wlr_drm_format_set_add(&p->formats, drm_plane->formats[i], mod); } if (p->props.in_formats && drm->addfb2_modifiers) { @@ -150,13 +155,6 @@ static bool add_plane(struct wlr_drm_backend *drm, } drmModeFreePropertyBlob(blob); - } else if (type == DRM_PLANE_TYPE_CURSOR) { - // Force a LINEAR layout for the cursor if the driver doesn't support - // modifiers - for (size_t i = 0; i < p->formats.len; ++i) { - wlr_drm_format_set_add(&p->formats, p->formats.formats[i]->format, - DRM_FORMAT_MOD_LINEAR); - } } switch (type) { diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 6c26558f9..3d1a5fb21 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -149,7 +149,7 @@ struct wlr_drm_format *drm_plane_pick_render_format( const struct wlr_drm_format_set *plane_formats = &plane->formats; uint32_t fmt = DRM_FORMAT_ARGB8888; - if (!wlr_drm_format_set_has(&plane->formats, fmt, DRM_FORMAT_MOD_INVALID)) { + if (!wlr_drm_format_set_get(&plane->formats, fmt)) { const struct wlr_pixel_format_info *format_info = drm_get_pixel_format_info(fmt); assert(format_info != NULL && diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 6db9aa6c9..ae20559cb 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -354,6 +354,7 @@ static bool query_formats(struct wlr_x11_backend *x11) { } if (x11->have_dri3) { + // X11 always supports implicit modifiers wlr_drm_format_set_add(&x11->dri3_formats, format->drm, DRM_FORMAT_MOD_INVALID); if (!query_dri3_modifiers(x11, format)) { diff --git a/render/allocator/gbm.c b/render/allocator/gbm.c index b546e412c..8f73862a2 100644 --- a/render/allocator/gbm.c +++ b/render/allocator/gbm.c @@ -10,6 +10,7 @@ #include #include "render/allocator/gbm.h" +#include "render/drm_format_set.h" static const struct wlr_buffer_impl buffer_impl; @@ -89,17 +90,22 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc, int width, int height, const struct wlr_drm_format *format) { struct gbm_device *gbm_device = alloc->gbm_device; - struct gbm_bo *bo = NULL; + assert(format->len > 0); + bool has_modifier = true; - if (format->len > 0) { - bo = gbm_bo_create_with_modifiers(gbm_device, width, height, - format->format, format->modifiers, format->len); - } + uint64_t fallback_modifier = DRM_FORMAT_MOD_INVALID; + struct gbm_bo *bo = gbm_bo_create_with_modifiers(gbm_device, width, height, + format->format, format->modifiers, format->len); if (bo == NULL) { uint32_t usage = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; if (format->len == 1 && format->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { usage |= GBM_BO_USE_LINEAR; + fallback_modifier = DRM_FORMAT_MOD_LINEAR; + } else if (!wlr_drm_format_has(format, DRM_FORMAT_MOD_INVALID)) { + // If the format doesn't accept an implicit modifier, bail out. + wlr_log(WLR_ERROR, "gbm_bo_create_with_modifiers failed"); + return NULL; } bo = gbm_bo_create(gbm_device, width, height, format->format, usage); has_modifier = false; @@ -128,7 +134,7 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc, // don't populate the modifier field: other parts of the stack may not // understand modifiers, and they can't strip the modifier. if (!has_modifier) { - buffer->dmabuf.modifier = DRM_FORMAT_MOD_INVALID; + buffer->dmabuf.modifier = fallback_modifier; } wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer (format 0x%"PRIX32", " diff --git a/render/drm_format_set.c b/render/drm_format_set.c index ef2929b75..90256098d 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -43,11 +43,6 @@ bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, if (!fmt) { return false; } - - if (modifier == DRM_FORMAT_MOD_INVALID) { - return true; - } - return wlr_drm_format_has(fmt, modifier); } @@ -112,10 +107,6 @@ bool wlr_drm_format_has(const struct wlr_drm_format *fmt, uint64_t modifier) { bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { struct wlr_drm_format *fmt = *fmt_ptr; - if (modifier == DRM_FORMAT_MOD_INVALID) { - return true; - } - if (wlr_drm_format_has(fmt, modifier)) { return true; } @@ -153,15 +144,17 @@ struct wlr_drm_format *wlr_drm_format_intersect( const struct wlr_drm_format *a, const struct wlr_drm_format *b) { assert(a->format == b->format); - // Special case: if a format only supports LINEAR and the other doesn't - // support any modifier, force LINEAR. This will force the allocator to - // create a buffer with a LINEAR layout instead of an implicit modifier. - if (a->len == 0 && b->len == 1 && b->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { - return wlr_drm_format_dup(b); - } - if (b->len == 0 && a->len == 1 && a->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { + // Special case: if a format only supports LINEAR and the other supports + // implicit modifiers, force LINEAR. This will force the allocator to + // create a buffer with a linear layout instead of an implicit modifier. + if (a->len == 1 && a->modifiers[0] == DRM_FORMAT_MOD_LINEAR && + wlr_drm_format_has(b, DRM_FORMAT_MOD_INVALID)) { return wlr_drm_format_dup(a); } + if (b->len == 1 && b->modifiers[0] == DRM_FORMAT_MOD_LINEAR && + wlr_drm_format_has(a, DRM_FORMAT_MOD_INVALID)) { + return wlr_drm_format_dup(b); + } size_t format_cap = a->len < b->len ? a->len : b->len; size_t format_size = sizeof(struct wlr_drm_format) + @@ -185,9 +178,9 @@ struct wlr_drm_format *wlr_drm_format_intersect( } } - // If both formats support modifiers, but the intersection is empty, then - // the formats aren't compatible with each other - if (format->len == 0 && a->len > 0 && b->len > 0) { + // If the intersection is empty, then the formats aren't compatible with + // each other. + if (format->len == 0) { free(format); return NULL; } diff --git a/render/egl.c b/render/egl.c index ec23ce8d8..a398d586b 100644 --- a/render/egl.c +++ b/render/egl.c @@ -119,12 +119,11 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { has_modifiers = has_modifiers || modifiers_len > 0; - if (modifiers_len == 0) { - wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, - DRM_FORMAT_MOD_INVALID); - wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, - DRM_FORMAT_MOD_INVALID); - } + // EGL always supports implicit modifiers + wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, + DRM_FORMAT_MOD_INVALID); + wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, + DRM_FORMAT_MOD_INVALID); for (int j = 0; j < modifiers_len; j++) { wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 63b52023d..dc5ca8af2 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -9,6 +9,7 @@ #include #include #include "linux-dmabuf-unstable-v1-protocol.h" +#include "render/drm_format_set.h" #include "util/signal.h" #define LINUX_DMABUF_VERSION 3 @@ -427,7 +428,9 @@ static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = { static void linux_dmabuf_send_modifiers(struct wl_resource *resource, const struct wlr_drm_format *fmt) { if (wl_resource_get_version(resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { - zwp_linux_dmabuf_v1_send_format(resource, fmt->format); + if (wlr_drm_format_has(fmt, DRM_FORMAT_MOD_INVALID)) { + zwp_linux_dmabuf_v1_send_format(resource, fmt->format); + } return; } @@ -436,10 +439,6 @@ static void linux_dmabuf_send_modifiers(struct wl_resource *resource, zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, mod >> 32, mod & 0xFFFFFFFF); } - - // We always support buffers with an implicit modifier - zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, - DRM_FORMAT_MOD_INVALID >> 32, DRM_FORMAT_MOD_INVALID & 0xFFFFFFFF); } static void linux_dmabuf_send_formats(struct wlr_linux_dmabuf_v1 *linux_dmabuf, From e163a7cf486bf85e982e0fbe9c7a6588b0afb657 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 31 Mar 2021 22:05:18 +0200 Subject: [PATCH 049/190] backend/drm: fail on explicit modifier in drmModeAddFB2 drmModeAddFB2 doesn't support explicit modifiers. Only accept INVALID which indicates an implicit modifier and LINEAR which may indicate that GBM_BO_USE_LINEAR has been used. --- backend/drm/renderer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 3d1a5fb21..bfc94a24d 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -220,6 +220,13 @@ static uint32_t get_fb_for_bo(struct wlr_drm_backend *drm, wlr_log_errno(WLR_DEBUG, "drmModeAddFB2WithModifiers failed"); } } else { + if (dmabuf->modifier != DRM_FORMAT_MOD_INVALID && + dmabuf->modifier != DRM_FORMAT_MOD_LINEAR) { + wlr_log(WLR_ERROR, "Cannot import DRM framebuffer with explicit " + "modifier 0x%"PRIX64, dmabuf->modifier); + return 0; + } + int ret = drmModeAddFB2(drm->fd, dmabuf->width, dmabuf->height, dmabuf->format, handles, dmabuf->stride, dmabuf->offset, &id, 0); if (ret != 0 && dmabuf->format == DRM_FORMAT_ARGB8888 && From d5df8d5cbf5055a4712f3871f4ba227464ebebb5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 31 Mar 2021 22:20:24 +0200 Subject: [PATCH 050/190] render/egl: always add LINEAR to supported modifiers --- render/egl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/render/egl.c b/render/egl.c index a398d586b..9dae0724b 100644 --- a/render/egl.c +++ b/render/egl.c @@ -125,6 +125,15 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, DRM_FORMAT_MOD_INVALID); + if (modifiers_len == 0) { + // Asume the linear layout is supported if the driver doesn't + // explicitly say otherwise + wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, + DRM_FORMAT_MOD_LINEAR); + wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, + DRM_FORMAT_MOD_LINEAR); + } + for (int j = 0; j < modifiers_len; j++) { wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, modifiers[j]); From 98f2efde9837dec3e39fbe1f56832d18940eb6cd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 31 Mar 2021 22:07:54 +0200 Subject: [PATCH 051/190] render/drm_format_set: remove special LINEAR case This was used to make the intersection of INVALID and LINEAR result in LINEAR. We can now just require LINEAR to be in both lists. --- render/drm_format_set.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/render/drm_format_set.c b/render/drm_format_set.c index 90256098d..82997eda9 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -144,18 +144,6 @@ struct wlr_drm_format *wlr_drm_format_intersect( const struct wlr_drm_format *a, const struct wlr_drm_format *b) { assert(a->format == b->format); - // Special case: if a format only supports LINEAR and the other supports - // implicit modifiers, force LINEAR. This will force the allocator to - // create a buffer with a linear layout instead of an implicit modifier. - if (a->len == 1 && a->modifiers[0] == DRM_FORMAT_MOD_LINEAR && - wlr_drm_format_has(b, DRM_FORMAT_MOD_INVALID)) { - return wlr_drm_format_dup(a); - } - if (b->len == 1 && b->modifiers[0] == DRM_FORMAT_MOD_LINEAR && - wlr_drm_format_has(a, DRM_FORMAT_MOD_INVALID)) { - return wlr_drm_format_dup(b); - } - size_t format_cap = a->len < b->len ? a->len : b->len; size_t format_size = sizeof(struct wlr_drm_format) + format_cap * sizeof(a->modifiers[0]); From ef1669d33e15134e09d30c6989d53773629fd9ba Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 12:17:39 +0100 Subject: [PATCH 052/190] backend/drm: always add LINEAR to supported modifiers --- backend/drm/drm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index e22e06905..d7c532316 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -121,11 +121,12 @@ static bool add_plane(struct wlr_drm_backend *drm, for (size_t i = 0; i < drm_plane->count_formats; ++i) { // Force a LINEAR layout for the cursor if the driver doesn't support // modifiers - uint64_t mod = DRM_FORMAT_MOD_INVALID; - if (type == DRM_PLANE_TYPE_CURSOR) { - mod = DRM_FORMAT_MOD_LINEAR; + wlr_drm_format_set_add(&p->formats, drm_plane->formats[i], + DRM_FORMAT_MOD_LINEAR); + if (type != DRM_PLANE_TYPE_CURSOR) { + wlr_drm_format_set_add(&p->formats, drm_plane->formats[i], + DRM_FORMAT_MOD_INVALID); } - wlr_drm_format_set_add(&p->formats, drm_plane->formats[i], mod); } if (p->props.in_formats && drm->addfb2_modifiers) { From 83d78f9fd415a1110e888b3c5f9cc9fb79627217 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Nov 2021 21:42:08 +0100 Subject: [PATCH 053/190] render: add DMA-BUF docs Document some of the assumptions for DMA-BUF buffer sharing and modifiers. --- include/wlr/render/allocator.h | 12 ++++++++++++ include/wlr/render/dmabuf.h | 21 +++++++++++++++++++-- include/wlr/render/drm_format_set.h | 21 +++++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/include/wlr/render/allocator.h b/include/wlr/render/allocator.h index 3caeffa09..3150e36c3 100644 --- a/include/wlr/render/allocator.h +++ b/include/wlr/render/allocator.h @@ -51,6 +51,18 @@ void wlr_allocator_destroy(struct wlr_allocator *alloc); * * When the caller is done with it, they must unreference it by calling * wlr_buffer_drop. + * + * The `format` passed in indicates the format to use and the list of + * acceptable modifiers. The order in which modifiers are listed is not + * significant. + * + * When running with legacy drivers which don't support explicit modifiers, the + * allocator must recognize two modifiers: INVALID (for implicit tiling and/or + * compression) and LINEAR. + * + * The allocator must return a buffer using one of the modifiers listed. In + * particular, allocators must not return a buffer with an implicit modifier + * unless the user has allowed it by passing INVALID in the modifier list. */ struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, int width, int height, const struct wlr_drm_format *format); diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 76aad6295..62f8e0217 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -14,10 +14,27 @@ #define WLR_DMABUF_MAX_PLANES 4 +/** + * A Linux DMA-BUF pixel buffer. + * + * If the buffer was allocated with explicit modifiers enabled, the `modifier` + * field must not be INVALID. + * + * If the buffer was allocated with explicit modifiers disabled (either because + * the driver doesn't support it, or because the user didn't specify a valid + * modifier list), the `modifier` field can have two values: INVALID means that + * an implicit vendor-defined modifier is in use, LINEAR means that the buffer + * is linear. The `modifier` field must not have any other value. + * + * When importing a DMA-BUF, users must not ignore the modifier unless it's + * INVALID or LINEAR. In particular, users must not import a DMA-BUF to a + * legacy API which doesn't support specifying an explicit modifier unless the + * modifier is set to INVALID or LINEAR. + */ struct wlr_dmabuf_attributes { int32_t width, height; - uint32_t format; - uint64_t modifier; + uint32_t format; // FourCC code, see DRM_FORMAT_* in + uint64_t modifier; // see DRM_FORMAT_MOD_* in int n_planes; uint32_t offset[WLR_DMABUF_MAX_PLANES]; diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h index cb367a632..9427df3bd 100644 --- a/include/wlr/render/drm_format_set.h +++ b/include/wlr/render/drm_format_set.h @@ -5,7 +5,7 @@ #include #include -/** A single DRM format */ +/** A single DRM format, with a set of modifiers attached. */ struct wlr_drm_format { // The actual DRM format, from `drm_fourcc.h` uint32_t format; @@ -17,7 +17,24 @@ struct wlr_drm_format { uint64_t modifiers[]; }; -/** A set of DRM formats */ +/** + * A set of DRM formats and modifiers. + * + * This is used to describe the supported format + modifier combinations. For + * instance, backends will report the set they can display, and renderers will + * report the set they can render to. For a more general overview of formats + * and modifiers, see: + * https://lore.kernel.org/dri-devel/20210905122742.86029-1-daniels@collabora.com/ + * + * For compatibility with legacy drivers which don't support explicit + * modifiers, the special modifier DRM_FORMAT_MOD_INVALID is used to indicate + * that implicit modifiers are supported. Legacy drivers can also support the + * DRM_FORMAT_MOD_LINEAR modifier, which forces the buffer to have a linear + * layout. + * + * Users must not assume that implicit modifiers are supported unless INVALID + * is listed in the modifier list. + */ struct wlr_drm_format_set { // The number of formats size_t len; From 254ab890e787ccee1e33fb420781c9696761ce3c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 10:26:01 +0100 Subject: [PATCH 054/190] scene: add support for viewporter If the surface has a source box set, use that. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3172 --- types/scene/wlr_scene.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index b6eed4177..03439223b 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -715,7 +715,11 @@ static void render_node_iterator(struct wlr_scene_node *node, wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, NULL, &dst_box, matrix); + struct wlr_fbox src_box = {0}; + wlr_surface_get_buffer_source_box(surface, &src_box); + + render_texture(output, output_damage, texture, + &src_box, &dst_box, matrix); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); From d37eb5c2eaedcada7dd39da1a31c6e9a39c8ed46 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 27 Nov 2021 19:08:18 +0100 Subject: [PATCH 055/190] linux-dmabuf-v1: filter out LINEAR if implicit If only INVALID and LINEAR are valid modifiers, we need to filter out LINEAR since Xwayland won't be able to allocate a BO with the explicit linear modifier on hardware that does not support explicit modifiers. The addition of LINEAR is an internal implementation detail which simplifies the wlroots architecture for now. Evntually Xwayland should be fixed to filter out modifiers that are not supported by the GBM implementation, see [1]. This could be done by querying EGL for the supported modifiers. [1]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 --- types/wlr_linux_dmabuf_v1.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index dc5ca8af2..4b2b965cc 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -434,6 +434,16 @@ static void linux_dmabuf_send_modifiers(struct wl_resource *resource, return; } + // In case only INVALID and LINEAR are advertised, send INVALID only due to XWayland: + // https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + if (fmt->len == 2 && wlr_drm_format_has(fmt, DRM_FORMAT_MOD_INVALID) + && wlr_drm_format_has(fmt, DRM_FORMAT_MOD_INVALID)) { + uint64_t mod = DRM_FORMAT_MOD_INVALID; + zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, + mod >> 32, mod & 0xFFFFFFFF); + return; + } + for (size_t i = 0; i < fmt->len; i++) { uint64_t mod = fmt->modifiers[i]; zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, From 0fb479ca611b31be20e7adc44ff14491ffcadf11 Mon Sep 17 00:00:00 2001 From: Jonathan Wong Date: Sun, 28 Nov 2021 16:56:09 +0000 Subject: [PATCH 056/190] Added whitespace between "output" and "(not" --- types/wlr_cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 7ae9c46cd..a6b0716c7 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -854,7 +854,7 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { wlr_log(WLR_ERROR, "Cannot map device \"%s\" to output" - "(not found in this cursor)", dev->name); + " (not found in this cursor)", dev->name); return; } From bff5b2c5597b30b90b201825b6c1c6537bb06d84 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Mon, 29 Nov 2021 08:12:45 -0500 Subject: [PATCH 057/190] Insert new outputs at the end of the list This prevents auto-configuring a new output from changing the position of existing outputs. (v2: simplify insert-at-end logic) --- types/wlr_output_layout.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 782f5b71c..eb672f06e 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -185,7 +185,12 @@ static struct wlr_output_layout_output *output_layout_output_create( l_output->state->layout = layout; l_output->output = output; wl_signal_init(&l_output->events.destroy); - wl_list_insert(&layout->outputs, &l_output->link); + + /* + * Insert at the end of the list so that auto-configuring the + * new output doesn't change the layout of other outputs + */ + wl_list_insert(layout->outputs.prev, &l_output->link); wl_signal_add(&output->events.mode, &l_output->state->mode); l_output->state->mode.notify = handle_output_mode; From fbaefd90fc24f1c06be0d24cc3c4a01c71671157 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 22:46:10 +0100 Subject: [PATCH 058/190] backend/drm: poison buffers which cannot be scanned out Rather than repeatedly trying to import DMA-BUFs which cannot be scanned out, mark the failed ones with a special "poison" marker. Inspired from [1]. [1]: https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/731 --- backend/drm/renderer.c | 53 +++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index bfc94a24d..815ba9818 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -275,20 +275,56 @@ static void close_all_bo_handles(struct wlr_drm_backend *drm, } } +static void drm_poisoned_fb_handle_destroy(struct wlr_addon *addon) { + wlr_addon_finish(addon); + free(addon); +} + +static const struct wlr_addon_interface poisoned_fb_addon_impl = { + .name = "wlr_drm_poisoned_fb", + .destroy = drm_poisoned_fb_handle_destroy, +}; + +static bool is_buffer_poisoned(struct wlr_drm_backend *drm, + struct wlr_buffer *buf) { + return wlr_addon_find(&buf->addons, drm, &poisoned_fb_addon_impl) != NULL; +} + +/** + * Mark the buffer as "poisoned", ie. it cannot be imported into KMS. This + * allows us to avoid repeatedly trying to import it when it's not + * scanout-capable. + */ +static void poison_buffer(struct wlr_drm_backend *drm, + struct wlr_buffer *buf) { + struct wlr_addon *addon = calloc(1, sizeof(*addon)); + if (addon == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return; + } + wlr_addon_init(addon, &buf->addons, drm, &poisoned_fb_addon_impl); + wlr_log(WLR_DEBUG, "Poisoning buffer"); +} + static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) { + struct wlr_dmabuf_attributes attribs; + if (!wlr_buffer_get_dmabuf(buf, &attribs)) { + wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer"); + return NULL; + } + + if (is_buffer_poisoned(drm, buf)) { + wlr_log(WLR_DEBUG, "Buffer is poisoned"); + return NULL; + } + struct wlr_drm_fb *fb = calloc(1, sizeof(*fb)); if (!fb) { wlr_log_errno(WLR_ERROR, "Allocation failed"); return NULL; } - struct wlr_dmabuf_attributes attribs; - if (!wlr_buffer_get_dmabuf(buf, &attribs)) { - wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer"); - goto error_get_dmabuf; - } - if (formats && !wlr_drm_format_set_has(formats, attribs.format, attribs.modifier)) { // The format isn't supported by the plane. Try stripping the alpha @@ -302,7 +338,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, wlr_log(WLR_DEBUG, "Buffer format 0x%"PRIX32" with modifier " "0x%"PRIX64" cannot be scanned out", attribs.format, attribs.modifier); - goto error_get_dmabuf; + goto error_fb; } } @@ -318,6 +354,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, fb->id = get_fb_for_bo(drm, &attribs, handles); if (!fb->id) { wlr_log(WLR_DEBUG, "Failed to import BO in KMS"); + poison_buffer(drm, buf); goto error_bo_handle; } @@ -333,7 +370,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, error_bo_handle: close_all_bo_handles(drm, handles); -error_get_dmabuf: +error_fb: free(fb); return NULL; } From 6bfb930aa70ceb41455b9da2719a10538493a65d Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Mon, 29 Nov 2021 09:40:02 +0100 Subject: [PATCH 059/190] linux-dmabuf-v1: fix implicit check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The implicit check to filter out LINEAR for dmabuf checked for INVALID twice instead of checking for INVALID & LINEAR. Fix this. Fixes: d37eb5c2eaed ("linux-dmabuf-v1: filter out LINEAR if implicit") Reported-by: Dawid CzeluÅ›niak --- types/wlr_linux_dmabuf_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 4b2b965cc..b91fb59d9 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -437,7 +437,7 @@ static void linux_dmabuf_send_modifiers(struct wl_resource *resource, // In case only INVALID and LINEAR are advertised, send INVALID only due to XWayland: // https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 if (fmt->len == 2 && wlr_drm_format_has(fmt, DRM_FORMAT_MOD_INVALID) - && wlr_drm_format_has(fmt, DRM_FORMAT_MOD_INVALID)) { + && wlr_drm_format_has(fmt, DRM_FORMAT_MOD_LINEAR)) { uint64_t mod = DRM_FORMAT_MOD_INVALID; zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, mod >> 32, mod & 0xFFFFFFFF); From 456b971099b135512ce01383b486965290bf29db Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 18:07:39 +0100 Subject: [PATCH 060/190] output: destroy swapchain when disabled This avoids consuming GPU memory when an output is disabled. --- types/output/output.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/types/output/output.c b/types/output/output.c index 76c9ed9e9..d6f8f97ac 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -715,6 +715,15 @@ bool wlr_output_commit(struct wlr_output *output) { wlr_output_schedule_done(output); } + // Destroy the swapchains when an output is disabled + if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && + !output->pending.enabled) { + wlr_swapchain_destroy(output->swapchain); + output->swapchain = NULL; + wlr_swapchain_destroy(output->cursor_swapchain); + output->cursor_swapchain = NULL; + } + // Unset the front-buffer when a new buffer will replace it or when the // output is getting disabled if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) || From 2540de494e66c6fa056e9608755bfa7474d4ee47 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 18:33:08 +0100 Subject: [PATCH 061/190] output: don't leave dangling cursor_front_buffer Sometimes we were calling wlr_output_impl.set_cursor with a NULL buffer, but we weren't clearing wlr_output.cursor_front_buffer. Avoid leaving a dangling buffer behind. Introduce a helper function output_set_hardware_cursor which calls wlr_output_impl.set_cursor and keeps cursor_front_buffer in sync. --- types/output/cursor.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/types/output/cursor.c b/types/output/cursor.c index 8fa2cf010..efbf65032 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -11,6 +11,26 @@ #include "types/wlr_output.h" #include "util/signal.h" +static bool output_set_hardware_cursor(struct wlr_output *output, + struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) { + if (!output->impl->set_cursor) { + return false; + } + + if (!output->impl->set_cursor(output, buffer, hotspot_x, hotspot_y)) { + return false; + } + + wlr_buffer_unlock(output->cursor_front_buffer); + output->cursor_front_buffer = NULL; + + if (buffer != NULL) { + output->cursor_front_buffer = wlr_buffer_lock(buffer); + } + + return true; +} + static void output_cursor_damage_whole(struct wlr_output_cursor *cursor); void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) { @@ -25,8 +45,7 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) { output->software_cursor_locks); if (output->software_cursor_locks > 0 && output->hardware_cursor != NULL) { - assert(output->impl->set_cursor); - output->impl->set_cursor(output, NULL, 0, 0); + output_set_hardware_cursor(output, NULL, 0, 0); output_cursor_damage_whole(output->hardware_cursor); output->hardware_cursor = NULL; } @@ -345,14 +364,10 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { wlr_output_transform_invert(output->transform), buffer ? buffer->width : 0, buffer ? buffer->height : 0); - bool ok = output->impl->set_cursor(cursor->output, buffer, - hotspot.x, hotspot.y); + bool ok = output_set_hardware_cursor(output, buffer, hotspot.x, hotspot.y); + wlr_buffer_unlock(buffer); if (ok) { - wlr_buffer_unlock(output->cursor_front_buffer); - output->cursor_front_buffer = buffer; output->hardware_cursor = cursor; - } else { - wlr_buffer_unlock(buffer); } return ok; } @@ -465,9 +480,8 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, wlr_output_transform_invert(cursor->output->transform), buffer ? buffer->width : 0, buffer ? buffer->height : 0); - assert(cursor->output->impl->set_cursor); - cursor->output->impl->set_cursor(cursor->output, - buffer, hotspot.x, hotspot.y); + output_set_hardware_cursor(cursor->output, buffer, + hotspot.x, hotspot.y); } return; } @@ -490,8 +504,7 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, cursor->height = 0; if (cursor->output->hardware_cursor == cursor) { - assert(cursor->output->impl->set_cursor); - cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0); + output_set_hardware_cursor(cursor->output, NULL, 0, 0); } } } @@ -552,9 +565,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { wlr_signal_emit_safe(&cursor->events.destroy, cursor); if (cursor->output->hardware_cursor == cursor) { // If this cursor was the hardware cursor, disable it - if (cursor->output->impl->set_cursor) { - cursor->output->impl->set_cursor(cursor->output, NULL, 0, 0); - } + output_set_hardware_cursor(cursor->output, NULL, 0, 0); cursor->output->hardware_cursor = NULL; } wlr_texture_destroy(cursor->texture); From e93435016e0dfad0fefed3b68a9b60fe453c723e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 20:33:36 +0100 Subject: [PATCH 062/190] output: fix typo in wlr_output_impl.get_primary_formats docs The buffer capabilities indicate whether the formats returned are for DMA-BUFs or shared memory buffers. --- include/wlr/interfaces/wlr_output.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 5ae1ab56f..79cc8ee0a 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -86,7 +86,7 @@ struct wlr_output_impl { */ void (*get_cursor_size)(struct wlr_output *output, int *width, int *height); /** - * Get the list of DMA-BUF formats suitable for the primary buffer, + * Get the list of DRM formats suitable for the primary buffer, * assuming a buffer with the specified capabilities. * * If unimplemented, the primary buffer has no format constraint. If NULL From 697a1cd0f59f9a64f02e47b0f62a7184d04ad794 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 20:26:11 +0100 Subject: [PATCH 063/190] output: add wlr_output_get_primary_formats This allows compositors to get primary formats without manually calling wlr_output_impl.get_primary_formats. For example, the Sway patch for linux-dmabuf feedback [1] needs this. [1]: https://github.com/swaywm/sway/pull/6313 --- include/wlr/types/wlr_output.h | 10 ++++++++++ types/output/output.c | 30 ++++++++++++++++++++---------- types/output/render.c | 12 ++---------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 7d7fbaad8..9e18a2166 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -460,6 +460,16 @@ void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock); */ void wlr_output_render_software_cursors(struct wlr_output *output, pixman_region32_t *damage); +/** + * Get the set of DRM formats suitable for the primary buffer, assuming a + * buffer with the specified capabilities. + * + * NULL is returned if the backend doesn't have any format constraint, ie. all + * formats are supported. An empty set is returned if the backend doesn't + * support any format. + */ +const struct wlr_drm_format_set *wlr_output_get_primary_formats( + struct wlr_output *output, uint32_t buffer_caps); struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); diff --git a/types/output/output.c b/types/output/output.c index d6f8f97ac..e82ec1dc8 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -560,16 +560,8 @@ static bool output_basic_test(struct wlr_output *output) { struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); - const struct wlr_drm_format_set *display_formats = NULL; - if (output->impl->get_primary_formats) { - display_formats = - output->impl->get_primary_formats(output, allocator->buffer_caps); - if (display_formats == NULL) { - wlr_log(WLR_ERROR, "Failed to get primary display formats"); - return false; - } - } - + const struct wlr_drm_format_set *display_formats = + wlr_output_get_primary_formats(output, allocator->buffer_caps); struct wlr_drm_format *format = output_pick_format(output, display_formats, output->pending.render_format); if (format == NULL) { @@ -868,3 +860,21 @@ void wlr_output_damage_whole(struct wlr_output *output) { pixman_region32_fini(&damage); } + +const struct wlr_drm_format_set *wlr_output_get_primary_formats( + struct wlr_output *output, uint32_t buffer_caps) { + if (!output->impl->get_primary_formats) { + return NULL; + } + + const struct wlr_drm_format_set *formats = + output->impl->get_primary_formats(output, buffer_caps); + if (formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get primary display formats"); + + static const struct wlr_drm_format_set empty_format_set = {0}; + return &empty_format_set; + } + + return formats; +} diff --git a/types/output/render.c b/types/output/render.c index f23d1a9a8..97c62a58d 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -51,16 +51,8 @@ static bool output_create_swapchain(struct wlr_output *output, struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); - const struct wlr_drm_format_set *display_formats = NULL; - if (output->impl->get_primary_formats) { - display_formats = - output->impl->get_primary_formats(output, allocator->buffer_caps); - if (display_formats == NULL) { - wlr_log(WLR_ERROR, "Failed to get primary display formats"); - return false; - } - } - + const struct wlr_drm_format_set *display_formats = + wlr_output_get_primary_formats(output, allocator->buffer_caps); struct wlr_drm_format *format = output_pick_format(output, display_formats, output->render_format); if (format == NULL) { From dd84c5a1ccc322c4775282bbfc781f17e4ddac3a Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 30 Nov 2021 14:51:07 -0500 Subject: [PATCH 064/190] types/wlr_drm_lease_v1: add NULL check to drm lease resource destroy --- types/wlr_drm_lease_v1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index 7da40686e..7063e0d31 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -218,7 +218,9 @@ void wlr_drm_lease_v1_revoke(struct wlr_drm_lease_v1 *lease) { static void drm_lease_v1_handle_resource_destroy(struct wl_resource *resource) { struct wlr_drm_lease_v1 *lease = drm_lease_v1_from_resource(resource); - wlr_drm_lease_terminate(lease->drm_lease); + if (lease != NULL) { + wlr_drm_lease_terminate(lease->drm_lease); + } } static void drm_lease_v1_handle_destroy( From ba974a4e9f17e5f75efebe312e8bd1b24ad7b06d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 20:55:04 +0100 Subject: [PATCH 065/190] scene: add wlr_scene_get_scene_output This allows getting a wlr_scene_output from a wlr_output. Since an output can only be added once to a scene-graph there's no ambiguity. This is useful for compositors using wlr_scene_attach_output_layout: the output layout integration automatically creates a scene-graph output for each wlr_output added to the layout. --- include/wlr/types/wlr_scene.h | 7 +++++++ types/scene/wlr_scene.c | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 622dbb280..bca0b269e 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -282,6 +282,13 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); */ void wlr_scene_output_for_each_surface(struct wlr_scene_output *scene_output, wlr_surface_iterator_func_t iterator, void *user_data); +/** + * Get a scene-graph output from a wlr_output. + * + * If the output hasn't been added to the scene-graph, returns NULL. + */ +struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, + struct wlr_output *output); /** * Attach an output layout to a scene. diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 03439223b..d1236fe0e 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -828,6 +828,18 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { free(scene_output); } +struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, + struct wlr_output *output) { + struct wlr_addon *addon = + wlr_addon_find(&output->addons, scene, &output_addon_impl); + if (addon == NULL) { + return NULL; + } + struct wlr_scene_output *scene_output = + wl_container_of(addon, scene_output, addon); + return scene_output; +} + void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, int lx, int ly) { if (scene_output->x == lx && scene_output->y == ly) { From a44b2af6722397d5750c81cb29d09c4e6a52e546 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 25 Nov 2021 20:28:54 +0100 Subject: [PATCH 066/190] tinywl: use wlr_scene --- tinywl/tinywl.c | 268 ++++++++++++++++-------------------------------- 1 file changed, 89 insertions(+), 179 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index ab5ed7ce4..5ce7c4e81 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200112L +#include #include #include #include @@ -14,10 +15,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ struct tinywl_server { struct wlr_backend *backend; struct wlr_renderer *renderer; struct wlr_allocator *allocator; + struct wlr_scene *scene; struct wlr_xdg_shell *xdg_shell; struct wl_listener new_xdg_surface; @@ -76,12 +78,12 @@ struct tinywl_view { struct wl_list link; struct tinywl_server *server; struct wlr_xdg_surface *xdg_surface; + struct wlr_scene_node *scene_node; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; struct wl_listener request_move; struct wl_listener request_resize; - bool mapped; int x, y; }; @@ -118,6 +120,7 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); /* Move the view to the front */ + wlr_scene_node_raise_to_top(view->scene_node); wl_list_remove(&view->link); wl_list_insert(&server->views, &view->link); /* Activate the new surface */ @@ -166,14 +169,9 @@ static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) { if (wl_list_length(&server->views) < 2) { break; } - struct tinywl_view *current_view = wl_container_of( - server->views.next, current_view, link); struct tinywl_view *next_view = wl_container_of( - current_view->link.next, next_view, link); + server->views.prev, next_view, link); focus_view(next_view, next_view->xdg_surface->surface); - /* Move the previous view to the end of the list */ - wl_list_remove(¤t_view->link); - wl_list_insert(server->views.prev, ¤t_view->link); break; default: return false; @@ -199,7 +197,8 @@ static void keyboard_handle_key( bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if ((modifiers & WLR_MODIFIER_ALT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { /* If alt is held down and this button was _pressed_, we attempt to * process it as a compositor keybinding. */ for (int i = 0; i < nsyms; i++) { @@ -310,52 +309,32 @@ static void seat_request_set_selection(struct wl_listener *listener, void *data) wlr_seat_set_selection(server->seat, event->source, event->serial); } -static bool view_at(struct tinywl_view *view, - double lx, double ly, struct wlr_surface **surface, - double *sx, double *sy) { - /* - * XDG toplevels may have nested surfaces, such as popup windows for context - * menus or tooltips. This function tests if any of those are underneath the - * coordinates lx and ly (in output Layout Coordinates). If so, it sets the - * surface pointer to that wlr_surface and the sx and sy coordinates to the - * coordinates relative to that surface's top-left corner. - */ - double view_sx = lx - view->x; - double view_sy = ly - view->y; - - double _sx, _sy; - struct wlr_surface *_surface = NULL; - _surface = wlr_xdg_surface_surface_at( - view->xdg_surface, view_sx, view_sy, &_sx, &_sy); - - if (_surface != NULL) { - *sx = _sx; - *sy = _sy; - *surface = _surface; - return true; - } - - return false; -} - static struct tinywl_view *desktop_view_at( struct tinywl_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - /* This iterates over all of our surfaces and attempts to find one under the - * cursor. This relies on server->views being ordered from top-to-bottom. */ - struct tinywl_view *view; - wl_list_for_each(view, &server->views, link) { - if (view_at(view, lx, ly, surface, sx, sy)) { - return view; - } + /* This returns the topmost node in the scene at the given layout coords. + * we only care about surface nodes as we are specifically looking for a + * surface in the surface tree of a tinywl_view. */ + struct wlr_scene_node *node = wlr_scene_node_at( + &server->scene->node, lx, ly, sx, sy); + if (node == NULL || node->type != WLR_SCENE_NODE_SURFACE) { + return NULL; } - return NULL; + *surface = wlr_scene_surface_from_node(node)->surface; + /* Find the node corresponding to the tinywl_view at the root of this + * surface tree, it is the only one for which we set the data field. */ + while (node != NULL && node->data == NULL) { + node = node->parent; + } + return node->data; } static void process_cursor_move(struct tinywl_server *server, uint32_t time) { /* Move the grabbed view to the new position. */ - server->grabbed_view->x = server->cursor->x - server->grab_x; - server->grabbed_view->y = server->cursor->y - server->grab_y; + struct tinywl_view *view = server->grabbed_view; + view->x = server->cursor->x - server->grab_x; + view->y = server->cursor->y - server->grab_y; + wlr_scene_node_set_position(view->scene_node, view->x, view->y); } static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { @@ -404,6 +383,7 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); view->x = new_left - geo_box.x; view->y = new_top - geo_box.y; + wlr_scene_node_set_position(view->scene_node, view->x, view->y); int new_width = new_right - new_left; int new_height = new_bottom - new_top; @@ -530,74 +510,12 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(server->seat); } -/* Used to move all of the data necessary to render a surface from the top-level - * frame handler to the per-surface render function. */ -struct render_data { - struct wlr_output *output; - struct wlr_renderer *renderer; - struct tinywl_view *view; - struct timespec *when; -}; - -static void render_surface(struct wlr_surface *surface, +// TODO: We should avoid sending the frame done event twice if a surface +// appears on multiple outputs. +// https://github.com/swaywm/wlroots/issues/3210 +static void send_frame_done(struct wlr_surface *surface, int sx, int sy, void *data) { - /* This function is called for every surface that needs to be rendered. */ - struct render_data *rdata = data; - struct tinywl_view *view = rdata->view; - struct wlr_output *output = rdata->output; - - /* We first obtain a wlr_texture, which is a GPU resource. wlroots - * automatically handles negotiating these with the client. The underlying - * resource could be an opaque handle passed from the client, or the client - * could have sent a pixel buffer which we copied to the GPU, or a few other - * means. You don't have to worry about this, wlroots takes care of it. */ - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - return; - } - - /* The view has a position in layout coordinates. If you have two displays, - * one next to the other, both 1080p, a view on the rightmost display might - * have layout coordinates of 2000,100. We need to translate that to - * output-local coordinates, or (2000 - 1920). */ - double ox = 0, oy = 0; - wlr_output_layout_output_coords( - view->server->output_layout, output, &ox, &oy); - ox += view->x + sx, oy += view->y + sy; - - /* We also have to apply the scale factor for HiDPI outputs. This is only - * part of the puzzle, TinyWL does not fully support HiDPI. */ - struct wlr_box box = { - .x = ox * output->scale, - .y = oy * output->scale, - .width = surface->current.width * output->scale, - .height = surface->current.height * output->scale, - }; - - /* - * Those familiar with OpenGL are also familiar with the role of matricies - * in graphics programming. We need to prepare a matrix to render the view - * with. wlr_matrix_project_box is a helper which takes a box with a desired - * x, y coordinates, width and height, and an output geometry, then - * prepares an orthographic projection and multiplies the necessary - * transforms to produce a model-view-projection matrix. - * - * Naturally you can do this any way you like, for example to make a 3D - * compositor. - */ - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, 0, - output->transform_matrix); - - /* This takes our matrix, the texture, and an alpha, and performs the actual - * rendering on the GPU. */ - wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); - - /* This lets the client know that we've displayed that frame and it can - * prepare another one now if it likes. */ - wlr_surface_send_frame_done(surface, rdata->when); + wlr_surface_send_frame_done(surface, data); } static void output_frame(struct wl_listener *listener, void *data) { @@ -605,56 +523,16 @@ static void output_frame(struct wl_listener *listener, void *data) { * generally at the output's refresh rate (e.g. 60Hz). */ struct tinywl_output *output = wl_container_of(listener, output, frame); - struct wlr_renderer *renderer = output->server->renderer; + + struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( + output->server->scene, output->wlr_output); + + /* Render the scene if needed and commit the output */ + wlr_scene_output_commit(scene_output); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - - /* wlr_output_attach_render makes the OpenGL context current. */ - if (!wlr_output_attach_render(output->wlr_output, NULL)) { - return; - } - /* The "effective" resolution can change if you rotate your outputs. */ - int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); - /* Begin the renderer (calls glViewport and some other GL sanity checks) */ - wlr_renderer_begin(renderer, width, height); - - float color[4] = {0.3, 0.3, 0.3, 1.0}; - wlr_renderer_clear(renderer, color); - - /* Each subsequent window we render is rendered on top of the last. Because - * our view list is ordered front-to-back, we iterate over it backwards. */ - struct tinywl_view *view; - wl_list_for_each_reverse(view, &output->server->views, link) { - if (!view->mapped) { - /* An unmapped view should not be rendered. */ - continue; - } - struct render_data rdata = { - .output = output->wlr_output, - .view = view, - .renderer = renderer, - .when = &now, - }; - /* This calls our render_surface function for each surface among the - * xdg_surface's toplevel and popups. */ - wlr_xdg_surface_for_each_surface(view->xdg_surface, - render_surface, &rdata); - } - - /* Hardware cursors are rendered by the GPU on a separate plane, and can be - * moved around without re-rendering what's beneath them - which is more - * efficient. However, not all hardware supports hardware cursors. For this - * reason, wlroots provides a software fallback, which we ask it to render - * here. wlr_cursor handles configuring hardware vs software cursors for you, - * and this function is a no-op when hardware cursors are in use. */ - wlr_output_render_software_cursors(output->wlr_output, NULL); - - /* Conclude rendering and swap the buffers, showing the final frame - * on-screen. */ - wlr_renderer_end(renderer); - wlr_output_commit(output->wlr_output); + wlr_scene_output_for_each_surface(scene_output, send_frame_done, &now); } static void server_new_output(struct wl_listener *listener, void *data) { @@ -704,23 +582,32 @@ static void server_new_output(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(server->output_layout, wlr_output); } -static void xdg_surface_map(struct wl_listener *listener, void *data) { +static void xdg_toplevel_map(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ struct tinywl_view *view = wl_container_of(listener, view, map); - view->mapped = true; + + wl_list_insert(&view->server->views, &view->link); + focus_view(view, view->xdg_surface->surface); } -static void xdg_surface_unmap(struct wl_listener *listener, void *data) { +static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ struct tinywl_view *view = wl_container_of(listener, view, unmap); - view->mapped = false; + + wl_list_remove(&view->link); } -static void xdg_surface_destroy(struct wl_listener *listener, void *data) { +static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { /* Called when the surface is destroyed and should never be shown again. */ struct tinywl_view *view = wl_container_of(listener, view, destroy); - wl_list_remove(&view->link); + + wl_list_remove(&view->map.link); + wl_list_remove(&view->unmap.link); + wl_list_remove(&view->destroy.link); + wl_list_remove(&view->request_move.link); + wl_list_remove(&view->request_resize.link); + free(view); } @@ -746,8 +633,10 @@ static void begin_interactive(struct tinywl_view *view, struct wlr_box geo_box; wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); - double border_x = (view->x + geo_box.x) + ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); - double border_y = (view->y + geo_box.y) + ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); + double border_x = (view->x + geo_box.x) + + ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); + double border_y = (view->y + geo_box.y) + + ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); server->grab_x = server->cursor->x - border_x; server->grab_y = server->cursor->y - border_y; @@ -788,22 +677,38 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { struct tinywl_server *server = wl_container_of(listener, server, new_xdg_surface); struct wlr_xdg_surface *xdg_surface = data; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + + /* We must add xdg popups to the scene graph so they get rendered. The + * wlroots scene graph provides a helper for this, but to use it we must + * provide the proper parent scene node of the xdg popup. To enable this, + * we always set the user data field of xdg_surfaces to the corresponding + * scene node. */ + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface( + xdg_surface->popup->parent); + struct wlr_scene_node *parent_node = parent->data; + xdg_surface->data = wlr_scene_xdg_surface_create( + parent_node, xdg_surface); return; } + assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); /* Allocate a tinywl_view for this surface */ struct tinywl_view *view = calloc(1, sizeof(struct tinywl_view)); view->server = server; view->xdg_surface = xdg_surface; + view->scene_node = wlr_scene_xdg_surface_create( + &view->server->scene->node, view->xdg_surface); + view->scene_node->data = view; + xdg_surface->data = view->scene_node; /* Listen to the various events it can emit */ - view->map.notify = xdg_surface_map; + view->map.notify = xdg_toplevel_map; wl_signal_add(&xdg_surface->events.map, &view->map); - view->unmap.notify = xdg_surface_unmap; + view->unmap.notify = xdg_toplevel_unmap; wl_signal_add(&xdg_surface->events.unmap, &view->unmap); - view->destroy.notify = xdg_surface_destroy; + view->destroy.notify = xdg_toplevel_destroy; wl_signal_add(&xdg_surface->events.destroy, &view->destroy); /* cotd */ @@ -812,9 +717,6 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { wl_signal_add(&toplevel->events.request_move, &view->request_move); view->request_resize.notify = xdg_toplevel_request_resize; wl_signal_add(&toplevel->events.request_resize, &view->request_resize); - - /* Add it to the list of views. */ - wl_list_insert(&server->views, &view->link); } int main(int argc, char *argv[]) { @@ -880,9 +782,17 @@ int main(int argc, char *argv[]) { server.new_output.notify = server_new_output; wl_signal_add(&server.backend->events.new_output, &server.new_output); - /* Set up our list of views and the xdg-shell. The xdg-shell is a Wayland - * protocol which is used for application windows. For more detail on - * shells, refer to my article: + /* Create a scene graph. This is a wlroots abstraction that handles all + * rendering and damage tracking. All the compositor author needs to do + * is add things that should be rendered to the scene graph at the proper + * positions and then call wlr_scene_output_commit() to render a frame if + * necessary. + */ + server.scene = wlr_scene_create(); + wlr_scene_attach_output_layout(server.scene, server.output_layout); + + /* Set up the xdg-shell. The xdg-shell is a Wayland protocol which is used + * for application windows. For more detail on shells, refer to my article: * * https://drewdevault.com/2018/07/29/Wayland-shells.html */ From 611b9ca84331f3278cfc31e188a86ed117aadb82 Mon Sep 17 00:00:00 2001 From: Moon Sungjoon Date: Wed, 1 Dec 2021 05:40:23 +0900 Subject: [PATCH 067/190] backend/wayland: improve wayland input device name Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3332 This makes input device names include it's type name --- backend/wayland/seat.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 7792d136e..c2bac46a9 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -468,9 +468,32 @@ struct wlr_wl_input_device *create_wl_input_device( unsigned int vendor = 0, product = 0; - size_t name_size = 8 + strlen(seat->name) + 1; + const char *type_name; + + switch (type) { + case WLR_INPUT_DEVICE_KEYBOARD: + type_name = "keyboard"; + break; + case WLR_INPUT_DEVICE_POINTER: + type_name = "pointer"; + break; + case WLR_INPUT_DEVICE_TOUCH: + type_name = "touch"; + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + type_name = "tablet-tool"; + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + type_name = "tablet-pad"; + break; + case WLR_INPUT_DEVICE_SWITCH: + type_name = "switch"; + break; + } + + size_t name_size = 8 + strlen(type_name) + strlen(seat->name) + 1; char name[name_size]; - (void) snprintf(name, name_size, "wayland-%s", seat->name); + (void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name); wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, product); From 812ab2e716dc7c1ac906a206709ce009ae30c45c Mon Sep 17 00:00:00 2001 From: Quantum Date: Wed, 1 Dec 2021 02:31:45 -0500 Subject: [PATCH 068/190] Fix uninitialized variable errors in release mode When using `meson --buildtype=release`, `-Wextra -Werror` is passed. This includes `-Werror=maybe-uninitialized`, which complains about the instances fixed in this commit. --- backend/wayland/seat.c | 2 +- tinywl/tinywl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index c2bac46a9..76c25fe5a 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -468,7 +468,7 @@ struct wlr_wl_input_device *create_wl_input_device( unsigned int vendor = 0, product = 0; - const char *type_name; + const char *type_name = "unknown"; switch (type) { case WLR_INPUT_DEVICE_KEYBOARD: diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 5ce7c4e81..487757409 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -475,7 +475,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); double sx, sy; - struct wlr_surface *surface; + struct wlr_surface *surface = NULL; struct tinywl_view *view = desktop_view_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); if (event->state == WLR_BUTTON_RELEASED) { From ffd4a27714833826542e1b083b3f3ad431f49107 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Dec 2021 14:03:37 +0100 Subject: [PATCH 069/190] render/egl: store IMG_context_priority in wlr_egl The next commit will split extension lookup and context initialization. --- include/wlr/render/egl.h | 1 + render/egl.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 903b70a3f..8db0718ab 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -40,6 +40,7 @@ struct wlr_egl { bool KHR_image_base; bool EXT_image_dma_buf_import; bool EXT_image_dma_buf_import_modifiers; + bool IMG_context_priority; // Device extensions bool EXT_device_drm; diff --git a/render/egl.c b/render/egl.c index 9dae0724b..a7b39cc27 100644 --- a/render/egl.c +++ b/render/egl.c @@ -324,6 +324,9 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, return false; } + egl->exts.IMG_context_priority = + check_egl_ext(display_exts_str, "EGL_IMG_context_priority"); + wlr_log(WLR_INFO, "Supported EGL display extensions: %s", display_exts_str); if (device_exts_str != NULL) { wlr_log(WLR_INFO, "Supported EGL device extensions: %s", device_exts_str); @@ -336,9 +339,6 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, init_dmabuf_formats(egl); - bool ext_context_priority = - check_egl_ext(display_exts_str, "EGL_IMG_context_priority"); - size_t atti = 0; EGLint attribs[5]; attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; @@ -346,7 +346,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, // Request a high priority context if possible // TODO: only do this if we're running as the DRM master - bool request_high_priority = ext_context_priority; + bool request_high_priority = egl->exts.IMG_context_priority; // Try to reschedule all of our rendering to be completed first. If it // fails, it will fallback to the default priority (MEDIUM). From 051d1ce90ef9ab3ce931b3b2df43012960df514b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 27 Nov 2021 20:01:48 +0100 Subject: [PATCH 070/190] render/egl: add wlr_egl_create_with_context This allows creating a wlr_egl from an already-existing EGL display and context. This is useful to allow compositors to choose the exact EGL initialization parameters. --- include/wlr/render/egl.h | 3 ++ render/egl.c | 59 ++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 8db0718ab..2af073cae 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -69,6 +69,9 @@ struct wlr_egl { struct wlr_drm_format_set dmabuf_render_formats; }; +struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, + EGLContext context); + /** * Make the EGL context current. * diff --git a/render/egl.c b/render/egl.c index a7b39cc27..a5801a1d1 100644 --- a/render/egl.c +++ b/render/egl.c @@ -232,14 +232,8 @@ static struct wlr_egl *egl_create(void) { return egl; } -static bool egl_init(struct wlr_egl *egl, EGLenum platform, - void *remote_display) { - egl->display = egl->procs.eglGetPlatformDisplayEXT(platform, - remote_display, NULL); - if (egl->display == EGL_NO_DISPLAY) { - wlr_log(WLR_ERROR, "Failed to create EGL display"); - return false; - } +static bool egl_init_display(struct wlr_egl *egl, EGLDisplay *display) { + egl->display = display; EGLint major, minor; if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { @@ -327,11 +321,11 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, egl->exts.IMG_context_priority = check_egl_ext(display_exts_str, "EGL_IMG_context_priority"); + wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(WLR_INFO, "Supported EGL display extensions: %s", display_exts_str); if (device_exts_str != NULL) { wlr_log(WLR_INFO, "Supported EGL device extensions: %s", device_exts_str); } - wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(WLR_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); if (driver_name != NULL) { wlr_log(WLR_INFO, "EGL driver name: %s", driver_name); @@ -339,6 +333,23 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, init_dmabuf_formats(egl); + return true; +} + +static bool egl_init(struct wlr_egl *egl, EGLenum platform, + void *remote_display) { + EGLDisplay display = egl->procs.eglGetPlatformDisplayEXT(platform, + remote_display, NULL); + if (display == EGL_NO_DISPLAY) { + wlr_log(WLR_ERROR, "Failed to create EGL display"); + return false; + } + + if (!egl_init_display(egl, display)) { + eglTerminate(display); + return false; + } + size_t atti = 0; EGLint attribs[5]; attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; @@ -516,6 +527,36 @@ error: return NULL; } +struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, + EGLContext context) { + EGLint client_type; + if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &client_type) || + client_type != EGL_OPENGL_ES_API) { + wlr_log(WLR_ERROR, "Unsupported EGL context client type (need OpenGL ES)"); + return NULL; + } + + EGLint client_version; + if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_VERSION, &client_version) || + client_version < 2) { + wlr_log(WLR_ERROR, "Unsupported EGL context client version (need OpenGL ES >= 2)"); + return NULL; + } + + struct wlr_egl *egl = egl_create(); + if (egl == NULL) { + return NULL; + } + + if (!egl_init_display(egl, display)) { + return NULL; + } + + egl->context = context; + + return egl; +} + void wlr_egl_destroy(struct wlr_egl *egl) { if (egl == NULL) { return; From de0bc7831954a5e4baa367b01bb02b755b53e5d0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Dec 2021 14:12:09 +0100 Subject: [PATCH 071/190] render/pixman: advertise MOD_INVALID instead of MOD_LINEAR The backends and allocators use INVALID, but the renderer uses LINEAR. Running a compositor with WLR_RENDERER=pixman results in: 00:00:00.744 [types/output/render.c:59] Failed to pick primary buffer format for output 'WL-1' --- render/pixman/renderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/pixman/renderer.c b/render/pixman/renderer.c index c65523b0f..13db08800 100644 --- a/render/pixman/renderer.c +++ b/render/pixman/renderer.c @@ -528,7 +528,7 @@ struct wlr_renderer *wlr_pixman_renderer_create(void) { for (size_t i = 0; i < len; ++i) { wlr_drm_format_set_add(&renderer->drm_formats, formats[i], - DRM_FORMAT_MOD_LINEAR); + DRM_FORMAT_MOD_INVALID); } return &renderer->wlr_renderer; From 1bf9676e8781c281265267d71ad7c911516be023 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 27 Nov 2021 18:33:04 +0100 Subject: [PATCH 072/190] render/egl: improve modifier support detection Support for EXT_image_dma_buf_import_modifiers doesn't necessarily indicate support for modifiers. For instance, Mesa will advertise EXT_image_dma_buf_import_modifiers for all drivers. This is a trick to allow EGL clients to enumerate supported formats (something EXT_image_dma_buf_import is missing). For more information, see [1]. Add a new wlr_egl.has_modifiers flag which indicates whether modifiers are supported. It's set to true if any eglQueryDmaBufModifiersEXT query returned a non-empty list. Use that flag to figure out whether the buffer modifier should be passed to the EGL implementation on import. [1]: https://github.com/KhronosGroup/EGL-Registry/issues/142 --- include/wlr/render/egl.h | 1 + render/egl.c | 23 +++++++++-------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 2af073cae..0d84958be 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -65,6 +65,7 @@ struct wlr_egl { PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT; } procs; + bool has_modifiers; struct wlr_drm_format_set dmabuf_texture_formats; struct wlr_drm_format_set dmabuf_render_formats; }; diff --git a/render/egl.c b/render/egl.c index a5801a1d1..d5d6cfb7d 100644 --- a/render/egl.c +++ b/render/egl.c @@ -160,6 +160,8 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { has_modifiers ? "supported" : "unsupported"); free(str_formats); + egl->has_modifiers = has_modifiers; + out: free(formats); } @@ -644,19 +646,11 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, return NULL; } - bool has_modifier = false; - - // we assume the same way we assumed formats without the import_modifiers - // extension that mod_linear is supported. The special mod mod_invalid - // is sometimes used to signal modifier unawareness which is what we - // have here if (attributes->modifier != DRM_FORMAT_MOD_INVALID && - attributes->modifier != DRM_FORMAT_MOD_LINEAR) { - if (!egl->exts.EXT_image_dma_buf_import_modifiers) { - wlr_log(WLR_ERROR, "dmabuf modifiers extension not present"); - return NULL; - } - has_modifier = true; + attributes->modifier != DRM_FORMAT_MOD_LINEAR && + !egl->has_modifiers) { + wlr_log(WLR_ERROR, "EGL implementation doesn't support modifiers"); + return NULL; } unsigned int atti = 0; @@ -702,14 +696,15 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, } }; - for (int i=0; i < attributes->n_planes; i++) { + for (int i = 0; i < attributes->n_planes; i++) { attribs[atti++] = attr_names[i].fd; attribs[atti++] = attributes->fd[i]; attribs[atti++] = attr_names[i].offset; attribs[atti++] = attributes->offset[i]; attribs[atti++] = attr_names[i].pitch; attribs[atti++] = attributes->stride[i]; - if (has_modifier) { + if (egl->has_modifiers && + attributes->modifier != DRM_FORMAT_MOD_INVALID) { attribs[atti++] = attr_names[i].mod_lo; attribs[atti++] = attributes->modifier & 0xFFFFFFFF; attribs[atti++] = attr_names[i].mod_hi; From 0d32118a8087061c17eac30e9b00ee527d6d3a4e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Dec 2021 08:49:48 +0100 Subject: [PATCH 073/190] output: fix modifier stripping DRM formats with an empty modifier list are invalid. Instead of emptying the list, reduce it to { INVALID }. Add a check to make sure the renderer and backend support implicit modifiers, so that we don't fallback on e.g. Vulkan. Closes: https://github.com/swaywm/sway/issues/6692 --- types/output/render.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/types/output/render.c b/types/output/render.c index 97c62a58d..985b93a98 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -74,7 +74,14 @@ static bool output_create_swapchain(struct wlr_output *output, format->format, output->name); if (!allow_modifiers && (format->len != 1 || format->modifiers[0] != DRM_FORMAT_MOD_LINEAR)) { + if (!wlr_drm_format_has(format, DRM_FORMAT_MOD_INVALID)) { + wlr_log(WLR_DEBUG, "Implicit modifiers not supported"); + free(format); + return false; + } + format->len = 0; + wlr_drm_format_add(&format, DRM_FORMAT_MOD_INVALID); } struct wlr_swapchain *swapchain = From 92080b3a014d92af628de964e66aca705da3041d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Dec 2021 11:45:57 +0100 Subject: [PATCH 074/190] readme: update wrapper libraries link Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3336 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33c59104b..2f9adf71e 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,6 @@ See [CONTRIBUTING.md]. [wiki]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Getting-started [#sway-devel on Libera Chat]: https://web.libera.chat/gamja/?channels=#sway-devel [Sway]: https://github.com/swaywm/sway -[wrapper libraries]: https://github.com/search?q=topic%3Abindings+org%3Aswaywm&type=Repositories +[wrapper libraries]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Projects-which-use-wlroots#wrapper-libraries [libseat]: https://git.sr.ht/~kennylevinsen/seatd [CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md From 7201aae3d607ad121ea0dfb3a50eb2c3f65b7d85 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Dec 2021 13:35:50 +0100 Subject: [PATCH 075/190] render/drm-format-set: add wlr_drm_format_set_intersect This intersects two DRM format sets. This is useful for implementing DMA-BUF feedback in compositors, see e.g. the Sway PR [1]. [1]: https://github.com/swaywm/sway/pull/6313 --- include/wlr/render/drm_format_set.h | 9 +++++++ render/drm_format_set.c | 38 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h index 9427df3bd..9f4a86ea4 100644 --- a/include/wlr/render/drm_format_set.h +++ b/include/wlr/render/drm_format_set.h @@ -63,4 +63,13 @@ bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, uint64_t modifier); +/** + * Intersect two DRM format sets `a` and `b`, storing in the destination set + * `dst` the format + modifier pairs which are in both source sets. + * + * Returns false on failure or when the intersection is empty. + */ +bool wlr_drm_format_set_intersect(struct wlr_drm_format_set *dst, + const struct wlr_drm_format_set *a, const struct wlr_drm_format_set *b); + #endif diff --git a/render/drm_format_set.c b/render/drm_format_set.c index 82997eda9..134717462 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -175,3 +175,41 @@ struct wlr_drm_format *wlr_drm_format_intersect( return format; } + +bool wlr_drm_format_set_intersect(struct wlr_drm_format_set *dst, + const struct wlr_drm_format_set *a, const struct wlr_drm_format_set *b) { + assert(dst != a && dst != b); + + struct wlr_drm_format_set out = {0}; + out.capacity = a->len < b->len ? a->len : b->len; + out.formats = calloc(out.capacity, sizeof(struct wlr_drm_format *)); + if (out.formats == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } + + for (size_t i = 0; i < a->len; i++) { + for (size_t j = 0; j < b->len; j++) { + if (a->formats[i]->format == b->formats[j]->format) { + // When the two formats have no common modifier, keep + // intersecting the rest of the formats: they may be compatible + // with each other + struct wlr_drm_format *format = + wlr_drm_format_intersect(a->formats[i], b->formats[j]); + if (format != NULL) { + out.formats[out.len] = format; + out.len++; + } + break; + } + } + } + + if (out.len == 0) { + wlr_drm_format_set_finish(&out); + return false; + } + + *dst = out; + return true; +} From f016eca97cf046c5273c5112201588d4fdca9818 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Dec 2021 11:06:49 +0100 Subject: [PATCH 076/190] output: add wlr_output_event_commit.buffer This allows output commit listeners to access the newly committed buffer. Currently wlr_output.front_buffer is used but it'll get removed in the next commit. --- include/wlr/types/wlr_output.h | 1 + types/output/output.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 9e18a2166..689b8158c 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -211,6 +211,7 @@ struct wlr_output_event_commit { struct wlr_output *output; uint32_t committed; // bitmask of enum wlr_output_state_field struct timespec *when; + struct wlr_buffer *buffer; // NULL if no buffer is committed }; enum wlr_output_present_flag { diff --git a/types/output/output.c b/types/output/output.c index e82ec1dc8..8655ef981 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -743,6 +743,7 @@ bool wlr_output_commit(struct wlr_output *output) { .output = output, .committed = committed, .when = &now, + .buffer = back_buffer, }; wlr_signal_emit_safe(&output->events.commit, &event); From 60b7267e1846b1bce39d30e73abe817faaa8fcff Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Dec 2021 11:10:05 +0100 Subject: [PATCH 077/190] export-dmabuf-v1: use wlr_output_event_commit.buffer --- types/wlr_export_dmabuf_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index d26a9a450..b47758c63 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -66,7 +66,7 @@ static void frame_output_handle_commit(struct wl_listener *listener, wl_list_init(&frame->output_commit.link); struct wlr_dmabuf_attributes attribs = {0}; - if (!wlr_buffer_get_dmabuf(frame->output->front_buffer, &attribs)) { + if (!wlr_buffer_get_dmabuf(event->buffer, &attribs)) { zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource, ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY); frame_destroy(frame); From 45069fb6234010e59933baad813c63def0254536 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 3 Dec 2021 11:19:20 +0100 Subject: [PATCH 078/190] screencopy-v1: use wlr_output_event_commit.buffer --- types/wlr_screencopy_v1.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index e0e7916ba..e2c020db5 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -189,7 +190,7 @@ static void frame_send_ready(struct wlr_screencopy_frame_v1 *frame, } static bool frame_shm_copy(struct wlr_screencopy_frame_v1 *frame, - uint32_t *flags) { + struct wlr_buffer *src_buffer, uint32_t *flags) { struct wl_shm_buffer *shm_buffer = frame->shm_buffer; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = output->renderer; @@ -208,7 +209,7 @@ static bool frame_shm_copy(struct wlr_screencopy_frame_v1 *frame, void *data = wl_shm_buffer_get_data(shm_buffer); uint32_t renderer_flags = 0; bool ok; - ok = wlr_renderer_begin_with_buffer(renderer, output->front_buffer); + ok = wlr_renderer_begin_with_buffer(renderer, src_buffer); ok = ok && wlr_renderer_read_pixels(renderer, drm_format, &renderer_flags, stride, width, height, x, y, 0, 0, data); wlr_renderer_end(renderer); @@ -254,20 +255,21 @@ error_src_tex: return false; } -static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame) { - struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; +static bool frame_dma_copy(struct wlr_screencopy_frame_v1 *frame, + struct wlr_buffer *src_buffer) { + struct wlr_dmabuf_v1_buffer *dst_buffer = frame->dma_buffer; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = output->renderer; assert(renderer); // TODO: add support for copying regions with DMA-BUFs if (frame->box.x != 0 || frame->box.y != 0 || - output->width != frame->box.width || - output->height != frame->box.height) { + src_buffer->width != frame->box.width || + src_buffer->height != frame->box.height) { return false; } - return blit_dmabuf(renderer, dma_buffer, output->front_buffer); + return blit_dmabuf(renderer, dst_buffer, src_buffer); } static void frame_handle_output_commit(struct wl_listener *listener, @@ -277,6 +279,7 @@ static void frame_handle_output_commit(struct wl_listener *listener, struct wlr_output_event_commit *event = data; struct wlr_output *output = frame->output; struct wlr_renderer *renderer = output->renderer; + struct wlr_buffer *buffer = event->buffer; assert(renderer); if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { @@ -298,9 +301,10 @@ static void frame_handle_output_commit(struct wl_listener *listener, wl_list_remove(&frame->output_commit.link); wl_list_init(&frame->output_commit.link); + uint32_t flags = 0; bool ok = frame->shm_buffer ? - frame_shm_copy(frame, &flags) : frame_dma_copy(frame); + frame_shm_copy(frame, buffer, &flags) : frame_dma_copy(frame, buffer); if (!ok) { zwlr_screencopy_frame_v1_send_failed(frame->resource); frame_destroy(frame); @@ -483,15 +487,6 @@ static struct wlr_screencopy_v1_client *client_from_resource( return wl_resource_get_user_data(resource); } -static uint32_t get_output_fourcc(struct wlr_output *output) { - struct wlr_dmabuf_attributes attr = {0}; - if (!output->front_buffer || - !wlr_buffer_get_dmabuf(output->front_buffer, &attr)) { - return DRM_FORMAT_INVALID; - } - return attr.format; -} - static void capture_output(struct wl_client *wl_client, struct wlr_screencopy_v1_client *client, uint32_t version, uint32_t id, int32_t overlay_cursor, struct wlr_output *output, @@ -549,7 +544,12 @@ static void capture_output(struct wl_client *wl_client, } frame->format = convert_drm_format_to_wl_shm(drm_format); - frame->fourcc = get_output_fourcc(output); + if (output->allocator && + (output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { + frame->fourcc = output->render_format; + } else { + frame->fourcc = DRM_FORMAT_INVALID; + } struct wlr_box buffer_box = {0}; if (box == NULL) { From efeb8346cfc6a18d2d9341460033883e4f89c28a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Dec 2021 08:49:48 +0100 Subject: [PATCH 079/190] output: drop front_buffer This lets backends immediately release committed buffers if they want to. --- include/wlr/types/wlr_output.h | 2 +- types/output/output.c | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 689b8158c..fd8e65563 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -188,7 +188,7 @@ struct wlr_output { struct wlr_allocator *allocator; struct wlr_renderer *renderer; struct wlr_swapchain *swapchain; - struct wlr_buffer *back_buffer, *front_buffer; + struct wlr_buffer *back_buffer; struct wl_listener display_destroy; diff --git a/types/output/output.c b/types/output/output.c index 8655ef981..9a715d120 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -393,9 +393,6 @@ void wlr_output_destroy(struct wlr_output *output) { return; } - wlr_buffer_unlock(output->front_buffer); - output->front_buffer = NULL; - wl_list_remove(&output->display_destroy.link); wlr_output_destroy_global(output); output_clear_back_buffer(output); @@ -716,15 +713,6 @@ bool wlr_output_commit(struct wlr_output *output) { output->cursor_swapchain = NULL; } - // Unset the front-buffer when a new buffer will replace it or when the - // output is getting disabled - if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) || - ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && - !output->pending.enabled)) { - wlr_buffer_unlock(output->front_buffer); - output->front_buffer = NULL; - } - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { output->frame_pending = true; output->needs_frame = false; @@ -732,8 +720,6 @@ bool wlr_output_commit(struct wlr_output *output) { if (back_buffer != NULL) { wlr_swapchain_set_buffer_submitted(output->swapchain, back_buffer); - wlr_buffer_unlock(output->front_buffer); - output->front_buffer = back_buffer; } uint32_t committed = output->pending.committed; @@ -747,6 +733,10 @@ bool wlr_output_commit(struct wlr_output *output) { }; wlr_signal_emit_safe(&output->events.commit, &event); + if (back_buffer != NULL) { + wlr_buffer_unlock(back_buffer); + } + return true; } From ca1af8119c8f441b6ab95eb2210b65c39d21cf18 Mon Sep 17 00:00:00 2001 From: tiosgz Date: Sat, 4 Dec 2021 22:12:58 +0000 Subject: [PATCH 080/190] Fix wlr_scene_node_lower_to_bottom Before this commit, it would keep the node at the top or make it second- topmost. --- types/scene/wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index d1236fe0e..b1db7b8f2 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -483,7 +483,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->state.children.prev, current_bottom, state.link); + node->parent->state.children.next, current_bottom, state.link); if (node == current_bottom) { return; } From c9f3c2b4f7052e4d4901661a953072ac030bf153 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 20 Nov 2021 13:30:18 +0300 Subject: [PATCH 081/190] surface: fix damage transformation --- types/wlr_surface.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index ffc77547a..6237a552a 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -123,6 +123,19 @@ static void surface_handle_set_input_region(struct wl_client *client, } } +static void surface_state_transformed_buffer_size(struct wlr_surface_state *state, + int *out_width, int *out_height) { + int width = state->buffer_width; + int height = state->buffer_height; + if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) { + int tmp = width; + width = height; + height = tmp; + } + *out_width = width; + *out_height = height; +} + /** * Computes the surface viewport source size, ie. the size after applying the * surface's scale, transform and cropping (via the viewport's source @@ -140,15 +153,10 @@ static void surface_state_viewport_src_size(struct wlr_surface_state *state, *out_width = state->viewport.src.width; *out_height = state->viewport.src.height; } else { - int width = state->buffer_width / state->scale; - int height = state->buffer_height / state->scale; - if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int tmp = width; - width = height; - height = tmp; - } - *out_width = width; - *out_height = height; + surface_state_transformed_buffer_size(state, + out_width, out_height); + *out_width /= state->scale; + *out_height /= state->scale; } } @@ -225,10 +233,13 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, floor(pending->viewport.src.y)); } + wlr_region_scale(&surface_damage, &surface_damage, pending->scale); + + int width, height; + surface_state_transformed_buffer_size(pending, &width, &height); wlr_region_transform(&surface_damage, &surface_damage, wlr_output_transform_invert(pending->transform), - pending->width, pending->height); - wlr_region_scale(&surface_damage, &surface_damage, pending->scale); + width, height); pixman_region32_union(buffer_damage, &pending->buffer_damage, &surface_damage); @@ -1472,7 +1483,11 @@ void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, box->y = surface->current.viewport.src.y * surface->current.scale; box->width = surface->current.viewport.src.width * surface->current.scale; box->height = surface->current.viewport.src.height * surface->current.scale; - wlr_fbox_transform(box, box, surface->current.transform, - surface->current.buffer_width, surface->current.buffer_height); + + int width, height; + surface_state_transformed_buffer_size(&surface->current, &width, &height); + wlr_fbox_transform(box, box, + wlr_output_transform_invert(surface->current.transform), + width, height); } } From 77d811a21b3d1dfb4ef6634e870c6c37228f3c15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 7 Jun 2021 16:31:53 +0200 Subject: [PATCH 082/190] render: add wlr_renderer_init_wl_shm This allows compositors to initialize wl_shm without initializing other globals like linux-dmabuf. --- include/wlr/render/wlr_renderer.h | 8 +++++++- render/wlr_renderer.c | 24 +++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index bae2fa976..d8b04dc72 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -99,13 +99,19 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data); /** - * Creates necessary shm and invokes the initialization of the implementation. + * Initializes wl_shm, linux-dmabuf and other buffer factory protocols. * * Returns false on failure. */ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, struct wl_display *wl_display); +/** + * Initializes wl_shm on the provided wl_display. + */ +bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, + struct wl_display *wl_display); + /** * Obtains the FD of the DRM device used for rendering, or -1 if unavailable. * diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index ff3159135..2b5cf9945 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -202,17 +202,18 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt, src_x, src_y, dst_x, dst_y, data); } -bool wlr_renderer_init_wl_display(struct wlr_renderer *r, +bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, struct wl_display *wl_display) { - if (wl_display_init_shm(wl_display)) { - wlr_log(WLR_ERROR, "Failed to initialize shm"); + if (wl_display_init_shm(wl_display) != 0) { + wlr_log(WLR_ERROR, "Failed to initialize wl_shm"); return false; } size_t len; const uint32_t *formats = wlr_renderer_get_shm_texture_formats(r, &len); if (formats == NULL) { - wlr_log(WLR_ERROR, "Failed to initialize shm: cannot get formats"); + wlr_log(WLR_ERROR, "Failed to initialize wl_shm: " + "cannot get renderer formats"); return false; } @@ -229,11 +230,24 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, xrgb8888 = true; break; default: - wl_display_add_shm_format(wl_display, fmt); + if (wl_display_add_shm_format(wl_display, fmt) == NULL) { + wlr_log(WLR_ERROR, "Failed to initialize wl_shm: " + "failed to add format"); + return false; + } } } assert(argb8888 && xrgb8888); + return true; +} + +bool wlr_renderer_init_wl_display(struct wlr_renderer *r, + struct wl_display *wl_display) { + if (!wlr_renderer_init_wl_shm(r, wl_display)) { + return false; + } + if (wlr_renderer_get_dmabuf_texture_formats(r) != NULL) { if (wlr_renderer_get_drm_fd(r) >= 0) { if (wlr_drm_create(wl_display, r) == NULL) { From 1d8340754b85eaa60669875c32f9476411941892 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 13 Nov 2018 12:35:08 +0100 Subject: [PATCH 083/190] linux-dmabuf-v1: implement v4 Implement a basic version of linux-dmabuf-unstable-v1 version 4. Only default hints are implemented. The new wlr_linux_dmabuf_feedback_v1 data structure will allow compositors to define their own custom hints in the future. This data structure makes it easy to describe feedback metadata. It's converted to a "compiled" form suitable for marshalling over the Wayland socket via feedback_compile. --- include/wlr/types/wlr_linux_dmabuf_v1.h | 15 ++ protocol/meson.build | 2 +- types/wlr_linux_dmabuf_v1.c | 271 +++++++++++++++++++++++- 3 files changed, 283 insertions(+), 5 deletions(-) diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index b4eb8675d..bbbb27723 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -10,6 +10,7 @@ #define WLR_TYPES_WLR_LINUX_DMABUF_H #include +#include #include #include #include @@ -38,6 +39,18 @@ bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource); struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource( struct wl_resource *buffer_resource); +struct wlr_linux_dmabuf_feedback_v1 { + dev_t main_device; + size_t tranches_len; + const struct wlr_linux_dmabuf_feedback_v1_tranche *tranches; +}; + +struct wlr_linux_dmabuf_feedback_v1_tranche { + dev_t target_device; + uint32_t flags; // bitfield of enum zwp_linux_dmabuf_feedback_v1_tranche_flags + const struct wlr_drm_format_set *formats; +}; + /* the protocol interface */ struct wlr_linux_dmabuf_v1 { struct wl_global *global; @@ -49,6 +62,8 @@ struct wlr_linux_dmabuf_v1 { // private state + struct wlr_linux_dmabuf_feedback_v1_compiled *default_feedback; + struct wl_listener display_destroy; struct wl_listener renderer_destroy; }; diff --git a/protocol/meson.build b/protocol/meson.build index 8d8b2502e..3e34f7881 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,5 +1,5 @@ wayland_protos = dependency('wayland-protocols', - version: '>=1.23', + version: '>=1.24', fallback: ['wayland-protocols', 'wayland_protocols'], default_options: ['tests=false'], ) diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index b91fb59d9..325b53625 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -2,17 +2,17 @@ #include #include #include +#include #include -#include -#include #include #include #include #include "linux-dmabuf-unstable-v1-protocol.h" #include "render/drm_format_set.h" #include "util/signal.h" +#include "util/shm.h" -#define LINUX_DMABUF_VERSION 3 +#define LINUX_DMABUF_VERSION 4 struct wlr_linux_buffer_params_v1 { struct wl_resource *resource; @@ -21,6 +21,32 @@ struct wlr_linux_buffer_params_v1 { bool has_modifier; }; +struct wlr_linux_dmabuf_feedback_v1_compiled_tranche { + dev_t target_device; + uint32_t flags; // bitfield of enum zwp_linux_dmabuf_feedback_v1_tranche_flags + struct wl_array indices; // uint16_t +}; + +struct wlr_linux_dmabuf_feedback_v1_compiled { + dev_t main_device; + int table_fd; + size_t table_size; + + size_t tranches_len; + struct wlr_linux_dmabuf_feedback_v1_compiled_tranche tranches[]; +}; + +struct wlr_linux_dmabuf_feedback_v1_table_entry { + uint32_t format; + uint32_t pad; // unused + uint64_t modifier; +}; + +// TODO: switch back to static_assert once this fix propagates in stable trees: +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=255290 +_Static_assert(sizeof(struct wlr_linux_dmabuf_feedback_v1_table_entry) == 16, + "Expected wlr_linux_dmabuf_feedback_v1_table_entry to be tightly packed"); + static void buffer_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -415,6 +441,228 @@ static void linux_dmabuf_create_params(struct wl_client *client, &buffer_params_impl, params, params_handle_resource_destroy); } +static void linux_dmabuf_feedback_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwp_linux_dmabuf_feedback_v1_interface + linux_dmabuf_feedback_impl = { + .destroy = linux_dmabuf_feedback_destroy, +}; + +static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( + const struct wlr_linux_dmabuf_feedback_v1 *feedback) { + assert(feedback->tranches_len > 0); + + // Require the last tranche to be the fallback tranche and contain all + // formats/modifiers + const struct wlr_linux_dmabuf_feedback_v1_tranche *fallback_tranche = + &feedback->tranches[feedback->tranches_len - 1]; + + size_t table_len = 0; + for (size_t i = 0; i < fallback_tranche->formats->len; i++) { + const struct wlr_drm_format *fmt = fallback_tranche->formats->formats[i]; + table_len += 1 + fmt->len; + } + assert(table_len > 0); + + size_t table_size = + table_len * sizeof(struct wlr_linux_dmabuf_feedback_v1_table_entry); + int rw_fd, ro_fd; + if (!allocate_shm_file_pair(table_size, &rw_fd, &ro_fd)) { + wlr_log(WLR_ERROR, "Failed to allocate shm file for format table"); + return NULL; + } + + struct wlr_linux_dmabuf_feedback_v1_table_entry *table = + mmap(NULL, table_size, PROT_READ | PROT_WRITE, MAP_SHARED, rw_fd, 0); + if (table == MAP_FAILED) { + wlr_log_errno(WLR_ERROR, "mmap failed"); + close(rw_fd); + close(ro_fd); + return NULL; + } + + close(rw_fd); + + size_t n = 0; + for (size_t i = 0; i < fallback_tranche->formats->len; i++) { + const struct wlr_drm_format *fmt = fallback_tranche->formats->formats[i]; + + table[n] = (struct wlr_linux_dmabuf_feedback_v1_table_entry){ + .format = fmt->format, + .modifier = DRM_FORMAT_MOD_INVALID, + }; + n++; + + for (size_t k = 0; k < fmt->len; k++) { + table[n] = (struct wlr_linux_dmabuf_feedback_v1_table_entry){ + .format = fmt->format, + .modifier = fmt->modifiers[k], + }; + n++; + } + } + assert(n == table_len); + + munmap(table, table_size); + + struct wlr_linux_dmabuf_feedback_v1_compiled *compiled = calloc(1, + sizeof(struct wlr_linux_dmabuf_feedback_v1_compiled) + + feedback->tranches_len * sizeof(struct wlr_linux_dmabuf_feedback_v1_compiled_tranche)); + if (compiled == NULL) { + close(ro_fd); + return NULL; + } + + compiled->main_device = feedback->main_device; + compiled->tranches_len = feedback->tranches_len; + compiled->table_fd = ro_fd; + compiled->table_size = table_size; + + // Build the indices lists for all but the last (fallback) tranches + for (size_t i = 0; i < feedback->tranches_len - 1; i++) { + assert(false); // TODO: unimplemented + } + + struct wlr_linux_dmabuf_feedback_v1_compiled_tranche *fallback_compiled_tranche = + &compiled->tranches[compiled->tranches_len - 1]; + fallback_compiled_tranche->target_device = fallback_tranche->target_device; + fallback_compiled_tranche->flags = fallback_tranche->flags; + + // Build the indices list for the last (fallback) tranche + wl_array_init(&fallback_compiled_tranche->indices); + if (!wl_array_add(&fallback_compiled_tranche->indices, + table_len * sizeof(uint16_t))) { + wlr_log(WLR_ERROR, "Failed to allocate fallback tranche indices array"); + goto error_compiled; + } + + n = 0; + uint16_t *index_ptr; + wl_array_for_each(index_ptr, &fallback_compiled_tranche->indices) { + *index_ptr = n; + n++; + } + + return compiled; + +error_compiled: + close(compiled->table_fd); + free(compiled); + return NULL; +} + +static void compiled_feedback_destroy( + struct wlr_linux_dmabuf_feedback_v1_compiled *feedback) { + for (size_t i = 0; i < feedback->tranches_len; i++) { + wl_array_release(&feedback->tranches[i].indices); + } + close(feedback->table_fd); + free(feedback); +} + +static bool feedback_tranche_init_with_renderer( + struct wlr_linux_dmabuf_feedback_v1_tranche *tranche, + struct wlr_renderer *renderer) { + memset(tranche, 0, sizeof(*tranche)); + + int drm_fd = wlr_renderer_get_drm_fd(renderer); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM FD from renderer"); + return false; + } + + struct stat stat; + if (fstat(drm_fd, &stat) != 0) { + wlr_log_errno(WLR_ERROR, "fstat failed"); + return false; + } + tranche->target_device = stat.st_rdev; + + tranche->formats = wlr_renderer_get_dmabuf_texture_formats(renderer); + if (tranche->formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get renderer DMA-BUF texture formats"); + return false; + } + + return true; +} + +static struct wlr_linux_dmabuf_feedback_v1_compiled *compile_default_feedback( + struct wlr_renderer *renderer) { + struct wlr_linux_dmabuf_feedback_v1_tranche tranche = {0}; + if (!feedback_tranche_init_with_renderer(&tranche, renderer)) { + return NULL; + } + + const struct wlr_linux_dmabuf_feedback_v1 feedback = { + .main_device = tranche.target_device, + .tranches = &tranche, + .tranches_len = 1, + }; + + return feedback_compile(&feedback); +} + +static void feedback_tranche_send( + const struct wlr_linux_dmabuf_feedback_v1_compiled_tranche *tranche, + struct wl_resource *resource) { + struct wl_array dev_array = { + .size = sizeof(tranche->target_device), + .data = (void *)&tranche->target_device, + }; + zwp_linux_dmabuf_feedback_v1_send_tranche_target_device(resource, &dev_array); + zwp_linux_dmabuf_feedback_v1_send_tranche_flags(resource, tranche->flags); + zwp_linux_dmabuf_feedback_v1_send_tranche_formats(resource, + (struct wl_array *)&tranche->indices); + zwp_linux_dmabuf_feedback_v1_send_tranche_done(resource); +} + +static void feedback_send(const struct wlr_linux_dmabuf_feedback_v1_compiled *feedback, + struct wl_resource *resource) { + struct wl_array dev_array = { + .size = sizeof(feedback->main_device), + .data = (void *)&feedback->main_device, + }; + zwp_linux_dmabuf_feedback_v1_send_main_device(resource, &dev_array); + + zwp_linux_dmabuf_feedback_v1_send_format_table(resource, + feedback->table_fd, feedback->table_size); + + for (size_t i = 0; i < feedback->tranches_len; i++) { + feedback_tranche_send(&feedback->tranches[i], resource); + } + + zwp_linux_dmabuf_feedback_v1_send_done(resource); +} + +static void linux_dmabuf_get_default_feedback(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + struct wlr_linux_dmabuf_v1 *linux_dmabuf = + linux_dmabuf_from_resource(resource); + + uint32_t version = wl_resource_get_version(resource); + struct wl_resource *feedback_resource = wl_resource_create(client, + &zwp_linux_dmabuf_feedback_v1_interface, version, id); + if (feedback_resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(feedback_resource, &linux_dmabuf_feedback_impl, + NULL, NULL); + + feedback_send(linux_dmabuf->default_feedback, feedback_resource); +} + +static void linux_dmabuf_get_surface_feedback(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource) { + // TODO: implement per-surface feedback + linux_dmabuf_get_default_feedback(client, resource, id); +} + static void linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -423,6 +671,8 @@ static void linux_dmabuf_destroy(struct wl_client *client, static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = { .destroy = linux_dmabuf_destroy, .create_params = linux_dmabuf_create_params, + .get_default_feedback = linux_dmabuf_get_default_feedback, + .get_surface_feedback = linux_dmabuf_get_surface_feedback, }; static void linux_dmabuf_send_modifiers(struct wl_resource *resource, @@ -477,12 +727,17 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, } wl_resource_set_implementation(resource, &linux_dmabuf_impl, linux_dmabuf, NULL); - linux_dmabuf_send_formats(linux_dmabuf, resource); + + if (version < ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) { + linux_dmabuf_send_formats(linux_dmabuf, resource); + } } static void linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) { wlr_signal_emit_safe(&linux_dmabuf->events.destroy, linux_dmabuf); + compiled_feedback_destroy(linux_dmabuf->default_feedback); + wl_list_remove(&linux_dmabuf->display_destroy.link); wl_list_remove(&linux_dmabuf->renderer_destroy.link); @@ -523,6 +778,14 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *displa return NULL; } + linux_dmabuf->default_feedback = compile_default_feedback(renderer); + if (linux_dmabuf->default_feedback == NULL) { + wlr_log(WLR_ERROR, "Failed to init default linux-dmabuf feedback"); + wl_global_destroy(linux_dmabuf->global); + free(linux_dmabuf); + return NULL; + } + linux_dmabuf->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy); From c50c4fc5cc7fc4c1e8e7ecd5d21bb821d0f7cfb6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 7 Jun 2021 18:20:45 +0200 Subject: [PATCH 084/190] linux-dmabuf-v1: add per-surface feedback --- include/wlr/types/wlr_linux_dmabuf_v1.h | 12 ++ types/wlr_linux_dmabuf_v1.c | 217 +++++++++++++++++++++++- 2 files changed, 226 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index bbbb27723..df89a1219 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -15,6 +15,8 @@ #include #include +struct wlr_surface; + struct wlr_dmabuf_v1_buffer { struct wlr_buffer base; @@ -63,6 +65,7 @@ struct wlr_linux_dmabuf_v1 { // private state struct wlr_linux_dmabuf_feedback_v1_compiled *default_feedback; + struct wl_list surfaces; // wlr_linux_dmabuf_v1_surface.link struct wl_listener display_destroy; struct wl_listener renderer_destroy; @@ -74,4 +77,13 @@ struct wlr_linux_dmabuf_v1 { struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, struct wlr_renderer *renderer); +/** + * Set a surface's DMA-BUF feedback. + * + * Passing a NULL feedback resets it to the default feedback. + */ +bool wlr_linux_dmabuf_v1_set_surface_feedback( + struct wlr_linux_dmabuf_v1 *linux_dmabuf, struct wlr_surface *surface, + const struct wlr_linux_dmabuf_feedback_v1 *feedback); + #endif diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 325b53625..ae9bfeb90 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "linux-dmabuf-unstable-v1-protocol.h" #include "render/drm_format_set.h" @@ -47,6 +48,17 @@ struct wlr_linux_dmabuf_feedback_v1_table_entry { _Static_assert(sizeof(struct wlr_linux_dmabuf_feedback_v1_table_entry) == 16, "Expected wlr_linux_dmabuf_feedback_v1_table_entry to be tightly packed"); +struct wlr_linux_dmabuf_v1_surface { + struct wlr_surface *surface; + struct wlr_linux_dmabuf_v1 *linux_dmabuf; + struct wl_list link; // wlr_linux_dmabuf_v1.surfaces + + struct wlr_addon addon; + struct wlr_linux_dmabuf_feedback_v1_compiled *feedback; + + struct wl_list feedback_resources; // wl_resource_get_link +}; + static void buffer_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -451,6 +463,36 @@ static const struct zwp_linux_dmabuf_feedback_v1_interface .destroy = linux_dmabuf_feedback_destroy, }; +static ssize_t get_drm_format_set_index(const struct wlr_drm_format_set *set, + uint32_t format, uint64_t modifier) { + bool format_found = false; + const struct wlr_drm_format *fmt; + size_t idx = 0; + for (size_t i = 0; i < set->len; i++) { + fmt = set->formats[i]; + if (fmt->format == format) { + format_found = true; + break; + } + idx += 1 + fmt->len; + } + if (!format_found) { + return -1; + } + + if (modifier == DRM_FORMAT_MOD_INVALID) { + return idx; + } + + for (size_t i = 0; i < fmt->len; i++) { + if (fmt->modifiers[i] == modifier) { + return idx; + } + idx++; + } + return -1; +} + static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( const struct wlr_linux_dmabuf_feedback_v1 *feedback) { assert(feedback->tranches_len > 0); @@ -523,7 +565,53 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( // Build the indices lists for all but the last (fallback) tranches for (size_t i = 0; i < feedback->tranches_len - 1; i++) { - assert(false); // TODO: unimplemented + const struct wlr_linux_dmabuf_feedback_v1_tranche *tranche = + &feedback->tranches[i]; + struct wlr_linux_dmabuf_feedback_v1_compiled_tranche *compiled_tranche = + &compiled->tranches[i]; + + compiled_tranche->target_device = tranche->target_device; + compiled_tranche->flags = tranche->flags; + + wl_array_init(&compiled_tranche->indices); + if (!wl_array_add(&compiled_tranche->indices, table_len * sizeof(uint16_t))) { + wlr_log(WLR_ERROR, "Failed to allocate tranche indices array"); + goto error_compiled; + } + + n = 0; + uint16_t *indices = compiled_tranche->indices.data; + for (size_t j = 0; j < tranche->formats->len; j++) { + const struct wlr_drm_format *fmt = tranche->formats->formats[j]; + + ssize_t index = get_drm_format_set_index( + fallback_tranche->formats, fmt->format, + DRM_FORMAT_MOD_INVALID); + if (index < 0) { + wlr_log(WLR_ERROR, "Format 0x%" PRIX32 " and modifier " + "INVALID are in tranche #%zu but are missing " + "from the fallback tranche", + fmt->format, i); + goto error_compiled; + } + indices[n] = index; + n++; + + for (size_t k = 0; k < fmt->len; k++) { + ssize_t index = get_drm_format_set_index( + fallback_tranche->formats, fmt->format, fmt->modifiers[k]); + if (index < 0) { + wlr_log(WLR_ERROR, "Format 0x%" PRIX32 " and modifier " + "0x%" PRIX64 " are in tranche #%zu but are missing " + "from the fallback tranche", + fmt->format, fmt->modifiers[k], i); + goto error_compiled; + } + indices[n] = index; + n++; + } + } + compiled_tranche->indices.size = n * sizeof(uint16_t); } struct wlr_linux_dmabuf_feedback_v1_compiled_tranche *fallback_compiled_tranche = @@ -556,6 +644,9 @@ error_compiled: static void compiled_feedback_destroy( struct wlr_linux_dmabuf_feedback_v1_compiled *feedback) { + if (feedback == NULL) { + return; + } for (size_t i = 0; i < feedback->tranches_len; i++) { wl_array_release(&feedback->tranches[i].indices); } @@ -656,11 +747,96 @@ static void linux_dmabuf_get_default_feedback(struct wl_client *client, feedback_send(linux_dmabuf->default_feedback, feedback_resource); } +static void surface_destroy(struct wlr_linux_dmabuf_v1_surface *surface) { + struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &surface->feedback_resources) { + struct wl_list *link = wl_resource_get_link(resource); + wl_list_remove(link); + wl_list_init(link); + } + + compiled_feedback_destroy(surface->feedback); + + wlr_addon_finish(&surface->addon); + wl_list_remove(&surface->link); + free(surface); +} + +static void surface_addon_destroy(struct wlr_addon *addon) { + struct wlr_linux_dmabuf_v1_surface *surface = + wl_container_of(addon, surface, addon); + surface_destroy(surface); +} + +static const struct wlr_addon_interface surface_addon_impl = { + .name = "wlr_linux_dmabuf_v1_surface", + .destroy = surface_addon_destroy, +}; + +static struct wlr_linux_dmabuf_v1_surface *surface_get_or_create( + struct wlr_linux_dmabuf_v1 *linux_dmabuf, + struct wlr_surface *wlr_surface) { + struct wlr_addon *addon = + wlr_addon_find(&wlr_surface->addons, linux_dmabuf, &surface_addon_impl); + if (addon != NULL) { + struct wlr_linux_dmabuf_v1_surface *surface = + wl_container_of(addon, surface, addon); + return surface; + } + + struct wlr_linux_dmabuf_v1_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) { + return NULL; + } + + surface->surface = wlr_surface; + surface->linux_dmabuf = linux_dmabuf; + wl_list_init(&surface->feedback_resources); + wlr_addon_init(&surface->addon, &wlr_surface->addons, linux_dmabuf, + &surface_addon_impl); + wl_list_insert(&linux_dmabuf->surfaces, &surface->link); + + return surface; +} + +static const struct wlr_linux_dmabuf_feedback_v1_compiled *surface_get_feedback( + struct wlr_linux_dmabuf_v1_surface *surface) { + if (surface->feedback != NULL) { + return surface->feedback; + } + return surface->linux_dmabuf->default_feedback; +} + +static void surface_feedback_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + static void linux_dmabuf_get_surface_feedback(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource) { - // TODO: implement per-surface feedback - linux_dmabuf_get_default_feedback(client, resource, id); + struct wlr_linux_dmabuf_v1 *linux_dmabuf = + linux_dmabuf_from_resource(resource); + struct wlr_surface *wlr_surface = wlr_surface_from_resource(surface_resource); + + struct wlr_linux_dmabuf_v1_surface *surface = + surface_get_or_create(linux_dmabuf, wlr_surface); + if (surface == NULL) { + wl_client_post_no_memory(client); + return; + } + + uint32_t version = wl_resource_get_version(resource); + struct wl_resource *feedback_resource = wl_resource_create(client, + &zwp_linux_dmabuf_feedback_v1_interface, version, id); + if (feedback_resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(feedback_resource, &linux_dmabuf_feedback_impl, + NULL, surface_feedback_handle_resource_destroy); + wl_list_insert(&surface->feedback_resources, wl_resource_get_link(feedback_resource)); + + feedback_send(surface_get_feedback(surface), feedback_resource); } static void linux_dmabuf_destroy(struct wl_client *client, @@ -736,6 +912,11 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, static void linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) { wlr_signal_emit_safe(&linux_dmabuf->events.destroy, linux_dmabuf); + struct wlr_linux_dmabuf_v1_surface *surface, *surface_tmp; + wl_list_for_each_safe(surface, surface_tmp, &linux_dmabuf->surfaces, link) { + surface_destroy(surface); + } + compiled_feedback_destroy(linux_dmabuf->default_feedback); wl_list_remove(&linux_dmabuf->display_destroy.link); @@ -767,6 +948,7 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *displa } linux_dmabuf->renderer = renderer; + wl_list_init(&linux_dmabuf->surfaces); wl_signal_init(&linux_dmabuf->events.destroy); linux_dmabuf->global = @@ -794,3 +976,32 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *displa return linux_dmabuf; } + +bool wlr_linux_dmabuf_v1_set_surface_feedback( + struct wlr_linux_dmabuf_v1 *linux_dmabuf, + struct wlr_surface *wlr_surface, + const struct wlr_linux_dmabuf_feedback_v1 *feedback) { + struct wlr_linux_dmabuf_v1_surface *surface = + surface_get_or_create(linux_dmabuf, wlr_surface); + if (surface == NULL) { + return false; + } + + struct wlr_linux_dmabuf_feedback_v1_compiled *compiled = NULL; + if (feedback != NULL) { + compiled = feedback_compile(feedback); + if (compiled == NULL) { + return false; + } + } + + compiled_feedback_destroy(surface->feedback); + surface->feedback = compiled; + + struct wl_resource *resource; + wl_resource_for_each(resource, &surface->feedback_resources) { + feedback_send(surface_get_feedback(surface), resource); + } + + return true; +} From ad28490cf496e0ddae991fc553f24e63efe72a34 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Dec 2021 16:11:29 +0100 Subject: [PATCH 085/190] build: move wayland-client dep to backend/wayland/ wayland-client isn't really used by wlroots core, so let's move the dep to where it's needed in the Wayland backend. --- backend/wayland/meson.build | 6 ++++++ examples/meson.build | 1 + meson.build | 5 ----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/wayland/meson.build b/backend/wayland/meson.build index ebe315296..103d3f9fa 100644 --- a/backend/wayland/meson.build +++ b/backend/wayland/meson.build @@ -1,3 +1,9 @@ +wayland_client = dependency('wayland-client', + fallback: ['wayland', 'wayland_client_dep'], + default_options: wayland_project_options, +) +wlr_deps += wayland_client + wlr_files += files( 'backend.c', 'output.c', diff --git a/examples/meson.build b/examples/meson.build index 1e428e81b..3ec4dac4e 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,6 +1,7 @@ threads = dependency('threads') wayland_egl = dependency('wayland-egl') wayland_cursor = dependency('wayland-cursor') +wayland_client = dependency('wayland-client') libpng = dependency('libpng', required: false, disabler: true) egl = dependency('egl', required: false, disabler: true) glesv2 = dependency('glesv2', required: false, disabler: true) diff --git a/meson.build b/meson.build index 2f2969496..2e72e4451 100644 --- a/meson.build +++ b/meson.build @@ -103,10 +103,6 @@ wayland_server = dependency('wayland-server', fallback: ['wayland', 'wayland_server_dep'], default_options: wayland_project_options, ) -wayland_client = dependency('wayland-client', - fallback: ['wayland', 'wayland_client_dep'], - default_options: wayland_project_options, -) drm = dependency('libdrm', version: '>=2.4.105') gbm = dependency('gbm', version: '>=17.1.0') @@ -119,7 +115,6 @@ rt = cc.find_library('rt') wlr_files = [] wlr_deps = [ wayland_server, - wayland_client, drm, gbm, xkbcommon, From 83bdb3ad0759a8043f0010e4bfd18f03b88f1e1e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Dec 2021 16:19:26 +0100 Subject: [PATCH 086/190] examples/layer-shell: remove wlroots dependency This is a client example, it shouldn't use a compositor library like wlroots. --- examples/layer-shell.c | 13 +++++-------- examples/meson.build | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 274858d4f..56a8d4aa5 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "egl_common.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" @@ -177,8 +176,7 @@ static const struct xdg_surface_listener xdg_surface_listener = { static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height) { - wlr_log(WLR_DEBUG, "Popup configured %dx%d@%d,%d", - width, height, x, y); + fprintf(stderr, "Popup configured %dx%d@%d,%d\n", width, height, x, y); popup_width = width; popup_height = height; if (popup_egl_window) { @@ -197,7 +195,7 @@ static void popup_destroy(void) { } static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { - wlr_log(WLR_DEBUG, "Popup done"); + fprintf(stderr, "Popup done\n"); popup_destroy(); } @@ -377,17 +375,17 @@ static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - wlr_log(WLR_DEBUG, "Keyboard enter"); + fprintf(stderr, "Keyboard enter\n"); } static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { - wlr_log(WLR_DEBUG, "Keyboard leave"); + fprintf(stderr, "Keyboard leave\n"); } static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - wlr_log(WLR_DEBUG, "Key event: %d %d", key, state); + fprintf(stderr, "Key event: %d %d\n", key, state); } static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, @@ -473,7 +471,6 @@ static const struct wl_registry_listener registry_listener = { }; int main(int argc, char **argv) { - wlr_log_init(WLR_DEBUG, NULL); char *namespace = "wlroots"; int exclusive_zone = 0; int32_t margin_right = 0, margin_bottom = 0, margin_left = 0; diff --git a/examples/meson.build b/examples/meson.build index 3ec4dac4e..3189f0b43 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -82,7 +82,7 @@ clients = { }, 'layer-shell': { 'src': ['layer-shell.c', 'egl_common.c'], - 'dep': [wayland_egl, wayland_cursor, wlroots, egl, glesv2], + 'dep': [wayland_egl, wayland_cursor, egl, glesv2], 'proto': [ 'wlr-layer-shell-unstable-v1', 'xdg-shell', From 90e9d327ddc64b1b80c0e3b286cfbb9675b619d0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Dec 2021 16:20:20 +0100 Subject: [PATCH 087/190] examples: remove unnecessary wlroots deps for clients These clients don't need wlroots. --- examples/meson.build | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index 3189f0b43..bb798f259 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -103,7 +103,7 @@ clients = { }, 'output-power-management': { 'src': 'output-power-management.c', - 'dep': [wayland_client, wlroots], + 'dep': [wayland_client], 'proto': ['wlr-output-power-management-unstable-v1'], }, 'pointer-constraints': { @@ -174,12 +174,10 @@ clients = { }, 'foreign-toplevel': { 'src': 'foreign-toplevel.c', - 'dep': [wlroots], 'proto': ['wlr-foreign-toplevel-management-unstable-v1'], }, 'virtual-pointer': { 'src': 'virtual-pointer.c', - 'dep': wlroots, 'proto': ['wlr-virtual-pointer-unstable-v1'], }, 'input-method-keyboard-grab': { @@ -216,7 +214,7 @@ foreach name, info : clients executable( name, [info.get('src'), extra_src], - dependencies: [wayland_client, info.get('dep')], + dependencies: [wayland_client, info.get('dep', [])], build_by_default: get_option('examples'), ) endforeach From 1fbd13ec799c472558aef37436367f0e947f7d89 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Dec 2021 16:20:54 +0100 Subject: [PATCH 088/190] examples: remove unnecessary partial_dependency() call The definition of the "drm" dep already calls it. --- examples/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/meson.build b/examples/meson.build index bb798f259..26d103bbb 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -129,7 +129,7 @@ clients = { libavcodec, libavformat, libavutil, - drm.partial_dependency(compile_args: true), # + drm, threads, ], 'proto': ['wlr-export-dmabuf-unstable-v1'], From 36a2b19485ad299ee0039eb97c0f688d68205539 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Dec 2021 15:43:19 +0100 Subject: [PATCH 089/190] output: introduce wlr_output_set_name wlroots picks names for all outputs, but it might be desirable for compositor to override it. For instance, Sway will use a headless output as a fallback in case no outputs are connected. Sway wants to clearly label the fallback output as such and label "real" headless outputs starting from HEADLESS-1. --- backend/drm/drm.c | 3 +-- backend/headless/output.c | 6 ++++-- backend/wayland/output.c | 6 ++++-- backend/x11/output.c | 6 ++++-- include/wlr/types/wlr_output.h | 13 ++++++++++++- types/output/output.c | 8 ++++++++ 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index d7c532316..1a46b4959 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1299,8 +1299,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, drm->display); - memcpy(wlr_conn->output.name, wlr_conn->name, - sizeof(wlr_conn->output.name)); + wlr_output_set_name(&wlr_conn->output, wlr_conn->name); wlr_conn->output.phys_width = drm_conn->mmWidth; wlr_conn->output.phys_height = drm_conn->mmHeight; diff --git a/backend/headless/output.c b/backend/headless/output.c index 50d914e44..fbec8110a 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -116,8 +116,10 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, output_set_custom_mode(output, width, height, 0); strncpy(wlr_output->make, "headless", sizeof(wlr_output->make)); strncpy(wlr_output->model, "headless", sizeof(wlr_output->model)); - snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%zd", - ++backend->last_output_num); + + char name[64]; + snprintf(name, sizeof(name), "HEADLESS-%zd", ++backend->last_output_num); + wlr_output_set_name(wlr_output, name); char description[128]; snprintf(description, sizeof(description), diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 3fa86a3cf..27195592d 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -520,8 +520,10 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wlr_output_update_custom_mode(wlr_output, 1280, 720, 0); strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make)); strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); - snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%zd", - ++backend->last_output_num); + + char name[64]; + snprintf(name, sizeof(name), "WL-%zd", ++backend->last_output_num); + wlr_output_set_name(wlr_output, name); char description[128]; snprintf(description, sizeof(description), diff --git a/backend/x11/output.c b/backend/x11/output.c index 9081769e3..25194e708 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -512,8 +512,10 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_custom_mode(wlr_output, 1024, 768, 0); - snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%zd", - ++x11->last_output_num); + char name[64]; + snprintf(name, sizeof(name), "X11-%zd", ++x11->last_output_num); + wlr_output_set_name(wlr_output, name); + parse_xcb_setup(wlr_output, x11->xcb); char description[128]; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index fd8e65563..791023d2e 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -118,7 +118,7 @@ struct wlr_output { struct wl_global *global; struct wl_list resources; - char name[24]; + char *name; char *description; // may be NULL char make[56]; char model[16]; @@ -336,6 +336,17 @@ void wlr_output_set_render_format(struct wlr_output *output, uint32_t format); void wlr_output_set_scale(struct wlr_output *output, float scale); void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel subpixel); +/** + * Set the output name. + * + * Output names are subject to the following rules: + * + * - Each output name must be unique. + * - The name cannot change after the output has been advertised to clients. + * + * For more details, see the protocol documentation for wl_output.name. + */ +void wlr_output_set_name(struct wlr_output *output, const char *name); void wlr_output_set_description(struct wlr_output *output, const char *desc); /** * Schedule a done event. diff --git a/types/output/output.c b/types/output/output.c index 9a715d120..91a45f131 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -324,6 +324,13 @@ void wlr_output_set_subpixel(struct wlr_output *output, wlr_output_schedule_done(output); } +void wlr_output_set_name(struct wlr_output *output, const char *name) { + assert(output->global == NULL); + + free(output->name); + output->name = strdup(name); +} + void wlr_output_set_description(struct wlr_output *output, const char *desc) { if (output->description != NULL && desc != NULL && strcmp(output->description, desc) == 0) { @@ -420,6 +427,7 @@ void wlr_output_destroy(struct wlr_output *output) { wl_event_source_remove(output->idle_done); } + free(output->name); free(output->description); pixman_region32_fini(&output->pending.damage); From 818fc4a87b9ea6b7174443e19c1a7c2756b3c002 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Dec 2021 16:39:09 +0100 Subject: [PATCH 090/190] Fix incorrect %zd formatting directives %zd is for ssize_t. For size_t we should use %zu. --- backend/headless/output.c | 4 ++-- backend/wayland/output.c | 4 ++-- backend/x11/output.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/headless/output.c b/backend/headless/output.c index fbec8110a..f03d6ee0d 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -118,12 +118,12 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, strncpy(wlr_output->model, "headless", sizeof(wlr_output->model)); char name[64]; - snprintf(name, sizeof(name), "HEADLESS-%zd", ++backend->last_output_num); + snprintf(name, sizeof(name), "HEADLESS-%zu", ++backend->last_output_num); wlr_output_set_name(wlr_output, name); char description[128]; snprintf(description, sizeof(description), - "Headless output %zd", backend->last_output_num); + "Headless output %zu", backend->last_output_num); wlr_output_set_description(wlr_output, description); struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 27195592d..de5d42edd 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -522,12 +522,12 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); char name[64]; - snprintf(name, sizeof(name), "WL-%zd", ++backend->last_output_num); + snprintf(name, sizeof(name), "WL-%zu", ++backend->last_output_num); wlr_output_set_name(wlr_output, name); char description[128]; snprintf(description, sizeof(description), - "Wayland output %zd", backend->last_output_num); + "Wayland output %zu", backend->last_output_num); wlr_output_set_description(wlr_output, description); output->backend = backend; diff --git a/backend/x11/output.c b/backend/x11/output.c index 25194e708..b87b08dc5 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -513,14 +513,14 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_custom_mode(wlr_output, 1024, 768, 0); char name[64]; - snprintf(name, sizeof(name), "X11-%zd", ++x11->last_output_num); + snprintf(name, sizeof(name), "X11-%zu", ++x11->last_output_num); wlr_output_set_name(wlr_output, name); parse_xcb_setup(wlr_output, x11->xcb); char description[128]; snprintf(description, sizeof(description), - "X11 output %zd", x11->last_output_num); + "X11 output %zu", x11->last_output_num); wlr_output_set_description(wlr_output, description); // The X11 protocol requires us to set a colormap and border pixel if the From f463ca669ac7ddc24a19b32aac33e457c93aaf61 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 3 Dec 2021 23:14:13 +0300 Subject: [PATCH 091/190] subsurface: simplify and fix parent commit handling --- types/wlr_surface.c | 49 ++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 6237a552a..bef4300f1 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -400,6 +400,8 @@ static void surface_update_input_region(struct wlr_surface *surface) { static void surface_state_init(struct wlr_surface_state *state); +static void subsurface_parent_commit(struct wlr_subsurface *subsurface); + static void surface_cache_pending(struct wlr_surface *surface) { struct wlr_surface_state *cached = calloc(1, sizeof(*cached)); if (!cached) { @@ -452,6 +454,7 @@ static void surface_commit_state(struct wlr_surface *surface, // TODO: damage all the subsurfaces surface_damage_subsurfaces(subsurface); } + subsurface_parent_commit(subsurface); } wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below, pending.link) { @@ -463,6 +466,7 @@ static void surface_commit_state(struct wlr_surface *surface, // TODO: damage all the subsurfaces surface_damage_subsurfaces(subsurface); } + subsurface_parent_commit(subsurface); } // If we're committing the pending state, bump the pending sequence number @@ -497,28 +501,12 @@ static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { return false; } -/** - * Recursive function to commit the effectively synchronized children. - */ -static void subsurface_parent_commit(struct wlr_subsurface *subsurface, - bool synchronized) { +static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { struct wlr_surface *surface = subsurface->surface; - if (synchronized || subsurface->synchronized) { - if (subsurface->has_cache) { - wlr_surface_unlock_cached(surface, subsurface->cached_seq); - subsurface->has_cache = false; - subsurface->cached_seq = 0; - } - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->current.subsurfaces_below, - current.link) { - subsurface_parent_commit(subsurface, true); - } - wl_list_for_each(subsurface, &surface->current.subsurfaces_above, - current.link) { - subsurface_parent_commit(subsurface, true); - } + if (subsurface->synchronized && subsurface->has_cache) { + wlr_surface_unlock_cached(surface, subsurface->cached_seq); + subsurface->has_cache = false; } } @@ -557,13 +545,6 @@ static void surface_handle_commit(struct wl_client *client, } else { surface_commit_state(surface, &surface->pending); } - - wl_list_for_each(subsurface, &surface->current.subsurfaces_below, current.link) { - subsurface_parent_commit(subsurface, false); - } - wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) { - subsurface_parent_commit(subsurface, false); - } } static void surface_handle_set_buffer_transform(struct wl_client *client, @@ -989,15 +970,11 @@ static void subsurface_handle_set_desync(struct wl_client *client, if (subsurface->synchronized) { subsurface->synchronized = false; - if (!subsurface_is_synchronized(subsurface)) { - if (subsurface->has_cache) { - wlr_surface_unlock_cached(subsurface->surface, - subsurface->cached_seq); - subsurface->has_cache = false; - subsurface->cached_seq = 0; - } - - subsurface_parent_commit(subsurface, true); + if (!subsurface_is_synchronized(subsurface) && + subsurface->has_cache) { + wlr_surface_unlock_cached(subsurface->surface, + subsurface->cached_seq); + subsurface->has_cache = false; } } } From df7d28034325ae80fd4b1660e2c6d5f67dc30d67 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 3 Dec 2021 23:15:55 +0300 Subject: [PATCH 092/190] subsurface: apply position change at the right moment Subsurface position is considered to be a part of the parent surface's state, therefore it should be modified when the parent is committed. --- types/wlr_surface.c | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index bef4300f1..360e4dffe 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -508,6 +508,30 @@ static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { wlr_surface_unlock_cached(surface, subsurface->cached_seq); subsurface->has_cache = false; } + + if (subsurface->current.x != subsurface->pending.x || + subsurface->current.y != subsurface->pending.y) { + // Subsurface has moved + int dx = subsurface->current.x - subsurface->pending.x; + int dy = subsurface->current.y - subsurface->pending.y; + + subsurface->current.x = subsurface->pending.x; + subsurface->current.y = subsurface->pending.y; + + if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) { + int tmp = dx; + dx = dy; + dy = tmp; + } + + pixman_region32_union_rect(&surface->buffer_damage, + &surface->buffer_damage, + dx * surface->previous.scale, dy * surface->previous.scale, + surface->previous.buffer_width, surface->previous.buffer_height); + pixman_region32_union_rect(&surface->buffer_damage, + &surface->buffer_damage, 0, 0, + surface->current.buffer_width, surface->current.buffer_height); + } } static void subsurface_commit(struct wlr_subsurface *subsurface) { @@ -1055,30 +1079,6 @@ static void subsurface_role_commit(struct wlr_surface *surface) { return; } - if (subsurface->current.x != subsurface->pending.x || - subsurface->current.y != subsurface->pending.y) { - // Subsurface has moved - int dx = subsurface->current.x - subsurface->pending.x; - int dy = subsurface->current.y - subsurface->pending.y; - - subsurface->current.x = subsurface->pending.x; - subsurface->current.y = subsurface->pending.y; - - if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int tmp = dx; - dx = dy; - dy = tmp; - } - - pixman_region32_union_rect(&surface->buffer_damage, - &surface->buffer_damage, - dx * surface->previous.scale, dy * surface->previous.scale, - surface->previous.buffer_width, surface->previous.buffer_height); - pixman_region32_union_rect(&surface->buffer_damage, - &surface->buffer_damage, 0, 0, - surface->current.buffer_width, surface->current.buffer_height); - } - subsurface_consider_map(subsurface, true); } From 7964bdae760a5417fe18cd893f91bd85c7123173 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 4 Dec 2021 20:05:32 +0300 Subject: [PATCH 093/190] surface: fix non-buffer damage handling This commit fixes the way the damage that doesn't come directly from the client is handled. --- include/wlr/types/wlr_surface.h | 12 +++- types/wlr_surface.c | 108 +++++++++++--------------------- 2 files changed, 44 insertions(+), 76 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index ae3ae80f6..4255a1f2c 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -111,6 +111,11 @@ struct wlr_surface { * positions need to be damaged. */ pixman_region32_t buffer_damage; + /** + * The last commit's damage caused by surface and its subsurfaces' + * movement, in surface-local coordinates. + */ + pixman_region32_t external_damage; /** * The current opaque region, in surface-local coordinates. It is clipped to * the surface bounds. If the surface's buffer is using a fully opaque @@ -273,9 +278,10 @@ void wlr_surface_for_each_surface(struct wlr_surface *surface, wlr_surface_iterator_func_t iterator, void *user_data); /** - * Get the effective damage to the surface in terms of surface local - * coordinates. This includes damage induced by resizing and moving the - * surface. The damage is not expected to be bounded by the surface itself. + * Get the effective surface damage in surface-local coordinate space. Besides + * buffer damage, this includes damage induced by resizing and moving the + * surface and its subsurfaces. The resulting damage is not expected to be + * bounded by the surface itself. */ void wlr_surface_get_effective_damage(struct wlr_surface *surface, pixman_region32_t *damage); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 360e4dffe..42b75f96f 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -315,29 +315,6 @@ static void surface_state_move(struct wlr_surface_state *state, next->cached_state_locks = 0; } -static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { - // XXX: This is probably the wrong way to do it, because this damage should - // come from the client, but weston doesn't do it correctly either and it - // seems to work ok. See the comment on weston_surface_damage for more info - // about a better approach. - struct wlr_surface *surface = subsurface->surface; - pixman_region32_union_rect(&surface->buffer_damage, - &surface->buffer_damage, 0, 0, - surface->current.buffer_width, surface->current.buffer_height); - - subsurface->reordered = false; - - struct wlr_subsurface *child; - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_below, - current.link) { - surface_damage_subsurfaces(child); - } - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_above, - current.link) { - surface_damage_subsurfaces(child); - } -} - static void surface_apply_damage(struct wlr_surface *surface) { if (surface->current.buffer == NULL) { // NULL commit @@ -427,6 +404,15 @@ static void surface_commit_state(struct wlr_surface *surface, surface->sy += next->dy; surface_update_damage(&surface->buffer_damage, &surface->current, next); + pixman_region32_clear(&surface->external_damage); + if (surface->current.width > next->width || + surface->current.height > next->height || + next->dx != 0 || next->dy != 0) { + pixman_region32_union_rect(&surface->external_damage, + &surface->external_damage, -next->dx, -next->dy, + surface->current.width, surface->current.height); + } + surface->previous.scale = surface->current.scale; surface->previous.transform = surface->current.transform; surface->previous.width = surface->current.width; @@ -450,10 +436,6 @@ static void surface_commit_state(struct wlr_surface *surface, wl_list_insert(&surface->current.subsurfaces_above, &subsurface->current.link); - if (subsurface->reordered) { - // TODO: damage all the subsurfaces - surface_damage_subsurfaces(subsurface); - } subsurface_parent_commit(subsurface); } wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below, @@ -462,10 +444,6 @@ static void surface_commit_state(struct wlr_surface *surface, wl_list_insert(&surface->current.subsurfaces_below, &subsurface->current.link); - if (subsurface->reordered) { - // TODO: damage all the subsurfaces - surface_damage_subsurfaces(subsurface); - } subsurface_parent_commit(subsurface); } @@ -501,36 +479,37 @@ static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { return false; } +static void collect_subsurface_damage_iter(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct wlr_subsurface *subsurface = data; + pixman_region32_t *damage = &subsurface->parent->external_damage; + pixman_region32_union_rect(damage, damage, + subsurface->current.x + sx, + subsurface->current.y + sy, + surface->current.width, surface->current.height); +} + static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { struct wlr_surface *surface = subsurface->surface; + + bool moved = subsurface->current.x != subsurface->pending.x || + subsurface->current.y != subsurface->pending.y; + if (subsurface->mapped && moved) { + wlr_surface_for_each_surface(surface, + collect_subsurface_damage_iter, subsurface); + } if (subsurface->synchronized && subsurface->has_cache) { wlr_surface_unlock_cached(surface, subsurface->cached_seq); subsurface->has_cache = false; } - if (subsurface->current.x != subsurface->pending.x || - subsurface->current.y != subsurface->pending.y) { - // Subsurface has moved - int dx = subsurface->current.x - subsurface->pending.x; - int dy = subsurface->current.y - subsurface->pending.y; - - subsurface->current.x = subsurface->pending.x; - subsurface->current.y = subsurface->pending.y; - - if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int tmp = dx; - dx = dy; - dy = tmp; - } - - pixman_region32_union_rect(&surface->buffer_damage, - &surface->buffer_damage, - dx * surface->previous.scale, dy * surface->previous.scale, - surface->previous.buffer_width, surface->previous.buffer_height); - pixman_region32_union_rect(&surface->buffer_damage, - &surface->buffer_damage, 0, 0, - surface->current.buffer_width, surface->current.buffer_height); + subsurface->current.x = subsurface->pending.x; + subsurface->current.y = subsurface->pending.y; + if (subsurface->mapped && (moved || subsurface->reordered)) { + subsurface->reordered = false; + wlr_surface_for_each_surface(surface, + collect_subsurface_damage_iter, subsurface); } } @@ -720,6 +699,7 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { surface_state_finish(&surface->pending); surface_state_finish(&surface->current); pixman_region32_fini(&surface->buffer_damage); + pixman_region32_fini(&surface->external_damage); pixman_region32_fini(&surface->opaque_region); pixman_region32_fini(&surface->input_region); if (surface->buffer != NULL) { @@ -766,6 +746,7 @@ struct wlr_surface *surface_create(struct wl_client *client, wl_list_init(&surface->current_outputs); wl_list_init(&surface->cached); pixman_region32_init(&surface->buffer_damage); + pixman_region32_init(&surface->external_damage); pixman_region32_init(&surface->opaque_region); pixman_region32_init(&surface->input_region); wlr_addon_set_init(&surface->addons); @@ -1427,26 +1408,7 @@ void wlr_surface_get_effective_damage(struct wlr_surface *surface, wlr_region_scale_xy(damage, damage, scale_x, scale_y); } - // On resize, damage the previous bounds of the surface. The current bounds - // have already been damaged in surface_update_damage. - if (surface->previous.width > surface->current.width || - surface->previous.height > surface->current.height) { - pixman_region32_union_rect(damage, damage, 0, 0, - surface->previous.width, surface->previous.height); - } - - // On move, damage where the surface was with its old dimensions. - if (surface->current.dx != 0 || surface->current.dy != 0) { - int prev_x = -surface->current.dx; - int prev_y = -surface->current.dy; - if ((surface->previous.transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int temp = prev_x; - prev_x = prev_y; - prev_y = temp; - } - pixman_region32_union_rect(damage, damage, prev_x, prev_y, - surface->previous.width, surface->previous.height); - } + pixman_region32_union(damage, damage, &surface->external_damage); } void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, From 0fcc842291d9d714e9c210839ae72429c5c3eae4 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Mon, 6 Dec 2021 14:59:00 +0300 Subject: [PATCH 094/190] subsurface: don't add to parent list immediately --- include/wlr/types/wlr_surface.h | 1 + types/wlr_surface.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 4255a1f2c..59168eaa3 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -185,6 +185,7 @@ struct wlr_subsurface { bool synchronized; bool reordered; bool mapped; + bool added; struct wl_listener surface_destroy; struct wl_listener parent_destroy; diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 42b75f96f..d5d495714 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -511,6 +511,12 @@ static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { wlr_surface_for_each_surface(surface, collect_subsurface_damage_iter, subsurface); } + + if (!subsurface->added) { + subsurface->added = true; + wlr_signal_emit_safe(&subsurface->parent->events.new_subsurface, + subsurface); + } } static void subsurface_commit(struct wlr_subsurface *subsurface) { @@ -877,12 +883,12 @@ static struct wlr_subsurface *subsurface_find_sibling( struct wlr_surface *parent = subsurface->parent; struct wlr_subsurface *sibling; - wl_list_for_each(sibling, &parent->current.subsurfaces_below, current.link) { + wl_list_for_each(sibling, &parent->pending.subsurfaces_below, pending.link) { if (sibling->surface == surface && sibling != subsurface) { return sibling; } } - wl_list_for_each(sibling, &parent->current.subsurfaces_above, current.link) { + wl_list_for_each(sibling, &parent->pending.subsurfaces_above, pending.link) { if (sibling->surface == surface && sibling != subsurface) { return sibling; } @@ -1134,14 +1140,13 @@ struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, subsurface->parent = parent; wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; - wl_list_insert(parent->current.subsurfaces_above.prev, &subsurface->current.link); + + wl_list_init(&subsurface->current.link); wl_list_insert(parent->pending.subsurfaces_above.prev, &subsurface->pending.link); surface->role_data = subsurface; - wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface); - return subsurface; } From e3fefda0235e548e4d23639adfe375edf380825c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Dec 2021 16:37:51 +0100 Subject: [PATCH 095/190] output: add support for protocol interface version 4 Two new events are added: name and description. The name is immutable. The description can be updated on-the-fly. --- meson.build | 2 +- types/output/output.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 2e72e4451..a84f3df79 100644 --- a/meson.build +++ b/meson.build @@ -99,7 +99,7 @@ internal_features = { wayland_project_options = ['tests=false', 'documentation=false'] wayland_server = dependency('wayland-server', - version: '>=1.19', + version: '>=1.20', fallback: ['wayland', 'wayland_server_dep'], default_options: wayland_project_options, ) diff --git a/types/output/output.c b/types/output/output.c index 91a45f131..900cfda67 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -13,7 +13,7 @@ #include "util/global.h" #include "util/signal.h" -#define OUTPUT_VERSION 3 +#define OUTPUT_VERSION 4 static void send_geometry(struct wl_resource *resource) { struct wlr_output *output = wlr_output_from_resource(resource); @@ -43,6 +43,23 @@ static void send_scale(struct wl_resource *resource) { } } +static void send_name(struct wl_resource *resource) { + struct wlr_output *output = wlr_output_from_resource(resource); + uint32_t version = wl_resource_get_version(resource); + if (version >= WL_OUTPUT_NAME_SINCE_VERSION) { + wl_output_send_name(resource, output->name); + } +} + +static void send_description(struct wl_resource *resource) { + struct wlr_output *output = wlr_output_from_resource(resource); + uint32_t version = wl_resource_get_version(resource); + if (output->description != NULL && + version >= WL_OUTPUT_DESCRIPTION_SINCE_VERSION) { + wl_output_send_description(resource, output->description); + } +} + static void send_done(struct wl_resource *resource) { uint32_t version = wl_resource_get_version(resource); if (version >= WL_OUTPUT_DONE_SINCE_VERSION) { @@ -87,6 +104,8 @@ static void output_bind(struct wl_client *wl_client, void *data, send_geometry(resource); send_current_mode(resource); send_scale(resource); + send_name(resource); + send_description(resource); send_done(resource); struct wlr_output_event_bind evt = { @@ -131,10 +150,7 @@ static void schedule_done_handle_idle_timer(void *data) { struct wl_resource *resource; wl_resource_for_each(resource, &output->resources) { - uint32_t version = wl_resource_get_version(resource); - if (version >= WL_OUTPUT_DONE_SINCE_VERSION) { - wl_output_send_done(resource); - } + send_done(resource); } } @@ -344,6 +360,12 @@ void wlr_output_set_description(struct wlr_output *output, const char *desc) { output->description = NULL; } + struct wl_resource *resource; + wl_resource_for_each(resource, &output->resources) { + send_description(resource); + } + wlr_output_schedule_done(output); + wlr_signal_emit_safe(&output->events.description, output); } From f6d3efbf4b76a2100949fb0b88662a1324d4af54 Mon Sep 17 00:00:00 2001 From: Chris Chamberlain Date: Mon, 13 Dec 2021 14:53:41 +0100 Subject: [PATCH 096/190] backend: fix return value of attempt_drm_backend The multi backend was returned instead of the primary DRM backend. --- backend/backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/backend.c b/backend/backend.c index 33a218518..34c1e3667 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -239,7 +239,7 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, return NULL; } - return backend; + return primary_drm; } #endif From d8ca4945581577f570c02ad46878571c48a08c79 Mon Sep 17 00:00:00 2001 From: Chris Chamberlain Date: Fri, 10 Dec 2021 21:14:57 +0100 Subject: [PATCH 097/190] backend/drm: add wlr_drm_backend_monitor This helper is responsible for listening for new DRM devices and create new child DRM backends as necessary. --- backend/backend.c | 3 + backend/drm/meson.build | 1 + backend/drm/monitor.c | 94 +++++++++++++++++++++++++++++++ backend/session/session.c | 6 +- include/backend/drm/monitor.h | 24 ++++++++ include/backend/session/session.h | 3 + 6 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 backend/drm/monitor.c create mode 100644 include/backend/drm/monitor.h diff --git a/backend/backend.c b/backend/backend.c index 34c1e3667..24150b13d 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -21,6 +21,7 @@ #if WLR_HAS_DRM_BACKEND #include +#include "backend/drm/monitor.h" #endif #if WLR_HAS_LIBINPUT_BACKEND @@ -375,6 +376,8 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { return NULL; } + drm_backend_monitor_create(backend, primary_drm, multi->session); + return backend; #endif diff --git a/backend/drm/meson.build b/backend/drm/meson.build index b076b4728..cc791f362 100644 --- a/backend/drm/meson.build +++ b/backend/drm/meson.build @@ -4,6 +4,7 @@ wlr_files += files( 'cvt.c', 'drm.c', 'legacy.c', + 'monitor.c', 'properties.c', 'renderer.c', 'util.c', diff --git a/backend/drm/monitor.c b/backend/drm/monitor.c new file mode 100644 index 000000000..539e7925f --- /dev/null +++ b/backend/drm/monitor.c @@ -0,0 +1,94 @@ +#include +#include +#include "backend/drm/monitor.h" +#include "backend/multi.h" +#include "backend/session/session.h" + +static void drm_backend_monitor_destroy(struct wlr_drm_backend_monitor* monitor) { + wl_list_remove(&monitor->session_add_drm_card.link); + wl_list_remove(&monitor->session_destroy.link); + wl_list_remove(&monitor->primary_drm_destroy.link); + wl_list_remove(&monitor->multi_destroy.link); + free(monitor); +} + +static void handle_add_drm_card(struct wl_listener *listener, void *data) { + struct wlr_session_add_event *event = data; + struct wlr_drm_backend_monitor *backend_monitor = + wl_container_of(listener, backend_monitor, session_add_drm_card); + + struct wlr_device *dev = + session_open_if_kms(backend_monitor->session, event->path); + if (!dev) { + wlr_log(WLR_ERROR, "Unable to open %s as DRM device", event->path); + return; + } + + wlr_log(WLR_DEBUG, "Creating DRM backend for %s after hotplug", event->path); + struct wlr_backend *child_drm = wlr_drm_backend_create( + backend_monitor->session->display, backend_monitor->session, + dev, backend_monitor->primary_drm); + if (!child_drm) { + wlr_log(WLR_ERROR, "Failed to create DRM backend after hotplug"); + return; + } + + if (!wlr_multi_backend_add(backend_monitor->multi, child_drm)) { + wlr_log(WLR_ERROR, "Failed to add new drm backend to multi backend"); + wlr_backend_destroy(child_drm); + return; + } + + if (!wlr_backend_start(child_drm)) { + wlr_log(WLR_ERROR, "Failed to start new child DRM backend"); + wlr_backend_destroy(child_drm); + } +} + +static void handle_session_destroy(struct wl_listener *listener, void *data) { + struct wlr_drm_backend_monitor *backend_monitor = + wl_container_of(listener, backend_monitor, session_destroy); + drm_backend_monitor_destroy(backend_monitor); +} + +static void handle_primary_drm_destroy(struct wl_listener *listener, void *data) { + struct wlr_drm_backend_monitor *backend_monitor = + wl_container_of(listener, backend_monitor, primary_drm_destroy); + drm_backend_monitor_destroy(backend_monitor); +} + +static void handle_multi_destroy(struct wl_listener *listener, void *data) { + struct wlr_drm_backend_monitor *backend_monitor = + wl_container_of(listener, backend_monitor, multi_destroy); + drm_backend_monitor_destroy(backend_monitor); +} + +struct wlr_drm_backend_monitor *drm_backend_monitor_create( + struct wlr_backend *multi, + struct wlr_backend *primary_drm, + struct wlr_session *session) { + struct wlr_drm_backend_monitor *monitor = + calloc(1, sizeof(struct wlr_drm_backend_monitor)); + if (!monitor) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + + monitor->multi = multi; + monitor->primary_drm = primary_drm; + monitor->session = session; + + monitor->session_add_drm_card.notify = handle_add_drm_card; + wl_signal_add(&session->events.add_drm_card, &monitor->session_add_drm_card); + + monitor->session_destroy.notify = handle_session_destroy; + wl_signal_add(&session->events.destroy, &monitor->session_destroy); + + monitor->primary_drm_destroy.notify = handle_primary_drm_destroy; + wl_signal_add(&primary_drm->events.destroy, &monitor->primary_drm_destroy); + + monitor->multi_destroy.notify = handle_multi_destroy; + wl_signal_add(&multi->events.destroy, &monitor->multi_destroy); + + return monitor; +} diff --git a/backend/session/session.c b/backend/session/session.c index e83a8b4c1..7d6d080da 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -370,7 +370,7 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { /* Tests if 'path' is KMS compatible by trying to open it. Returns the opened * device on success. */ -static struct wlr_device *open_if_kms(struct wlr_session *restrict session, +struct wlr_device *session_open_if_kms(struct wlr_session *restrict session, const char *restrict path) { if (!path) { return NULL; @@ -406,7 +406,7 @@ static ssize_t explicit_find_gpus(struct wlr_session *session, break; } - ret[i] = open_if_kms(session, ptr); + ret[i] = session_open_if_kms(session, ptr); if (!ret[i]) { wlr_log(WLR_ERROR, "Unable to open %s as DRM device", ptr); } else { @@ -542,7 +542,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, } struct wlr_device *wlr_dev = - open_if_kms(session, udev_device_get_devnode(dev)); + session_open_if_kms(session, udev_device_get_devnode(dev)); if (!wlr_dev) { udev_device_unref(dev); continue; diff --git a/include/backend/drm/monitor.h b/include/backend/drm/monitor.h new file mode 100644 index 000000000..518171932 --- /dev/null +++ b/include/backend/drm/monitor.h @@ -0,0 +1,24 @@ +#ifndef BACKEND_DRM_MONITOR_H +#define BACKEND_DRM_MONITOR_H + +#include + +/** + * Helper to create new DRM sub-backends on GPU hotplug. + */ +struct wlr_drm_backend_monitor { + struct wlr_backend *multi; + struct wlr_backend *primary_drm; + struct wlr_session *session; + + struct wl_listener multi_destroy; + struct wl_listener primary_drm_destroy; + struct wl_listener session_destroy; + struct wl_listener session_add_drm_card; +}; + +struct wlr_drm_backend_monitor *drm_backend_monitor_create( + struct wlr_backend *multi, struct wlr_backend *primary_drm, + struct wlr_session *session); + +#endif diff --git a/include/backend/session/session.h b/include/backend/session/session.h index ebe6fc700..5eca7f576 100644 --- a/include/backend/session/session.h +++ b/include/backend/session/session.h @@ -11,4 +11,7 @@ bool libseat_change_vt(struct wlr_session *base, unsigned vt); void session_init(struct wlr_session *session); +struct wlr_device *session_open_if_kms(struct wlr_session *restrict session, + const char *restrict path); + #endif From 0215dffba51b63dc394ee028039ac811e1330c60 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 9 Dec 2021 23:17:16 +0100 Subject: [PATCH 098/190] scene: send surface enter/leave output events Co-authored-by: Simon Ser --- include/wlr/types/wlr_scene.h | 6 ++ types/scene/wlr_scene.c | 111 +++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index bca0b269e..1238653d3 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -76,6 +76,8 @@ struct wlr_scene_surface { // private state + int prev_width, prev_height; + struct wl_listener surface_destroy; struct wl_listener surface_commit; }; @@ -201,6 +203,10 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent); * Add a node displaying a single surface to the scene-graph. * * The child sub-surfaces are ignored. + * + * wlr_surface_send_enter()/wlr_surface_send_leave() will be called + * automatically based on the position of the surface and outputs in + * the scene. */ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, struct wlr_surface *surface); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index b1db7b8f2..d2f3f4a7f 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -39,6 +39,13 @@ static struct wlr_scene_buffer *scene_buffer_from_node( return (struct wlr_scene_buffer *)node; } +static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { + while (node->parent != NULL) { + node = node->parent; + } + return scene_root_from_node(node); +} + static void scene_node_state_init(struct wlr_scene_node_state *state) { wl_list_init(&state->children); wl_list_init(&state->link); @@ -85,11 +92,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { scene_node_damage_whole(node); scene_node_finish(node); + struct wlr_scene *scene = scene_node_get_root(node); + struct wlr_scene_output *scene_output; switch (node->type) { case WLR_SCENE_NODE_ROOT:; - struct wlr_scene *scene = scene_root_from_node(node); - - struct wlr_scene_output *scene_output, *scene_output_tmp; + struct wlr_scene_output *scene_output_tmp; wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { wlr_scene_output_destroy(scene_output); } @@ -102,8 +109,16 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + + wl_list_for_each(scene_output, &scene->outputs, link) { + // This is a noop if wlr_surface_send_enter() wasn't previously called for + // the given output. + wlr_surface_send_leave(scene_surface->surface, scene_output->output); + } + wl_list_remove(&scene_surface->surface_commit.link); wl_list_remove(&scene_surface->surface_destroy.link); + free(scene_surface); break; case WLR_SCENE_NODE_RECT:; @@ -146,11 +161,60 @@ static void scene_surface_handle_surface_destroy(struct wl_listener *listener, wlr_scene_node_destroy(&scene_surface->node); } -static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { - while (node->parent != NULL) { - node = node->parent; +// This function must be called whenever the coordinates/dimensions of a scene +// surface or scene output change. It is not necessary to call when a scene +// surface's node is enabled/disabled or obscured by other nodes. To quote the +// protocol: "The surface might be hidden even if no leave event has been sent." +static void scene_surface_update_outputs( + struct wlr_scene_surface *scene_surface, + int lx, int ly, struct wlr_scene *scene) { + struct wlr_box surface_box = { + .x = lx, + .y = ly, + .width = scene_surface->surface->current.width, + .height = scene_surface->surface->current.height, + }; + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + struct wlr_box output_box = { + .x = scene_output->x, + .y = scene_output->y, + }; + wlr_output_effective_resolution(scene_output->output, + &output_box.width, &output_box.height); + + // These enter/leave functions are a noop if the event has already been + // sent for the given output. + struct wlr_box intersection; + if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { + wlr_surface_send_enter(scene_surface->surface, scene_output->output); + } else { + wlr_surface_send_leave(scene_surface->surface, scene_output->output); + } } - return scene_root_from_node(node); +} + +static void scene_node_update_surface_outputs_iterator( + struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + scene_surface_update_outputs(scene_surface, lx, ly, scene); + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_node_update_surface_outputs_iterator(child, lx + child->state.x, + ly + child->state.y, scene); + } +} + +static void scene_node_update_surface_outputs(struct wlr_scene_node *node) { + struct wlr_scene *scene = scene_node_get_root(node); + int lx, ly; + wlr_scene_node_coords(node, &lx, &ly); + scene_node_update_surface_outputs_iterator(node, lx, ly, scene); } static void scene_surface_handle_surface_commit(struct wl_listener *listener, @@ -163,12 +227,21 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, return; } + struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); + int lx, ly; - if (!wlr_scene_node_coords(&scene_surface->node, &lx, &ly)) { - return; + bool enabled = wlr_scene_node_coords(&scene_surface->node, &lx, &ly); + + if (surface->current.width != scene_surface->prev_width || + surface->current.height != scene_surface->prev_height) { + scene_surface_update_outputs(scene_surface, lx, ly, scene); + scene_surface->prev_width = surface->current.width; + scene_surface->prev_height = surface->current.height; } - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); + if (!enabled) { + return; + } struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { @@ -212,6 +285,8 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent scene_node_damage_whole(&scene_surface->node); + scene_node_update_surface_outputs(&scene_surface->node); + return scene_surface; } @@ -438,6 +513,8 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { node->state.x = x; node->state.y = y; scene_node_damage_whole(node); + + scene_node_update_surface_outputs(node); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -511,6 +588,8 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, wl_list_insert(new_parent->state.children.prev, &node->state.link); scene_node_damage_whole(node); + + scene_node_update_surface_outputs(node); } bool wlr_scene_node_coords(struct wlr_scene_node *node, @@ -822,9 +901,19 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return scene_output; } +static void scene_output_send_leave_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct wlr_output *output = data; + wlr_surface_send_leave(surface, output); +} + void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); + + wlr_scene_output_for_each_surface(scene_output, + scene_output_send_leave_iterator, scene_output->output); + free(scene_output); } @@ -849,6 +938,8 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; wlr_output_damage_add_whole(scene_output->damage); + + scene_node_update_surface_outputs(&scene_output->scene->node); } struct check_scanout_data { From fb1f613510b871bcc117179a9d3a32aabc4508c0 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 11 Dec 2021 12:25:53 +0100 Subject: [PATCH 099/190] scene: add primary output to wlr_scene_surface This allows compositors to avoid sending multiple frame done events to a surface that is rendered on multiple outputs at once. This may also be used in the same way for presentation feedback. --- include/wlr/types/wlr_scene.h | 8 ++++++++ types/scene/wlr_scene.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 1238653d3..6c2928eed 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -74,6 +74,14 @@ struct wlr_scene_surface { struct wlr_scene_node node; struct wlr_surface *surface; + /** + * The output that the largest area of this surface is displayed on. + * This may be NULL if the surface is not currently displayed on any + * outputs. This is the output that should be used for frame callbacks, + * presentation feedback, etc. + */ + struct wlr_output *primary_output; + // private state int prev_width, prev_height; diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index d2f3f4a7f..42697074a 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -175,6 +175,9 @@ static void scene_surface_update_outputs( .height = scene_surface->surface->current.height, }; + int largest_overlap = 0; + scene_surface->primary_output = NULL; + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_box output_box = { @@ -184,10 +187,16 @@ static void scene_surface_update_outputs( wlr_output_effective_resolution(scene_output->output, &output_box.width, &output_box.height); - // These enter/leave functions are a noop if the event has already been - // sent for the given output. struct wlr_box intersection; if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { + int overlap = intersection.width * intersection.height; + if (overlap > largest_overlap) { + largest_overlap = overlap; + scene_surface->primary_output = scene_output->output; + } + + // These enter/leave functions are a noop if the event has already been + // sent for the given output. wlr_surface_send_enter(scene_surface->surface, scene_output->output); } else { wlr_surface_send_leave(scene_surface->surface, scene_output->output); From fecde72be3ebdc5ad0aa526db7405aaf1eddf847 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 13 Dec 2021 16:11:19 +0100 Subject: [PATCH 100/190] scene: add wlr_scene_send_frame_done() --- include/wlr/types/wlr_scene.h | 7 +++++++ types/scene/wlr_scene.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 6c2928eed..f388a6587 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -201,6 +201,13 @@ struct wlr_scene *wlr_scene_create(void); */ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, int lx, int ly, pixman_region32_t *damage); +/** + * Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by + * wlr_scene_render_output() for which wlr_scene_surface->primary_output + * matches the given output. + */ +void wlr_scene_send_frame_done(struct wlr_scene *scene, + struct wlr_output *output, struct timespec *now); /** * Add a node displaying nothing but its children. diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 42697074a..daaf8d97e 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -876,6 +876,31 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } +static void scene_send_frame_done_iterator(struct wlr_scene_node *node, + struct wlr_output *output, struct timespec *now) { + if (!node->state.enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + if (scene_surface->primary_output == output) { + wlr_surface_send_frame_done(scene_surface->surface, now); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_send_frame_done_iterator(child, output, now); + } +} + +void wlr_scene_send_frame_done(struct wlr_scene *scene, + struct wlr_output *output, struct timespec *now) { + scene_send_frame_done_iterator(&scene->node, output, now); +} + static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); From ad01cdf0b218a8d49698bf0ff85b84a4540a4f6f Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 13 Dec 2021 16:13:03 +0100 Subject: [PATCH 101/190] tinywl: use wlr_scene_send_frame_done() --- tinywl/tinywl.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 487757409..581fcfca3 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -510,29 +510,21 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(server->seat); } -// TODO: We should avoid sending the frame done event twice if a surface -// appears on multiple outputs. -// https://github.com/swaywm/wlroots/issues/3210 -static void send_frame_done(struct wlr_surface *surface, - int sx, int sy, void *data) { - wlr_surface_send_frame_done(surface, data); -} - static void output_frame(struct wl_listener *listener, void *data) { /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ - struct tinywl_output *output = - wl_container_of(listener, output, frame); + struct tinywl_output *output = wl_container_of(listener, output, frame); + struct wlr_scene *scene = output->server->scene; struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( - output->server->scene, output->wlr_output); + scene, output->wlr_output); /* Render the scene if needed and commit the output */ wlr_scene_output_commit(scene_output); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_for_each_surface(scene_output, send_frame_done, &now); + wlr_scene_send_frame_done(scene, output->wlr_output, &now); } static void server_new_output(struct wl_listener *listener, void *data) { From 1c3e0816f3cc4c653b24256486234d02fcf59e02 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 13 Dec 2021 17:23:47 +0100 Subject: [PATCH 102/190] scene: fix wlr_scene_send_frame_done() API This doesn't work if scene outputs are not used as the primary output of scene surfaces will always be NULL. Therefore, take a wlr_scene_output instead of separate wlr_scene and wlr_output arguments and rename the function to wlr_scene_output_send_frame_done(). The actual behavior of the function is unchanged. --- include/wlr/types/wlr_scene.h | 15 +++++------ tinywl/tinywl.c | 2 +- types/scene/wlr_scene.c | 51 ++++++++++++++++++----------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index f388a6587..d2af9c5af 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -201,13 +201,6 @@ struct wlr_scene *wlr_scene_create(void); */ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, int lx, int ly, pixman_region32_t *damage); -/** - * Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by - * wlr_scene_render_output() for which wlr_scene_surface->primary_output - * matches the given output. - */ -void wlr_scene_send_frame_done(struct wlr_scene *scene, - struct wlr_output *output, struct timespec *now); /** * Add a node displaying nothing but its children. @@ -295,7 +288,13 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, * Render and commit an output. */ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); - +/** + * Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by + * wlr_scene_output_commit() for which wlr_scene_surface->primary_output + * matches the given scene_output. + */ +void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, + struct timespec *now); /** * Call `iterator` on each surface in the scene-graph visible on the output, * with the surface's position in layout coordinates. The function is called diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 581fcfca3..faa0a9a13 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -524,7 +524,7 @@ static void output_frame(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_send_frame_done(scene, output->wlr_output, &now); + wlr_scene_output_send_frame_done(scene_output, &now); } static void server_new_output(struct wl_listener *listener, void *data) { diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index daaf8d97e..3d19acefc 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -876,31 +876,6 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } -static void scene_send_frame_done_iterator(struct wlr_scene_node *node, - struct wlr_output *output, struct timespec *now) { - if (!node->state.enabled) { - return; - } - - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - if (scene_surface->primary_output == output) { - wlr_surface_send_frame_done(scene_surface->surface, now); - } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_send_frame_done_iterator(child, output, now); - } -} - -void wlr_scene_send_frame_done(struct wlr_scene *scene, - struct wlr_output *output, struct timespec *now) { - scene_send_frame_done_iterator(&scene->node, output, now); -} - static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); @@ -1121,6 +1096,32 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return wlr_output_commit(output); } +static void scene_output_send_frame_done_iterator(struct wlr_scene_node *node, + struct wlr_output *output, struct timespec *now) { + if (!node->state.enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + if (scene_surface->primary_output == output) { + wlr_surface_send_frame_done(scene_surface->surface, now); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_output_send_frame_done_iterator(child, output, now); + } +} + +void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, + struct timespec *now) { + scene_output_send_frame_done_iterator(&scene_output->scene->node, + scene_output->output, now); +} + static void scene_output_for_each_surface(const struct wlr_box *output_box, struct wlr_scene_node *node, int lx, int ly, wlr_surface_iterator_func_t user_iterator, void *user_data) { From 31914928d22934a09d2f19ef996500c324bd5ff2 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 14 Dec 2021 08:15:45 +0100 Subject: [PATCH 103/190] seat: Only resend keyboard/pointer enter to focused clients Otherwise it will send enter events to clients that already have keyboard/pointer focus. Notably Qt applications warns about this. --- types/seat/wlr_seat_keyboard.c | 2 +- types/seat/wlr_seat_pointer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index e97b48252..57dbfe2f5 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -415,7 +415,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, seat_client->seat->keyboard_state.focused_surface; // Send an enter event if there is a focused client/surface stored - if (focused_client != NULL && focused_surface != NULL) { + if (focused_client == seat_client && focused_surface != NULL) { uint32_t *keycodes = keyboard->keycodes; size_t num_keycodes = keyboard->num_keycodes; diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 27ece5e88..2fa911ee0 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -446,7 +446,7 @@ void seat_client_create_pointer(struct wlr_seat_client *seat_client, seat_client->seat->pointer_state.focused_surface; // Send an enter event if there is a focused client/surface stored - if (focused_client != NULL && focused_surface != NULL) { + if (focused_client == seat_client && focused_surface != NULL) { double sx = seat_client->seat->pointer_state.sx; double sy = seat_client->seat->pointer_state.sy; From 4c59f7d46a949548caa55805b00922f846d58525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 11 Nov 2021 15:31:27 +0100 Subject: [PATCH 104/190] xdg-activation: Allow to submit tokens Allows the compositor to submit tokens to the pool of currently active tokens. This can be useful when the launcher doesn't use or support xdg-activation-v1 by itself - e.g. when it is X11 based or use gtk_shell1. --- include/wlr/types/wlr_xdg_activation_v1.h | 4 ++++ types/wlr_xdg_activation_v1.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/wlr/types/wlr_xdg_activation_v1.h b/include/wlr/types/wlr_xdg_activation_v1.h index 463562151..97801af2a 100644 --- a/include/wlr/types/wlr_xdg_activation_v1.h +++ b/include/wlr/types/wlr_xdg_activation_v1.h @@ -81,4 +81,8 @@ struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_find_token( const char *wlr_xdg_activation_token_v1_get_name( struct wlr_xdg_activation_token_v1 *token); +// Add a token to the pool of known tokens +struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_add_token( + struct wlr_xdg_activation_v1 *activation, const char *token_str); + #endif diff --git a/types/wlr_xdg_activation_v1.c b/types/wlr_xdg_activation_v1.c index 64864d882..208ada28c 100644 --- a/types/wlr_xdg_activation_v1.c +++ b/types/wlr_xdg_activation_v1.c @@ -407,3 +407,23 @@ const char *wlr_xdg_activation_token_v1_get_name( struct wlr_xdg_activation_token_v1 *token) { return token->token; } + +struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_add_token( + struct wlr_xdg_activation_v1 *activation, const char *token_str) { + assert(token_str); + + struct wlr_xdg_activation_token_v1 *token = calloc(1, sizeof(*token)); + if (token == NULL) { + return NULL; + } + wl_list_init(&token->link); + wl_list_init(&token->seat_destroy.link); + wl_list_init(&token->surface_destroy.link); + + token->activation = activation; + token->token = strdup(token_str); + + wl_list_insert(&activation->tokens, &token->link); + + return token; +} From 4377b5529279aa9dab64256d22ad0f2e9009843c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 29 Jun 2021 19:12:50 +0200 Subject: [PATCH 105/190] util/global: remove wl_display arg from wlr_global_destroy_safe Since [1], we can get the wl_display directly from the wl_global. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/commit/2b22160fb690a76247aa9bd0be3069ff43e8239f --- include/util/global.h | 3 +-- types/output/output.c | 2 +- types/seat/wlr_seat.c | 2 +- types/wlr_drm_lease_v1.c | 2 +- util/global.c | 4 ++-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/util/global.h b/include/util/global.h index ea0fda83b..1c979ab11 100644 --- a/include/util/global.h +++ b/include/util/global.h @@ -9,7 +9,6 @@ * Globals that are created and destroyed on the fly need special handling to * prevent race conditions with wl_registry. Use this function to destroy them. */ -void wlr_global_destroy_safe(struct wl_global *global, - struct wl_display *display); +void wlr_global_destroy_safe(struct wl_global *global); #endif diff --git a/types/output/output.c b/types/output/output.c index 900cfda67..85590ab63 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -140,7 +140,7 @@ void wlr_output_destroy_global(struct wlr_output *output) { wl_list_init(wl_resource_get_link(resource)); } - wlr_global_destroy_safe(output->global, output->display); + wlr_global_destroy_safe(output->global); output->global = NULL; } diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index f93147443..4933133c6 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -191,7 +191,7 @@ void wlr_seat_destroy(struct wlr_seat *seat) { } } - wlr_global_destroy_safe(seat->global, seat->display); + wlr_global_destroy_safe(seat->global); free(seat->pointer_state.default_grab); free(seat->keyboard_state.default_grab); free(seat->touch_state.default_grab); diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index 7063e0d31..7cb9974d7 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -127,7 +127,7 @@ static void drm_lease_device_v1_destroy( } wl_list_remove(&device->link); - wlr_global_destroy_safe(device->global, device->manager->display); + wlr_global_destroy_safe(device->global); free(device); } diff --git a/util/global.c b/util/global.c index a0d84ed30..fa99a9946 100644 --- a/util/global.c +++ b/util/global.c @@ -14,8 +14,7 @@ static int destroy_global(void *_data) { return 0; } -void wlr_global_destroy_safe(struct wl_global *global, - struct wl_display *display) { +void wlr_global_destroy_safe(struct wl_global *global) { // Don't destroy the global immediately. If the global has been created // recently, clients might try to bind to it after we've destroyed it. // Instead, remove the global so that clients stop seeing it and wait an @@ -25,6 +24,7 @@ void wlr_global_destroy_safe(struct wl_global *global, wl_global_remove(global); wl_global_set_user_data(global, NULL); // safety net + struct wl_display *display = wl_global_get_display(global); struct wl_event_loop *event_loop = wl_display_get_event_loop(display); struct destroy_global_data *data = calloc(1, sizeof(*data)); if (data == NULL) { From a15c327718dafb1b7b7f1213c8878187b6351dba Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Nov 2021 16:44:42 +0100 Subject: [PATCH 106/190] backend/drm: use drmModeFormatModifierBlobIterNext This avoids open-coding our own logic. The resulting code is more readable. References: https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/146 --- backend/drm/drm.c | 14 +++----------- meson.build | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1a46b4959..43de54e55 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -142,17 +142,9 @@ static bool add_plane(struct wlr_drm_backend *drm, goto error; } - struct drm_format_modifier_blob *data = blob->data; - uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); - struct drm_format_modifier *mods = (struct drm_format_modifier *) - ((char *)data + data->modifiers_offset); - for (uint32_t i = 0; i < data->count_modifiers; ++i) { - for (int j = 0; j < 64; ++j) { - if (mods[i].formats & ((uint64_t)1 << j)) { - wlr_drm_format_set_add(&p->formats, - fmts[j + mods[i].offset], mods[i].modifier); - } - } + drmModeFormatModifierIterator iter = {0}; + while (drmModeFormatModifierBlobIterNext(blob, &iter)) { + wlr_drm_format_set_add(&p->formats, iter.fmt, iter.mod); } drmModeFreePropertyBlob(blob); diff --git a/meson.build b/meson.build index a84f3df79..bdb6df193 100644 --- a/meson.build +++ b/meson.build @@ -104,7 +104,7 @@ wayland_server = dependency('wayland-server', default_options: wayland_project_options, ) -drm = dependency('libdrm', version: '>=2.4.105') +drm = dependency('libdrm', version: '>=2.4.108') gbm = dependency('gbm', version: '>=17.1.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') From bedfec94bb57cf7dc32f03fce463a30d3370bb20 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 2 Oct 2021 17:24:08 +0200 Subject: [PATCH 107/190] backend/drm: use drmCloseBufferHandle This has been added in [1] and allows us to close buffer handles without manually calling drmIoctl. [1]: https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/192 --- backend/drm/legacy.c | 8 ++++++-- backend/drm/renderer.c | 4 +++- backend/drm/util.c | 11 ----------- include/backend/drm/util.h | 7 ------- 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index cb672023b..84e8a914f 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -151,9 +151,13 @@ static bool legacy_crtc_commit(struct wlr_drm_connector *conn, int ret = drmModeSetCursor(drm->fd, crtc->id, cursor_handle, cursor_width, cursor_height); - close_bo_handle(drm->fd, cursor_handle); + int set_cursor_errno = errno; + if (drmCloseBufferHandle(drm->fd, cursor_handle) != 0) { + wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed"); + } if (ret != 0) { - wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed"); + wlr_drm_conn_log(conn, WLR_DEBUG, "drmModeSetCursor failed: %s", + strerror(set_cursor_errno)); return false; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 815ba9818..792de938f 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -271,7 +271,9 @@ static void close_all_bo_handles(struct wlr_drm_backend *drm, continue; } - close_bo_handle(drm->fd, handles[i]); + if (drmCloseBufferHandle(drm->fd, handles[i]) != 0) { + wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed"); + } } } diff --git a/backend/drm/util.c b/backend/drm/util.c index 407c19a5e..3cf656fb3 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -320,14 +320,3 @@ size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], match_obj_(&st, 0, 0, 0, 0); return st.score; } - -void close_bo_handle(int drm_fd, uint32_t handle) { - if (handle == 0) { - return; - } - - struct drm_gem_close args = { .handle = handle }; - if (drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &args) != 0) { - wlr_log_errno(WLR_ERROR, "drmIoctl(GEM_CLOSE) failed"); - } -} diff --git a/include/backend/drm/util.h b/include/backend/drm/util.h index 6e97505c3..b4cdee7d7 100644 --- a/include/backend/drm/util.h +++ b/include/backend/drm/util.h @@ -36,11 +36,4 @@ size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], size_t num_res, const uint32_t res[static restrict num_res], uint32_t out[static restrict num_res]); -/** - * Close a GEM buffer handle. - * - * TODO: replace with drmCloseBufferHandle. - */ -void close_bo_handle(int drm_fd, uint32_t handle); - #endif From c0b120a30caae4cc538d1f83b722950d3d71a921 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 2 Oct 2021 17:29:42 +0200 Subject: [PATCH 108/190] build: add subproject fallback for libdrm --- meson.build | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bdb6df193..67fe86fd4 100644 --- a/meson.build +++ b/meson.build @@ -104,7 +104,27 @@ wayland_server = dependency('wayland-server', default_options: wayland_project_options, ) -drm = dependency('libdrm', version: '>=2.4.108') +drm = dependency('libdrm', + version: '>=2.4.108', + fallback: ['libdrm', 'ext_libdrm'], + default_options: [ + 'libkms=false', + 'intel=false', + 'radeon=false', + 'amdgpu=false', + 'nouveau=false', + 'vmwgfx=false', + 'omap=false', + 'exynos=false', + 'freedreno=false', + 'tegra=false', + 'vc4=false', + 'etnaviv=false', + 'cairo-tests=false', + 'man-pages=false', + 'valgrind=false', + ], +) gbm = dependency('gbm', version: '>=17.1.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') From 07ccc6e0b357dd3c7be0939957657d0a03738b9d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 14 Dec 2021 18:35:44 +0100 Subject: [PATCH 109/190] scene: add wlr_scene_set_presentation() This helper automates sending presentation feedback to clients based on the primary output of scene surfaces. --- include/wlr/types/wlr_scene.h | 14 ++++++++++++ types/scene/wlr_scene.c | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index d2af9c5af..e0b370adf 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -62,6 +62,12 @@ struct wlr_scene { struct wlr_scene_node node; struct wl_list outputs; // wlr_scene_output.link + + // private state + + // May be NULL + struct wlr_presentation *presentation; + struct wl_listener presentation_destroy; }; /** A sub-tree in the scene-graph. */ @@ -201,6 +207,14 @@ struct wlr_scene *wlr_scene_create(void); */ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, int lx, int ly, pixman_region32_t *damage); +/** + * Handle presentation feedback for all surfaces in the scene, assuming that + * scene outputs and the scene rendering functions are used. + * + * Asserts that a wlr_presentation hasn't already been set for the scene. + */ +void wlr_scene_set_presentation(struct wlr_scene *scene, + struct wlr_presentation *presentation); /** * Add a node displaying nothing but its children. diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 3d19acefc..7b5509638 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,8 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_scene_output_destroy(scene_output); } + wl_list_remove(&scene->presentation_destroy.link); + free(scene); break; case WLR_SCENE_NODE_TREE:; @@ -141,6 +144,7 @@ struct wlr_scene *wlr_scene_create(void) { } scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); wl_list_init(&scene->outputs); + wl_list_init(&scene->presentation_destroy.link); return scene; } @@ -767,6 +771,9 @@ static void render_texture(struct wlr_output *output, struct render_data { struct wlr_output *output; pixman_region32_t *damage; + + // May be NULL + struct wlr_presentation *presentation; }; static void render_node_iterator(struct wlr_scene_node *node, @@ -808,6 +815,11 @@ static void render_node_iterator(struct wlr_scene_node *node, render_texture(output, output_damage, texture, &src_box, &dst_box, matrix); + + if (data->presentation != NULL && scene_surface->primary_output == output) { + wlr_presentation_surface_sampled_on_output(data->presentation, + surface, output); + } break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); @@ -867,6 +879,7 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, struct render_data data = { .output = output, .damage = damage, + .presentation = scene->presentation, }; scene_node_for_each_node(&scene->node, -lx, -ly, render_node_iterator, &data); @@ -876,6 +889,23 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } +static void scene_handle_presentation_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene *scene = + wl_container_of(listener, scene, presentation_destroy); + wl_list_remove(&scene->presentation_destroy.link); + wl_list_init(&scene->presentation_destroy.link); + scene->presentation = NULL; +} + +void wlr_scene_set_presentation(struct wlr_scene *scene, + struct wlr_presentation *presentation) { + assert(scene->presentation == NULL); + scene->presentation = presentation; + scene->presentation_destroy.notify = scene_handle_presentation_destroy; + wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy); +} + static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); @@ -1028,6 +1058,18 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { return false; } + struct wlr_presentation *presentation = scene_output->scene->presentation; + if (presentation != NULL && node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + // Since outputs may overlap, we still need to check this even though + // we know that the surface size matches the size of this output. + if (scene_surface->primary_output == output) { + wlr_presentation_surface_sampled_on_output(presentation, + scene_surface->surface, output); + } + } + return wlr_output_commit(output); } From 8e566f716c464d886f1aed7e57b5bf26c3502426 Mon Sep 17 00:00:00 2001 From: Stacy Harper Date: Tue, 14 Dec 2021 18:09:31 +0100 Subject: [PATCH 110/190] layer-shell: don't set committed flag if the property didn't change This fixes configure loop in Sway when clients re-send same properties on every configure event. Original issue: https://todo.sr.ht/~mil/sxmo-tickets/413 --- types/wlr_layer_shell_v1.c | 44 +++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 4495472a1..456dbc0eb 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -103,7 +103,14 @@ static void layer_surface_handle_set_size(struct wl_client *client, if (!surface) { return; } - surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_DESIRED_SIZE; + + if (surface->current.desired_width == width + && surface->current.desired_height == height) { + surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_DESIRED_SIZE; + } else { + surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_DESIRED_SIZE; + } + surface->pending.desired_width = width; surface->pending.desired_height = height; } @@ -125,7 +132,13 @@ static void layer_surface_handle_set_anchor(struct wl_client *client, if (!surface) { return; } - surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_ANCHOR; + + if (surface->current.anchor == anchor) { + surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_ANCHOR; + } else { + surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_ANCHOR; + } + surface->pending.anchor = anchor; } @@ -136,7 +149,13 @@ static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, if (!surface) { return; } - surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_EXCLUSIVE_ZONE; + + if (surface->current.exclusive_zone == zone) { + surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_EXCLUSIVE_ZONE; + } else { + surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_EXCLUSIVE_ZONE; + } + surface->pending.exclusive_zone = zone; } @@ -148,7 +167,16 @@ static void layer_surface_handle_set_margin( if (!surface) { return; } - surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_MARGIN; + + if (surface->current.margin.top == (uint32_t) top + && surface->current.margin.right == (uint32_t) right + && surface->current.margin.bottom == (uint32_t) bottom + && surface->current.margin.left == (uint32_t) left) { + surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_MARGIN; + } else { + surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_MARGIN; + } + surface->pending.margin.top = top; surface->pending.margin.right = right; surface->pending.margin.bottom = bottom; @@ -209,7 +237,13 @@ static void layer_surface_set_layer(struct wl_client *client, "Invalid layer %" PRIu32, layer); return; } - surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_LAYER; + + if (surface->current.layer == layer) { + surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_LAYER; + } else { + surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_LAYER; + } + surface->pending.layer = layer; } From 9f41627aa10a94d9427bc315fa3d363a61b94d7c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 8 Dec 2021 01:43:15 +0100 Subject: [PATCH 111/190] backend/wayland: add basic linux-dmabuf feedback support This patch makes it so we bind to zwp_linux_dmabuf_v1 version 4 and we use it to grab the main device. v4 sends supported formats via a table so we need to handle this as well. v4 allows wlroots to remove the requirement for Mesa's internal wl_drm interface. --- backend/wayland/backend.c | 166 ++++++++++++++++++++++++++++++++++++-- meson.build | 2 +- 2 files changed, 162 insertions(+), 6 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 63d6a7df6..1df753b93 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -30,6 +32,21 @@ #include "tablet-unstable-v2-client-protocol.h" #include "relative-pointer-unstable-v1-client-protocol.h" +struct wlr_wl_linux_dmabuf_feedback_v1 { + struct wlr_wl_backend *backend; + dev_t main_device_id; + struct wlr_wl_linux_dmabuf_v1_table_entry *format_table; + size_t format_table_size; + + dev_t tranche_target_device_id; +}; + +struct wlr_wl_linux_dmabuf_v1_table_entry { + uint32_t format; + uint32_t pad; /* unused */ + uint64_t modifier; +}; + struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend) { assert(wlr_backend_is_wl(backend)); return (struct wlr_wl_backend *)backend; @@ -108,6 +125,119 @@ static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_v1_listener = { .modifier = linux_dmabuf_v1_handle_modifier, }; +static void linux_dmabuf_feedback_v1_handle_done(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback) { + // This space is intentionally left blank +} + +static void linux_dmabuf_feedback_v1_handle_format_table(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, int fd, uint32_t size) { + struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data; + + feedback_data->format_table = NULL; + + void *table_data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (table_data == MAP_FAILED) { + wlr_log_errno(WLR_ERROR, "failed to mmap DMA-BUF format table"); + } else { + feedback_data->format_table = table_data; + feedback_data->format_table_size = size; + } + close(fd); +} + +static void linux_dmabuf_feedback_v1_handle_main_device(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *dev_id_arr) { + struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data; + + dev_t dev_id; + assert(dev_id_arr->size == sizeof(dev_id)); + memcpy(&dev_id, dev_id_arr->data, sizeof(dev_id)); + + feedback_data->main_device_id = dev_id; + + drmDevice *device = NULL; + if (drmGetDeviceFromDevId(dev_id, 0, &device) != 0) { + wlr_log_errno(WLR_ERROR, "drmGetDeviceFromDevId failed"); + return; + } + + const char *name = NULL; + if (device->available_nodes & (1 << DRM_NODE_RENDER)) { + name = device->nodes[DRM_NODE_RENDER]; + } else { + // Likely a split display/render setup. Pick the primary node and hope + // Mesa will open the right render node under-the-hood. + assert(device->available_nodes & (1 << DRM_NODE_PRIMARY)); + name = device->nodes[DRM_NODE_PRIMARY]; + wlr_log(WLR_DEBUG, "DRM device %s has no render node, " + "falling back to primary node", name); + } + + feedback_data->backend->drm_render_name = strdup(name); + + drmFreeDevice(&device); +} + +static void linux_dmabuf_feedback_v1_handle_tranche_done(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback) { + struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data; + feedback_data->tranche_target_device_id = 0; +} + +static void linux_dmabuf_feedback_v1_handle_tranche_target_device(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *dev_id_arr) { + struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data; + + dev_t dev_id; + assert(dev_id_arr->size == sizeof(dev_id)); + memcpy(&dev_id, dev_id_arr->data, sizeof(dev_id)); + + feedback_data->tranche_target_device_id = dev_id; +} + +static void linux_dmabuf_feedback_v1_handle_tranche_formats(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *indices_arr) { + struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data; + + if (feedback_data->format_table == NULL) { + return; + } + if (feedback_data->tranche_target_device_id != feedback_data->main_device_id) { + return; + } + + size_t table_cap = feedback_data->format_table_size / + sizeof(struct wlr_wl_linux_dmabuf_v1_table_entry); + uint16_t *index_ptr; + wl_array_for_each(index_ptr, indices_arr) { + assert(*index_ptr < table_cap); + const struct wlr_wl_linux_dmabuf_v1_table_entry *entry = + &feedback_data->format_table[*index_ptr]; + wlr_drm_format_set_add(&feedback_data->backend->linux_dmabuf_v1_formats, + entry->format, entry->modifier); + } +} + +static void linux_dmabuf_feedback_v1_handle_tranche_flags(void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, uint32_t flags) { + // TODO: handle SCANOUT flag +} + +static const struct zwp_linux_dmabuf_feedback_v1_listener + linux_dmabuf_feedback_v1_listener = { + .done = linux_dmabuf_feedback_v1_handle_done, + .format_table = linux_dmabuf_feedback_v1_handle_format_table, + .main_device = linux_dmabuf_feedback_v1_handle_main_device, + .tranche_done = linux_dmabuf_feedback_v1_handle_tranche_done, + .tranche_target_device = linux_dmabuf_feedback_v1_handle_tranche_target_device, + .tranche_formats = linux_dmabuf_feedback_v1_handle_tranche_formats, + .tranche_flags = linux_dmabuf_feedback_v1_handle_tranche_flags, +}; + static bool device_has_name(const drmDevice *device, const char *name) { for (size_t i = 0; i < DRM_NODE_MAX; i++) { if (!(device->available_nodes & (1 << i))) { @@ -172,8 +302,6 @@ static char *get_render_name(const char *name) { static void legacy_drm_handle_device(void *data, struct wl_drm *drm, const char *name) { struct wlr_wl_backend *wl = data; - - // TODO: get FD from linux-dmabuf hints instead wl->drm_render_name = get_render_name(name); } @@ -245,7 +373,7 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, zwp_linux_dmabuf_v1_interface.name) == 0 && version >= 3) { wl->zwp_linux_dmabuf_v1 = wl_registry_bind(registry, name, - &zwp_linux_dmabuf_v1_interface, 3); + &zwp_linux_dmabuf_v1_interface, version >= 4 ? 4 : version); zwp_linux_dmabuf_v1_add_listener(wl->zwp_linux_dmabuf_v1, &linux_dmabuf_v1_listener, wl); } else if (strcmp(iface, zwp_relative_pointer_manager_v1_interface.name) == 0) { @@ -428,10 +556,9 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry"); goto error_display; } - wl_registry_add_listener(wl->registry, ®istry_listener, wl); + wl_display_roundtrip(wl->remote_display); // get globals - wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats if (!wl->compositor) { wlr_log(WLR_ERROR, @@ -444,6 +571,35 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, goto error_registry; } + struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback_v1 = NULL; + struct wlr_wl_linux_dmabuf_feedback_v1 feedback_data = { .backend = wl }; + if (wl->zwp_linux_dmabuf_v1 != NULL && + zwp_linux_dmabuf_v1_get_version(wl->zwp_linux_dmabuf_v1) >= + ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) { + linux_dmabuf_feedback_v1 = + zwp_linux_dmabuf_v1_get_default_feedback(wl->zwp_linux_dmabuf_v1); + if (linux_dmabuf_feedback_v1 == NULL) { + wlr_log(WLR_ERROR, "Allocation failed"); + goto error_registry; + } + zwp_linux_dmabuf_feedback_v1_add_listener(linux_dmabuf_feedback_v1, + &linux_dmabuf_feedback_v1_listener, &feedback_data); + + if (wl->legacy_drm != NULL) { + wl_drm_destroy(wl->legacy_drm); + wl->legacy_drm = NULL; + } + } + + wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats + + if (feedback_data.format_table != NULL) { + munmap(feedback_data.format_table, feedback_data.format_table_size); + } + if (linux_dmabuf_feedback_v1 != NULL) { + zwp_linux_dmabuf_feedback_v1_destroy(linux_dmabuf_feedback_v1); + } + struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display); int fd = wl_display_get_fd(wl->remote_display); wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, diff --git a/meson.build b/meson.build index 67fe86fd4..681b07cc4 100644 --- a/meson.build +++ b/meson.build @@ -105,7 +105,7 @@ wayland_server = dependency('wayland-server', ) drm = dependency('libdrm', - version: '>=2.4.108', + version: '>=2.4.109', fallback: ['libdrm', 'ext_libdrm'], default_options: [ 'libkms=false', From 7360810f2e5c71fe143b25b63517ab1a6475ce0a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 17 Dec 2021 11:54:06 +0100 Subject: [PATCH 112/190] build: bump to version 0.16.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 681b07cc4..a12cd19bf 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.15.0', + version: '0.16.0', license: 'MIT', meson_version: '>=0.58.1', default_options: [ From 92d137c78ac05b565bfa06b5659aea52992e0dd7 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 15 Dec 2021 16:30:32 +0100 Subject: [PATCH 113/190] layer-shell: fix type of margins These currently use uint32_t while they are an int32_t in the protocol. --- include/wlr/types/wlr_layer_shell_v1.h | 2 +- types/wlr_layer_shell_v1.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index 694fb3b29..79e435a00 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -58,7 +58,7 @@ struct wlr_layer_surface_v1_state { uint32_t anchor; int32_t exclusive_zone; struct { - uint32_t top, right, bottom, left; + int32_t top, right, bottom, left; } margin; enum zwlr_layer_surface_v1_keyboard_interactivity keyboard_interactive; uint32_t desired_width, desired_height; diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 456dbc0eb..d7a2123e9 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -168,10 +168,10 @@ static void layer_surface_handle_set_margin( return; } - if (surface->current.margin.top == (uint32_t) top - && surface->current.margin.right == (uint32_t) right - && surface->current.margin.bottom == (uint32_t) bottom - && surface->current.margin.left == (uint32_t) left) { + if (surface->current.margin.top == top + && surface->current.margin.right == right + && surface->current.margin.bottom == bottom + && surface->current.margin.left == left) { surface->pending.committed &= ~WLR_LAYER_SURFACE_V1_STATE_MARGIN; } else { surface->pending.committed |= WLR_LAYER_SURFACE_V1_STATE_MARGIN; From 562b24b9fc8e2c2e3de23dfaa32af5e3637c6da0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 17 Dec 2021 12:51:54 +0100 Subject: [PATCH 114/190] build: bump soversion According to [1] this should be done at each release with breaking ABI changes. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Core-contributor-guide#releasing-a-new-version Fixes: 7360810f2e5c ("build: bump to version 0.16.0") --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a12cd19bf..24aa6f7a1 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ project( # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. -soversion = 10 +soversion = 11 little_endian = host_machine.endian() == 'little' big_endian = host_machine.endian() == 'big' From 93e050c602df91b00454046b12dc7331a555c437 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 17 Dec 2021 15:37:07 +0100 Subject: [PATCH 115/190] Remove wlr_box.h redirection Compositors should've all been updated to use the new header by now. --- include/wlr/types/wlr_box.h | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 include/wlr/types/wlr_box.h diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h deleted file mode 100644 index 8720cef8f..000000000 --- a/include/wlr/types/wlr_box.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef WLR_TYPES_WLR_BOX_H -#define WLR_TYPES_WLR_BOX_H - -#warning "wlr_box has been moved to wlr/util/box.h" -#include - -#endif From b5a019d5754064788471e9eba4ee9354c7cc4cd5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 14 Dec 2021 12:10:31 +0100 Subject: [PATCH 116/190] build: simplify Meson subproject fallbacks All of these projects use meson.override_dependency() so we can stop referencing their internal variable name to grab the depndencies we need. --- backend/session/meson.build | 2 +- backend/wayland/meson.build | 2 +- meson.build | 4 ++-- protocol/meson.build | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/session/meson.build b/backend/session/meson.build index 66c908a2e..27915506b 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -1,6 +1,6 @@ libseat = dependency('libseat', version: '>=0.2.0', - fallback: ['seatd', 'libseat'], + fallback: 'seatd', default_options: ['server=disabled', 'man-pages=disabled'], ) wlr_files += files('session.c') diff --git a/backend/wayland/meson.build b/backend/wayland/meson.build index 103d3f9fa..1831bbb30 100644 --- a/backend/wayland/meson.build +++ b/backend/wayland/meson.build @@ -1,5 +1,5 @@ wayland_client = dependency('wayland-client', - fallback: ['wayland', 'wayland_client_dep'], + fallback: 'wayland', default_options: wayland_project_options, ) wlr_deps += wayland_client diff --git a/meson.build b/meson.build index 24aa6f7a1..f7fb659c4 100644 --- a/meson.build +++ b/meson.build @@ -100,13 +100,13 @@ internal_features = { wayland_project_options = ['tests=false', 'documentation=false'] wayland_server = dependency('wayland-server', version: '>=1.20', - fallback: ['wayland', 'wayland_server_dep'], + fallback: 'wayland', default_options: wayland_project_options, ) drm = dependency('libdrm', version: '>=2.4.109', - fallback: ['libdrm', 'ext_libdrm'], + fallback: 'libdrm', default_options: [ 'libkms=false', 'intel=false', diff --git a/protocol/meson.build b/protocol/meson.build index 3e34f7881..ae2b2ef48 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,6 +1,6 @@ wayland_protos = dependency('wayland-protocols', version: '>=1.24', - fallback: ['wayland-protocols', 'wayland_protocols'], + fallback: 'wayland-protocols', default_options: ['tests=false'], ) wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') From ec2845750862cc0b175bef59de4305f6da91960a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 19 Dec 2021 16:39:57 +0100 Subject: [PATCH 117/190] backend: error out in autocreate without libinput support The libinput backend is now optional. However, this means that a user building wlroots without the correct libinput dependencies will end up with a compositor which doesn't respond to input events. wlr_backend_autocreate is supposed to return a sensible setup, so in this case let's just error out and explain what happened. Users can suppress the check by setting WLR_LIBINPUT_NO_DEVICES=1 (already used to suppress the zero input device case inside the libinput backend). Compositors which really want to create a bare DRM backend can easily create it manually instead of using wlr_backend_autocreate. --- backend/backend.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/backend.c b/backend/backend.c index 24150b13d..bfb43ba07 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -364,6 +364,19 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { return NULL; } wlr_multi_backend_add(backend, libinput); +#else + const char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES"); + if (no_devs && strcmp(no_devs, "1") == 0) { + wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, " + "starting without libinput backend"); + } else { + wlr_log(WLR_ERROR, "libinput support is not compiled in, " + "refusing to start"); + wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check"); + wlr_session_destroy(multi->session); + wlr_backend_destroy(backend); + return NULL; + } #endif #if WLR_HAS_DRM_BACKEND From 823476e76ed166762095330a8f51eabc825febff Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 20 Dec 2021 20:41:44 +0000 Subject: [PATCH 118/190] wlr_texture: remove wlr_texture_from_wl_drm() from header This function was already removed in e5b5592a but it was forgotten to remove it from the header. --- include/wlr/render/wlr_texture.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 3495c4439..1dbcba1de 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -33,16 +33,6 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data); -/** - * Create a new texture from a wl_drm resource. The returned texture is - * immutable. - * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. - */ -struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer, - struct wl_resource *data); - /** * Create a new texture from a DMA-BUF. The returned texture is immutable. * From 812951f5bc47f502429406e49f4e24f377b7799b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Dec 2021 16:30:24 +0100 Subject: [PATCH 119/190] scene: schedule an output frame on wl_surface.frame Some clients (e.g. mpv, Firefox) request a new wl_surface.frame callback without damaging their surface. When this happens, schedule a new output frame. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3350 --- types/scene/wlr_scene.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 7b5509638..a0c06b6bf 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -236,10 +236,6 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, wl_container_of(listener, scene_surface, surface_commit); struct wlr_surface *surface = scene_surface->surface; - if (!pixman_region32_not_empty(&surface->buffer_damage)) { - return; - } - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); int lx, ly; @@ -256,6 +252,17 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, return; } + // Even if the surface hasn't submitted damage, schedule a new frame if + // the client has requested a wl_surface.frame callback. + if (!wl_list_empty(&surface->current.frame_callback_list) && + scene_surface->primary_output != NULL) { + wlr_output_schedule_frame(scene_surface->primary_output); + } + + if (!pixman_region32_not_empty(&surface->buffer_damage)) { + return; + } + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_output *output = scene_output->output; From 9988eb3378dbc3301059aa9b5e1ff476354cb92b Mon Sep 17 00:00:00 2001 From: nyorain Date: Sun, 26 Dec 2021 13:21:54 +0100 Subject: [PATCH 120/190] vulkan: Fix imported image layout --- render/vulkan/renderer.c | 2 +- render/vulkan/texture.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index a1d8d41ef..21b36bdd6 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -598,7 +598,7 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) { wl_list_for_each_safe(texture, tmp_tex, &renderer->foreign_textures, foreign_link) { VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL; if (!texture->transitioned) { - src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + src_layout = VK_IMAGE_LAYOUT_UNDEFINED; texture->transitioned = true; } diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index 76c370113..b705603cf 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -438,7 +438,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer, img_info.arrayLayers = 1; img_info.samples = VK_SAMPLE_COUNT_1_BIT; img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - img_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; img_info.extent = (VkExtent3D) { attribs->width, attribs->height, 1 }; img_info.usage = for_render ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : From 59b9518f072527ac59593e51df7f5d5331a34f0e Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Wed, 5 Jan 2022 00:16:59 -0800 Subject: [PATCH 121/190] render/gles2: don't constrain shm formats to ones that support reading commit 44e8451cd93e ("render/gles2: hide shm formats without GL support") added the is_gles2_pixel_format_supported() function to render/gles2/pixel_format.c, whose stated purpose is to "check whether the renderer has the needed GL extensions to read a given pixel format." It then used that function to filter the pixel formats returned by get_gles2_shm_formats(). The result of this change is that RGB formats are no longer reported for GL drivers that don't implement EXT_read_format_bgra, even when those formats are supported for rendering (which they have to be for wlr_gles2_renderer_create() to succeed). This is a pretty clear regression, since wlr_renderer_init_wl_shm() fails when either of WL_SHM_FORMAT_ARGB8888 or WL_SHM_FORMAT_XRGB8888 are missing. To fix the regression, change is_gles2_pixel_format_supported() to accept all pixel formats that support rendering, regardless of whether we can read them or not, and move the check for EXT_read_format_bgra back into gles2_read_pixels(). (There's already a check for this extension in gles2_preferred_read_format(), so we're not breaking any abstraction that wasn't already broken.) Tested on the NVIDIA 495.46 proprietary driver, which doesn't support EXT_read_format_bgra. Fixes: 44e8451cd93e ("render/gles2: hide shm formats without GL support") --- render/gles2/pixel_format.c | 14 ++++++++++---- render/gles2/renderer.c | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index 31bb3908e..b155bbbe9 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -98,6 +98,10 @@ static const struct wlr_gles2_pixel_format formats[] = { // TODO: more pixel formats +/* + * Return true if supported for texturing, even if other operations like + * reading aren't supported. + */ bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, const struct wlr_gles2_pixel_format *format) { if (format->gl_type == GL_UNSIGNED_INT_2_10_10_10_REV_EXT @@ -108,10 +112,12 @@ bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, && !renderer->exts.OES_texture_half_float_linear) { return false; } - if (format->gl_format == GL_BGRA_EXT - && !renderer->exts.EXT_read_format_bgra) { - return false; - } + /* + * Note that we don't need to check for GL_EXT_texture_format_BGRA8888 + * here, since we've already checked if we have it at renderer creation + * time and bailed out if not. We do the check there because Wayland + * requires all compositors to support SHM buffers in that format. + */ return true; } diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 527d85bfa..67b8ead47 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -441,6 +441,12 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return false; } + if (fmt->gl_format == GL_BGRA_EXT && !renderer->exts.EXT_read_format_bgra) { + wlr_log(WLR_ERROR, + "Cannot read pixels: missing GL_EXT_read_format_bgra extension"); + return false; + } + const struct wlr_pixel_format_info *drm_fmt = drm_get_pixel_format_info(fmt->drm_format); assert(drm_fmt); From 83ab5055fd36bd0f8a0106257e45d8ed303636d8 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 1 Jan 2022 14:04:53 +0300 Subject: [PATCH 122/190] scene/subsurface_tree: fix handling subsurface destruction This commit renames map/unmap listeners to clarify that they handle subsurface events, and ensures the node is always destroyed before the subsurface. Without this patch, wl_list_remove() would operate on listener links in already freed memory. glibc is usually lenient to bugs like this, but musl isn't. --- types/scene/subsurface_tree.c | 65 +++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/types/scene/subsurface_tree.c b/types/scene/subsurface_tree.c index 3f22ee3d6..bb3c7ff7a 100644 --- a/types/scene/subsurface_tree.c +++ b/types/scene/subsurface_tree.c @@ -13,15 +13,20 @@ struct wlr_scene_subsurface_tree { struct wlr_surface *surface; struct wlr_scene_surface *scene_surface; - struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface - struct wlr_addon surface_addon; // only set if there's a parent - struct wl_listener tree_destroy; struct wl_listener surface_destroy; struct wl_listener surface_commit; - struct wl_listener surface_map; - struct wl_listener surface_unmap; struct wl_listener surface_new_subsurface; + + struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface + + // Only valid if the surface is a sub-surface + + struct wlr_addon surface_addon; + + struct wl_listener subsurface_destroy; + struct wl_listener subsurface_map; + struct wl_listener subsurface_unmap; }; static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, @@ -31,23 +36,17 @@ static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, // tree and scene_surface will be cleaned up by scene_node_finish if (subsurface_tree->parent) { wlr_addon_finish(&subsurface_tree->surface_addon); + wl_list_remove(&subsurface_tree->subsurface_destroy.link); + wl_list_remove(&subsurface_tree->subsurface_map.link); + wl_list_remove(&subsurface_tree->subsurface_unmap.link); } wl_list_remove(&subsurface_tree->tree_destroy.link); wl_list_remove(&subsurface_tree->surface_destroy.link); wl_list_remove(&subsurface_tree->surface_commit.link); - wl_list_remove(&subsurface_tree->surface_map.link); - wl_list_remove(&subsurface_tree->surface_unmap.link); wl_list_remove(&subsurface_tree->surface_new_subsurface.link); free(subsurface_tree); } -static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_destroy); - wlr_scene_node_destroy(&subsurface_tree->tree->node); -} - static const struct wlr_addon_interface subsurface_tree_addon_impl; static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( @@ -97,6 +96,13 @@ static void subsurface_tree_reconfigure( } } +static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = @@ -106,18 +112,25 @@ static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, subsurface_tree_reconfigure(subsurface_tree); } -static void subsurface_tree_handle_surface_map(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_map); + wl_container_of(listener, subsurface_tree, subsurface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + +static void subsurface_tree_handle_subsurface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, subsurface_map); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true); } -static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_unmap(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_unmap); + wl_container_of(listener, subsurface_tree, subsurface_unmap); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false); } @@ -151,8 +164,14 @@ static bool subsurface_tree_create_subsurface( wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, parent, &subsurface_tree_addon_impl); - wl_signal_add(&subsurface->events.map, &child->surface_map); - wl_signal_add(&subsurface->events.unmap, &child->surface_unmap); + child->subsurface_destroy.notify = subsurface_tree_handle_subsurface_destroy; + wl_signal_add(&subsurface->events.destroy, &child->subsurface_destroy); + + child->subsurface_map.notify = subsurface_tree_handle_subsurface_map; + wl_signal_add(&subsurface->events.map, &child->subsurface_map); + + child->subsurface_unmap.notify = subsurface_tree_handle_subsurface_unmap; + wl_signal_add(&subsurface->events.unmap, &child->subsurface_unmap); return true; } @@ -214,12 +233,6 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); - subsurface_tree->surface_map.notify = subsurface_tree_handle_surface_map; - wl_list_init(&subsurface_tree->surface_map.link); - - subsurface_tree->surface_unmap.notify = subsurface_tree_handle_surface_unmap; - wl_list_init(&subsurface_tree->surface_unmap.link); - subsurface_tree->surface_new_subsurface.notify = subsurface_tree_handle_surface_new_subsurface; wl_signal_add(&surface->events.new_subsurface, From 6cdf843a8cef420255e0a55c842530184abb3fe4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 9 Jan 2022 12:01:58 +0100 Subject: [PATCH 123/190] readme: drop mention of the Sway project wlroots has historically been started as a Sway project, but these days many wlroots contributors are working on other compositors. wlroots now also has its own namespace on gitlab.freedesktop.org. Let's remove the mention about Sway in the README, to make it clearer that Sway isn't treated in a special manner when it comes to wlroots development. --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2f9adf71e..418aab94b 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,8 @@ to implement yourself. Check out our [wiki] to get started with wlroots. Join our IRC channel: [#sway-devel on Libera Chat]. -wlroots is developed under the direction of the [sway] project. A variety of -[wrapper libraries] are available for using it with your favorite programming -language. +A variety of [wrapper libraries] are available for using it with your favorite +programming language. ## Building @@ -77,7 +76,6 @@ See [CONTRIBUTING.md]. [Wayland]: https://wayland.freedesktop.org/ [wiki]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Getting-started [#sway-devel on Libera Chat]: https://web.libera.chat/gamja/?channels=#sway-devel -[Sway]: https://github.com/swaywm/sway [wrapper libraries]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Projects-which-use-wlroots#wrapper-libraries [libseat]: https://git.sr.ht/~kennylevinsen/seatd [CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md From b6f43ab2e16931c5604b7e570edf481b3392fd25 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: [PATCH 124/190] subcompositor: split out from compositor --- include/wlr/types/wlr_compositor.h | 15 ---- include/wlr/types/wlr_subcompositor.h | 37 ++++++++ tinywl/tinywl.c | 5 +- types/meson.build | 1 + types/wlr_compositor.c | 112 ++---------------------- types/wlr_subcompositor.c | 120 ++++++++++++++++++++++++++ types/wlr_surface.c | 1 + 7 files changed, 168 insertions(+), 123 deletions(-) create mode 100644 include/wlr/types/wlr_subcompositor.h create mode 100644 types/wlr_subcompositor.c diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 04391c741..756f6f30d 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -14,16 +14,10 @@ struct wlr_surface; -struct wlr_subcompositor { - struct wl_global *global; -}; - struct wlr_compositor { struct wl_global *global; struct wlr_renderer *renderer; - struct wlr_subcompositor subcompositor; - struct wl_listener display_destroy; struct { @@ -35,13 +29,4 @@ struct wlr_compositor { struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_renderer *renderer); -bool wlr_surface_is_subsurface(struct wlr_surface *surface); - -/** - * Get a subsurface from a surface. Can return NULL if the subsurface has been - * destroyed. - */ -struct wlr_subsurface *wlr_subsurface_from_wlr_surface( - struct wlr_surface *surface); - #endif diff --git a/include/wlr/types/wlr_subcompositor.h b/include/wlr/types/wlr_subcompositor.h new file mode 100644 index 000000000..f9c887bb7 --- /dev/null +++ b/include/wlr/types/wlr_subcompositor.h @@ -0,0 +1,37 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_SUBCOMPOSITOR_H +#define WLR_TYPES_WLR_SUBCOMPOSITOR_H + +#include + +struct wlr_surface; + +struct wlr_subcompositor { + struct wl_global *global; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +bool wlr_surface_is_subsurface(struct wlr_surface *surface); + +/** + * Get a subsurface from a surface. Can return NULL if the subsurface has been + * destroyed. + */ +struct wlr_subsurface *wlr_subsurface_from_wlr_surface( + struct wlr_surface *surface); + +struct wlr_subcompositor *wlr_subcompositor_create(struct wl_display *display); + +#endif diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index faa0a9a13..722abd10c 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -756,12 +757,14 @@ int main(int argc, char *argv[]) { server.renderer); /* This creates some hands-off wlroots interfaces. The compositor is - * necessary for clients to allocate surfaces and the data device manager + * necessary for clients to allocate surfaces, the subcompositor allows to + * assign the role of subsurfaces to surfaces and the data device manager * handles the clipboard. Each of these wlroots interfaces has room for you * to dig your fingers in and play with their behavior if you want. Note that * the clients cannot set the selection directly without compositor approval, * see the handling of the request_set_selection event below.*/ wlr_compositor_create(server.wl_display, server.renderer); + wlr_subcompositor_create(server.wl_display); wlr_data_device_manager_create(server.wl_display); /* Creates an output layout, which a wlroots utility for working with an diff --git a/types/meson.build b/types/meson.build index 1694ac94a..8aa93a4ac 100644 --- a/types/meson.build +++ b/types/meson.build @@ -58,6 +58,7 @@ wlr_files += files( 'wlr_relative_pointer_v1.c', 'wlr_screencopy_v1.c', 'wlr_server_decoration.c', + 'wlr_subcompositor.c', 'wlr_surface.c', 'wlr_switch.c', 'wlr_tablet_pad.c', diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 7ad684543..65549627d 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -3,108 +3,11 @@ #include #include #include -#include #include "types/wlr_region.h" #include "types/wlr_surface.h" #include "util/signal.h" #define COMPOSITOR_VERSION 4 -#define SUBCOMPOSITOR_VERSION 1 - -extern const struct wlr_surface_role subsurface_role; - -bool wlr_surface_is_subsurface(struct wlr_surface *surface) { - return surface->role == &subsurface_role; -} - -struct wlr_subsurface *wlr_subsurface_from_wlr_surface( - struct wlr_surface *surface) { - assert(wlr_surface_is_subsurface(surface)); - return (struct wlr_subsurface *)surface->role_data; -} - -static void subcompositor_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void subcompositor_handle_get_subsurface(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *surface_resource, - struct wl_resource *parent_resource) { - struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); - struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); - - static const char msg[] = "get_subsurface: wl_subsurface@"; - - if (surface == parent) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%" PRIu32 ": wl_surface@%" PRIu32 " cannot be its own parent", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (wlr_surface_is_subsurface(surface) && - wlr_subsurface_from_wlr_surface(surface) != NULL) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%" PRIu32 ": wl_surface@%" PRIu32 " is already a sub-surface", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (wlr_surface_get_root_surface(parent) == surface) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%" PRIu32 ": wl_surface@%" PRIu32 " is an ancestor of parent", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (!wlr_surface_set_role(surface, &subsurface_role, NULL, - resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE)) { - return; - } - - subsurface_create(surface, parent, wl_resource_get_version(resource), id); -} - -static const struct wl_subcompositor_interface subcompositor_impl = { - .destroy = subcompositor_handle_destroy, - .get_subsurface = subcompositor_handle_get_subsurface, -}; - -static void subcompositor_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - struct wlr_subcompositor *subcompositor = data; - struct wl_resource *resource = - wl_resource_create(client, &wl_subcompositor_interface, 1, id); - if (resource == NULL) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &subcompositor_impl, - subcompositor, NULL); -} - -static bool subcompositor_init(struct wlr_subcompositor *subcompositor, - struct wl_display *display) { - subcompositor->global = wl_global_create(display, - &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, subcompositor, - subcompositor_bind); - if (subcompositor->global == NULL) { - wlr_log_errno(WLR_ERROR, "Could not allocate subcompositor global"); - return false; - } - - return true; -} - -static void subcompositor_finish(struct wlr_subcompositor *subcompositor) { - wl_global_destroy(subcompositor->global); -} - static const struct wl_compositor_interface compositor_impl; @@ -152,11 +55,11 @@ static void compositor_bind(struct wl_client *wl_client, void *data, wl_resource_set_implementation(resource, &compositor_impl, compositor, NULL); } -static void handle_display_destroy(struct wl_listener *listener, void *data) { +static void compositor_handle_display_destroy( + struct wl_listener *listener, void *data) { struct wlr_compositor *compositor = wl_container_of(listener, compositor, display_destroy); - wlr_signal_emit_safe(&compositor->events.destroy, compositor); - subcompositor_finish(&compositor->subcompositor); + wlr_signal_emit_safe(&compositor->events.destroy, NULL); wl_list_remove(&compositor->display_destroy.link); wl_global_destroy(compositor->global); free(compositor); @@ -164,10 +67,8 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_renderer *renderer) { - struct wlr_compositor *compositor = - calloc(1, sizeof(struct wlr_compositor)); + struct wlr_compositor *compositor = calloc(1, sizeof(*compositor)); if (!compositor) { - wlr_log_errno(WLR_ERROR, "Could not allocate wlr compositor"); return NULL; } @@ -175,7 +76,6 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, COMPOSITOR_VERSION, compositor, compositor_bind); if (!compositor->global) { free(compositor); - wlr_log_errno(WLR_ERROR, "Could not allocate compositor global"); return NULL; } compositor->renderer = renderer; @@ -183,9 +83,7 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, wl_signal_init(&compositor->events.new_surface); wl_signal_init(&compositor->events.destroy); - subcompositor_init(&compositor->subcompositor, display); - - compositor->display_destroy.notify = handle_display_destroy; + compositor->display_destroy.notify = compositor_handle_display_destroy; wl_display_add_destroy_listener(display, &compositor->display_destroy); return compositor; diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c new file mode 100644 index 000000000..f5a624865 --- /dev/null +++ b/types/wlr_subcompositor.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include "types/wlr_region.h" +#include "types/wlr_surface.h" +#include "util/signal.h" + +#define SUBCOMPOSITOR_VERSION 1 + +extern const struct wlr_surface_role subsurface_role; + +bool wlr_surface_is_subsurface(struct wlr_surface *surface) { + return surface->role == &subsurface_role; +} + +struct wlr_subsurface *wlr_subsurface_from_wlr_surface( + struct wlr_surface *surface) { + assert(wlr_surface_is_subsurface(surface)); + return (struct wlr_subsurface *)surface->role_data; +} + +static void subcompositor_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void subcompositor_handle_get_subsurface(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource) { + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); + + static const char msg[] = "get_subsurface: wl_subsurface@"; + + if (surface == parent) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%" PRIu32 ": wl_surface@%" PRIu32 " cannot be its own parent", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (wlr_surface_is_subsurface(surface) && + wlr_subsurface_from_wlr_surface(surface) != NULL) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is already a sub-surface", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (wlr_surface_get_root_surface(parent) == surface) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is an ancestor of parent", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (!wlr_surface_set_role(surface, &subsurface_role, NULL, + resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE)) { + return; + } + + subsurface_create(surface, parent, wl_resource_get_version(resource), id); +} + +static const struct wl_subcompositor_interface subcompositor_impl = { + .destroy = subcompositor_handle_destroy, + .get_subsurface = subcompositor_handle_get_subsurface, +}; + +static void subcompositor_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_subcompositor *subcompositor = data; + struct wl_resource *resource = + wl_resource_create(client, &wl_subcompositor_interface, 1, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &subcompositor_impl, + subcompositor, NULL); +} + +static void subcompositor_handle_display_destroy( + struct wl_listener *listener, void *data) { + struct wlr_subcompositor *subcompositor = + wl_container_of(listener, subcompositor, display_destroy); + wlr_signal_emit_safe(&subcompositor->events.destroy, NULL); + wl_list_remove(&subcompositor->display_destroy.link); + wl_global_destroy(subcompositor->global); + free(subcompositor); +} + +struct wlr_subcompositor *wlr_subcompositor_create(struct wl_display *display) { + struct wlr_subcompositor *subcompositor = + calloc(1, sizeof(*subcompositor)); + if (!subcompositor) { + return NULL; + } + + subcompositor->global = wl_global_create(display, + &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, + subcompositor, subcompositor_bind); + if (!subcompositor->global) { + free(subcompositor); + return NULL; + } + + wl_signal_init(&subcompositor->events.destroy); + + subcompositor->display_destroy.notify = subcompositor_handle_display_destroy; + wl_display_add_destroy_listener(display, &subcompositor->display_destroy); + + return subcompositor; +} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index d5d495714..fc4a509c3 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include From 4ec683ad1c62fe47e0a3bc238446ae8e79f08246 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: [PATCH 125/190] surface: introduce events.client_commit wlr_surface.events.client_commit is fired when wl_surface.commit request is received. --- include/wlr/types/wlr_surface.h | 2 ++ types/wlr_surface.c | 46 ++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 59168eaa3..ca1a55ac0 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -140,6 +140,7 @@ struct wlr_surface { void *role_data; // role-specific data struct { + struct wl_signal client_commit; struct wl_signal commit; struct wl_signal new_subsurface; struct wl_signal destroy; @@ -188,6 +189,7 @@ struct wlr_subsurface { bool added; struct wl_listener surface_destroy; + struct wl_listener surface_client_commit; struct wl_listener parent_destroy; struct { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index fc4a509c3..1b49a21b8 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -520,32 +520,13 @@ static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { } } -static void subsurface_commit(struct wlr_subsurface *subsurface) { - struct wlr_surface *surface = subsurface->surface; - - if (subsurface_is_synchronized(subsurface)) { - if (subsurface->has_cache) { - // We already lock a previous commit. The prevents any future - // commit to be applied before we release the previous commit. - return; - } - subsurface->has_cache = true; - subsurface->cached_seq = wlr_surface_lock_pending(surface); - } -} - static void surface_handle_commit(struct wl_client *client, struct wl_resource *resource) { struct wlr_surface *surface = wlr_surface_from_resource(resource); - - struct wlr_subsurface *subsurface = wlr_surface_is_subsurface(surface) ? - wlr_subsurface_from_wlr_surface(surface) : NULL; - if (subsurface != NULL) { - subsurface_commit(subsurface); - } - surface_finalize_pending(surface); + wlr_signal_emit_safe(&surface->events.client_commit, NULL); + if (surface->role && surface->role->precommit) { surface->role->precommit(surface); } @@ -668,6 +649,7 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); wl_list_remove(&subsurface->surface_destroy.link); + wl_list_remove(&subsurface->surface_client_commit.link); if (subsurface->parent) { wl_list_remove(&subsurface->current.link); @@ -747,6 +729,7 @@ struct wlr_surface *surface_create(struct wl_client *client, surface_state_init(&surface->pending); surface->pending.seq = 1; + wl_signal_init(&surface->events.client_commit); wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.new_subsurface); @@ -1108,6 +1091,23 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener, subsurface_destroy(subsurface); } +static void subsurface_handle_surface_client_commit( + struct wl_listener *listener, void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, surface_client_commit); + struct wlr_surface *surface = subsurface->surface; + + if (subsurface_is_synchronized(subsurface)) { + if (subsurface->has_cache) { + // We already lock a previous commit. The prevents any future + // commit to be applied before we release the previous commit. + return; + } + subsurface->has_cache = true; + subsurface->cached_seq = wlr_surface_lock_pending(surface); + } +} + struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, struct wlr_surface *parent, uint32_t version, uint32_t id) { struct wl_client *client = wl_resource_get_client(surface->resource); @@ -1136,6 +1136,10 @@ struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy); subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; + wl_signal_add(&surface->events.client_commit, + &subsurface->surface_client_commit); + subsurface->surface_client_commit.notify = + subsurface_handle_surface_client_commit; // link parent subsurface->parent = parent; From 36b5d5888cc48c40857b6d9275917cd57d0dfa0c Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: [PATCH 126/190] surface: move impl to types/wlr_{sub,}compositor.c --- include/types/wlr_surface.h | 20 - types/meson.build | 1 - types/wlr_compositor.c | 1061 +++++++++++++++++++++++++- types/wlr_subcompositor.c | 375 ++++++++- types/wlr_surface.c | 1442 ----------------------------------- 5 files changed, 1433 insertions(+), 1466 deletions(-) delete mode 100644 include/types/wlr_surface.h delete mode 100644 types/wlr_surface.c diff --git a/include/types/wlr_surface.h b/include/types/wlr_surface.h deleted file mode 100644 index b8c7d02d2..000000000 --- a/include/types/wlr_surface.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TYPES_WLR_SURFACE_H -#define TYPES_WLR_SURFACE_H - -#include - -struct wlr_renderer; - -/** - * Create a new surface resource with the provided new ID. - */ -struct wlr_surface *surface_create(struct wl_client *client, - uint32_t version, uint32_t id, struct wlr_renderer *renderer); - -/** - * Create a new subsurface resource with the provided new ID. - */ -struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, - struct wlr_surface *parent, uint32_t version, uint32_t id); - -#endif diff --git a/types/meson.build b/types/meson.build index 8aa93a4ac..476bffe82 100644 --- a/types/meson.build +++ b/types/meson.build @@ -59,7 +59,6 @@ wlr_files += files( 'wlr_screencopy_v1.c', 'wlr_server_decoration.c', 'wlr_subcompositor.c', - 'wlr_surface.c', 'wlr_switch.c', 'wlr_tablet_pad.c', 'wlr_tablet_tool.c', diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 65549627d..4b4b34f99 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -1,13 +1,1072 @@ #include #include #include +#include +#include #include +#include +#include +#include #include +#include +#include +#include #include "types/wlr_region.h" -#include "types/wlr_surface.h" #include "util/signal.h" +#include "util/time.h" #define COMPOSITOR_VERSION 4 +#define CALLBACK_VERSION 1 + +static int min(int fst, int snd) { + if (fst < snd) { + return fst; + } else { + return snd; + } +} + +static int max(int fst, int snd) { + if (fst > snd) { + return fst; + } else { + return snd; + } +} + +static void surface_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void surface_handle_attach(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer_resource, int32_t dx, int32_t dy) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + + struct wlr_buffer *buffer = NULL; + if (buffer_resource != NULL) { + buffer = wlr_buffer_from_resource(buffer_resource); + if (buffer == NULL) { + wl_resource_post_error(buffer_resource, 0, "unknown buffer type"); + return; + } + } + + surface->pending.committed |= WLR_SURFACE_STATE_BUFFER; + surface->pending.dx = dx; + surface->pending.dy = dy; + + wlr_buffer_unlock(surface->pending.buffer); + surface->pending.buffer = buffer; +} + +static void surface_handle_damage(struct wl_client *client, + struct wl_resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + if (width < 0 || height < 0) { + return; + } + surface->pending.committed |= WLR_SURFACE_STATE_SURFACE_DAMAGE; + pixman_region32_union_rect(&surface->pending.surface_damage, + &surface->pending.surface_damage, + x, y, width, height); +} + +static void callback_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void surface_handle_frame(struct wl_client *client, + struct wl_resource *resource, uint32_t callback) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + + struct wl_resource *callback_resource = wl_resource_create(client, + &wl_callback_interface, CALLBACK_VERSION, callback); + if (callback_resource == NULL) { + wl_resource_post_no_memory(resource); + return; + } + wl_resource_set_implementation(callback_resource, NULL, NULL, + callback_handle_resource_destroy); + + wl_list_insert(surface->pending.frame_callback_list.prev, + wl_resource_get_link(callback_resource)); + + surface->pending.committed |= WLR_SURFACE_STATE_FRAME_CALLBACK_LIST; +} + +static void surface_handle_set_opaque_region(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *region_resource) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + surface->pending.committed |= WLR_SURFACE_STATE_OPAQUE_REGION; + if (region_resource) { + pixman_region32_t *region = wlr_region_from_resource(region_resource); + pixman_region32_copy(&surface->pending.opaque, region); + } else { + pixman_region32_clear(&surface->pending.opaque); + } +} + +static void surface_handle_set_input_region(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *region_resource) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + surface->pending.committed |= WLR_SURFACE_STATE_INPUT_REGION; + if (region_resource) { + pixman_region32_t *region = wlr_region_from_resource(region_resource); + pixman_region32_copy(&surface->pending.input, region); + } else { + pixman_region32_fini(&surface->pending.input); + pixman_region32_init_rect(&surface->pending.input, + INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); + } +} + +static void surface_state_transformed_buffer_size(struct wlr_surface_state *state, + int *out_width, int *out_height) { + int width = state->buffer_width; + int height = state->buffer_height; + if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) { + int tmp = width; + width = height; + height = tmp; + } + *out_width = width; + *out_height = height; +} + +/** + * Computes the surface viewport source size, ie. the size after applying the + * surface's scale, transform and cropping (via the viewport's source + * rectangle) but before applying the viewport scaling (via the viewport's + * destination rectangle). + */ +static void surface_state_viewport_src_size(struct wlr_surface_state *state, + int *out_width, int *out_height) { + if (state->buffer_width == 0 && state->buffer_height == 0) { + *out_width = *out_height = 0; + return; + } + + if (state->viewport.has_src) { + *out_width = state->viewport.src.width; + *out_height = state->viewport.src.height; + } else { + surface_state_transformed_buffer_size(state, + out_width, out_height); + *out_width /= state->scale; + *out_height /= state->scale; + } +} + +static void surface_finalize_pending(struct wlr_surface *surface) { + struct wlr_surface_state *pending = &surface->pending; + + if ((pending->committed & WLR_SURFACE_STATE_BUFFER)) { + if (pending->buffer != NULL) { + pending->buffer_width = pending->buffer->width; + pending->buffer_height = pending->buffer->height; + } else { + pending->buffer_width = pending->buffer_height = 0; + } + } + + if (!pending->viewport.has_src && + (pending->buffer_width % pending->scale != 0 || + pending->buffer_height % pending->scale != 0)) { + // TODO: send WL_SURFACE_ERROR_INVALID_SIZE error once this issue is + // resolved: + // https://gitlab.freedesktop.org/wayland/wayland/-/issues/194 + wlr_log(WLR_DEBUG, "Client bug: submitted a buffer whose size (%dx%d) " + "is not divisible by scale (%d)", pending->buffer_width, + pending->buffer_height, pending->scale); + } + + if (pending->viewport.has_dst) { + if (pending->buffer_width == 0 && pending->buffer_height == 0) { + pending->width = pending->height = 0; + } else { + pending->width = pending->viewport.dst_width; + pending->height = pending->viewport.dst_height; + } + } else { + surface_state_viewport_src_size(pending, &pending->width, &pending->height); + } + + pixman_region32_intersect_rect(&pending->surface_damage, + &pending->surface_damage, 0, 0, pending->width, pending->height); + + pixman_region32_intersect_rect(&pending->buffer_damage, + &pending->buffer_damage, 0, 0, pending->buffer_width, + pending->buffer_height); +} + +static void surface_update_damage(pixman_region32_t *buffer_damage, + struct wlr_surface_state *current, struct wlr_surface_state *pending) { + pixman_region32_clear(buffer_damage); + + if (pending->width != current->width || + pending->height != current->height) { + // Damage the whole buffer on resize + pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, + pending->buffer_width, pending->buffer_height); + } else { + // Copy over surface damage + buffer damage + pixman_region32_t surface_damage; + pixman_region32_init(&surface_damage); + + pixman_region32_copy(&surface_damage, &pending->surface_damage); + + if (pending->viewport.has_dst) { + int src_width, src_height; + surface_state_viewport_src_size(pending, &src_width, &src_height); + float scale_x = (float)pending->viewport.dst_width / src_width; + float scale_y = (float)pending->viewport.dst_height / src_height; + wlr_region_scale_xy(&surface_damage, &surface_damage, + 1.0 / scale_x, 1.0 / scale_y); + } + if (pending->viewport.has_src) { + // This is lossy: do a best-effort conversion + pixman_region32_translate(&surface_damage, + floor(pending->viewport.src.x), + floor(pending->viewport.src.y)); + } + + wlr_region_scale(&surface_damage, &surface_damage, pending->scale); + + int width, height; + surface_state_transformed_buffer_size(pending, &width, &height); + wlr_region_transform(&surface_damage, &surface_damage, + wlr_output_transform_invert(pending->transform), + width, height); + + pixman_region32_union(buffer_damage, + &pending->buffer_damage, &surface_damage); + + pixman_region32_fini(&surface_damage); + } +} + +/** + * Append pending state to current state and clear pending state. + */ +static void surface_state_move(struct wlr_surface_state *state, + struct wlr_surface_state *next) { + state->width = next->width; + state->height = next->height; + state->buffer_width = next->buffer_width; + state->buffer_height = next->buffer_height; + + if (next->committed & WLR_SURFACE_STATE_SCALE) { + state->scale = next->scale; + } + if (next->committed & WLR_SURFACE_STATE_TRANSFORM) { + state->transform = next->transform; + } + if (next->committed & WLR_SURFACE_STATE_BUFFER) { + state->dx = next->dx; + state->dy = next->dy; + next->dx = next->dy = 0; + + wlr_buffer_unlock(state->buffer); + state->buffer = NULL; + if (next->buffer) { + state->buffer = wlr_buffer_lock(next->buffer); + } + wlr_buffer_unlock(next->buffer); + next->buffer = NULL; + } else { + state->dx = state->dy = 0; + } + if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) { + pixman_region32_copy(&state->surface_damage, &next->surface_damage); + pixman_region32_clear(&next->surface_damage); + } else { + pixman_region32_clear(&state->surface_damage); + } + if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) { + pixman_region32_copy(&state->buffer_damage, &next->buffer_damage); + pixman_region32_clear(&next->buffer_damage); + } else { + pixman_region32_clear(&state->buffer_damage); + } + if (next->committed & WLR_SURFACE_STATE_OPAQUE_REGION) { + pixman_region32_copy(&state->opaque, &next->opaque); + } + if (next->committed & WLR_SURFACE_STATE_INPUT_REGION) { + pixman_region32_copy(&state->input, &next->input); + } + if (next->committed & WLR_SURFACE_STATE_VIEWPORT) { + memcpy(&state->viewport, &next->viewport, sizeof(state->viewport)); + } + if (next->committed & WLR_SURFACE_STATE_FRAME_CALLBACK_LIST) { + wl_list_insert_list(&state->frame_callback_list, + &next->frame_callback_list); + wl_list_init(&next->frame_callback_list); + } + + state->committed |= next->committed; + next->committed = 0; + + state->seq = next->seq; + + state->cached_state_locks = next->cached_state_locks; + next->cached_state_locks = 0; +} + +static void surface_apply_damage(struct wlr_surface *surface) { + if (surface->current.buffer == NULL) { + // NULL commit + if (surface->buffer != NULL) { + wlr_buffer_unlock(&surface->buffer->base); + } + surface->buffer = NULL; + return; + } + + if (surface->buffer != NULL) { + if (wlr_client_buffer_apply_damage(surface->buffer, + surface->current.buffer, &surface->buffer_damage)) { + wlr_buffer_unlock(surface->current.buffer); + surface->current.buffer = NULL; + return; + } + } + + struct wlr_client_buffer *buffer = wlr_client_buffer_create( + surface->current.buffer, surface->renderer); + + wlr_buffer_unlock(surface->current.buffer); + surface->current.buffer = NULL; + + if (buffer == NULL) { + wlr_log(WLR_ERROR, "Failed to upload buffer"); + return; + } + + if (surface->buffer != NULL) { + wlr_buffer_unlock(&surface->buffer->base); + } + surface->buffer = buffer; +} + +static void surface_update_opaque_region(struct wlr_surface *surface) { + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { + pixman_region32_clear(&surface->opaque_region); + return; + } + + if (wlr_texture_is_opaque(texture)) { + pixman_region32_init_rect(&surface->opaque_region, + 0, 0, surface->current.width, surface->current.height); + return; + } + + pixman_region32_intersect_rect(&surface->opaque_region, + &surface->current.opaque, + 0, 0, surface->current.width, surface->current.height); +} + +static void surface_update_input_region(struct wlr_surface *surface) { + pixman_region32_intersect_rect(&surface->input_region, + &surface->current.input, + 0, 0, surface->current.width, surface->current.height); +} + +static void surface_state_init(struct wlr_surface_state *state); + +static void subsurface_parent_commit(struct wlr_subsurface *subsurface); + +static void surface_cache_pending(struct wlr_surface *surface) { + struct wlr_surface_state *cached = calloc(1, sizeof(*cached)); + if (!cached) { + wl_resource_post_no_memory(surface->resource); + return; + } + + surface_state_init(cached); + surface_state_move(cached, &surface->pending); + + wl_list_insert(surface->cached.prev, &cached->cached_state_link); + + surface->pending.seq++; +} + +static void surface_commit_state(struct wlr_surface *surface, + struct wlr_surface_state *next) { + assert(next->cached_state_locks == 0); + + bool invalid_buffer = next->committed & WLR_SURFACE_STATE_BUFFER; + + surface->sx += next->dx; + surface->sy += next->dy; + surface_update_damage(&surface->buffer_damage, &surface->current, next); + + pixman_region32_clear(&surface->external_damage); + if (surface->current.width > next->width || + surface->current.height > next->height || + next->dx != 0 || next->dy != 0) { + pixman_region32_union_rect(&surface->external_damage, + &surface->external_damage, -next->dx, -next->dy, + surface->current.width, surface->current.height); + } + + surface->previous.scale = surface->current.scale; + surface->previous.transform = surface->current.transform; + surface->previous.width = surface->current.width; + surface->previous.height = surface->current.height; + surface->previous.buffer_width = surface->current.buffer_width; + surface->previous.buffer_height = surface->current.buffer_height; + + surface_state_move(&surface->current, next); + + if (invalid_buffer) { + surface_apply_damage(surface); + } + surface_update_opaque_region(surface); + surface_update_input_region(surface); + + // commit subsurface order + struct wlr_subsurface *subsurface; + wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_above, + pending.link) { + wl_list_remove(&subsurface->current.link); + wl_list_insert(&surface->current.subsurfaces_above, + &subsurface->current.link); + + subsurface_parent_commit(subsurface); + } + wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below, + pending.link) { + wl_list_remove(&subsurface->current.link); + wl_list_insert(&surface->current.subsurfaces_below, + &subsurface->current.link); + + subsurface_parent_commit(subsurface); + } + + // If we're committing the pending state, bump the pending sequence number + // here, to allow commit listeners to lock the new pending state. + if (next == &surface->pending) { + surface->pending.seq++; + } + + if (surface->role && surface->role->commit) { + surface->role->commit(surface); + } + + wlr_signal_emit_safe(&surface->events.commit, surface); +} + +static void collect_subsurface_damage_iter(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct wlr_subsurface *subsurface = data; + pixman_region32_t *damage = &subsurface->parent->external_damage; + pixman_region32_union_rect(damage, damage, + subsurface->current.x + sx, + subsurface->current.y + sy, + surface->current.width, surface->current.height); +} + +// TODO: untangle from wlr_surface +static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { + struct wlr_surface *surface = subsurface->surface; + + bool moved = subsurface->current.x != subsurface->pending.x || + subsurface->current.y != subsurface->pending.y; + if (subsurface->mapped && moved) { + wlr_surface_for_each_surface(surface, + collect_subsurface_damage_iter, subsurface); + } + + if (subsurface->synchronized && subsurface->has_cache) { + wlr_surface_unlock_cached(surface, subsurface->cached_seq); + subsurface->has_cache = false; + } + + subsurface->current.x = subsurface->pending.x; + subsurface->current.y = subsurface->pending.y; + if (subsurface->mapped && (moved || subsurface->reordered)) { + subsurface->reordered = false; + wlr_surface_for_each_surface(surface, + collect_subsurface_damage_iter, subsurface); + } + + if (!subsurface->added) { + subsurface->added = true; + wlr_signal_emit_safe(&subsurface->parent->events.new_subsurface, + subsurface); + } +} + +static void surface_handle_commit(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + surface_finalize_pending(surface); + + wlr_signal_emit_safe(&surface->events.client_commit, NULL); + + if (surface->role && surface->role->precommit) { + surface->role->precommit(surface); + } + + if (surface->pending.cached_state_locks > 0 || !wl_list_empty(&surface->cached)) { + surface_cache_pending(surface); + } else { + surface_commit_state(surface, &surface->pending); + } +} + +static void surface_handle_set_buffer_transform(struct wl_client *client, + struct wl_resource *resource, int32_t transform) { + if (transform < WL_OUTPUT_TRANSFORM_NORMAL || + transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM, + "Specified transform value (%d) is invalid", transform); + return; + } + struct wlr_surface *surface = wlr_surface_from_resource(resource); + surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM; + surface->pending.transform = transform; +} + +static void surface_handle_set_buffer_scale(struct wl_client *client, + struct wl_resource *resource, int32_t scale) { + if (scale <= 0) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE, + "Specified scale value (%d) is not positive", scale); + return; + } + struct wlr_surface *surface = wlr_surface_from_resource(resource); + surface->pending.committed |= WLR_SURFACE_STATE_SCALE; + surface->pending.scale = scale; +} + +static void surface_handle_damage_buffer(struct wl_client *client, + struct wl_resource *resource, + int32_t x, int32_t y, int32_t width, + int32_t height) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + if (width < 0 || height < 0) { + return; + } + surface->pending.committed |= WLR_SURFACE_STATE_BUFFER_DAMAGE; + pixman_region32_union_rect(&surface->pending.buffer_damage, + &surface->pending.buffer_damage, + x, y, width, height); +} + +static const struct wl_surface_interface surface_implementation = { + .destroy = surface_handle_destroy, + .attach = surface_handle_attach, + .damage = surface_handle_damage, + .frame = surface_handle_frame, + .set_opaque_region = surface_handle_set_opaque_region, + .set_input_region = surface_handle_set_input_region, + .commit = surface_handle_commit, + .set_buffer_transform = surface_handle_set_buffer_transform, + .set_buffer_scale = surface_handle_set_buffer_scale, + .damage_buffer = surface_handle_damage_buffer +}; + +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_surface_interface, + &surface_implementation)); + return wl_resource_get_user_data(resource); +} + +static void surface_state_init(struct wlr_surface_state *state) { + state->scale = 1; + state->transform = WL_OUTPUT_TRANSFORM_NORMAL; + + wl_list_init(&state->subsurfaces_above); + wl_list_init(&state->subsurfaces_below); + + wl_list_init(&state->frame_callback_list); + + pixman_region32_init(&state->surface_damage); + pixman_region32_init(&state->buffer_damage); + pixman_region32_init(&state->opaque); + pixman_region32_init_rect(&state->input, + INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); +} + +static void surface_state_finish(struct wlr_surface_state *state) { + wlr_buffer_unlock(state->buffer); + + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) { + wl_resource_destroy(resource); + } + + pixman_region32_fini(&state->surface_damage); + pixman_region32_fini(&state->buffer_damage); + pixman_region32_fini(&state->opaque); + pixman_region32_fini(&state->input); +} + +static void surface_state_destroy_cached(struct wlr_surface_state *state) { + surface_state_finish(state); + wl_list_remove(&state->cached_state_link); + free(state); +} + +static void surface_output_destroy(struct wlr_surface_output *surface_output); + +static void surface_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + + struct wlr_surface_output *surface_output, *surface_output_tmp; + wl_list_for_each_safe(surface_output, surface_output_tmp, + &surface->current_outputs, link) { + surface_output_destroy(surface_output); + } + + wlr_signal_emit_safe(&surface->events.destroy, surface); + + wlr_addon_set_finish(&surface->addons); + + struct wlr_surface_state *cached, *cached_tmp; + wl_list_for_each_safe(cached, cached_tmp, &surface->cached, cached_state_link) { + surface_state_destroy_cached(cached); + } + + wl_list_remove(&surface->renderer_destroy.link); + surface_state_finish(&surface->pending); + surface_state_finish(&surface->current); + pixman_region32_fini(&surface->buffer_damage); + pixman_region32_fini(&surface->external_damage); + pixman_region32_fini(&surface->opaque_region); + pixman_region32_fini(&surface->input_region); + if (surface->buffer != NULL) { + wlr_buffer_unlock(&surface->buffer->base); + } + free(surface); +} + +static void surface_handle_renderer_destroy(struct wl_listener *listener, + void *data) { + struct wlr_surface *surface = + wl_container_of(listener, surface, renderer_destroy); + wl_resource_destroy(surface->resource); +} + +static struct wlr_surface *surface_create(struct wl_client *client, + uint32_t version, uint32_t id, struct wlr_renderer *renderer) { + struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface)); + if (!surface) { + wl_client_post_no_memory(client); + return NULL; + } + surface->resource = wl_resource_create(client, &wl_surface_interface, + version, id); + if (surface->resource == NULL) { + free(surface); + wl_client_post_no_memory(client); + return NULL; + } + wl_resource_set_implementation(surface->resource, &surface_implementation, + surface, surface_handle_resource_destroy); + + wlr_log(WLR_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource); + + surface->renderer = renderer; + + surface_state_init(&surface->current); + surface_state_init(&surface->pending); + surface->pending.seq = 1; + + wl_signal_init(&surface->events.client_commit); + wl_signal_init(&surface->events.commit); + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.new_subsurface); + wl_list_init(&surface->current_outputs); + wl_list_init(&surface->cached); + pixman_region32_init(&surface->buffer_damage); + pixman_region32_init(&surface->external_damage); + pixman_region32_init(&surface->opaque_region); + pixman_region32_init(&surface->input_region); + wlr_addon_set_init(&surface->addons); + + wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy); + surface->renderer_destroy.notify = surface_handle_renderer_destroy; + + return surface; +} + +struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) { + if (surface->buffer == NULL) { + return NULL; + } + return surface->buffer->texture; +} + +bool wlr_surface_has_buffer(struct wlr_surface *surface) { + return wlr_surface_get_texture(surface) != NULL; +} + +bool wlr_surface_set_role(struct wlr_surface *surface, + const struct wlr_surface_role *role, void *role_data, + struct wl_resource *error_resource, uint32_t error_code) { + assert(role != NULL); + + if (surface->role != NULL && surface->role != role) { + if (error_resource != NULL) { + wl_resource_post_error(error_resource, error_code, + "Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n", + role->name, wl_resource_get_id(surface->resource), + surface->role->name); + } + return false; + } + if (surface->role_data != NULL && surface->role_data != role_data) { + wl_resource_post_error(error_resource, error_code, + "Cannot reassign role %s to wl_surface@%" PRIu32 "," + "role object still exists", role->name, + wl_resource_get_id(surface->resource)); + return false; + } + + surface->role = role; + surface->role_data = role_data; + return true; +} + +uint32_t wlr_surface_lock_pending(struct wlr_surface *surface) { + surface->pending.cached_state_locks++; + return surface->pending.seq; +} + +void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq) { + if (surface->pending.seq == seq) { + assert(surface->pending.cached_state_locks > 0); + surface->pending.cached_state_locks--; + return; + } + + bool found = false; + struct wlr_surface_state *cached; + wl_list_for_each(cached, &surface->cached, cached_state_link) { + if (cached->seq == seq) { + found = true; + break; + } + } + assert(found); + + assert(cached->cached_state_locks > 0); + cached->cached_state_locks--; + + if (cached->cached_state_locks != 0) { + return; + } + + if (cached->cached_state_link.prev != &surface->cached) { + // This isn't the first cached state. This means we're blocked on a + // previous cached state. + return; + } + + // TODO: consider merging all committed states together + struct wlr_surface_state *next, *tmp; + wl_list_for_each_safe(next, tmp, &surface->cached, cached_state_link) { + if (next->cached_state_locks > 0) { + break; + } + + surface_commit_state(surface, next); + surface_state_destroy_cached(next); + } +} + +struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { + while (wlr_surface_is_subsurface(surface)) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + break; + } + if (subsurface->parent == NULL) { + return NULL; + } + surface = subsurface->parent; + } + return surface; +} + +bool wlr_surface_point_accepts_input(struct wlr_surface *surface, + double sx, double sy) { + return sx >= 0 && sx < surface->current.width && + sy >= 0 && sy < surface->current.height && + pixman_region32_contains_point(&surface->current.input, floor(sx), floor(sy), NULL); +} + +struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, + double sx, double sy, double *sub_x, double *sub_y) { + struct wlr_subsurface *subsurface; + wl_list_for_each_reverse(subsurface, &surface->current.subsurfaces_above, + current.link) { + if (!subsurface->mapped) { + continue; + } + + double _sub_x = subsurface->current.x; + double _sub_y = subsurface->current.y; + struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, + sx - _sub_x, sy - _sub_y, sub_x, sub_y); + if (sub != NULL) { + return sub; + } + } + + if (wlr_surface_point_accepts_input(surface, sx, sy)) { + if (sub_x) { + *sub_x = sx; + } + if (sub_y) { + *sub_y = sy; + } + return surface; + } + + wl_list_for_each_reverse(subsurface, &surface->current.subsurfaces_below, + current.link) { + if (!subsurface->mapped) { + continue; + } + + double _sub_x = subsurface->current.x; + double _sub_y = subsurface->current.y; + struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, + sx - _sub_x, sy - _sub_y, sub_x, sub_y); + if (sub != NULL) { + return sub; + } + } + + return NULL; +} + +static void surface_output_destroy(struct wlr_surface_output *surface_output) { + wl_list_remove(&surface_output->bind.link); + wl_list_remove(&surface_output->destroy.link); + wl_list_remove(&surface_output->link); + + free(surface_output); +} + +static void surface_handle_output_bind(struct wl_listener *listener, + void *data) { + struct wlr_output_event_bind *evt = data; + struct wlr_surface_output *surface_output = + wl_container_of(listener, surface_output, bind); + struct wl_client *client = wl_resource_get_client( + surface_output->surface->resource); + if (client == wl_resource_get_client(evt->resource)) { + wl_surface_send_enter(surface_output->surface->resource, evt->resource); + } +} + +static void surface_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_surface_output *surface_output = + wl_container_of(listener, surface_output, destroy); + surface_output_destroy(surface_output); +} + +void wlr_surface_send_enter(struct wlr_surface *surface, + struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_surface_output *surface_output; + struct wl_resource *resource; + + wl_list_for_each(surface_output, &surface->current_outputs, link) { + if (surface_output->output == output) { + return; + } + } + + surface_output = calloc(1, sizeof(struct wlr_surface_output)); + if (surface_output == NULL) { + return; + } + surface_output->bind.notify = surface_handle_output_bind; + surface_output->destroy.notify = surface_handle_output_destroy; + + wl_signal_add(&output->events.bind, &surface_output->bind); + wl_signal_add(&output->events.destroy, &surface_output->destroy); + + surface_output->surface = surface; + surface_output->output = output; + wl_list_insert(&surface->current_outputs, &surface_output->link); + + wl_resource_for_each(resource, &output->resources) { + if (client == wl_resource_get_client(resource)) { + wl_surface_send_enter(surface->resource, resource); + } + } +} + +void wlr_surface_send_leave(struct wlr_surface *surface, + struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_surface_output *surface_output, *tmp; + struct wl_resource *resource; + + wl_list_for_each_safe(surface_output, tmp, + &surface->current_outputs, link) { + if (surface_output->output == output) { + surface_output_destroy(surface_output); + wl_resource_for_each(resource, &output->resources) { + if (client == wl_resource_get_client(resource)) { + wl_surface_send_leave(surface->resource, resource); + } + } + break; + } + } +} + +void wlr_surface_send_frame_done(struct wlr_surface *surface, + const struct timespec *when) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, + &surface->current.frame_callback_list) { + wl_callback_send_done(resource, timespec_to_msec(when)); + wl_resource_destroy(resource); + } +} + +static void surface_for_each_surface(struct wlr_surface *surface, int x, int y, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->current.subsurfaces_below, current.link) { + if (!subsurface->mapped) { + continue; + } + + struct wlr_subsurface_parent_state *state = &subsurface->current; + int sx = state->x; + int sy = state->y; + + surface_for_each_surface(subsurface->surface, x + sx, y + sy, + iterator, user_data); + } + + iterator(surface, x, y, user_data); + + wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) { + if (!subsurface->mapped) { + continue; + } + + struct wlr_subsurface_parent_state *state = &subsurface->current; + int sx = state->x; + int sy = state->y; + + surface_for_each_surface(subsurface->surface, x + sx, y + sy, + iterator, user_data); + } +} + +void wlr_surface_for_each_surface(struct wlr_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + surface_for_each_surface(surface, 0, 0, iterator, user_data); +} + +struct bound_acc { + int32_t min_x, min_y; + int32_t max_x, max_y; +}; + +static void handle_bounding_box_surface(struct wlr_surface *surface, + int x, int y, void *data) { + struct bound_acc *acc = data; + + acc->min_x = min(x, acc->min_x); + acc->min_y = min(y, acc->min_y); + + acc->max_x = max(x + surface->current.width, acc->max_x); + acc->max_y = max(y + surface->current.height, acc->max_y); +} + +void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) { + struct bound_acc acc = { + .min_x = 0, + .min_y = 0, + .max_x = surface->current.width, + .max_y = surface->current.height, + }; + + wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc); + + box->x = acc.min_x; + box->y = acc.min_y; + box->width = acc.max_x - acc.min_x; + box->height = acc.max_y - acc.min_y; +} + +static void crop_region(pixman_region32_t *dst, pixman_region32_t *src, + const struct wlr_box *box) { + pixman_region32_intersect_rect(dst, src, + box->x, box->y, box->width, box->height); + pixman_region32_translate(dst, -box->x, -box->y); +} + +void wlr_surface_get_effective_damage(struct wlr_surface *surface, + pixman_region32_t *damage) { + pixman_region32_clear(damage); + + // Transform and copy the buffer damage in terms of surface coordinates. + wlr_region_transform(damage, &surface->buffer_damage, + surface->current.transform, surface->current.buffer_width, + surface->current.buffer_height); + wlr_region_scale(damage, damage, 1.0 / (float)surface->current.scale); + + if (surface->current.viewport.has_src) { + struct wlr_box src_box = { + .x = floor(surface->current.viewport.src.x), + .y = floor(surface->current.viewport.src.y), + .width = ceil(surface->current.viewport.src.width), + .height = ceil(surface->current.viewport.src.height), + }; + crop_region(damage, damage, &src_box); + } + if (surface->current.viewport.has_dst) { + int src_width, src_height; + surface_state_viewport_src_size(&surface->current, + &src_width, &src_height); + float scale_x = (float)surface->current.viewport.dst_width / src_width; + float scale_y = (float)surface->current.viewport.dst_height / src_height; + wlr_region_scale_xy(damage, damage, scale_x, scale_y); + } + + pixman_region32_union(damage, damage, &surface->external_damage); +} + +void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, + struct wlr_fbox *box) { + box->x = box->y = 0; + box->width = surface->current.buffer_width; + box->height = surface->current.buffer_height; + + if (surface->current.viewport.has_src) { + box->x = surface->current.viewport.src.x * surface->current.scale; + box->y = surface->current.viewport.src.y * surface->current.scale; + box->width = surface->current.viewport.src.width * surface->current.scale; + box->height = surface->current.viewport.src.height * surface->current.scale; + + int width, height; + surface_state_transformed_buffer_size(&surface->current, &width, &height); + wlr_fbox_transform(box, box, + wlr_output_transform_invert(surface->current.transform), + width, height); + } +} static const struct wl_compositor_interface compositor_impl; diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index f5a624865..45d0349d2 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -4,12 +4,383 @@ #include #include #include "types/wlr_region.h" -#include "types/wlr_surface.h" #include "util/signal.h" #define SUBCOMPOSITOR_VERSION 1 -extern const struct wlr_surface_role subsurface_role; +static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { + while (subsurface != NULL) { + if (subsurface->synchronized) { + return true; + } + + if (!subsurface->parent) { + return false; + } + + if (!wlr_surface_is_subsurface(subsurface->parent)) { + break; + } + subsurface = wlr_subsurface_from_wlr_surface(subsurface->parent); + } + + return false; +} + +static void subsurface_unmap(struct wlr_subsurface *subsurface); + +static void subsurface_destroy(struct wlr_subsurface *subsurface) { + if (subsurface == NULL) { + return; + } + + if (subsurface->has_cache) { + wlr_surface_unlock_cached(subsurface->surface, + subsurface->cached_seq); + } + + subsurface_unmap(subsurface); + + wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); + + wl_list_remove(&subsurface->surface_destroy.link); + wl_list_remove(&subsurface->surface_client_commit.link); + + if (subsurface->parent) { + wl_list_remove(&subsurface->current.link); + wl_list_remove(&subsurface->pending.link); + wl_list_remove(&subsurface->parent_destroy.link); + } + + wl_resource_set_user_data(subsurface->resource, NULL); + if (subsurface->surface) { + subsurface->surface->role_data = NULL; + } + free(subsurface); +} + +static const struct wl_subsurface_interface subsurface_implementation; + +static struct wlr_subsurface *subsurface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_subsurface_interface, + &subsurface_implementation)); + return wl_resource_get_user_data(resource); +} + +static void subsurface_resource_destroy(struct wl_resource *resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + subsurface_destroy(subsurface); +} + +static void subsurface_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void subsurface_handle_set_position(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + subsurface->pending.x = x; + subsurface->pending.y = y; +} + +static struct wlr_subsurface *subsurface_find_sibling( + struct wlr_subsurface *subsurface, struct wlr_surface *surface) { + struct wlr_surface *parent = subsurface->parent; + + struct wlr_subsurface *sibling; + wl_list_for_each(sibling, &parent->pending.subsurfaces_below, pending.link) { + if (sibling->surface == surface && sibling != subsurface) { + return sibling; + } + } + wl_list_for_each(sibling, &parent->pending.subsurfaces_above, pending.link) { + if (sibling->surface == surface && sibling != subsurface) { + return sibling; + } + } + + return NULL; +} + +static void subsurface_handle_place_above(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *sibling_resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + struct wlr_surface *sibling_surface = + wlr_surface_from_resource(sibling_resource); + + struct wl_list *node; + if (sibling_surface == subsurface->parent) { + node = &subsurface->parent->pending.subsurfaces_above; + } else { + struct wlr_subsurface *sibling = + subsurface_find_sibling(subsurface, sibling_surface); + if (!sibling) { + wl_resource_post_error(subsurface->resource, + WL_SUBSURFACE_ERROR_BAD_SURFACE, + "%s: wl_surface@%" PRIu32 "is not a parent or sibling", + "place_above", wl_resource_get_id(sibling_resource)); + return; + } + node = &sibling->pending.link; + } + + wl_list_remove(&subsurface->pending.link); + wl_list_insert(node, &subsurface->pending.link); + + subsurface->reordered = true; +} + +static void subsurface_handle_place_below(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *sibling_resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + struct wlr_surface *sibling_surface = + wlr_surface_from_resource(sibling_resource); + + struct wl_list *node; + if (sibling_surface == subsurface->parent) { + node = &subsurface->parent->pending.subsurfaces_below; + } else { + struct wlr_subsurface *sibling = + subsurface_find_sibling(subsurface, sibling_surface); + if (!sibling) { + wl_resource_post_error(subsurface->resource, + WL_SUBSURFACE_ERROR_BAD_SURFACE, + "%s: wl_surface@%" PRIu32 " is not a parent or sibling", + "place_below", wl_resource_get_id(sibling_resource)); + return; + } + node = &sibling->pending.link; + } + + wl_list_remove(&subsurface->pending.link); + wl_list_insert(node->prev, &subsurface->pending.link); + + subsurface->reordered = true; +} + +static void subsurface_handle_set_sync(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + subsurface->synchronized = true; +} + +static void subsurface_handle_set_desync(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); + if (subsurface == NULL) { + return; + } + + if (subsurface->synchronized) { + subsurface->synchronized = false; + + if (!subsurface_is_synchronized(subsurface) && + subsurface->has_cache) { + wlr_surface_unlock_cached(subsurface->surface, + subsurface->cached_seq); + subsurface->has_cache = false; + } + } +} + +static const struct wl_subsurface_interface subsurface_implementation = { + .destroy = subsurface_handle_destroy, + .set_position = subsurface_handle_set_position, + .place_above = subsurface_handle_place_above, + .place_below = subsurface_handle_place_below, + .set_sync = subsurface_handle_set_sync, + .set_desync = subsurface_handle_set_desync, +}; + +/** + * Checks if this subsurface needs to be marked as mapped. This can happen if: + * - The subsurface has a buffer + * - Its parent is mapped + */ +static void subsurface_consider_map(struct wlr_subsurface *subsurface, + bool check_parent) { + if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) { + return; + } + + if (check_parent) { + if (subsurface->parent == NULL) { + return; + } + if (wlr_surface_is_subsurface(subsurface->parent)) { + struct wlr_subsurface *parent = + wlr_subsurface_from_wlr_surface(subsurface->parent); + if (parent == NULL || !parent->mapped) { + return; + } + } + } + + // Now we can map the subsurface + wlr_signal_emit_safe(&subsurface->events.map, subsurface); + subsurface->mapped = true; + + // Try mapping all children too + struct wlr_subsurface *child; + wl_list_for_each(child, &subsurface->surface->current.subsurfaces_below, + current.link) { + subsurface_consider_map(child, false); + } + wl_list_for_each(child, &subsurface->surface->current.subsurfaces_above, + current.link) { + subsurface_consider_map(child, false); + } +} + +static void subsurface_unmap(struct wlr_subsurface *subsurface) { + if (!subsurface->mapped) { + return; + } + + wlr_signal_emit_safe(&subsurface->events.unmap, subsurface); + subsurface->mapped = false; + + // Unmap all children + struct wlr_subsurface *child; + wl_list_for_each(child, &subsurface->surface->current.subsurfaces_below, + current.link) { + subsurface_unmap(child); + } + wl_list_for_each(child, &subsurface->surface->current.subsurfaces_above, + current.link) { + subsurface_unmap(child); + } +} + +static void subsurface_role_commit(struct wlr_surface *surface) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + return; + } + + subsurface_consider_map(subsurface, true); +} + +static void subsurface_role_precommit(struct wlr_surface *surface) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + return; + } + + if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + surface->pending.buffer == NULL) { + // This is a NULL commit + subsurface_unmap(subsurface); + } +} + +const struct wlr_surface_role subsurface_role = { + .name = "wl_subsurface", + .commit = subsurface_role_commit, + .precommit = subsurface_role_precommit, +}; + +static void subsurface_handle_parent_destroy(struct wl_listener *listener, + void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, parent_destroy); + subsurface_unmap(subsurface); + wl_list_remove(&subsurface->current.link); + wl_list_remove(&subsurface->pending.link); + wl_list_remove(&subsurface->parent_destroy.link); + subsurface->parent = NULL; +} + +static void subsurface_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, surface_destroy); + subsurface_destroy(subsurface); +} + +static void subsurface_handle_surface_client_commit( + struct wl_listener *listener, void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, surface_client_commit); + struct wlr_surface *surface = subsurface->surface; + + if (subsurface_is_synchronized(subsurface)) { + if (subsurface->has_cache) { + // We already lock a previous commit. The prevents any future + // commit to be applied before we release the previous commit. + return; + } + subsurface->has_cache = true; + subsurface->cached_seq = wlr_surface_lock_pending(surface); + } +} + +static struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, + struct wlr_surface *parent, uint32_t version, uint32_t id) { + struct wl_client *client = wl_resource_get_client(surface->resource); + + struct wlr_subsurface *subsurface = + calloc(1, sizeof(struct wlr_subsurface)); + if (!subsurface) { + wl_client_post_no_memory(client); + return NULL; + } + subsurface->synchronized = true; + subsurface->surface = surface; + subsurface->resource = + wl_resource_create(client, &wl_subsurface_interface, version, id); + if (subsurface->resource == NULL) { + free(subsurface); + wl_client_post_no_memory(client); + return NULL; + } + wl_resource_set_implementation(subsurface->resource, + &subsurface_implementation, subsurface, subsurface_resource_destroy); + + wl_signal_init(&subsurface->events.destroy); + wl_signal_init(&subsurface->events.map); + wl_signal_init(&subsurface->events.unmap); + + wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy); + subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; + wl_signal_add(&surface->events.client_commit, + &subsurface->surface_client_commit); + subsurface->surface_client_commit.notify = + subsurface_handle_surface_client_commit; + + // link parent + subsurface->parent = parent; + wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); + subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; + + wl_list_init(&subsurface->current.link); + wl_list_insert(parent->pending.subsurfaces_above.prev, + &subsurface->pending.link); + + surface->role_data = subsurface; + + return subsurface; +} bool wlr_surface_is_subsurface(struct wlr_surface *surface) { return surface->role == &subsurface_role; diff --git a/types/wlr_surface.c b/types/wlr_surface.c deleted file mode 100644 index 1b49a21b8..000000000 --- a/types/wlr_surface.c +++ /dev/null @@ -1,1442 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "types/wlr_surface.h" -#include "util/signal.h" -#include "util/time.h" - -#define CALLBACK_VERSION 1 - -static int min(int fst, int snd) { - if (fst < snd) { - return fst; - } else { - return snd; - } -} - -static int max(int fst, int snd) { - if (fst > snd) { - return fst; - } else { - return snd; - } -} - -static void surface_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void surface_handle_attach(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *buffer_resource, int32_t dx, int32_t dy) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - - struct wlr_buffer *buffer = NULL; - if (buffer_resource != NULL) { - buffer = wlr_buffer_from_resource(buffer_resource); - if (buffer == NULL) { - wl_resource_post_error(buffer_resource, 0, "unknown buffer type"); - return; - } - } - - surface->pending.committed |= WLR_SURFACE_STATE_BUFFER; - surface->pending.dx = dx; - surface->pending.dy = dy; - - wlr_buffer_unlock(surface->pending.buffer); - surface->pending.buffer = buffer; -} - -static void surface_handle_damage(struct wl_client *client, - struct wl_resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - if (width < 0 || height < 0) { - return; - } - surface->pending.committed |= WLR_SURFACE_STATE_SURFACE_DAMAGE; - pixman_region32_union_rect(&surface->pending.surface_damage, - &surface->pending.surface_damage, - x, y, width, height); -} - -static void callback_handle_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); -} - -static void surface_handle_frame(struct wl_client *client, - struct wl_resource *resource, uint32_t callback) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - - struct wl_resource *callback_resource = wl_resource_create(client, - &wl_callback_interface, CALLBACK_VERSION, callback); - if (callback_resource == NULL) { - wl_resource_post_no_memory(resource); - return; - } - wl_resource_set_implementation(callback_resource, NULL, NULL, - callback_handle_resource_destroy); - - wl_list_insert(surface->pending.frame_callback_list.prev, - wl_resource_get_link(callback_resource)); - - surface->pending.committed |= WLR_SURFACE_STATE_FRAME_CALLBACK_LIST; -} - -static void surface_handle_set_opaque_region(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *region_resource) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - surface->pending.committed |= WLR_SURFACE_STATE_OPAQUE_REGION; - if (region_resource) { - pixman_region32_t *region = wlr_region_from_resource(region_resource); - pixman_region32_copy(&surface->pending.opaque, region); - } else { - pixman_region32_clear(&surface->pending.opaque); - } -} - -static void surface_handle_set_input_region(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *region_resource) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - surface->pending.committed |= WLR_SURFACE_STATE_INPUT_REGION; - if (region_resource) { - pixman_region32_t *region = wlr_region_from_resource(region_resource); - pixman_region32_copy(&surface->pending.input, region); - } else { - pixman_region32_fini(&surface->pending.input); - pixman_region32_init_rect(&surface->pending.input, - INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); - } -} - -static void surface_state_transformed_buffer_size(struct wlr_surface_state *state, - int *out_width, int *out_height) { - int width = state->buffer_width; - int height = state->buffer_height; - if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int tmp = width; - width = height; - height = tmp; - } - *out_width = width; - *out_height = height; -} - -/** - * Computes the surface viewport source size, ie. the size after applying the - * surface's scale, transform and cropping (via the viewport's source - * rectangle) but before applying the viewport scaling (via the viewport's - * destination rectangle). - */ -static void surface_state_viewport_src_size(struct wlr_surface_state *state, - int *out_width, int *out_height) { - if (state->buffer_width == 0 && state->buffer_height == 0) { - *out_width = *out_height = 0; - return; - } - - if (state->viewport.has_src) { - *out_width = state->viewport.src.width; - *out_height = state->viewport.src.height; - } else { - surface_state_transformed_buffer_size(state, - out_width, out_height); - *out_width /= state->scale; - *out_height /= state->scale; - } -} - -static void surface_finalize_pending(struct wlr_surface *surface) { - struct wlr_surface_state *pending = &surface->pending; - - if ((pending->committed & WLR_SURFACE_STATE_BUFFER)) { - if (pending->buffer != NULL) { - pending->buffer_width = pending->buffer->width; - pending->buffer_height = pending->buffer->height; - } else { - pending->buffer_width = pending->buffer_height = 0; - } - } - - if (!pending->viewport.has_src && - (pending->buffer_width % pending->scale != 0 || - pending->buffer_height % pending->scale != 0)) { - // TODO: send WL_SURFACE_ERROR_INVALID_SIZE error once this issue is - // resolved: - // https://gitlab.freedesktop.org/wayland/wayland/-/issues/194 - wlr_log(WLR_DEBUG, "Client bug: submitted a buffer whose size (%dx%d) " - "is not divisible by scale (%d)", pending->buffer_width, - pending->buffer_height, pending->scale); - } - - if (pending->viewport.has_dst) { - if (pending->buffer_width == 0 && pending->buffer_height == 0) { - pending->width = pending->height = 0; - } else { - pending->width = pending->viewport.dst_width; - pending->height = pending->viewport.dst_height; - } - } else { - surface_state_viewport_src_size(pending, &pending->width, &pending->height); - } - - pixman_region32_intersect_rect(&pending->surface_damage, - &pending->surface_damage, 0, 0, pending->width, pending->height); - - pixman_region32_intersect_rect(&pending->buffer_damage, - &pending->buffer_damage, 0, 0, pending->buffer_width, - pending->buffer_height); -} - -static void surface_update_damage(pixman_region32_t *buffer_damage, - struct wlr_surface_state *current, struct wlr_surface_state *pending) { - pixman_region32_clear(buffer_damage); - - if (pending->width != current->width || - pending->height != current->height) { - // Damage the whole buffer on resize - pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, - pending->buffer_width, pending->buffer_height); - } else { - // Copy over surface damage + buffer damage - pixman_region32_t surface_damage; - pixman_region32_init(&surface_damage); - - pixman_region32_copy(&surface_damage, &pending->surface_damage); - - if (pending->viewport.has_dst) { - int src_width, src_height; - surface_state_viewport_src_size(pending, &src_width, &src_height); - float scale_x = (float)pending->viewport.dst_width / src_width; - float scale_y = (float)pending->viewport.dst_height / src_height; - wlr_region_scale_xy(&surface_damage, &surface_damage, - 1.0 / scale_x, 1.0 / scale_y); - } - if (pending->viewport.has_src) { - // This is lossy: do a best-effort conversion - pixman_region32_translate(&surface_damage, - floor(pending->viewport.src.x), - floor(pending->viewport.src.y)); - } - - wlr_region_scale(&surface_damage, &surface_damage, pending->scale); - - int width, height; - surface_state_transformed_buffer_size(pending, &width, &height); - wlr_region_transform(&surface_damage, &surface_damage, - wlr_output_transform_invert(pending->transform), - width, height); - - pixman_region32_union(buffer_damage, - &pending->buffer_damage, &surface_damage); - - pixman_region32_fini(&surface_damage); - } -} - -/** - * Append pending state to current state and clear pending state. - */ -static void surface_state_move(struct wlr_surface_state *state, - struct wlr_surface_state *next) { - state->width = next->width; - state->height = next->height; - state->buffer_width = next->buffer_width; - state->buffer_height = next->buffer_height; - - if (next->committed & WLR_SURFACE_STATE_SCALE) { - state->scale = next->scale; - } - if (next->committed & WLR_SURFACE_STATE_TRANSFORM) { - state->transform = next->transform; - } - if (next->committed & WLR_SURFACE_STATE_BUFFER) { - state->dx = next->dx; - state->dy = next->dy; - next->dx = next->dy = 0; - - wlr_buffer_unlock(state->buffer); - state->buffer = NULL; - if (next->buffer) { - state->buffer = wlr_buffer_lock(next->buffer); - } - wlr_buffer_unlock(next->buffer); - next->buffer = NULL; - } else { - state->dx = state->dy = 0; - } - if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) { - pixman_region32_copy(&state->surface_damage, &next->surface_damage); - pixman_region32_clear(&next->surface_damage); - } else { - pixman_region32_clear(&state->surface_damage); - } - if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) { - pixman_region32_copy(&state->buffer_damage, &next->buffer_damage); - pixman_region32_clear(&next->buffer_damage); - } else { - pixman_region32_clear(&state->buffer_damage); - } - if (next->committed & WLR_SURFACE_STATE_OPAQUE_REGION) { - pixman_region32_copy(&state->opaque, &next->opaque); - } - if (next->committed & WLR_SURFACE_STATE_INPUT_REGION) { - pixman_region32_copy(&state->input, &next->input); - } - if (next->committed & WLR_SURFACE_STATE_VIEWPORT) { - memcpy(&state->viewport, &next->viewport, sizeof(state->viewport)); - } - if (next->committed & WLR_SURFACE_STATE_FRAME_CALLBACK_LIST) { - wl_list_insert_list(&state->frame_callback_list, - &next->frame_callback_list); - wl_list_init(&next->frame_callback_list); - } - - state->committed |= next->committed; - next->committed = 0; - - state->seq = next->seq; - - state->cached_state_locks = next->cached_state_locks; - next->cached_state_locks = 0; -} - -static void surface_apply_damage(struct wlr_surface *surface) { - if (surface->current.buffer == NULL) { - // NULL commit - if (surface->buffer != NULL) { - wlr_buffer_unlock(&surface->buffer->base); - } - surface->buffer = NULL; - return; - } - - if (surface->buffer != NULL) { - if (wlr_client_buffer_apply_damage(surface->buffer, - surface->current.buffer, &surface->buffer_damage)) { - wlr_buffer_unlock(surface->current.buffer); - surface->current.buffer = NULL; - return; - } - } - - struct wlr_client_buffer *buffer = wlr_client_buffer_create( - surface->current.buffer, surface->renderer); - - wlr_buffer_unlock(surface->current.buffer); - surface->current.buffer = NULL; - - if (buffer == NULL) { - wlr_log(WLR_ERROR, "Failed to upload buffer"); - return; - } - - if (surface->buffer != NULL) { - wlr_buffer_unlock(&surface->buffer->base); - } - surface->buffer = buffer; -} - -static void surface_update_opaque_region(struct wlr_surface *surface) { - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - pixman_region32_clear(&surface->opaque_region); - return; - } - - if (wlr_texture_is_opaque(texture)) { - pixman_region32_init_rect(&surface->opaque_region, - 0, 0, surface->current.width, surface->current.height); - return; - } - - pixman_region32_intersect_rect(&surface->opaque_region, - &surface->current.opaque, - 0, 0, surface->current.width, surface->current.height); -} - -static void surface_update_input_region(struct wlr_surface *surface) { - pixman_region32_intersect_rect(&surface->input_region, - &surface->current.input, - 0, 0, surface->current.width, surface->current.height); -} - -static void surface_state_init(struct wlr_surface_state *state); - -static void subsurface_parent_commit(struct wlr_subsurface *subsurface); - -static void surface_cache_pending(struct wlr_surface *surface) { - struct wlr_surface_state *cached = calloc(1, sizeof(*cached)); - if (!cached) { - wl_resource_post_no_memory(surface->resource); - return; - } - - surface_state_init(cached); - surface_state_move(cached, &surface->pending); - - wl_list_insert(surface->cached.prev, &cached->cached_state_link); - - surface->pending.seq++; -} - -static void surface_commit_state(struct wlr_surface *surface, - struct wlr_surface_state *next) { - assert(next->cached_state_locks == 0); - - bool invalid_buffer = next->committed & WLR_SURFACE_STATE_BUFFER; - - surface->sx += next->dx; - surface->sy += next->dy; - surface_update_damage(&surface->buffer_damage, &surface->current, next); - - pixman_region32_clear(&surface->external_damage); - if (surface->current.width > next->width || - surface->current.height > next->height || - next->dx != 0 || next->dy != 0) { - pixman_region32_union_rect(&surface->external_damage, - &surface->external_damage, -next->dx, -next->dy, - surface->current.width, surface->current.height); - } - - surface->previous.scale = surface->current.scale; - surface->previous.transform = surface->current.transform; - surface->previous.width = surface->current.width; - surface->previous.height = surface->current.height; - surface->previous.buffer_width = surface->current.buffer_width; - surface->previous.buffer_height = surface->current.buffer_height; - - surface_state_move(&surface->current, next); - - if (invalid_buffer) { - surface_apply_damage(surface); - } - surface_update_opaque_region(surface); - surface_update_input_region(surface); - - // commit subsurface order - struct wlr_subsurface *subsurface; - wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_above, - pending.link) { - wl_list_remove(&subsurface->current.link); - wl_list_insert(&surface->current.subsurfaces_above, - &subsurface->current.link); - - subsurface_parent_commit(subsurface); - } - wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below, - pending.link) { - wl_list_remove(&subsurface->current.link); - wl_list_insert(&surface->current.subsurfaces_below, - &subsurface->current.link); - - subsurface_parent_commit(subsurface); - } - - // If we're committing the pending state, bump the pending sequence number - // here, to allow commit listeners to lock the new pending state. - if (next == &surface->pending) { - surface->pending.seq++; - } - - if (surface->role && surface->role->commit) { - surface->role->commit(surface); - } - - wlr_signal_emit_safe(&surface->events.commit, surface); -} - -static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { - while (subsurface != NULL) { - if (subsurface->synchronized) { - return true; - } - - if (!subsurface->parent) { - return false; - } - - if (!wlr_surface_is_subsurface(subsurface->parent)) { - break; - } - subsurface = wlr_subsurface_from_wlr_surface(subsurface->parent); - } - - return false; -} - -static void collect_subsurface_damage_iter(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct wlr_subsurface *subsurface = data; - pixman_region32_t *damage = &subsurface->parent->external_damage; - pixman_region32_union_rect(damage, damage, - subsurface->current.x + sx, - subsurface->current.y + sy, - surface->current.width, surface->current.height); -} - -static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { - struct wlr_surface *surface = subsurface->surface; - - bool moved = subsurface->current.x != subsurface->pending.x || - subsurface->current.y != subsurface->pending.y; - if (subsurface->mapped && moved) { - wlr_surface_for_each_surface(surface, - collect_subsurface_damage_iter, subsurface); - } - - if (subsurface->synchronized && subsurface->has_cache) { - wlr_surface_unlock_cached(surface, subsurface->cached_seq); - subsurface->has_cache = false; - } - - subsurface->current.x = subsurface->pending.x; - subsurface->current.y = subsurface->pending.y; - if (subsurface->mapped && (moved || subsurface->reordered)) { - subsurface->reordered = false; - wlr_surface_for_each_surface(surface, - collect_subsurface_damage_iter, subsurface); - } - - if (!subsurface->added) { - subsurface->added = true; - wlr_signal_emit_safe(&subsurface->parent->events.new_subsurface, - subsurface); - } -} - -static void surface_handle_commit(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - surface_finalize_pending(surface); - - wlr_signal_emit_safe(&surface->events.client_commit, NULL); - - if (surface->role && surface->role->precommit) { - surface->role->precommit(surface); - } - - if (surface->pending.cached_state_locks > 0 || !wl_list_empty(&surface->cached)) { - surface_cache_pending(surface); - } else { - surface_commit_state(surface, &surface->pending); - } -} - -static void surface_handle_set_buffer_transform(struct wl_client *client, - struct wl_resource *resource, int32_t transform) { - if (transform < WL_OUTPUT_TRANSFORM_NORMAL || - transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) { - wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM, - "Specified transform value (%d) is invalid", transform); - return; - } - struct wlr_surface *surface = wlr_surface_from_resource(resource); - surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM; - surface->pending.transform = transform; -} - -static void surface_handle_set_buffer_scale(struct wl_client *client, - struct wl_resource *resource, int32_t scale) { - if (scale <= 0) { - wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE, - "Specified scale value (%d) is not positive", scale); - return; - } - struct wlr_surface *surface = wlr_surface_from_resource(resource); - surface->pending.committed |= WLR_SURFACE_STATE_SCALE; - surface->pending.scale = scale; -} - -static void surface_handle_damage_buffer(struct wl_client *client, - struct wl_resource *resource, - int32_t x, int32_t y, int32_t width, - int32_t height) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - if (width < 0 || height < 0) { - return; - } - surface->pending.committed |= WLR_SURFACE_STATE_BUFFER_DAMAGE; - pixman_region32_union_rect(&surface->pending.buffer_damage, - &surface->pending.buffer_damage, - x, y, width, height); -} - -static const struct wl_surface_interface surface_implementation = { - .destroy = surface_handle_destroy, - .attach = surface_handle_attach, - .damage = surface_handle_damage, - .frame = surface_handle_frame, - .set_opaque_region = surface_handle_set_opaque_region, - .set_input_region = surface_handle_set_input_region, - .commit = surface_handle_commit, - .set_buffer_transform = surface_handle_set_buffer_transform, - .set_buffer_scale = surface_handle_set_buffer_scale, - .damage_buffer = surface_handle_damage_buffer -}; - -struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &wl_surface_interface, - &surface_implementation)); - return wl_resource_get_user_data(resource); -} - -static void surface_state_init(struct wlr_surface_state *state) { - state->scale = 1; - state->transform = WL_OUTPUT_TRANSFORM_NORMAL; - - wl_list_init(&state->subsurfaces_above); - wl_list_init(&state->subsurfaces_below); - - wl_list_init(&state->frame_callback_list); - - pixman_region32_init(&state->surface_damage); - pixman_region32_init(&state->buffer_damage); - pixman_region32_init(&state->opaque); - pixman_region32_init_rect(&state->input, - INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); -} - -static void surface_state_finish(struct wlr_surface_state *state) { - wlr_buffer_unlock(state->buffer); - - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) { - wl_resource_destroy(resource); - } - - pixman_region32_fini(&state->surface_damage); - pixman_region32_fini(&state->buffer_damage); - pixman_region32_fini(&state->opaque); - pixman_region32_fini(&state->input); -} - -static void surface_state_destroy_cached(struct wlr_surface_state *state) { - surface_state_finish(state); - wl_list_remove(&state->cached_state_link); - free(state); -} - -static void subsurface_unmap(struct wlr_subsurface *subsurface); - -static void subsurface_destroy(struct wlr_subsurface *subsurface) { - if (subsurface == NULL) { - return; - } - - if (subsurface->has_cache) { - wlr_surface_unlock_cached(subsurface->surface, - subsurface->cached_seq); - } - - subsurface_unmap(subsurface); - - wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); - - wl_list_remove(&subsurface->surface_destroy.link); - wl_list_remove(&subsurface->surface_client_commit.link); - - if (subsurface->parent) { - wl_list_remove(&subsurface->current.link); - wl_list_remove(&subsurface->pending.link); - wl_list_remove(&subsurface->parent_destroy.link); - } - - wl_resource_set_user_data(subsurface->resource, NULL); - if (subsurface->surface) { - subsurface->surface->role_data = NULL; - } - free(subsurface); -} - -static void surface_output_destroy(struct wlr_surface_output *surface_output); - -static void surface_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_surface *surface = wlr_surface_from_resource(resource); - - struct wlr_surface_output *surface_output, *surface_output_tmp; - wl_list_for_each_safe(surface_output, surface_output_tmp, - &surface->current_outputs, link) { - surface_output_destroy(surface_output); - } - - wlr_signal_emit_safe(&surface->events.destroy, surface); - - wlr_addon_set_finish(&surface->addons); - - struct wlr_surface_state *cached, *cached_tmp; - wl_list_for_each_safe(cached, cached_tmp, &surface->cached, cached_state_link) { - surface_state_destroy_cached(cached); - } - - wl_list_remove(&surface->renderer_destroy.link); - surface_state_finish(&surface->pending); - surface_state_finish(&surface->current); - pixman_region32_fini(&surface->buffer_damage); - pixman_region32_fini(&surface->external_damage); - pixman_region32_fini(&surface->opaque_region); - pixman_region32_fini(&surface->input_region); - if (surface->buffer != NULL) { - wlr_buffer_unlock(&surface->buffer->base); - } - free(surface); -} - -static void surface_handle_renderer_destroy(struct wl_listener *listener, - void *data) { - struct wlr_surface *surface = - wl_container_of(listener, surface, renderer_destroy); - wl_resource_destroy(surface->resource); -} - -struct wlr_surface *surface_create(struct wl_client *client, - uint32_t version, uint32_t id, struct wlr_renderer *renderer) { - struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface)); - if (!surface) { - wl_client_post_no_memory(client); - return NULL; - } - surface->resource = wl_resource_create(client, &wl_surface_interface, - version, id); - if (surface->resource == NULL) { - free(surface); - wl_client_post_no_memory(client); - return NULL; - } - wl_resource_set_implementation(surface->resource, &surface_implementation, - surface, surface_handle_resource_destroy); - - wlr_log(WLR_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource); - - surface->renderer = renderer; - - surface_state_init(&surface->current); - surface_state_init(&surface->pending); - surface->pending.seq = 1; - - wl_signal_init(&surface->events.client_commit); - wl_signal_init(&surface->events.commit); - wl_signal_init(&surface->events.destroy); - wl_signal_init(&surface->events.new_subsurface); - wl_list_init(&surface->current_outputs); - wl_list_init(&surface->cached); - pixman_region32_init(&surface->buffer_damage); - pixman_region32_init(&surface->external_damage); - pixman_region32_init(&surface->opaque_region); - pixman_region32_init(&surface->input_region); - wlr_addon_set_init(&surface->addons); - - wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy); - surface->renderer_destroy.notify = surface_handle_renderer_destroy; - - return surface; -} - -struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) { - if (surface->buffer == NULL) { - return NULL; - } - return surface->buffer->texture; -} - -bool wlr_surface_has_buffer(struct wlr_surface *surface) { - return wlr_surface_get_texture(surface) != NULL; -} - -bool wlr_surface_set_role(struct wlr_surface *surface, - const struct wlr_surface_role *role, void *role_data, - struct wl_resource *error_resource, uint32_t error_code) { - assert(role != NULL); - - if (surface->role != NULL && surface->role != role) { - if (error_resource != NULL) { - wl_resource_post_error(error_resource, error_code, - "Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n", - role->name, wl_resource_get_id(surface->resource), - surface->role->name); - } - return false; - } - if (surface->role_data != NULL && surface->role_data != role_data) { - wl_resource_post_error(error_resource, error_code, - "Cannot reassign role %s to wl_surface@%" PRIu32 "," - "role object still exists", role->name, - wl_resource_get_id(surface->resource)); - return false; - } - - surface->role = role; - surface->role_data = role_data; - return true; -} - -uint32_t wlr_surface_lock_pending(struct wlr_surface *surface) { - surface->pending.cached_state_locks++; - return surface->pending.seq; -} - -void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq) { - if (surface->pending.seq == seq) { - assert(surface->pending.cached_state_locks > 0); - surface->pending.cached_state_locks--; - return; - } - - bool found = false; - struct wlr_surface_state *cached; - wl_list_for_each(cached, &surface->cached, cached_state_link) { - if (cached->seq == seq) { - found = true; - break; - } - } - assert(found); - - assert(cached->cached_state_locks > 0); - cached->cached_state_locks--; - - if (cached->cached_state_locks != 0) { - return; - } - - if (cached->cached_state_link.prev != &surface->cached) { - // This isn't the first cached state. This means we're blocked on a - // previous cached state. - return; - } - - // TODO: consider merging all committed states together - struct wlr_surface_state *next, *tmp; - wl_list_for_each_safe(next, tmp, &surface->cached, cached_state_link) { - if (next->cached_state_locks > 0) { - break; - } - - surface_commit_state(surface, next); - surface_state_destroy_cached(next); - } -} - -static const struct wl_subsurface_interface subsurface_implementation; - -static struct wlr_subsurface *subsurface_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &wl_subsurface_interface, - &subsurface_implementation)); - return wl_resource_get_user_data(resource); -} - -static void subsurface_resource_destroy(struct wl_resource *resource) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - subsurface_destroy(subsurface); -} - -static void subsurface_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void subsurface_handle_set_position(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - if (subsurface == NULL) { - return; - } - - subsurface->pending.x = x; - subsurface->pending.y = y; -} - -static struct wlr_subsurface *subsurface_find_sibling( - struct wlr_subsurface *subsurface, struct wlr_surface *surface) { - struct wlr_surface *parent = subsurface->parent; - - struct wlr_subsurface *sibling; - wl_list_for_each(sibling, &parent->pending.subsurfaces_below, pending.link) { - if (sibling->surface == surface && sibling != subsurface) { - return sibling; - } - } - wl_list_for_each(sibling, &parent->pending.subsurfaces_above, pending.link) { - if (sibling->surface == surface && sibling != subsurface) { - return sibling; - } - } - - return NULL; -} - -static void subsurface_handle_place_above(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - if (subsurface == NULL) { - return; - } - - struct wlr_surface *sibling_surface = - wlr_surface_from_resource(sibling_resource); - - struct wl_list *node; - if (sibling_surface == subsurface->parent) { - node = &subsurface->parent->pending.subsurfaces_above; - } else { - struct wlr_subsurface *sibling = - subsurface_find_sibling(subsurface, sibling_surface); - if (!sibling) { - wl_resource_post_error(subsurface->resource, - WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%" PRIu32 "is not a parent or sibling", - "place_above", wl_resource_get_id(sibling_resource)); - return; - } - node = &sibling->pending.link; - } - - wl_list_remove(&subsurface->pending.link); - wl_list_insert(node, &subsurface->pending.link); - - subsurface->reordered = true; -} - -static void subsurface_handle_place_below(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - if (subsurface == NULL) { - return; - } - - struct wlr_surface *sibling_surface = - wlr_surface_from_resource(sibling_resource); - - struct wl_list *node; - if (sibling_surface == subsurface->parent) { - node = &subsurface->parent->pending.subsurfaces_below; - } else { - struct wlr_subsurface *sibling = - subsurface_find_sibling(subsurface, sibling_surface); - if (!sibling) { - wl_resource_post_error(subsurface->resource, - WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%" PRIu32 " is not a parent or sibling", - "place_below", wl_resource_get_id(sibling_resource)); - return; - } - node = &sibling->pending.link; - } - - wl_list_remove(&subsurface->pending.link); - wl_list_insert(node->prev, &subsurface->pending.link); - - subsurface->reordered = true; -} - -static void subsurface_handle_set_sync(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - if (subsurface == NULL) { - return; - } - - subsurface->synchronized = true; -} - -static void subsurface_handle_set_desync(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - if (subsurface == NULL) { - return; - } - - if (subsurface->synchronized) { - subsurface->synchronized = false; - - if (!subsurface_is_synchronized(subsurface) && - subsurface->has_cache) { - wlr_surface_unlock_cached(subsurface->surface, - subsurface->cached_seq); - subsurface->has_cache = false; - } - } -} - -static const struct wl_subsurface_interface subsurface_implementation = { - .destroy = subsurface_handle_destroy, - .set_position = subsurface_handle_set_position, - .place_above = subsurface_handle_place_above, - .place_below = subsurface_handle_place_below, - .set_sync = subsurface_handle_set_sync, - .set_desync = subsurface_handle_set_desync, -}; - -/** - * Checks if this subsurface needs to be marked as mapped. This can happen if: - * - The subsurface has a buffer - * - Its parent is mapped - */ -static void subsurface_consider_map(struct wlr_subsurface *subsurface, - bool check_parent) { - if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) { - return; - } - - if (check_parent) { - if (subsurface->parent == NULL) { - return; - } - if (wlr_surface_is_subsurface(subsurface->parent)) { - struct wlr_subsurface *parent = - wlr_subsurface_from_wlr_surface(subsurface->parent); - if (parent == NULL || !parent->mapped) { - return; - } - } - } - - // Now we can map the subsurface - wlr_signal_emit_safe(&subsurface->events.map, subsurface); - subsurface->mapped = true; - - // Try mapping all children too - struct wlr_subsurface *child; - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_below, - current.link) { - subsurface_consider_map(child, false); - } - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_above, - current.link) { - subsurface_consider_map(child, false); - } -} - -static void subsurface_unmap(struct wlr_subsurface *subsurface) { - if (!subsurface->mapped) { - return; - } - - wlr_signal_emit_safe(&subsurface->events.unmap, subsurface); - subsurface->mapped = false; - - // Unmap all children - struct wlr_subsurface *child; - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_below, - current.link) { - subsurface_unmap(child); - } - wl_list_for_each(child, &subsurface->surface->current.subsurfaces_above, - current.link) { - subsurface_unmap(child); - } -} - -static void subsurface_role_commit(struct wlr_surface *surface) { - struct wlr_subsurface *subsurface = - wlr_subsurface_from_wlr_surface(surface); - if (subsurface == NULL) { - return; - } - - subsurface_consider_map(subsurface, true); -} - -static void subsurface_role_precommit(struct wlr_surface *surface) { - struct wlr_subsurface *subsurface = - wlr_subsurface_from_wlr_surface(surface); - if (subsurface == NULL) { - return; - } - - if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - surface->pending.buffer == NULL) { - // This is a NULL commit - subsurface_unmap(subsurface); - } -} - -const struct wlr_surface_role subsurface_role = { - .name = "wl_subsurface", - .commit = subsurface_role_commit, - .precommit = subsurface_role_precommit, -}; - -static void subsurface_handle_parent_destroy(struct wl_listener *listener, - void *data) { - struct wlr_subsurface *subsurface = - wl_container_of(listener, subsurface, parent_destroy); - subsurface_unmap(subsurface); - wl_list_remove(&subsurface->current.link); - wl_list_remove(&subsurface->pending.link); - wl_list_remove(&subsurface->parent_destroy.link); - subsurface->parent = NULL; -} - -static void subsurface_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_subsurface *subsurface = - wl_container_of(listener, subsurface, surface_destroy); - subsurface_destroy(subsurface); -} - -static void subsurface_handle_surface_client_commit( - struct wl_listener *listener, void *data) { - struct wlr_subsurface *subsurface = - wl_container_of(listener, subsurface, surface_client_commit); - struct wlr_surface *surface = subsurface->surface; - - if (subsurface_is_synchronized(subsurface)) { - if (subsurface->has_cache) { - // We already lock a previous commit. The prevents any future - // commit to be applied before we release the previous commit. - return; - } - subsurface->has_cache = true; - subsurface->cached_seq = wlr_surface_lock_pending(surface); - } -} - -struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, - struct wlr_surface *parent, uint32_t version, uint32_t id) { - struct wl_client *client = wl_resource_get_client(surface->resource); - - struct wlr_subsurface *subsurface = - calloc(1, sizeof(struct wlr_subsurface)); - if (!subsurface) { - wl_client_post_no_memory(client); - return NULL; - } - subsurface->synchronized = true; - subsurface->surface = surface; - subsurface->resource = - wl_resource_create(client, &wl_subsurface_interface, version, id); - if (subsurface->resource == NULL) { - free(subsurface); - wl_client_post_no_memory(client); - return NULL; - } - wl_resource_set_implementation(subsurface->resource, - &subsurface_implementation, subsurface, subsurface_resource_destroy); - - wl_signal_init(&subsurface->events.destroy); - wl_signal_init(&subsurface->events.map); - wl_signal_init(&subsurface->events.unmap); - - wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy); - subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; - wl_signal_add(&surface->events.client_commit, - &subsurface->surface_client_commit); - subsurface->surface_client_commit.notify = - subsurface_handle_surface_client_commit; - - // link parent - subsurface->parent = parent; - wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); - subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; - - wl_list_init(&subsurface->current.link); - wl_list_insert(parent->pending.subsurfaces_above.prev, - &subsurface->pending.link); - - surface->role_data = subsurface; - - return subsurface; -} - - -struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { - while (wlr_surface_is_subsurface(surface)) { - struct wlr_subsurface *subsurface = - wlr_subsurface_from_wlr_surface(surface); - if (subsurface == NULL) { - break; - } - if (subsurface->parent == NULL) { - return NULL; - } - surface = subsurface->parent; - } - return surface; -} - -bool wlr_surface_point_accepts_input(struct wlr_surface *surface, - double sx, double sy) { - return sx >= 0 && sx < surface->current.width && - sy >= 0 && sy < surface->current.height && - pixman_region32_contains_point(&surface->current.input, floor(sx), floor(sy), NULL); -} - -struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, - double sx, double sy, double *sub_x, double *sub_y) { - struct wlr_subsurface *subsurface; - wl_list_for_each_reverse(subsurface, &surface->current.subsurfaces_above, - current.link) { - if (!subsurface->mapped) { - continue; - } - - double _sub_x = subsurface->current.x; - double _sub_y = subsurface->current.y; - struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, - sx - _sub_x, sy - _sub_y, sub_x, sub_y); - if (sub != NULL) { - return sub; - } - } - - if (wlr_surface_point_accepts_input(surface, sx, sy)) { - if (sub_x) { - *sub_x = sx; - } - if (sub_y) { - *sub_y = sy; - } - return surface; - } - - wl_list_for_each_reverse(subsurface, &surface->current.subsurfaces_below, - current.link) { - if (!subsurface->mapped) { - continue; - } - - double _sub_x = subsurface->current.x; - double _sub_y = subsurface->current.y; - struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, - sx - _sub_x, sy - _sub_y, sub_x, sub_y); - if (sub != NULL) { - return sub; - } - } - - return NULL; -} - -static void surface_output_destroy(struct wlr_surface_output *surface_output) { - wl_list_remove(&surface_output->bind.link); - wl_list_remove(&surface_output->destroy.link); - wl_list_remove(&surface_output->link); - - free(surface_output); -} - -static void surface_handle_output_bind(struct wl_listener *listener, - void *data) { - struct wlr_output_event_bind *evt = data; - struct wlr_surface_output *surface_output = - wl_container_of(listener, surface_output, bind); - struct wl_client *client = wl_resource_get_client( - surface_output->surface->resource); - if (client == wl_resource_get_client(evt->resource)) { - wl_surface_send_enter(surface_output->surface->resource, evt->resource); - } -} - -static void surface_handle_output_destroy(struct wl_listener *listener, - void *data) { - struct wlr_surface_output *surface_output = - wl_container_of(listener, surface_output, destroy); - surface_output_destroy(surface_output); -} - -void wlr_surface_send_enter(struct wlr_surface *surface, - struct wlr_output *output) { - struct wl_client *client = wl_resource_get_client(surface->resource); - struct wlr_surface_output *surface_output; - struct wl_resource *resource; - - wl_list_for_each(surface_output, &surface->current_outputs, link) { - if (surface_output->output == output) { - return; - } - } - - surface_output = calloc(1, sizeof(struct wlr_surface_output)); - if (surface_output == NULL) { - return; - } - surface_output->bind.notify = surface_handle_output_bind; - surface_output->destroy.notify = surface_handle_output_destroy; - - wl_signal_add(&output->events.bind, &surface_output->bind); - wl_signal_add(&output->events.destroy, &surface_output->destroy); - - surface_output->surface = surface; - surface_output->output = output; - wl_list_insert(&surface->current_outputs, &surface_output->link); - - wl_resource_for_each(resource, &output->resources) { - if (client == wl_resource_get_client(resource)) { - wl_surface_send_enter(surface->resource, resource); - } - } -} - -void wlr_surface_send_leave(struct wlr_surface *surface, - struct wlr_output *output) { - struct wl_client *client = wl_resource_get_client(surface->resource); - struct wlr_surface_output *surface_output, *tmp; - struct wl_resource *resource; - - wl_list_for_each_safe(surface_output, tmp, - &surface->current_outputs, link) { - if (surface_output->output == output) { - surface_output_destroy(surface_output); - wl_resource_for_each(resource, &output->resources) { - if (client == wl_resource_get_client(resource)) { - wl_surface_send_leave(surface->resource, resource); - } - } - break; - } - } -} - -void wlr_surface_send_frame_done(struct wlr_surface *surface, - const struct timespec *when) { - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, - &surface->current.frame_callback_list) { - wl_callback_send_done(resource, timespec_to_msec(when)); - wl_resource_destroy(resource); - } -} - -static void surface_for_each_surface(struct wlr_surface *surface, int x, int y, - wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->current.subsurfaces_below, current.link) { - if (!subsurface->mapped) { - continue; - } - - struct wlr_subsurface_parent_state *state = &subsurface->current; - int sx = state->x; - int sy = state->y; - - surface_for_each_surface(subsurface->surface, x + sx, y + sy, - iterator, user_data); - } - - iterator(surface, x, y, user_data); - - wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) { - if (!subsurface->mapped) { - continue; - } - - struct wlr_subsurface_parent_state *state = &subsurface->current; - int sx = state->x; - int sy = state->y; - - surface_for_each_surface(subsurface->surface, x + sx, y + sy, - iterator, user_data); - } -} - -void wlr_surface_for_each_surface(struct wlr_surface *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - surface_for_each_surface(surface, 0, 0, iterator, user_data); -} - -struct bound_acc { - int32_t min_x, min_y; - int32_t max_x, max_y; -}; - -static void handle_bounding_box_surface(struct wlr_surface *surface, - int x, int y, void *data) { - struct bound_acc *acc = data; - - acc->min_x = min(x, acc->min_x); - acc->min_y = min(y, acc->min_y); - - acc->max_x = max(x + surface->current.width, acc->max_x); - acc->max_y = max(y + surface->current.height, acc->max_y); -} - -void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) { - struct bound_acc acc = { - .min_x = 0, - .min_y = 0, - .max_x = surface->current.width, - .max_y = surface->current.height, - }; - - wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc); - - box->x = acc.min_x; - box->y = acc.min_y; - box->width = acc.max_x - acc.min_x; - box->height = acc.max_y - acc.min_y; -} - -static void crop_region(pixman_region32_t *dst, pixman_region32_t *src, - const struct wlr_box *box) { - pixman_region32_intersect_rect(dst, src, - box->x, box->y, box->width, box->height); - pixman_region32_translate(dst, -box->x, -box->y); -} - -void wlr_surface_get_effective_damage(struct wlr_surface *surface, - pixman_region32_t *damage) { - pixman_region32_clear(damage); - - // Transform and copy the buffer damage in terms of surface coordinates. - wlr_region_transform(damage, &surface->buffer_damage, - surface->current.transform, surface->current.buffer_width, - surface->current.buffer_height); - wlr_region_scale(damage, damage, 1.0 / (float)surface->current.scale); - - if (surface->current.viewport.has_src) { - struct wlr_box src_box = { - .x = floor(surface->current.viewport.src.x), - .y = floor(surface->current.viewport.src.y), - .width = ceil(surface->current.viewport.src.width), - .height = ceil(surface->current.viewport.src.height), - }; - crop_region(damage, damage, &src_box); - } - if (surface->current.viewport.has_dst) { - int src_width, src_height; - surface_state_viewport_src_size(&surface->current, - &src_width, &src_height); - float scale_x = (float)surface->current.viewport.dst_width / src_width; - float scale_y = (float)surface->current.viewport.dst_height / src_height; - wlr_region_scale_xy(damage, damage, scale_x, scale_y); - } - - pixman_region32_union(damage, damage, &surface->external_damage); -} - -void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, - struct wlr_fbox *box) { - box->x = box->y = 0; - box->width = surface->current.buffer_width; - box->height = surface->current.buffer_height; - - if (surface->current.viewport.has_src) { - box->x = surface->current.viewport.src.x * surface->current.scale; - box->y = surface->current.viewport.src.y * surface->current.scale; - box->width = surface->current.viewport.src.width * surface->current.scale; - box->height = surface->current.viewport.src.height * surface->current.scale; - - int width, height; - surface_state_transformed_buffer_size(&surface->current, &width, &height); - wlr_fbox_transform(box, box, - wlr_output_transform_invert(surface->current.transform), - width, height); - } -} From e94e16ba5dd95e1fb27cdf46da9e3b42b4869521 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: [PATCH 127/190] surface: move decl to wlr_{sub,}compositor.h --- include/wlr/types/wlr_compositor.h | 273 +++++++++++++++++++++- include/wlr/types/wlr_subcompositor.h | 40 ++++ include/wlr/types/wlr_surface.h | 324 +------------------------- 3 files changed, 313 insertions(+), 324 deletions(-) diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 756f6f30d..0146a8ab5 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -9,10 +9,161 @@ #ifndef WLR_TYPES_WLR_COMPOSITOR_H #define WLR_TYPES_WLR_COMPOSITOR_H +#include +#include +#include +#include #include -#include +#include +#include +#include -struct wlr_surface; +enum wlr_surface_state_field { + WLR_SURFACE_STATE_BUFFER = 1 << 0, + WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1, + WLR_SURFACE_STATE_BUFFER_DAMAGE = 1 << 2, + WLR_SURFACE_STATE_OPAQUE_REGION = 1 << 3, + WLR_SURFACE_STATE_INPUT_REGION = 1 << 4, + WLR_SURFACE_STATE_TRANSFORM = 1 << 5, + WLR_SURFACE_STATE_SCALE = 1 << 6, + WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7, + WLR_SURFACE_STATE_VIEWPORT = 1 << 8, +}; + +struct wlr_surface_state { + uint32_t committed; // enum wlr_surface_state_field + // Sequence number of the surface state. Incremented on each commit, may + // overflow. + uint32_t seq; + + struct wlr_buffer *buffer; + int32_t dx, dy; // relative to previous position + pixman_region32_t surface_damage, buffer_damage; // clipped to bounds + pixman_region32_t opaque, input; + enum wl_output_transform transform; + int32_t scale; + struct wl_list frame_callback_list; // wl_resource + + int width, height; // in surface-local coordinates + int buffer_width, buffer_height; + + struct wl_list subsurfaces_below; + struct wl_list subsurfaces_above; + + /** + * The viewport is applied after the surface transform and scale. + * + * If has_src is true, the surface content is cropped to the provided + * rectangle. If has_dst is true, the surface content is scaled to the + * provided rectangle. + */ + struct { + bool has_src, has_dst; + // In coordinates after scale/transform are applied, but before the + // destination rectangle is applied + struct wlr_fbox src; + int dst_width, dst_height; // in surface-local coordinates + } viewport; + + // Number of locks that prevent this surface state from being committed. + size_t cached_state_locks; + struct wl_list cached_state_link; // wlr_surface.cached +}; + +struct wlr_surface_role { + const char *name; + void (*commit)(struct wlr_surface *surface); + void (*precommit)(struct wlr_surface *surface); +}; + +struct wlr_surface_output { + struct wlr_surface *surface; + struct wlr_output *output; + + struct wl_list link; // wlr_surface::current_outputs + struct wl_listener bind; + struct wl_listener destroy; +}; + +struct wlr_surface { + struct wl_resource *resource; + struct wlr_renderer *renderer; + /** + * The surface's buffer, if any. A surface has an attached buffer when it + * commits with a non-null buffer in its pending state. A surface will not + * have a buffer if it has never committed one, has committed a null buffer, + * or something went wrong with uploading the buffer. + */ + struct wlr_client_buffer *buffer; + /** + * The buffer position, in surface-local units. + */ + int sx, sy; + /** + * The last commit's buffer damage, in buffer-local coordinates. This + * contains both the damage accumulated by the client via + * `wlr_surface_state.surface_damage` and `wlr_surface_state.buffer_damage`. + * If the buffer has been resized, the whole buffer is damaged. + * + * This region needs to be scaled and transformed into output coordinates, + * just like the buffer's texture. In addition, if the buffer has shrunk the + * old size needs to be damaged and if the buffer has moved the old and new + * positions need to be damaged. + */ + pixman_region32_t buffer_damage; + /** + * The last commit's damage caused by surface and its subsurfaces' + * movement, in surface-local coordinates. + */ + pixman_region32_t external_damage; + /** + * The current opaque region, in surface-local coordinates. It is clipped to + * the surface bounds. If the surface's buffer is using a fully opaque + * format, this is set to the whole surface. + */ + pixman_region32_t opaque_region; + /** + * The current input region, in surface-local coordinates. It is clipped to + * the surface bounds. + */ + pixman_region32_t input_region; + /** + * `current` contains the current, committed surface state. `pending` + * accumulates state changes from the client between commits and shouldn't + * be accessed by the compositor directly. + */ + struct wlr_surface_state current, pending; + + struct wl_list cached; // wlr_surface_state.cached_link + + const struct wlr_surface_role *role; // the lifetime-bound role or NULL + void *role_data; // role-specific data + + struct { + struct wl_signal client_commit; + struct wl_signal commit; + struct wl_signal new_subsurface; + struct wl_signal destroy; + } events; + + struct wl_list current_outputs; // wlr_surface_output::link + + struct wlr_addon_set addons; + void *data; + + // private state + + struct wl_listener renderer_destroy; + + struct { + int32_t scale; + enum wl_output_transform transform; + int width, height; + int buffer_width, buffer_height; + } previous; +}; + +struct wlr_renderer; struct wlr_compositor { struct wl_global *global; @@ -26,6 +177,124 @@ struct wlr_compositor { } events; }; +typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface, + int sx, int sy, void *data); + +/** + * Set the lifetime role for this surface. Returns 0 on success or -1 if the + * role cannot be set. + */ +bool wlr_surface_set_role(struct wlr_surface *surface, + const struct wlr_surface_role *role, void *role_data, + struct wl_resource *error_resource, uint32_t error_code); + +/** + * Whether or not this surface currently has an attached buffer. A surface has + * an attached buffer when it commits with a non-null buffer in its pending + * state. A surface will not have a buffer if it has never committed one, has + * committed a null buffer, or something went wrong with uploading the buffer. + */ +bool wlr_surface_has_buffer(struct wlr_surface *surface); + +/** + * Get the texture of the buffer currently attached to this surface. Returns + * NULL if no buffer is currently attached or if something went wrong with + * uploading the buffer. + */ +struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface); + +/** + * Get the root of the subsurface tree for this surface. Can return NULL if + * a surface in the tree has been destroyed. + */ +struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface); + +/** + * Check if the surface accepts input events at the given surface-local + * coordinates. Does not check the surface's subsurfaces. + */ +bool wlr_surface_point_accepts_input(struct wlr_surface *surface, + double sx, double sy); + +/** + * Find a surface in this surface's tree that accepts input events and has all + * parents mapped (except this surface, which can be unmapped) at the given + * surface-local coordinates. Returns the surface and coordinates in the leaf + * surface coordinate system or NULL if no surface is found at that location. + */ +struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, + double sx, double sy, double *sub_x, double *sub_y); + +void wlr_surface_send_enter(struct wlr_surface *surface, + struct wlr_output *output); + +void wlr_surface_send_leave(struct wlr_surface *surface, + struct wlr_output *output); + +void wlr_surface_send_frame_done(struct wlr_surface *surface, + const struct timespec *when); + +/** + * Get the bounding box that contains the surface and all subsurfaces in + * surface coordinates. + * X and y may be negative, if there are subsurfaces with negative position. + */ +void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box); + +/** + * Get the wlr_surface corresponding to a wl_surface resource. This asserts + * that the resource is a valid wl_surface resource created by wlroots and + * will never return NULL. + */ +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); + +/** + * Call `iterator` on each mapped surface in the surface tree (whether or not + * this surface is mapped), with the surface's position relative to the root + * surface. The function is called from root to leaves (in rendering order). + */ +void wlr_surface_for_each_surface(struct wlr_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + +/** + * Get the effective surface damage in surface-local coordinate space. Besides + * buffer damage, this includes damage induced by resizing and moving the + * surface and its subsurfaces. The resulting damage is not expected to be + * bounded by the surface itself. + */ +void wlr_surface_get_effective_damage(struct wlr_surface *surface, + pixman_region32_t *damage); + +/** + * Get the source rectangle describing the region of the buffer that needs to + * be sampled to render this surface's current state. The box is in + * buffer-local coordinates. + * + * If the viewport's source rectangle is unset, the position is zero and the + * size is the buffer's. + */ +void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, + struct wlr_fbox *box); + +/** + * Acquire a lock for the pending surface state. + * + * The state won't be committed before the caller releases the lock. Instead, + * the state becomes cached. The caller needs to use wlr_surface_unlock_cached + * to release the lock. + * + * Returns a surface commit sequence number for the cached state. + */ +uint32_t wlr_surface_lock_pending(struct wlr_surface *surface); + +/** + * Release a lock for a cached state. + * + * Callers should not assume that the cached state will immediately be + * committed. Another caller may still have an active lock. + */ +void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq); + struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_renderer *renderer); diff --git a/include/wlr/types/wlr_subcompositor.h b/include/wlr/types/wlr_subcompositor.h index f9c887bb7..d8e57ed83 100644 --- a/include/wlr/types/wlr_subcompositor.h +++ b/include/wlr/types/wlr_subcompositor.h @@ -9,10 +9,50 @@ #ifndef WLR_TYPES_WLR_SUBCOMPOSITOR_H #define WLR_TYPES_WLR_SUBCOMPOSITOR_H +#include +#include #include struct wlr_surface; +/** + * The sub-surface state describing the sub-surface's relationship with its + * parent. Contrary to other states, this one is not applied on surface commit. + * Instead, it's applied on parent surface commit. + */ +struct wlr_subsurface_parent_state { + int32_t x, y; + struct wl_list link; +}; + +struct wlr_subsurface { + struct wl_resource *resource; + struct wlr_surface *surface; + struct wlr_surface *parent; + + struct wlr_subsurface_parent_state current, pending; + + uint32_t cached_seq; + bool has_cache; + + bool synchronized; + bool reordered; + bool mapped; + bool added; + + struct wl_listener surface_destroy; + struct wl_listener surface_client_commit; + struct wl_listener parent_destroy; + + struct { + struct wl_signal destroy; + struct wl_signal map; + struct wl_signal unmap; + } events; + + void *data; +}; + struct wlr_subcompositor { struct wl_global *global; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index ca1a55ac0..4a6801e8e 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -1,322 +1,2 @@ -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_TYPES_WLR_SURFACE_H -#define WLR_TYPES_WLR_SURFACE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -enum wlr_surface_state_field { - WLR_SURFACE_STATE_BUFFER = 1 << 0, - WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1, - WLR_SURFACE_STATE_BUFFER_DAMAGE = 1 << 2, - WLR_SURFACE_STATE_OPAQUE_REGION = 1 << 3, - WLR_SURFACE_STATE_INPUT_REGION = 1 << 4, - WLR_SURFACE_STATE_TRANSFORM = 1 << 5, - WLR_SURFACE_STATE_SCALE = 1 << 6, - WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7, - WLR_SURFACE_STATE_VIEWPORT = 1 << 8, -}; - -struct wlr_surface_state { - uint32_t committed; // enum wlr_surface_state_field - // Sequence number of the surface state. Incremented on each commit, may - // overflow. - uint32_t seq; - - struct wlr_buffer *buffer; - int32_t dx, dy; // relative to previous position - pixman_region32_t surface_damage, buffer_damage; // clipped to bounds - pixman_region32_t opaque, input; - enum wl_output_transform transform; - int32_t scale; - struct wl_list frame_callback_list; // wl_resource - - int width, height; // in surface-local coordinates - int buffer_width, buffer_height; - - struct wl_list subsurfaces_below; - struct wl_list subsurfaces_above; - - /** - * The viewport is applied after the surface transform and scale. - * - * If has_src is true, the surface content is cropped to the provided - * rectangle. If has_dst is true, the surface content is scaled to the - * provided rectangle. - */ - struct { - bool has_src, has_dst; - // In coordinates after scale/transform are applied, but before the - // destination rectangle is applied - struct wlr_fbox src; - int dst_width, dst_height; // in surface-local coordinates - } viewport; - - // Number of locks that prevent this surface state from being committed. - size_t cached_state_locks; - struct wl_list cached_state_link; // wlr_surface.cached -}; - -struct wlr_surface_role { - const char *name; - void (*commit)(struct wlr_surface *surface); - void (*precommit)(struct wlr_surface *surface); -}; - -struct wlr_surface_output { - struct wlr_surface *surface; - struct wlr_output *output; - - struct wl_list link; // wlr_surface::current_outputs - struct wl_listener bind; - struct wl_listener destroy; -}; - -struct wlr_surface { - struct wl_resource *resource; - struct wlr_renderer *renderer; - /** - * The surface's buffer, if any. A surface has an attached buffer when it - * commits with a non-null buffer in its pending state. A surface will not - * have a buffer if it has never committed one, has committed a null buffer, - * or something went wrong with uploading the buffer. - */ - struct wlr_client_buffer *buffer; - /** - * The buffer position, in surface-local units. - */ - int sx, sy; - /** - * The last commit's buffer damage, in buffer-local coordinates. This - * contains both the damage accumulated by the client via - * `wlr_surface_state.surface_damage` and `wlr_surface_state.buffer_damage`. - * If the buffer has been resized, the whole buffer is damaged. - * - * This region needs to be scaled and transformed into output coordinates, - * just like the buffer's texture. In addition, if the buffer has shrunk the - * old size needs to be damaged and if the buffer has moved the old and new - * positions need to be damaged. - */ - pixman_region32_t buffer_damage; - /** - * The last commit's damage caused by surface and its subsurfaces' - * movement, in surface-local coordinates. - */ - pixman_region32_t external_damage; - /** - * The current opaque region, in surface-local coordinates. It is clipped to - * the surface bounds. If the surface's buffer is using a fully opaque - * format, this is set to the whole surface. - */ - pixman_region32_t opaque_region; - /** - * The current input region, in surface-local coordinates. It is clipped to - * the surface bounds. - */ - pixman_region32_t input_region; - /** - * `current` contains the current, committed surface state. `pending` - * accumulates state changes from the client between commits and shouldn't - * be accessed by the compositor directly. - */ - struct wlr_surface_state current, pending; - - struct wl_list cached; // wlr_surface_state.cached_link - - const struct wlr_surface_role *role; // the lifetime-bound role or NULL - void *role_data; // role-specific data - - struct { - struct wl_signal client_commit; - struct wl_signal commit; - struct wl_signal new_subsurface; - struct wl_signal destroy; - } events; - - struct wl_list current_outputs; // wlr_surface_output::link - - struct wlr_addon_set addons; - void *data; - - // private state - - struct wl_listener renderer_destroy; - - struct { - int32_t scale; - enum wl_output_transform transform; - int width, height; - int buffer_width, buffer_height; - } previous; -}; - -/** - * The sub-surface state describing the sub-surface's relationship with its - * parent. Contrary to other states, this one is not applied on surface commit. - * Instead, it's applied on parent surface commit. - */ -struct wlr_subsurface_parent_state { - int32_t x, y; - struct wl_list link; -}; - -struct wlr_subsurface { - struct wl_resource *resource; - struct wlr_surface *surface; - struct wlr_surface *parent; - - struct wlr_subsurface_parent_state current, pending; - - uint32_t cached_seq; - bool has_cache; - - bool synchronized; - bool reordered; - bool mapped; - bool added; - - struct wl_listener surface_destroy; - struct wl_listener surface_client_commit; - struct wl_listener parent_destroy; - - struct { - struct wl_signal destroy; - struct wl_signal map; - struct wl_signal unmap; - } events; - - void *data; -}; - -typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface, - int sx, int sy, void *data); - -/** - * Set the lifetime role for this surface. Returns 0 on success or -1 if the - * role cannot be set. - */ -bool wlr_surface_set_role(struct wlr_surface *surface, - const struct wlr_surface_role *role, void *role_data, - struct wl_resource *error_resource, uint32_t error_code); - -/** - * Whether or not this surface currently has an attached buffer. A surface has - * an attached buffer when it commits with a non-null buffer in its pending - * state. A surface will not have a buffer if it has never committed one, has - * committed a null buffer, or something went wrong with uploading the buffer. - */ -bool wlr_surface_has_buffer(struct wlr_surface *surface); - -/** - * Get the texture of the buffer currently attached to this surface. Returns - * NULL if no buffer is currently attached or if something went wrong with - * uploading the buffer. - */ -struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface); - -/** - * Get the root of the subsurface tree for this surface. Can return NULL if - * a surface in the tree has been destroyed. - */ -struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface); - -/** - * Check if the surface accepts input events at the given surface-local - * coordinates. Does not check the surface's subsurfaces. - */ -bool wlr_surface_point_accepts_input(struct wlr_surface *surface, - double sx, double sy); - -/** - * Find a surface in this surface's tree that accepts input events and has all - * parents mapped (except this surface, which can be unmapped) at the given - * surface-local coordinates. Returns the surface and coordinates in the leaf - * surface coordinate system or NULL if no surface is found at that location. - */ -struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, - double sx, double sy, double *sub_x, double *sub_y); - -void wlr_surface_send_enter(struct wlr_surface *surface, - struct wlr_output *output); - -void wlr_surface_send_leave(struct wlr_surface *surface, - struct wlr_output *output); - -void wlr_surface_send_frame_done(struct wlr_surface *surface, - const struct timespec *when); - -/** - * Get the bounding box that contains the surface and all subsurfaces in - * surface coordinates. - * X and y may be negative, if there are subsurfaces with negative position. - */ -void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box); - -/** - * Get the wlr_surface corresponding to a wl_surface resource. This asserts - * that the resource is a valid wl_surface resource created by wlroots and - * will never return NULL. - */ -struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); - -/** - * Call `iterator` on each mapped surface in the surface tree (whether or not - * this surface is mapped), with the surface's position relative to the root - * surface. The function is called from root to leaves (in rendering order). - */ -void wlr_surface_for_each_surface(struct wlr_surface *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -/** - * Get the effective surface damage in surface-local coordinate space. Besides - * buffer damage, this includes damage induced by resizing and moving the - * surface and its subsurfaces. The resulting damage is not expected to be - * bounded by the surface itself. - */ -void wlr_surface_get_effective_damage(struct wlr_surface *surface, - pixman_region32_t *damage); - -/** - * Get the source rectangle describing the region of the buffer that needs to - * be sampled to render this surface's current state. The box is in - * buffer-local coordinates. - * - * If the viewport's source rectangle is unset, the position is zero and the - * size is the buffer's. - */ -void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, - struct wlr_fbox *box); - -/** - * Acquire a lock for the pending surface state. - * - * The state won't be committed before the caller releases the lock. Instead, - * the state becomes cached. The caller needs to use wlr_surface_unlock_cached - * to release the lock. - * - * Returns a surface commit sequence number for the cached state. - */ -uint32_t wlr_surface_lock_pending(struct wlr_surface *surface); - -/** - * Release a lock for a cached state. - * - * Callers should not assume that the cached state will immediately be - * committed. Another caller may still have an active lock. - */ -void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq); - -#endif +#include +#include From 617eb4fb9338c6960feb95b1a734c9cdd6bc5c46 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: [PATCH 128/190] surface: deprecate wlr_surface.h --- examples/fullscreen-shell.c | 1 - examples/scene-graph.c | 1 - include/wlr/types/wlr_layer_shell_v1.h | 2 +- include/wlr/types/wlr_pointer_gestures_v1.h | 3 ++- include/wlr/types/wlr_scene.h | 2 +- include/wlr/types/wlr_seat.h | 3 ++- include/wlr/types/wlr_surface.h | 2 ++ include/wlr/types/wlr_text_input_v3.h | 3 ++- include/wlr/types/wlr_xdg_shell.h | 1 + types/data_device/wlr_data_device.c | 1 + types/data_device/wlr_drag.c | 1 + types/output/cursor.c | 2 +- types/output/output.c | 2 +- types/scene/subsurface_tree.c | 1 + types/scene/wlr_scene.c | 2 +- types/seat/wlr_seat_keyboard.c | 1 + types/seat/wlr_seat_pointer.c | 1 + types/seat/wlr_seat_touch.c | 1 + types/tablet_v2/wlr_tablet_v2_pad.c | 1 + types/tablet_v2/wlr_tablet_v2_tablet.c | 1 + types/tablet_v2/wlr_tablet_v2_tool.c | 1 + types/wlr_compositor.c | 1 - types/wlr_foreign_toplevel_management_v1.c | 1 + types/wlr_fullscreen_shell_v1.c | 2 +- types/wlr_idle_inhibit_v1.c | 2 +- types/wlr_input_method_v2.c | 2 +- types/wlr_keyboard_shortcuts_inhibit_v1.c | 1 + types/wlr_layer_shell_v1.c | 2 +- types/wlr_linux_dmabuf_v1.c | 2 +- types/wlr_pointer_constraints_v1.c | 1 + types/wlr_pointer_gestures_v1.c | 1 + types/wlr_presentation_time.c | 2 +- types/wlr_server_decoration.c | 2 +- types/wlr_subcompositor.c | 2 +- types/wlr_text_input_v3.c | 1 + types/wlr_viewporter.c | 2 +- types/wlr_xdg_activation_v1.c | 2 +- xwayland/xwm.c | 2 +- 38 files changed, 39 insertions(+), 22 deletions(-) diff --git a/examples/fullscreen-shell.c b/examples/fullscreen-shell.c index 5a9d4c926..bc4bb7a86 100644 --- a/examples/fullscreen-shell.c +++ b/examples/fullscreen-shell.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/examples/scene-graph.c b/examples/scene-graph.c index bd2003f53..aa542996d 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index 79e435a00..370fad837 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "wlr-layer-shell-unstable-v1-protocol.h" /** diff --git a/include/wlr/types/wlr_pointer_gestures_v1.h b/include/wlr/types/wlr_pointer_gestures_v1.h index 0d91a517d..b05b1a30f 100644 --- a/include/wlr/types/wlr_pointer_gestures_v1.h +++ b/include/wlr/types/wlr_pointer_gestures_v1.h @@ -11,7 +11,8 @@ #include #include -#include + +struct wlr_surface; struct wlr_pointer_gestures_v1 { struct wl_global *global; diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index e0b370adf..7dfccbf9b 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -21,7 +21,7 @@ #include #include -#include +#include struct wlr_output; struct wlr_output_layout; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 631b7dd3d..41f3918b0 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -14,7 +14,8 @@ #include #include #include -#include + +struct wlr_surface; #define WLR_SERIAL_RINGSET_SIZE 128 diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 4a6801e8e..9612dc085 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -1,2 +1,4 @@ +#warning "wlr/types/wlr_surface.h has been deprecated and will be removed in the future. Use wlr/types/wlr_compositor.h and wlr/types/wlr_subcompositor.h." + #include #include diff --git a/include/wlr/types/wlr_text_input_v3.h b/include/wlr/types/wlr_text_input_v3.h index c9ee0b221..5bac69a65 100644 --- a/include/wlr/types/wlr_text_input_v3.h +++ b/include/wlr/types/wlr_text_input_v3.h @@ -11,9 +11,10 @@ #include #include -#include #include +struct wlr_surface; + enum wlr_text_input_v3_features { WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT = 1 << 0, WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE = 1 << 1, diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index cf42e82a7..8d1a6fce6 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -10,6 +10,7 @@ #define WLR_TYPES_WLR_XDG_SHELL_H #include +#include #include #include #include "xdg-shell-protocol.h" diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index 6cd84ec0a..ceaf80e72 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 1952dcb88..9865d9309 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/types/output/cursor.c b/types/output/cursor.c index efbf65032..f3055c5c4 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include #include "render/allocator/allocator.h" #include "render/swapchain.h" diff --git a/types/output/output.c b/types/output/output.c index 85590ab63..0062013f7 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include "render/allocator/allocator.h" #include "render/swapchain.h" diff --git a/types/scene/subsurface_tree.c b/types/scene/subsurface_tree.c index bb3c7ff7a..8384db8fb 100644 --- a/types/scene/subsurface_tree.c +++ b/types/scene/subsurface_tree.c @@ -1,6 +1,7 @@ #include #include #include +#include #include /** diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index a0c06b6bf..9353fef5c 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include "util/signal.h" diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 57dbfe2f5..9ed5fb345 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 2fa911ee0..ce4ca54e2 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "types/wlr_seat.h" diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index 195928a3b..99c50cf88 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "types/wlr_seat.h" diff --git a/types/tablet_v2/wlr_tablet_v2_pad.c b/types/tablet_v2/wlr_tablet_v2_pad.c index 020cba57c..58094f575 100644 --- a/types/tablet_v2/wlr_tablet_v2_pad.c +++ b/types/tablet_v2/wlr_tablet_v2_pad.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/types/tablet_v2/wlr_tablet_v2_tablet.c b/types/tablet_v2/wlr_tablet_v2_tablet.c index bf2a91593..1d3c08fd4 100644 --- a/types/tablet_v2/wlr_tablet_v2_tablet.c +++ b/types/tablet_v2/wlr_tablet_v2_tablet.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/types/tablet_v2/wlr_tablet_v2_tool.c b/types/tablet_v2/wlr_tablet_v2_tool.c index 51efc1e84..9e5b9658a 100644 --- a/types/tablet_v2/wlr_tablet_v2_tool.c +++ b/types/tablet_v2/wlr_tablet_v2_tool.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 4b4b34f99..96122c1c5 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 49805ef9f..9bf811a44 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/types/wlr_fullscreen_shell_v1.c b/types/wlr_fullscreen_shell_v1.c index 59636e4c7..7e9f85539 100644 --- a/types/wlr_fullscreen_shell_v1.c +++ b/types/wlr_fullscreen_shell_v1.c @@ -1,8 +1,8 @@ #include #include +#include #include #include -#include #include #include "util/signal.h" diff --git a/types/wlr_idle_inhibit_v1.c b/types/wlr_idle_inhibit_v1.c index 5acf740e5..61a66dc1f 100644 --- a/types/wlr_idle_inhibit_v1.c +++ b/types/wlr_idle_inhibit_v1.c @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include #include "idle-inhibit-unstable-v1-protocol.h" diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index 7ccd31ee0..c9390e979 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -6,8 +6,8 @@ #include #include #include +#include #include -#include #include #include #include "input-method-unstable-v2-protocol.h" diff --git a/types/wlr_keyboard_shortcuts_inhibit_v1.c b/types/wlr_keyboard_shortcuts_inhibit_v1.c index fe4e64b04..247d350d8 100644 --- a/types/wlr_keyboard_shortcuts_inhibit_v1.c +++ b/types/wlr_keyboard_shortcuts_inhibit_v1.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "keyboard-shortcuts-inhibit-unstable-v1-protocol.h" diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index d7a2123e9..983f2186e 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -3,9 +3,9 @@ #include #include #include +#include #include #include -#include #include #include #include "util/signal.h" diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index ae9bfeb90..5138e469f 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include #include #include "linux-dmabuf-unstable-v1-protocol.h" #include "render/drm_format_set.h" diff --git a/types/wlr_pointer_constraints_v1.c b/types/wlr_pointer_constraints_v1.c index d608b778a..e90daf72e 100644 --- a/types/wlr_pointer_constraints_v1.c +++ b/types/wlr_pointer_constraints_v1.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/types/wlr_pointer_gestures_v1.c b/types/wlr_pointer_gestures_v1.c index 6b09a764f..b8229dfc4 100644 --- a/types/wlr_pointer_gestures_v1.c +++ b/types/wlr_pointer_gestures_v1.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index 36b7fe95f..a6facbdbe 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include #include "presentation-time-protocol.h" #include "util/signal.h" diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index 39ba624aa..a80793939 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -1,7 +1,7 @@ #include #include +#include #include -#include #include #include "server-decoration-protocol.h" #include "util/signal.h" diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index 45d0349d2..8a9e6207a 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -1,8 +1,8 @@ #include #include #include +#include #include -#include #include "types/wlr_region.h" #include "util/signal.h" diff --git a/types/wlr_text_input_v3.c b/types/wlr_text_input_v3.c index f5267b359..65a8ebd6f 100644 --- a/types/wlr_text_input_v3.c +++ b/types/wlr_text_input_v3.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "text-input-unstable-v3-protocol.h" diff --git a/types/wlr_viewporter.c b/types/wlr_viewporter.c index f07c18feb..097af8576 100644 --- a/types/wlr_viewporter.c +++ b/types/wlr_viewporter.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include "util/signal.h" diff --git a/types/wlr_xdg_activation_v1.c b/types/wlr_xdg_activation_v1.c index 208ada28c..02ba9e07f 100644 --- a/types/wlr_xdg_activation_v1.c +++ b/types/wlr_xdg_activation_v1.c @@ -2,8 +2,8 @@ #include #include #include +#include #include -#include #include #include #include "util/signal.h" diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 313bfc0a7..f0a010d9c 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -5,9 +5,9 @@ #include #include #include +#include #include #include -#include #include #include #include From 50827ed7f5f01ed2f03f67c5e9e55e13ede06748 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 14:08:54 +0300 Subject: [PATCH 129/190] surface: improve role precommit hook Now the role precommit hook is called before the commit, not on wl_surface.commit request, and takes a state which is to be applied. --- include/types/wlr_xdg_shell.h | 3 ++- include/wlr/types/wlr_compositor.h | 3 ++- types/wlr_compositor.c | 8 ++++---- types/wlr_layer_shell_v1.c | 6 +++--- types/wlr_subcompositor.c | 6 +++--- types/xdg_shell/wlr_xdg_surface.c | 6 +++--- xwayland/xwm.c | 6 +++--- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 509b1d2c1..8b2c66cc2 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -20,7 +20,8 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface); void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface); void destroy_xdg_surface(struct wlr_xdg_surface *surface); void handle_xdg_surface_commit(struct wlr_surface *wlr_surface); -void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface); +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface, + const struct wlr_surface_state *state); void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 0146a8ab5..071610b8f 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -73,7 +73,8 @@ struct wlr_surface_state { struct wlr_surface_role { const char *name; void (*commit)(struct wlr_surface *surface); - void (*precommit)(struct wlr_surface *surface); + void (*precommit)(struct wlr_surface *surface, + const struct wlr_surface_state *state); }; struct wlr_surface_output { diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 96122c1c5..6c4eb61b3 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -399,6 +399,10 @@ static void surface_commit_state(struct wlr_surface *surface, struct wlr_surface_state *next) { assert(next->cached_state_locks == 0); + if (surface->role && surface->role->precommit) { + surface->role->precommit(surface, next); + } + bool invalid_buffer = next->committed & WLR_SURFACE_STATE_BUFFER; surface->sx += next->dx; @@ -509,10 +513,6 @@ static void surface_handle_commit(struct wl_client *client, wlr_signal_emit_safe(&surface->events.client_commit, NULL); - if (surface->role && surface->role->precommit) { - surface->role->precommit(surface); - } - if (surface->pending.cached_state_locks > 0 || !wl_list_empty(&surface->cached)) { surface_cache_pending(surface); } else { diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 983f2186e..b2c82955f 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -375,15 +375,15 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { } } -static void layer_surface_role_precommit(struct wlr_surface *wlr_surface) { +static void layer_surface_role_precommit(struct wlr_surface *wlr_surface, + const struct wlr_surface_state *state) { struct wlr_layer_surface_v1 *surface = wlr_layer_surface_v1_from_wlr_surface(wlr_surface); if (surface == NULL) { return; } - if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - wlr_surface->pending.buffer == NULL) { + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { // This is a NULL commit if (surface->configured && surface->mapped) { layer_surface_unmap(surface); diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index 8a9e6207a..397baf8c2 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -280,15 +280,15 @@ static void subsurface_role_commit(struct wlr_surface *surface) { subsurface_consider_map(subsurface, true); } -static void subsurface_role_precommit(struct wlr_surface *surface) { +static void subsurface_role_precommit(struct wlr_surface *surface, + const struct wlr_surface_state *state) { struct wlr_subsurface *subsurface = wlr_subsurface_from_wlr_surface(surface); if (subsurface == NULL) { return; } - if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - surface->pending.buffer == NULL) { + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { // This is a NULL commit subsurface_unmap(subsurface); } diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index c45baabb9..d54c058e0 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -338,15 +338,15 @@ void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { } } -void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface) { +void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface, + const struct wlr_surface_state *state) { struct wlr_xdg_surface *surface = wlr_xdg_surface_from_wlr_surface(wlr_surface); if (surface == NULL) { return; } - if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - wlr_surface->pending.buffer == NULL) { + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { // This is a NULL commit if (surface->configured && surface->mapped) { unmap_xdg_surface(surface); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index f0a010d9c..0c1992690 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -852,15 +852,15 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { } } -static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { +static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface, + const struct wlr_surface_state *state) { assert(wlr_surface->role == &xwayland_surface_role); struct wlr_xwayland_surface *surface = wlr_surface->role_data; if (surface == NULL) { return; } - if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - wlr_surface->pending.buffer == NULL) { + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { // This is a NULL commit if (surface->mapped) { wlr_signal_emit_safe(&surface->events.unmap, surface); From 89dc9a44968fbd3fe8a08a41858d1537ee145668 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 14 Jan 2022 20:46:20 +0100 Subject: [PATCH 130/190] tinywl: fix check whether client is focused or not Currently this check is too strict and denies the move/resize request if a subsurface of the client has pointer focus. --- tinywl/tinywl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 722abd10c..6f628836c 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -612,7 +612,8 @@ static void begin_interactive(struct tinywl_view *view, struct tinywl_server *server = view->server; struct wlr_surface *focused_surface = server->seat->pointer_state.focused_surface; - if (view->xdg_surface->surface != focused_surface) { + if (view->xdg_surface->surface != + wlr_surface_get_root_surface(focused_surface)) { /* Deny move/resize requests from unfocused clients. */ return; } From 5091118bed82394de5a151d658e895bb44059b61 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 30 Dec 2021 22:49:48 -0700 Subject: [PATCH 131/190] input_method_v2: improve mapping detection Detect NULL commits before the surface is actually committed, allowing the surface to be properly damaged on unmap. --- types/wlr_input_method_v2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index c9390e979..559927eb1 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -157,9 +157,22 @@ static void popup_surface_surface_role_commit(struct wlr_surface *surface) { && popup_surface->input_method->client_active); } +static void popup_surface_surface_role_precommit(struct wlr_surface *surface, + const struct wlr_surface_state *state) { + struct wlr_input_popup_surface_v2 *popup_surface = surface->role_data; + if (popup_surface == NULL) { + return; + } + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { + // This is a NULL commit + popup_surface_set_mapped(popup_surface, false); + } +} + static const struct wlr_surface_role input_popup_surface_v2_role = { .name = "zwp_input_popup_surface_v2", .commit = popup_surface_surface_role_commit, + .precommit = popup_surface_surface_role_precommit, }; bool wlr_surface_is_input_popup_surface_v2(struct wlr_surface *surface) { From 1bd0ea3a809bdba092ef051120bb6d32f79c0ffb Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 17 Jan 2022 19:11:08 +0100 Subject: [PATCH 132/190] foreign-toplevel: send enter if needed on output bind Currently the output enter event is never sent if the client has not yet bound the output, which happens every time the compositor creates a new output. To fix this, listen for the output bind event and inform clients as if needed. --- .../wlr_foreign_toplevel_management_v1.h | 7 +++++-- types/wlr_foreign_toplevel_management_v1.c | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index 6ea9d47fd..d9030b2ea 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -36,10 +36,13 @@ enum wlr_foreign_toplevel_handle_v1_state { struct wlr_foreign_toplevel_handle_v1_output { struct wl_list link; // wlr_foreign_toplevel_handle_v1::outputs - struct wl_listener output_destroy; struct wlr_output *output; - struct wlr_foreign_toplevel_handle_v1 *toplevel; + + // private state + + struct wl_listener output_bind; + struct wl_listener output_destroy; }; struct wlr_foreign_toplevel_handle_v1 { diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 9bf811a44..a700a115b 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -257,6 +257,23 @@ static void toplevel_send_output(struct wlr_foreign_toplevel_handle_v1 *toplevel toplevel_update_idle_source(toplevel); } +static void toplevel_handle_output_bind(struct wl_listener *listener, + void *data) { + struct wlr_foreign_toplevel_handle_v1_output *toplevel_output = + wl_container_of(listener, toplevel_output, output_bind); + struct wlr_output_event_bind *event = data; + struct wl_client *client = wl_resource_get_client(event->resource); + + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel_output->toplevel->resources) { + if (wl_resource_get_client(resource) == client) { + send_output_to_resource(resource, toplevel_output->output, true); + } + } + + toplevel_update_idle_source(toplevel_output->toplevel); +} + static void toplevel_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_foreign_toplevel_handle_v1_output *toplevel_output = @@ -286,6 +303,9 @@ void wlr_foreign_toplevel_handle_v1_output_enter( toplevel_output->toplevel = toplevel; wl_list_insert(&toplevel->outputs, &toplevel_output->link); + toplevel_output->output_bind.notify = toplevel_handle_output_bind; + wl_signal_add(&output->events.bind, &toplevel_output->output_bind); + toplevel_output->output_destroy.notify = toplevel_handle_output_destroy; wl_signal_add(&output->events.destroy, &toplevel_output->output_destroy); @@ -295,6 +315,7 @@ void wlr_foreign_toplevel_handle_v1_output_enter( static void toplevel_output_destroy( struct wlr_foreign_toplevel_handle_v1_output *toplevel_output) { wl_list_remove(&toplevel_output->link); + wl_list_remove(&toplevel_output->output_bind.link); wl_list_remove(&toplevel_output->output_destroy.link); free(toplevel_output); } From 8656c772489b9f7bde3b9e9c91c872a1d3d82f27 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 19 Jan 2022 04:38:19 -0500 Subject: [PATCH 133/190] scene_graph: use wlr_scene_output_send_frame_done --- examples/scene-graph.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/scene-graph.c b/examples/scene-graph.c index aa542996d..a8ac66844 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -64,11 +64,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - - struct surface *surface; - wl_list_for_each(surface, &output->server->surfaces, link) { - wlr_surface_send_frame_done(surface->wlr, &now); - } + wlr_scene_output_send_frame_done(output->scene_output, &now); } static void server_handle_new_output(struct wl_listener *listener, void *data) { From 1bc6f7f243f385881773f1034cf75d186d4b665f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 19 Jan 2022 04:42:01 -0500 Subject: [PATCH 134/190] scene_graph: remove unused outputs list --- examples/scene-graph.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/scene-graph.c b/examples/scene-graph.c index a8ac66844..cf1372e72 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -29,7 +29,6 @@ struct server { struct wlr_allocator *allocator; struct wlr_scene *scene; - struct wl_list outputs; struct wl_list surfaces; struct wl_listener new_output; @@ -79,7 +78,6 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { output->server = server; output->frame.notify = output_handle_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); - wl_list_insert(&server->outputs, &output->link); output->scene_output = wlr_scene_output_create(server->scene, wlr_output); @@ -172,7 +170,6 @@ int main(int argc, char *argv[]) { wlr_xdg_shell_create(server.display); - wl_list_init(&server.outputs); wl_list_init(&server.surfaces); server.new_output.notify = server_handle_new_output; From c22ea3eb9969de6cd141f280e14539d5c4b6bd3f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 19 Jan 2022 04:46:30 -0500 Subject: [PATCH 135/190] scene_graph: Simplify computation for offset of new surfaces. This became possible after the usage of wlr_surface_send_frame_done. --- examples/scene-graph.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/scene-graph.c b/examples/scene-graph.c index cf1372e72..c3ce05893 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -29,7 +29,7 @@ struct server { struct wlr_allocator *allocator; struct wlr_scene *scene; - struct wl_list surfaces; + uint32_t surface_offset; struct wl_listener new_output; struct wl_listener new_surface; @@ -111,7 +111,8 @@ static void server_handle_new_surface(struct wl_listener *listener, struct server *server = wl_container_of(listener, server, new_surface); struct wlr_surface *wlr_surface = data; - int pos = 50 * wl_list_length(&server->surfaces); + int pos = server->surface_offset; + server->surface_offset += 50; struct surface *surface = calloc(1, sizeof(struct surface)); surface->wlr = wlr_surface; @@ -127,7 +128,6 @@ static void server_handle_new_surface(struct wl_listener *listener, surface->scene_surface = wlr_scene_surface_create(&server->scene->node, wlr_surface); - wl_list_insert(server->surfaces.prev, &surface->link); wlr_scene_node_set_position(&surface->scene_surface->node, pos + border_width, pos + border_width); @@ -155,6 +155,7 @@ int main(int argc, char *argv[]) { } struct server server = {0}; + server.surface_offset = 0; server.display = wl_display_create(); server.backend = wlr_backend_autocreate(server.display); server.scene = wlr_scene_create(); @@ -170,8 +171,6 @@ int main(int argc, char *argv[]) { wlr_xdg_shell_create(server.display); - wl_list_init(&server.surfaces); - server.new_output.notify = server_handle_new_output; wl_signal_add(&server.backend->events.new_output, &server.new_output); From d8d30463ac3c094b243369761b70f21ff9c59ab9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 19 Jan 2022 13:08:46 +0100 Subject: [PATCH 136/190] render/vulkan: log physical device driver name This can be useful to figure out why a required feature is missing, e.g. as in [1]. We check VK_EXT_physical_device_drm availability after printing the driver name. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3358 --- render/vulkan/vulkan.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/render/vulkan/vulkan.c b/render/vulkan/vulkan.c index 4932ec4da..7e9e93962 100644 --- a/render/vulkan/vulkan.c +++ b/render/vulkan/vulkan.c @@ -343,22 +343,40 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) } const char *name = VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME; - if (find_extensions(avail_ext_props, avail_extc, &name, 1) != NULL) { + bool has_drm_props = find_extensions(avail_ext_props, avail_extc, &name, 1) == NULL; + name = VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME; + bool has_driver_props = find_extensions(avail_ext_props, avail_extc, &name, 1) == NULL; + + VkPhysicalDeviceProperties2 props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceDrmPropertiesEXT drm_props = {0}; + drm_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT; + if (has_drm_props) { + drm_props.pNext = props.pNext; + props.pNext = &drm_props; + } + + VkPhysicalDeviceDriverPropertiesKHR driver_props = {0}; + driver_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + if (has_driver_props) { + driver_props.pNext = props.pNext; + props.pNext = &driver_props; + } + + vkGetPhysicalDeviceProperties2(phdev, &props); + + if (has_driver_props) { + wlr_log(WLR_INFO, " Driver name: %s (%s)", driver_props.driverName, driver_props.driverInfo); + } + + if (!has_drm_props) { wlr_log(WLR_DEBUG, " Ignoring physical device \"%s\": " "VK_EXT_physical_device_drm not supported", phdev_props.deviceName); continue; } - VkPhysicalDeviceDrmPropertiesEXT drm_props = {0}; - drm_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT; - - VkPhysicalDeviceProperties2 props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - props.pNext = &drm_props; - - vkGetPhysicalDeviceProperties2(phdev, &props); - dev_t primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor); if (primary_devid == drm_stat.st_rdev || From cfba4c634497949d490fb8a72f457ee5c809de09 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 20 Jan 2022 15:09:15 +0100 Subject: [PATCH 137/190] editorconfig: set max_line_length See [1]. CONTRIBUTING.md says: > Try to keep your lines under 80 columns, but you can go up to 100 if it > improves readability. [1]: https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#max_line_length --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index f392d812a..9dcb30d7d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ charset = utf-8 trim_trailing_whitespace = true indent_style = tab indent_size = 4 +max_line_length = 80 [*.xml] indent_style = space From 7ce966a5d4c73cfe37f3538e887f2ec915b1a1dc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 20 Jan 2022 09:55:21 +0100 Subject: [PATCH 138/190] subcompositor: document subsurface_from_resource --- types/wlr_subcompositor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index 397baf8c2..e9d53f537 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -61,6 +61,12 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { static const struct wl_subsurface_interface subsurface_implementation; +/** + * Get a wlr_subsurface from a wl_subsurface resource. + * + * Returns NULL if the subsurface is inert (e.g. the wl_surface object got + * destroyed). + */ static struct wlr_subsurface *subsurface_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &wl_subsurface_interface, From 1d1b84541015d7b2914bdc69013f2a04548f4321 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 20 Jan 2022 10:03:31 +0100 Subject: [PATCH 139/190] subcompositor: destroy subsurface with parent When the parent surface is destroyed, also destroy the child wl_subsurface. No need to handle the wlr_subsurface.parent == NULL case anymore. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/1709 --- types/wlr_compositor.c | 5 +---- types/wlr_subcompositor.c | 38 ++++++++++++-------------------------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 6c4eb61b3..e7b922a5f 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -478,7 +478,7 @@ static void collect_subsurface_damage_iter(struct wlr_surface *surface, // TODO: untangle from wlr_surface static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { struct wlr_surface *surface = subsurface->surface; - + bool moved = subsurface->current.x != subsurface->pending.x || subsurface->current.y != subsurface->pending.y; if (subsurface->mapped && moved) { @@ -789,9 +789,6 @@ struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { if (subsurface == NULL) { break; } - if (subsurface->parent == NULL) { - return NULL; - } surface = subsurface->parent; } return surface; diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index e9d53f537..8ee5a9496 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -14,10 +14,6 @@ static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) { return true; } - if (!subsurface->parent) { - return false; - } - if (!wlr_surface_is_subsurface(subsurface->parent)) { break; } @@ -45,12 +41,9 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { wl_list_remove(&subsurface->surface_destroy.link); wl_list_remove(&subsurface->surface_client_commit.link); - - if (subsurface->parent) { - wl_list_remove(&subsurface->current.link); - wl_list_remove(&subsurface->pending.link); - wl_list_remove(&subsurface->parent_destroy.link); - } + wl_list_remove(&subsurface->current.link); + wl_list_remove(&subsurface->pending.link); + wl_list_remove(&subsurface->parent_destroy.link); wl_resource_set_user_data(subsurface->resource, NULL); if (subsurface->surface) { @@ -64,8 +57,8 @@ static const struct wl_subsurface_interface subsurface_implementation; /** * Get a wlr_subsurface from a wl_subsurface resource. * - * Returns NULL if the subsurface is inert (e.g. the wl_surface object got - * destroyed). + * Returns NULL if the subsurface is inert (e.g. the wl_surface object or the + * parent surface got destroyed). */ static struct wlr_subsurface *subsurface_from_resource( struct wl_resource *resource) { @@ -227,17 +220,12 @@ static void subsurface_consider_map(struct wlr_subsurface *subsurface, return; } - if (check_parent) { - if (subsurface->parent == NULL) { + if (check_parent && wlr_surface_is_subsurface(subsurface->parent)) { + struct wlr_subsurface *parent = + wlr_subsurface_from_wlr_surface(subsurface->parent); + if (parent == NULL || !parent->mapped) { return; } - if (wlr_surface_is_subsurface(subsurface->parent)) { - struct wlr_subsurface *parent = - wlr_subsurface_from_wlr_surface(subsurface->parent); - if (parent == NULL || !parent->mapped) { - return; - } - } } // Now we can map the subsurface @@ -310,11 +298,9 @@ static void subsurface_handle_parent_destroy(struct wl_listener *listener, void *data) { struct wlr_subsurface *subsurface = wl_container_of(listener, subsurface, parent_destroy); - subsurface_unmap(subsurface); - wl_list_remove(&subsurface->current.link); - wl_list_remove(&subsurface->pending.link); - wl_list_remove(&subsurface->parent_destroy.link); - subsurface->parent = NULL; + // Once the parent is destroyed, the client has no way to use the + // wl_subsurface object anymore, so we can destroy it. + subsurface_destroy(subsurface); } static void subsurface_handle_surface_destroy(struct wl_listener *listener, From da2491d4163e1d8e627d00c8ae594c7f8003472e Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 22 Jan 2022 11:35:22 +0300 Subject: [PATCH 140/190] compositor: damage the whole buffer on viewport src change wp_viewporter protocol doesn't seem to say anything about damage, but Firefox assumes that wp_viewport::set_source alone is enough to damage the whole surface, and that assumption kinda makes sense, so let's do that. --- types/wlr_compositor.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index e7b922a5f..bb4275ef3 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -208,8 +208,12 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, pixman_region32_clear(buffer_damage); if (pending->width != current->width || - pending->height != current->height) { - // Damage the whole buffer on resize + pending->height != current->height || + pending->viewport.src.x != current->viewport.src.x || + pending->viewport.src.y != current->viewport.src.y || + pending->viewport.src.width != current->viewport.src.width || + pending->viewport.src.height != current->viewport.src.height) { + // Damage the whole buffer on resize or viewport source box change pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, pending->buffer_width, pending->buffer_height); } else { From 77951968dc9df7214c04c33f4905a9a7aa92f60c Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 25 Jan 2022 22:30:36 +0300 Subject: [PATCH 141/190] subsurface: unlock cached state on commit if desynced wl_subsurface::set_desync description states: "If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached state, and applied as a whole." This commit reintroduces an implementation of said behavior, previously removed in 7daf6da9ac05be2cb74c0983e3caee0b21db75d4. Strictly speaking, this logic isn't fully correct, as the cached state and the pending state are applied individually instead, if the cached state isn't locked by anything else. However, the end result is still the same. This commit fixes the issue with Firefox permission popups. --- types/wlr_subcompositor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index 8ee5a9496..2b9b97cd2 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -324,6 +324,9 @@ static void subsurface_handle_surface_client_commit( } subsurface->has_cache = true; subsurface->cached_seq = wlr_surface_lock_pending(surface); + } else if (subsurface->has_cache) { + wlr_surface_unlock_cached(surface, subsurface->cached_seq); + subsurface->has_cache = false; } } From 2c59435e8223339070f963263f2caebf07620078 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 28 Jan 2022 17:38:39 +0100 Subject: [PATCH 142/190] xdg-output: remove dead code wlroots current requires wayland-protocols 1.24, so this if is no longer needed and hasn't been for a while. --- types/wlr_xdg_output_v1.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/types/wlr_xdg_output_v1.c b/types/wlr_xdg_output_v1.c index 819ea6c63..8d5fee485 100644 --- a/types/wlr_xdg_output_v1.c +++ b/types/wlr_xdg_output_v1.c @@ -253,12 +253,6 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_output_manager_v1 *wlr_xdg_output_manager_v1_create( struct wl_display *display, struct wlr_output_layout *layout) { - // TODO: require wayland-protocols 1.18 and remove this condition - int version = OUTPUT_MANAGER_VERSION; - if (version > zxdg_output_manager_v1_interface.version) { - version = zxdg_output_manager_v1_interface.version; - } - struct wlr_xdg_output_manager_v1 *manager = calloc(1, sizeof(struct wlr_xdg_output_manager_v1)); if (manager == NULL) { @@ -266,7 +260,7 @@ struct wlr_xdg_output_manager_v1 *wlr_xdg_output_manager_v1_create( } manager->layout = layout; manager->global = wl_global_create(display, - &zxdg_output_manager_v1_interface, version, manager, + &zxdg_output_manager_v1_interface, OUTPUT_MANAGER_VERSION, manager, output_manager_bind); if (!manager->global) { free(manager); From 498f30aad100ca616640c7bcbf11ab8ef7d48c45 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 29 Jan 2022 23:06:09 +0300 Subject: [PATCH 143/190] output-layout: make wlr_output_layout_get_box() take a box as parameter Closes https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/812 --- include/wlr/types/wlr_output_layout.h | 6 +- types/wlr_cursor.c | 54 ++++++------ types/wlr_output_layout.c | 117 ++++++++++++++------------ 3 files changed, 92 insertions(+), 85 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index abbe4884e..f537c418b 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -107,10 +107,10 @@ void wlr_output_layout_closest_point(struct wlr_output_layout *layout, /** * Get the box of the layout for the given reference output in layout * coordinates. If `reference` is NULL, the box will be for the extents of the - * entire layout. + * entire layout. If the output isn't in the layout, the box will be empty. */ -struct wlr_box *wlr_output_layout_get_box( - struct wlr_output_layout *layout, struct wlr_output *reference); +void wlr_output_layout_get_box(struct wlr_output_layout *layout, + struct wlr_output *reference, struct wlr_box *dest_box); /** * Add an auto configured output to the layout. This will place the output in a diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index a6b0716c7..97a4d1e9d 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -237,33 +237,32 @@ static void cursor_warp_unchecked(struct wlr_cursor *cur, * Absolute movement for touch and pen devices will be relative to this box and * pointer movement will be constrained to this box. * - * If none of these are set, returns NULL and absolute movement should be + * If none of these are set, empties the box and absolute movement should be * relative to the extents of the layout. */ -static struct wlr_box *get_mapping(struct wlr_cursor *cur, - struct wlr_input_device *dev) { +static void get_mapping(struct wlr_cursor *cur, + struct wlr_input_device *dev, struct wlr_box *box) { assert(cur->state->layout); struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (c_device) { if (c_device->mapped_box) { - return c_device->mapped_box; - } - if (c_device->mapped_output) { - return wlr_output_layout_get_box(cur->state->layout, - c_device->mapped_output); + *box = *c_device->mapped_box; + } else if (c_device->mapped_output) { + wlr_output_layout_get_box(cur->state->layout, + c_device->mapped_output, box); } + return; } if (cur->state->mapped_box) { - return cur->state->mapped_box; + *box = *cur->state->mapped_box; + } else if (cur->state->mapped_output) { + wlr_output_layout_get_box(cur->state->layout, + cur->state->mapped_output, box); + } else { + box->width = box->height = 0; } - if (cur->state->mapped_output) { - return wlr_output_layout_get_box(cur->state->layout, - cur->state->mapped_output); - } - - return NULL; } bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, @@ -271,9 +270,10 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, assert(cur->state->layout); bool result = false; - struct wlr_box *mapping = get_mapping(cur, dev); - if (mapping) { - result = wlr_box_contains_point(mapping, lx, ly); + struct wlr_box mapping; + get_mapping(cur, dev, &mapping); + if (!wlr_box_empty(&mapping)) { + result = wlr_box_contains_point(&mapping, lx, ly); } else { result = wlr_output_layout_contains_point(cur->state->layout, NULL, lx, ly); @@ -288,9 +288,10 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, void wlr_cursor_warp_closest(struct wlr_cursor *cur, struct wlr_input_device *dev, double lx, double ly) { - struct wlr_box *mapping = get_mapping(cur, dev); - if (mapping) { - wlr_box_closest_point(mapping, lx, ly, &lx, &ly); + struct wlr_box mapping; + get_mapping(cur, dev, &mapping); + if (!wlr_box_empty(&mapping)) { + wlr_box_closest_point(&mapping, lx, ly, &lx, &ly); if (isnan(lx) || isnan(ly)) { lx = 0; ly = 0; @@ -308,13 +309,14 @@ void wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur, double *lx, double *ly) { assert(cur->state->layout); - struct wlr_box *mapping = get_mapping(cur, dev); - if (!mapping) { - mapping = wlr_output_layout_get_box(cur->state->layout, NULL); + struct wlr_box mapping; + get_mapping(cur, dev, &mapping); + if (wlr_box_empty(&mapping)) { + wlr_output_layout_get_box(cur->state->layout, NULL, &mapping); } - *lx = !isnan(x) ? mapping->width * x + mapping->x : cur->x; - *ly = !isnan(y) ? mapping->height * y + mapping->y : cur->y; + *lx = !isnan(x) ? mapping.width * x + mapping.x : cur->x; + *ly = !isnan(y) ? mapping.height * y + mapping.y : cur->y; } void wlr_cursor_warp_absolute(struct wlr_cursor *cur, diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index eb672f06e..b102fdae7 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -73,15 +73,13 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { free(layout); } -static struct wlr_box *output_layout_output_get_box( - struct wlr_output_layout_output *l_output) { - l_output->state->_box.x = l_output->x; - l_output->state->_box.y = l_output->y; - int width, height; - wlr_output_effective_resolution(l_output->output, &width, &height); - l_output->state->_box.width = width; - l_output->state->_box.height = height; - return &l_output->state->_box; +static void output_layout_output_get_box( + struct wlr_output_layout_output *l_output, + struct wlr_box *box) { + box->x = l_output->x; + box->y = l_output->y; + wlr_output_effective_resolution(l_output->output, + &box->width, &box->height); } /** @@ -98,15 +96,17 @@ static void output_layout_reconfigure(struct wlr_output_layout *layout) { // find the rightmost x coordinate occupied by a manually configured output // in the layout struct wlr_output_layout_output *l_output; + struct wlr_box output_box; + wl_list_for_each(l_output, &layout->outputs, link) { if (l_output->state->auto_configured) { continue; } - struct wlr_box *box = output_layout_output_get_box(l_output); - if (box->x + box->width > max_x) { - max_x = box->x + box->width; - max_x_y = box->y; + output_layout_output_get_box(l_output, &output_box); + if (output_box.x + output_box.width > max_x) { + max_x = output_box.x + output_box.width; + max_x_y = output_box.y; } } @@ -120,10 +120,10 @@ static void output_layout_reconfigure(struct wlr_output_layout *layout) { if (!l_output->state->auto_configured) { continue; } - struct wlr_box *box = output_layout_output_get_box(l_output); + output_layout_output_get_box(l_output, &output_box); l_output->x = max_x; l_output->y = max_x_y; - max_x += box->width; + max_x += output_box.width; } wlr_signal_emit_safe(&layout->events.change, layout); @@ -242,8 +242,9 @@ bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, if (reference) { struct wlr_output_layout_output *l_output = wlr_output_layout_get(layout, reference); - struct wlr_box *box = output_layout_output_get_box(l_output); - return wlr_box_contains_point(box, lx, ly); + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + return wlr_box_contains_point(&output_box, lx, ly); } else { return !!wlr_output_layout_output_at(layout, lx, ly); } @@ -256,9 +257,9 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, if (reference == NULL) { struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { - struct wlr_box *output_box = - output_layout_output_get_box(l_output); - if (wlr_box_intersection(&out_box, output_box, target_lbox)) { + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + if (wlr_box_intersection(&out_box, &output_box, target_lbox)) { return true; } } @@ -270,8 +271,9 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, return false; } - struct wlr_box *output_box = output_layout_output_get_box(l_output); - return wlr_box_intersection(&out_box, output_box, target_lbox); + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + return wlr_box_intersection(&out_box, &output_box, target_lbox); } } @@ -279,8 +281,9 @@ struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, double lx, double ly) { struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { - struct wlr_box *box = output_layout_output_get_box(l_output); - if (wlr_box_contains_point(box, lx, ly)) { + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + if (wlr_box_contains_point(&output_box, lx, ly)) { return l_output->output; } } @@ -342,8 +345,9 @@ void wlr_output_layout_closest_point(struct wlr_output_layout *layout, } double output_x, output_y, output_distance; - struct wlr_box *box = output_layout_output_get_box(l_output); - wlr_box_closest_point(box, lx, ly, &output_x, &output_y); + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + wlr_box_closest_point(&output_box, lx, ly, &output_x, &output_y); // calculate squared distance suitable for comparison output_distance = @@ -368,17 +372,17 @@ void wlr_output_layout_closest_point(struct wlr_output_layout *layout, } } -struct wlr_box *wlr_output_layout_get_box( - struct wlr_output_layout *layout, struct wlr_output *reference) { +void wlr_output_layout_get_box(struct wlr_output_layout *layout, + struct wlr_output *reference, struct wlr_box *dest_box) { struct wlr_output_layout_output *l_output; if (reference) { // output extents l_output = wlr_output_layout_get(layout, reference); if (l_output) { - return output_layout_output_get_box(l_output); + output_layout_output_get_box(l_output, dest_box); } else { - return NULL; + dest_box->width = dest_box->height = 0; } } else { // layout extents @@ -387,31 +391,28 @@ struct wlr_box *wlr_output_layout_get_box( min_x = min_y = INT_MAX; max_x = max_y = INT_MIN; wl_list_for_each(l_output, &layout->outputs, link) { - struct wlr_box *box = output_layout_output_get_box(l_output); - if (box->x < min_x) { - min_x = box->x; + struct wlr_box output_box; + output_layout_output_get_box(l_output, &output_box); + if (output_box.x < min_x) { + min_x = output_box.x; } - if (box->y < min_y) { - min_y = box->y; + if (output_box.y < min_y) { + min_y = output_box.y; } - if (box->x + box->width > max_x) { - max_x = box->x + box->width; + if (output_box.x + output_box.width > max_x) { + max_x = output_box.x + output_box.width; } - if (box->y + box->height > max_y) { - max_y = box->y + box->height; + if (output_box.y + output_box.height > max_y) { + max_y = output_box.y + output_box.height; } } } - layout->state->_box.x = min_x; - layout->state->_box.y = min_y; - layout->state->_box.width = max_x - min_x; - layout->state->_box.height = max_y - min_y; - - return &layout->state->_box; + dest_box->x = min_x; + dest_box->y = min_y; + dest_box->width = max_x - min_x; + dest_box->height = max_y - min_y; } - - // not reached } void wlr_output_layout_add_auto(struct wlr_output_layout *layout, @@ -442,9 +443,10 @@ struct wlr_output *wlr_output_layout_get_center_output( return NULL; } - struct wlr_box *extents = wlr_output_layout_get_box(layout, NULL); - double center_x = extents->width / 2. + extents->x; - double center_y = extents->height / 2. + extents->y; + struct wlr_box extents; + wlr_output_layout_get_box(layout, NULL, &extents); + double center_x = extents.width / 2. + extents.x; + double center_y = extents.height / 2. + extents.y; double dest_x = 0, dest_y = 0; wlr_output_layout_closest_point(layout, NULL, center_x, center_y, @@ -464,7 +466,8 @@ static struct wlr_output *wlr_output_layout_output_in_direction( enum distance_selection_method distance_method) { assert(reference); - struct wlr_box *ref_box = wlr_output_layout_get_box(layout, reference); + struct wlr_box ref_box; + wlr_output_layout_get_box(layout, reference, &ref_box); double min_distance = (distance_method == NEAREST) ? DBL_MAX : DBL_MIN; struct wlr_output *closest_output = NULL; @@ -473,21 +476,23 @@ static struct wlr_output *wlr_output_layout_output_in_direction( if (reference != NULL && reference == l_output->output) { continue; } - struct wlr_box *box = output_layout_output_get_box(l_output); + + struct wlr_box box; + output_layout_output_get_box(l_output, &box); bool match = false; // test to make sure this output is in the given direction if (direction & WLR_DIRECTION_LEFT) { - match = box->x + box->width <= ref_box->x || match; + match = box.x + box.width <= ref_box.x || match; } if (direction & WLR_DIRECTION_RIGHT) { - match = box->x >= ref_box->x + ref_box->width || match; + match = box.x >= ref_box.x + ref_box.width || match; } if (direction & WLR_DIRECTION_UP) { - match = box->y + box->height <= ref_box->y || match; + match = box.y + box.height <= ref_box.y || match; } if (direction & WLR_DIRECTION_DOWN) { - match = box->y >= ref_box->y + ref_box->height || match; + match = box.y >= ref_box.y + ref_box.height || match; } if (!match) { continue; From 49fa060442f702a1343c7f5b18caa6c81bd70252 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 29 Jan 2022 23:10:22 +0300 Subject: [PATCH 144/190] output-layout: remove useless types/fields --- include/wlr/types/wlr_output_layout.h | 2 -- types/wlr_output_layout.c | 11 ----------- 2 files changed, 13 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index f537c418b..3cb6e1e2d 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -15,7 +15,6 @@ #include struct wlr_box; -struct wlr_output_layout_state; /** * Helper to arrange outputs in a 2D coordinate space. The output effective @@ -27,7 +26,6 @@ struct wlr_output_layout_state; */ struct wlr_output_layout { struct wl_list outputs; - struct wlr_output_layout_state *state; struct { struct wl_signal add; diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index b102fdae7..28d91e8d4 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -8,15 +8,10 @@ #include #include "util/signal.h" -struct wlr_output_layout_state { - struct wlr_box _box; // should never be read directly, use the getter -}; - struct wlr_output_layout_output_state { struct wlr_output_layout *layout; struct wlr_output_layout_output *l_output; - struct wlr_box _box; // should never be read directly, use the getter bool auto_configured; struct wl_listener mode; @@ -31,11 +26,6 @@ struct wlr_output_layout *wlr_output_layout_create(void) { if (layout == NULL) { return NULL; } - layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); - if (layout->state == NULL) { - free(layout); - return NULL; - } wl_list_init(&layout->outputs); wl_signal_init(&layout->events.add); @@ -69,7 +59,6 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { output_layout_output_destroy(l_output); } - free(layout->state); free(layout); } From ba6ba4b07ac2691b381a6a463d9217a031c699c7 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 29 Jan 2022 23:25:12 +0300 Subject: [PATCH 145/190] cursor: store mapped_box as value --- types/wlr_cursor.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 97a4d1e9d..bab5ed104 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -19,7 +19,7 @@ struct wlr_cursor_device { struct wlr_input_device *device; struct wl_list link; struct wlr_output *mapped_output; - struct wlr_box *mapped_box; + struct wlr_box mapped_box; // empty if unset struct wl_listener motion; struct wl_listener motion_absolute; @@ -63,7 +63,7 @@ struct wlr_cursor_state { struct wl_list output_cursors; // wlr_cursor_output_cursor::link struct wlr_output_layout *layout; struct wlr_output *mapped_output; - struct wlr_box *mapped_box; + struct wlr_box mapped_box; // empty if unset struct wl_listener layout_add; struct wl_listener layout_change; @@ -246,8 +246,8 @@ static void get_mapping(struct wlr_cursor *cur, struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (c_device) { - if (c_device->mapped_box) { - *box = *c_device->mapped_box; + if (!wlr_box_empty(&c_device->mapped_box)) { + *box = c_device->mapped_box; } else if (c_device->mapped_output) { wlr_output_layout_get_box(cur->state->layout, c_device->mapped_output, box); @@ -255,8 +255,8 @@ static void get_mapping(struct wlr_cursor *cur, return; } - if (cur->state->mapped_box) { - *box = *cur->state->mapped_box; + if (!wlr_box_empty(&cur->state->mapped_box)) { + *box = cur->state->mapped_box; } else if (cur->state->mapped_output) { wlr_output_layout_get_box(cur->state->layout, cur->state->mapped_output, box); @@ -865,22 +865,19 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box) { - if (box && wlr_box_empty(box)) { - wlr_log(WLR_ERROR, "cannot map cursor to an empty region"); - return; + if (box) { + if (wlr_box_empty(box)) { + wlr_log(WLR_ERROR, "cannot map cursor to an empty region"); + return; + } + cur->state->mapped_box = *box; + } else { + cur->state->mapped_box.width = cur->state->mapped_box.height = 0; } - - cur->state->mapped_box = box; } void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_box *box) { - if (box && wlr_box_empty(box)) { - wlr_log(WLR_ERROR, "cannot map device \"%s\" input to an empty region", - dev->name); - return; - } - struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { wlr_log(WLR_ERROR, "Cannot map device \"%s\" to geometry (not found in" @@ -888,5 +885,15 @@ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, return; } - c_device->mapped_box = box; + if (box) { + if (wlr_box_empty(box)) { + wlr_log(WLR_ERROR, + "cannot map device \"%s\" input to an empty region", + dev->name); + return; + } + c_device->mapped_box = *box; + } else { + c_device->mapped_box.width = c_device->mapped_box.height = 0; + } } From ab3b9f9a773e3ec2c40d80ab14277659b2a55ca6 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sun, 30 Jan 2022 21:56:02 +0100 Subject: [PATCH 146/190] xcursor: garbage collect XcursorLibraryLoadImages XcursorLibraryLoadImages is unused, let's drop it. Same as [1]. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/206 Co-authored-by: Simon Ser --- include/xcursor/xcursor.h | 3 -- xcursor/xcursor.c | 79 --------------------------------------- 2 files changed, 82 deletions(-) diff --git a/include/xcursor/xcursor.h b/include/xcursor/xcursor.h index 285f4de66..c21707b4b 100644 --- a/include/xcursor/xcursor.h +++ b/include/xcursor/xcursor.h @@ -54,9 +54,6 @@ typedef struct _XcursorImages { char *name; /* name used to load images */ } XcursorImages; -XcursorImages * -XcursorLibraryLoadImages (const char *file, const char *theme, int size); - void XcursorImagesDestroy (XcursorImages *images); diff --git a/xcursor/xcursor.c b/xcursor/xcursor.c index 4415a6596..293d6e9d8 100644 --- a/xcursor/xcursor.c +++ b/xcursor/xcursor.c @@ -795,85 +795,6 @@ _XcursorThemeInherits (const char *full) return result; } -static FILE * -XcursorScanTheme (const char *theme, const char *name) -{ - FILE *f = NULL; - char *full; - char *dir; - const char *path; - char *inherits = NULL; - const char *i; - - if (!theme || !name) - return NULL; - - /* - * Scan this theme - */ - for (path = XcursorLibraryPath (); - path && f == NULL; - path = _XcursorNextPath (path)) - { - dir = _XcursorBuildThemeDir (path, theme); - if (dir) - { - full = _XcursorBuildFullname (dir, "cursors", name); - if (full) - { - f = fopen (full, "r"); - free (full); - } - if (!f && !inherits) - { - full = _XcursorBuildFullname (dir, "", "index.theme"); - if (full) - { - inherits = _XcursorThemeInherits (full); - free (full); - } - } - free (dir); - } - } - /* - * Recurse to scan inherited themes - */ - for (i = inherits; i && f == NULL; i = _XcursorNextPath (i)) - { - if (strcmp(i, theme) != 0) - f = XcursorScanTheme (i, name); - else - printf("Not calling XcursorScanTheme because of circular dependency: %s. %s", i, name); - } - if (inherits != NULL) - free (inherits); - return f; -} - -XcursorImages * -XcursorLibraryLoadImages (const char *file, const char *theme, int size) -{ - FILE *f = NULL; - XcursorImages *images = NULL; - - if (!file) - return NULL; - - if (theme) - f = XcursorScanTheme (theme, file); - if (!f) - f = XcursorScanTheme ("default", file); - if (f) - { - images = XcursorFileLoadImages (f, size); - if (images) - XcursorImagesSetName (images, file); - fclose (f); - } - return images; -} - static void load_all_cursors_from_dir(const char *path, int size, void (*load_callback)(XcursorImages *, void *), From 3cfe29b5988190d7eb32cd0b76a6cfe810be7812 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Mon, 31 Jan 2022 20:55:52 +0300 Subject: [PATCH 147/190] cursor: ensure mapping box is always initialized Commit 498f30aad100ca616640c7bcbf11ab8ef7d48c45 changed the logic of get_mapping() in types/wlr_cursor.c to use updated version of wlr_output_layout_get_box(). However, the case where c_device isn't NULL but doesn't have output or geometry mappings wasn't handled properly, resulting in leaving the output value uninitialized. This commit fixes `c_device != NULL` branch by returning from the function only when a mapping is found. Fixes https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3369 --- types/wlr_cursor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index bab5ed104..034628cf0 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -248,11 +248,12 @@ static void get_mapping(struct wlr_cursor *cur, if (c_device) { if (!wlr_box_empty(&c_device->mapped_box)) { *box = c_device->mapped_box; + return; } else if (c_device->mapped_output) { wlr_output_layout_get_box(cur->state->layout, c_device->mapped_output, box); + return; } - return; } if (!wlr_box_empty(&cur->state->mapped_box)) { From 3db1bcbe641b407b9f5c9e5d0a012b45aa2c6cb7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 18 Jan 2022 14:27:37 +0100 Subject: [PATCH 148/190] scene: try to import buffers as textures before rendering The wlroots APIs currently don't allow importing/uploading a buffer during rendering operations. Scene-graph buffer nodes need to turn their wlr_buffer into a wlr_texture at some point. It's not always possible to do so at wlr_scene_buffer creation time because the scene-graph may have zero outputs at this point, thus no way to grab a wlr_renderer. Instead, add scene-graph buffers to a pending list and try to import them in wlr_scene_output_commit. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3354 --- include/wlr/types/wlr_scene.h | 4 ++++ types/scene/wlr_scene.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 7dfccbf9b..a77eb6c2f 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -68,6 +68,9 @@ struct wlr_scene { // May be NULL struct wlr_presentation *presentation; struct wl_listener presentation_destroy; + + // List of buffers which need to be imported as textures + struct wl_list pending_buffers; // wlr_scene_buffer.pending_link }; /** A sub-tree in the scene-graph. */ @@ -114,6 +117,7 @@ struct wlr_scene_buffer { struct wlr_fbox src_box; int dst_width, dst_height; enum wl_output_transform transform; + struct wl_list pending_link; // wlr_scene.pending_buffers }; /** A viewport for an output in the scene-graph */ diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 9353fef5c..5d5ff9657 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -130,6 +130,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + wl_list_remove(&scene_buffer->pending_link); wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); free(scene_buffer); @@ -145,6 +146,7 @@ struct wlr_scene *wlr_scene_create(void) { scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); + wl_list_init(&scene->pending_buffers); return scene; } @@ -360,6 +362,9 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, scene_node_damage_whole(&scene_buffer->node); + struct wlr_scene *scene = scene_node_get_root(parent); + wl_list_insert(&scene->pending_buffers, &scene_buffer->pending_link); + return scene_buffer; } @@ -1113,6 +1118,15 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return true; } + // Try to import new buffers as textures + struct wlr_scene_buffer *scene_buffer, *scene_buffer_tmp; + wl_list_for_each_safe(scene_buffer, scene_buffer_tmp, + &scene_output->scene->pending_buffers, pending_link) { + scene_buffer_get_texture(scene_buffer, renderer); + wl_list_remove(&scene_buffer->pending_link); + wl_list_init(&scene_buffer->pending_link); + } + wlr_renderer_begin(renderer, output->width, output->height); int nrects; From 1e3662ce5769bb82e5893733c48423e10ae47b56 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 9 Jan 2022 23:48:24 +0100 Subject: [PATCH 149/190] scene: Add layer_shell_v1 helper This helper behaves similar to the xdg_shell helper, and additionally provides a little assistance for positioning and exclusive_zone management. --- include/wlr/types/wlr_scene.h | 38 +++++++ types/meson.build | 1 + types/scene/layer_shell_v1.c | 183 ++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 types/scene/layer_shell_v1.c diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index a77eb6c2f..867753996 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -26,6 +26,7 @@ struct wlr_output; struct wlr_output_layout; struct wlr_xdg_surface; +struct wlr_layer_surface_v1; enum wlr_scene_node_type { WLR_SCENE_NODE_ROOT, @@ -136,6 +137,19 @@ struct wlr_scene_output { bool prev_scanout; }; +/** A layer shell scene helper */ +struct wlr_scene_layer_surface_v1 { + struct wlr_scene_node *node; + struct wlr_layer_surface_v1 *layer_surface; + + // private state + + struct wl_listener tree_destroy; + struct wl_listener layer_surface_destroy; + struct wl_listener layer_surface_map; + struct wl_listener layer_surface_unmap; +}; + typedef void (*wlr_scene_node_iterator_func_t)(struct wlr_scene_node *node, int sx, int sy, void *data); @@ -354,4 +368,28 @@ struct wlr_scene_node *wlr_scene_subsurface_tree_create( struct wlr_scene_node *wlr_scene_xdg_surface_create( struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface); +/** + * Add a node displaying a layer_surface_v1 and all of its sub-surfaces to the + * scene-graph. + * + * The origin of the returned scene-graph node will match the top-left corner + * of the layer surface. + */ +struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( + struct wlr_scene_node *parent, struct wlr_layer_surface_v1 *layer_surface); + +/** + * Configure a layer_surface_v1, position its scene node in accordance to its + * current state, and update the remaining usable area. + * + * full_area represents the entire area that may be used by the layer surface + * if its exclusive_zone is -1, and is usually the output dimensions. + * usable_area represents what remains of full_area that can be used if + * exclusive_zone is >= 0. usable_area is updated if the surface has a positive + * exclusive_zone, so that it can be used for the next layer surface. + */ +void wlr_scene_layer_surface_v1_configure( + struct wlr_scene_layer_surface_v1 *scene_layer_surface, + const struct wlr_box *full_area, struct wlr_box *usable_area); + #endif diff --git a/types/meson.build b/types/meson.build index 476bffe82..43e5875c0 100644 --- a/types/meson.build +++ b/types/meson.build @@ -11,6 +11,7 @@ wlr_files += files( 'scene/wlr_scene.c', 'scene/output_layout.c', 'scene/xdg_shell.c', + 'scene/layer_shell_v1.c', 'seat/wlr_seat_keyboard.c', 'seat/wlr_seat_pointer.c', 'seat/wlr_seat_touch.c', diff --git a/types/scene/layer_shell_v1.c b/types/scene/layer_shell_v1.c new file mode 100644 index 000000000..1c2b6e4ff --- /dev/null +++ b/types/scene/layer_shell_v1.c @@ -0,0 +1,183 @@ +#include +#include +#include + +static void scene_layer_surface_handle_tree_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, tree_destroy); + // tree and surface_node will be cleaned up by scene_node_finish + wl_list_remove(&scene_layer_surface->tree_destroy.link); + wl_list_remove(&scene_layer_surface->layer_surface_destroy.link); + wl_list_remove(&scene_layer_surface->layer_surface_map.link); + wl_list_remove(&scene_layer_surface->layer_surface_unmap.link); + free(scene_layer_surface); +} + +static void scene_layer_surface_handle_layer_surface_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_destroy); + wlr_scene_node_destroy(scene_layer_surface->node); +} + +static void scene_layer_surface_handle_layer_surface_map( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_map); + wlr_scene_node_set_enabled(scene_layer_surface->node, true); +} + +static void scene_layer_surface_handle_layer_surface_unmap( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_unmap); + wlr_scene_node_set_enabled(scene_layer_surface->node, false); +} + +static void layer_surface_exclusive_zone( + struct wlr_layer_surface_v1_state *state, + struct wlr_box *usable_area) { + switch (state->anchor) { + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): + // Anchor top + usable_area->y += state->exclusive_zone + state->margin.top; + usable_area->height -= state->exclusive_zone + state->margin.top; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): + // Anchor bottom + usable_area->height -= state->exclusive_zone + state->margin.bottom; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT): + // Anchor left + usable_area->x += state->exclusive_zone + state->margin.left; + usable_area->width -= state->exclusive_zone + state->margin.left; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor right + // Anchor right + usable_area->width -= state->exclusive_zone + state->margin.right; + break; + } +} + +void wlr_scene_layer_surface_v1_configure( + struct wlr_scene_layer_surface_v1 *scene_layer_surface, + const struct wlr_box *full_area, struct wlr_box *usable_area) { + struct wlr_layer_surface_v1 *layer_surface = + scene_layer_surface->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer_surface->current; + + // If the exclusive zone is set to -1, the layer surface will use the + // full area of the output, otherwise it is constrained to the + // remaining usable area. + struct wlr_box bounds; + if (state->exclusive_zone == -1) { + bounds = *full_area; + } else { + bounds = *usable_area; + } + + struct wlr_box box = { + .width = state->desired_width, + .height = state->desired_height, + }; + + // Horizontal positioning + if (box.width == 0) { + box.x = bounds.x + state->margin.left; + box.width = bounds.width - + state->margin.left + state->margin.right; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT && + state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + box.x = bounds.x + bounds.width/2 -box.width/2; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) { + box.x = bounds.x + state->margin.left; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + box.x = bounds.x + bounds.width - box.width - state->margin.right; + } else { + box.x = bounds.x + bounds.width/2 - box.width/2; + } + + // Vertical positioning + if (box.height == 0) { + box.y = bounds.y + state->margin.top; + box.height = bounds.height - + state->margin.top + state->margin.bottom; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP && + state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + box.y = bounds.y + bounds.height/2 - box.height/2; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { + box.y = bounds.y + state->margin.top; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + box.y = bounds.y + bounds.height - box.height - state->margin.bottom; + } else { + box.y = bounds.y + bounds.height/2 - box.height/2; + } + + wlr_scene_node_set_position(scene_layer_surface->node, box.x, box.y); + wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); + + if (state->exclusive_zone > 0) { + layer_surface_exclusive_zone(state, usable_area); + } +} + +struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( + struct wlr_scene_node *parent, + struct wlr_layer_surface_v1 *layer_surface) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + calloc(1, sizeof(*scene_layer_surface)); + if (scene_layer_surface == NULL) { + return NULL; + } + + scene_layer_surface->layer_surface = layer_surface; + + struct wlr_scene_tree *tree = wlr_scene_tree_create(parent); + if (tree == NULL) { + free(scene_layer_surface); + return NULL; + } + scene_layer_surface->node = &tree->node; + + struct wlr_scene_node *surface_node = wlr_scene_subsurface_tree_create( + scene_layer_surface->node, layer_surface->surface); + if (surface_node == NULL) { + wlr_scene_node_destroy(scene_layer_surface->node); + free(scene_layer_surface); + return NULL; + } + + scene_layer_surface->tree_destroy.notify = + scene_layer_surface_handle_tree_destroy; + wl_signal_add(&scene_layer_surface->node->events.destroy, + &scene_layer_surface->tree_destroy); + + scene_layer_surface->layer_surface_destroy.notify = + scene_layer_surface_handle_layer_surface_destroy; + wl_signal_add(&layer_surface->events.destroy, + &scene_layer_surface->layer_surface_destroy); + + scene_layer_surface->layer_surface_map.notify = + scene_layer_surface_handle_layer_surface_map; + wl_signal_add(&layer_surface->events.map, + &scene_layer_surface->layer_surface_map); + + scene_layer_surface->layer_surface_unmap.notify = + scene_layer_surface_handle_layer_surface_unmap; + wl_signal_add(&layer_surface->events.unmap, + &scene_layer_surface->layer_surface_unmap); + + wlr_scene_node_set_enabled(scene_layer_surface->node, + layer_surface->mapped); + + return scene_layer_surface; +} From 9de992b9fef35ac6ee733740ed0763f4f2a279c8 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 27 Dec 2021 05:49:03 +0000 Subject: [PATCH 150/190] ext-session-lock-v1: new protocol implementation This implements the new ext-session-lock-v1 protocol [1]. [1]: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/131 --- include/wlr/types/wlr_session_lock_v1.h | 98 +++++ protocol/meson.build | 3 +- types/meson.build | 1 + types/wlr_session_lock_v1.c | 457 ++++++++++++++++++++++++ 4 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 include/wlr/types/wlr_session_lock_v1.h create mode 100644 types/wlr_session_lock_v1.c diff --git a/include/wlr/types/wlr_session_lock_v1.h b/include/wlr/types/wlr_session_lock_v1.h new file mode 100644 index 000000000..b410b9e56 --- /dev/null +++ b/include/wlr/types/wlr_session_lock_v1.h @@ -0,0 +1,98 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_SESSION_LOCK_H +#define WLR_TYPES_WLR_SESSION_LOCK_H + +#include +#include +#include + +struct wlr_session_lock_manager_v1 { + struct wl_global *global; + + struct { + struct wl_signal new_lock; // struct wlr_session_lock_v1 * + struct wl_signal destroy; + } events; + + void *data; + + // private state + + struct wl_listener display_destroy; +}; + +struct wlr_session_lock_v1 { + struct wl_resource *resource; + + struct wl_list surfaces; // struct wlr_session_lock_surface_v1::link + + struct { + struct wl_signal new_surface; // struct wlr_session_lock_surface_v1 * + struct wl_signal unlock; + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_session_lock_surface_v1_state { + uint32_t width, height; + uint32_t configure_serial; +}; + +struct wlr_session_lock_surface_v1_configure { + struct wl_list link; // wlr_session_lock_surface_v1::configure_list + uint32_t serial; + + uint32_t width, height; +}; + +struct wlr_session_lock_surface_v1 { + struct wl_resource *resource; + struct wl_list link; // wlr_session_lock_v1::surfaces + + struct wlr_output *output; + struct wlr_surface *surface; + + bool configured, mapped; + + struct wl_list configure_list; // wlr_session_lock_surface_v1_configure::link + + struct wlr_session_lock_surface_v1_state current; + struct wlr_session_lock_surface_v1_state pending; + + struct { + struct wl_signal map; + struct wl_signal destroy; + } events; + + void *data; + + // private state + + struct wl_listener output_destroy; + struct wl_listener surface_destroy; +}; + +struct wlr_session_lock_manager_v1 *wlr_session_lock_manager_v1_create( + struct wl_display *display); + +void wlr_session_lock_v1_send_locked(struct wlr_session_lock_v1 *lock); +void wlr_session_lock_v1_destroy(struct wlr_session_lock_v1 *lock); + +uint32_t wlr_session_lock_surface_v1_configure( + struct wlr_session_lock_surface_v1 *lock_surface, + uint32_t width, uint32_t height); + +bool wlr_surface_is_session_lock_surface_v1(struct wlr_surface *surface); +struct wlr_session_lock_surface_v1 *wlr_session_lock_surface_v1_from_wlr_surface( + struct wlr_surface *surface); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index ae2b2ef48..179c731dc 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,5 +1,5 @@ wayland_protos = dependency('wayland-protocols', - version: '>=1.24', + version: '>=1.25', fallback: 'wayland-protocols', default_options: ['tests=false'], ) @@ -20,6 +20,7 @@ protocols = { # Staging upstream protocols 'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', 'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', + 'ext-session-lock-v1': wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', # Unstable upstream protocols 'fullscreen-shell-unstable-v1': wl_protocol_dir / 'unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml', diff --git a/types/meson.build b/types/meson.build index 43e5875c0..199815a90 100644 --- a/types/meson.build +++ b/types/meson.build @@ -59,6 +59,7 @@ wlr_files += files( 'wlr_relative_pointer_v1.c', 'wlr_screencopy_v1.c', 'wlr_server_decoration.c', + 'wlr_session_lock_v1.c', 'wlr_subcompositor.c', 'wlr_switch.c', 'wlr_tablet_pad.c', diff --git a/types/wlr_session_lock_v1.c b/types/wlr_session_lock_v1.c new file mode 100644 index 000000000..ffba20614 --- /dev/null +++ b/types/wlr_session_lock_v1.c @@ -0,0 +1,457 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "util/signal.h" +#include "ext-session-lock-v1-protocol.h" + +#define SESSION_LOCK_VERSION 1 + +static void resource_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct ext_session_lock_manager_v1_interface lock_manager_implementation; +static const struct ext_session_lock_v1_interface lock_implementation; +static const struct ext_session_lock_surface_v1_interface lock_surface_implementation; + +static struct wlr_session_lock_manager_v1 *lock_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_session_lock_manager_v1_interface, &lock_manager_implementation)); + struct wlr_session_lock_manager_v1 *lock_manager = + wl_resource_get_user_data(resource); + assert(lock_manager != NULL); + return lock_manager; +} + +static struct wlr_session_lock_v1 *lock_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_session_lock_v1_interface, &lock_implementation)); + return wl_resource_get_user_data(resource); +} + +static struct wlr_session_lock_surface_v1 *lock_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_session_lock_surface_v1_interface, &lock_surface_implementation)); + return wl_resource_get_user_data(resource); +} + +static const struct wlr_surface_role lock_surface_role; + +bool wlr_surface_is_session_lock_surface_v1(struct wlr_surface *surface) { + return surface->role == &lock_surface_role; +} + +struct wlr_session_lock_surface_v1 *wlr_session_lock_surface_v1_from_wlr_surface( + struct wlr_surface *surface) { + assert(wlr_surface_is_session_lock_surface_v1(surface)); + return (struct wlr_session_lock_surface_v1 *)surface->role_data; +} + +uint32_t wlr_session_lock_surface_v1_configure( + struct wlr_session_lock_surface_v1 *lock_surface, + uint32_t width, uint32_t height) { + struct wlr_session_lock_surface_v1_configure *configure = + calloc(1, sizeof(struct wlr_session_lock_surface_v1_configure)); + if (configure == NULL) { + wl_resource_post_no_memory(lock_surface->resource); + return lock_surface->pending.configure_serial; + } + + struct wl_display *display = + wl_client_get_display(wl_resource_get_client(lock_surface->resource)); + + configure->width = width; + configure->height = height; + configure->serial = wl_display_next_serial(display); + + wl_list_insert(lock_surface->configure_list.prev, &configure->link); + + ext_session_lock_surface_v1_send_configure(lock_surface->resource, + configure->serial, configure->width, configure->height); + + return configure->serial; +} + +static void lock_surface_handle_ack_configure(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_session_lock_surface_v1 *lock_surface = + lock_surface_from_resource(resource); + if (lock_surface == NULL) { + return; + } + + // First find the ack'ed configure + bool found = false; + struct wlr_session_lock_surface_v1_configure *configure, *tmp; + wl_list_for_each(configure, &lock_surface->configure_list, link) { + if (configure->serial == serial) { + found = true; + break; + } + } + if (!found) { + wl_resource_post_error(resource, + EXT_SESSION_LOCK_SURFACE_V1_ERROR_INVALID_SERIAL, + "ack_configure serial %" PRIu32 + " does not match any configure serial", serial); + return; + } + // Then remove old configures from the list + wl_list_for_each_safe(configure, tmp, &lock_surface->configure_list, link) { + if (configure->serial == serial) { + break; + } + wl_list_remove(&configure->link); + free(configure); + } + + lock_surface->pending.configure_serial = configure->serial; + lock_surface->pending.width = configure->width; + lock_surface->pending.height = configure->height; + + lock_surface->configured = true; + + wl_list_remove(&configure->link); + free(configure); +} + + +static const struct ext_session_lock_surface_v1_interface lock_surface_implementation = { + .destroy = resource_handle_destroy, + .ack_configure = lock_surface_handle_ack_configure, +}; + +static void lock_surface_role_commit(struct wlr_surface *surface) { + struct wlr_session_lock_surface_v1 *lock_surface = + wlr_session_lock_surface_v1_from_wlr_surface(surface); + if (lock_surface == NULL) { + return; + } + + if (!lock_surface->configured) { + wl_resource_post_error(lock_surface->resource, + EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, + "session lock surface has never been configured"); + return; + } + + if (surface->current.width < 0 || surface->current.height < 0 || + (uint32_t)surface->current.width != lock_surface->pending.width || + (uint32_t)surface->current.height != lock_surface->pending.height) { + wl_resource_post_error(lock_surface->resource, + EXT_SESSION_LOCK_SURFACE_V1_ERROR_DIMENSIONS_MISMATCH, + "committed surface dimensions do not match last acked configure"); + return; + } + + lock_surface->current = lock_surface->pending; + + if (!lock_surface->mapped) { + lock_surface->mapped = true; + wlr_signal_emit_safe(&lock_surface->events.map, NULL); + } +} + +static void lock_surface_role_precommit(struct wlr_surface *surface, + const struct wlr_surface_state *state) { + struct wlr_session_lock_surface_v1 *lock_surface = + wlr_session_lock_surface_v1_from_wlr_surface(surface); + if (lock_surface == NULL) { + return; + } + + if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { + wl_resource_post_error(lock_surface->resource, + EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, + "session lock surfaces committed with null buffer"); + return; + } +} + +static const struct wlr_surface_role lock_surface_role = { + .name = "ext_session_lock_surface_v1", + .commit = lock_surface_role_commit, + .precommit = lock_surface_role_precommit, +}; + +static void lock_surface_destroy( + struct wlr_session_lock_surface_v1 *lock_surface) { + wlr_signal_emit_safe(&lock_surface->events.destroy, NULL); + + wl_list_remove(&lock_surface->link); + + struct wlr_session_lock_surface_v1_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &lock_surface->configure_list, link) { + wl_list_remove(&configure->link); + free(configure); + } + + assert(wl_list_empty(&lock_surface->events.map.listener_list)); + assert(wl_list_empty(&lock_surface->events.destroy.listener_list)); + + wl_list_remove(&lock_surface->output_destroy.link); + wl_list_remove(&lock_surface->surface_destroy.link); + + lock_surface->surface->role_data = NULL; + wl_resource_set_user_data(lock_surface->resource, NULL); + free(lock_surface); +} + +static void lock_surface_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_session_lock_surface_v1 *lock_surface = + wl_container_of(listener, lock_surface, output_destroy); + lock_surface_destroy(lock_surface); +} + +static void lock_surface_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_session_lock_surface_v1 *lock_surface = + wl_container_of(listener, lock_surface, surface_destroy); + lock_surface_destroy(lock_surface); +} + +static void lock_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_session_lock_surface_v1 *lock_surface = + lock_surface_from_resource(resource); + if (lock_surface != NULL) { + lock_surface_destroy(lock_surface); + } +} + +static void lock_handle_get_lock_surface(struct wl_client *client, + struct wl_resource *lock_resource, uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *output_resource) { + // We always need to create a lock surface resource to stay in sync + // with the client, even if the lock resource or output resource is + // inert. For example, if the compositor denies the lock and immediately + // calls wlr_session_lock_v1_destroy() the client may have already sent + // get_lock_surface requests. + struct wl_resource *lock_surface_resource = wl_resource_create( + client, &ext_session_lock_surface_v1_interface, + wl_resource_get_version(lock_resource), id); + if (lock_surface_resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + // Leave the lock surface resource inert for now, we will set the + // user data at the end of this function if everything is successful. + wl_resource_set_implementation(lock_surface_resource, + &lock_surface_implementation, NULL, + lock_surface_resource_destroy); + + struct wlr_session_lock_v1 *lock = lock_from_resource(lock_resource); + if (lock == NULL) { + return; + } + + struct wlr_output *output = wlr_output_from_resource(output_resource); + if (output == NULL) { + return; + } + + struct wlr_session_lock_surface_v1 *other; + wl_list_for_each(other, &lock->surfaces, link) { + if (other->output == output) { + wl_resource_post_error(lock_resource, + EXT_SESSION_LOCK_V1_ERROR_DUPLICATE_OUTPUT, + "session lock surface already created for the given output"); + return; + } + } + + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + + if (wlr_surface_has_buffer(surface)) { + wl_resource_post_error(lock_resource, + EXT_SESSION_LOCK_V1_ERROR_ALREADY_CONSTRUCTED, + "surface already has a buffer attached"); + return; + } + + struct wlr_session_lock_surface_v1 *lock_surface = + calloc(1, sizeof(struct wlr_session_lock_surface_v1)); + if (lock_surface == NULL) { + wl_client_post_no_memory(client); + return; + } + + if (!wlr_surface_set_role(surface, &lock_surface_role, lock_surface, + lock_resource, EXT_SESSION_LOCK_V1_ERROR_ROLE)) { + free(lock_surface); + return; + } + + lock_surface->resource = lock_surface_resource; + wl_resource_set_user_data(lock_surface_resource, lock_surface); + + wl_list_insert(&lock->surfaces, &lock_surface->link); + + lock_surface->output = output; + lock_surface->surface = surface; + + wl_list_init(&lock_surface->configure_list); + + wl_signal_init(&lock_surface->events.map); + wl_signal_init(&lock_surface->events.destroy); + + wl_signal_add(&output->events.destroy, &lock_surface->output_destroy); + lock_surface->output_destroy.notify = lock_surface_handle_output_destroy; + + wl_signal_add(&surface->events.destroy, &lock_surface->surface_destroy); + lock_surface->surface_destroy.notify = lock_surface_handle_surface_destroy; + + wlr_signal_emit_safe(&lock->events.new_surface, lock_surface); +} + +static void lock_handle_unlock_and_destroy(struct wl_client *client, + struct wl_resource *lock_resource) { + struct wlr_session_lock_v1 *lock = lock_from_resource(lock_resource); + if (lock == NULL) { + return; + } + + wlr_signal_emit_safe(&lock->events.unlock, NULL); + + wl_resource_destroy(lock_resource); +} + +static const struct ext_session_lock_v1_interface lock_implementation = { + .destroy = resource_handle_destroy, + .get_lock_surface = lock_handle_get_lock_surface, + .unlock_and_destroy = lock_handle_unlock_and_destroy, +}; + +void wlr_session_lock_v1_send_locked(struct wlr_session_lock_v1 *lock) { + ext_session_lock_v1_send_locked(lock->resource); +} + +static void lock_destroy(struct wlr_session_lock_v1 *lock) { + struct wlr_session_lock_surface_v1 *lock_surface, *tmp; + wl_list_for_each_safe(lock_surface, tmp, &lock->surfaces, link) { + lock_surface_destroy(lock_surface); + } + assert(wl_list_empty(&lock->surfaces)); + + wlr_signal_emit_safe(&lock->events.destroy, NULL); + + assert(wl_list_empty(&lock->events.new_surface.listener_list)); + assert(wl_list_empty(&lock->events.unlock.listener_list)); + assert(wl_list_empty(&lock->events.destroy.listener_list)); + + wl_resource_set_user_data(lock->resource, NULL); + free(lock); +} + +void wlr_session_lock_v1_destroy(struct wlr_session_lock_v1 *lock) { + ext_session_lock_v1_send_finished(lock->resource); + lock_destroy(lock); +} + +static void lock_resource_destroy(struct wl_resource *lock_resource) { + struct wlr_session_lock_v1 *lock = lock_from_resource(lock_resource); + if (lock != NULL) { + lock_destroy(lock); + } +} + +static void lock_manager_handle_lock(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id) { + struct wlr_session_lock_manager_v1 *lock_manager = + lock_manager_from_resource(manager_resource); + + struct wlr_session_lock_v1 *lock = + calloc(1, sizeof(struct wlr_session_lock_v1)); + if (lock == NULL) { + wl_client_post_no_memory(client); + return; + } + + lock->resource = wl_resource_create(client, &ext_session_lock_v1_interface, + wl_resource_get_version(manager_resource), id); + if (lock->resource == NULL) { + free(lock); + wl_client_post_no_memory(client); + return; + } + + wl_list_init(&lock->surfaces); + + wl_signal_init(&lock->events.new_surface); + wl_signal_init(&lock->events.unlock); + wl_signal_init(&lock->events.destroy); + + wl_resource_set_implementation(lock->resource, &lock_implementation, + lock, lock_resource_destroy); + + wlr_signal_emit_safe(&lock_manager->events.new_lock, lock); +} + +static const struct ext_session_lock_manager_v1_interface lock_manager_implementation = { + .destroy = resource_handle_destroy, + .lock = lock_manager_handle_lock, +}; + +static void lock_manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_session_lock_manager_v1 *lock_manager = data; + + struct wl_resource *resource = wl_resource_create( + client, &ext_session_lock_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &lock_manager_implementation, + lock_manager, NULL); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_session_lock_manager_v1 *lock_manager = + wl_container_of(listener, lock_manager, display_destroy); + wlr_signal_emit_safe(&lock_manager->events.destroy, NULL); + wl_list_remove(&lock_manager->display_destroy.link); + + wl_global_destroy(lock_manager->global); + + assert(wl_list_empty(&lock_manager->events.new_lock.listener_list)); + assert(wl_list_empty(&lock_manager->events.destroy.listener_list)); + + free(lock_manager); +} + +struct wlr_session_lock_manager_v1 *wlr_session_lock_manager_v1_create(struct wl_display *display) { + struct wlr_session_lock_manager_v1 *lock_manager = + calloc(1, sizeof(struct wlr_session_lock_manager_v1)); + if (lock_manager == NULL) { + return NULL; + } + + struct wl_global *global = wl_global_create(display, + &ext_session_lock_manager_v1_interface, SESSION_LOCK_VERSION, + lock_manager, lock_manager_bind); + if (global == NULL) { + free(lock_manager); + return NULL; + } + lock_manager->global = global; + + wl_signal_init(&lock_manager->events.new_lock); + wl_signal_init(&lock_manager->events.destroy); + + lock_manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &lock_manager->display_destroy); + + return lock_manager; +} From cddc1c1bd9f796709c50f4bbb300788edd42fd4f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 20 Jan 2022 09:39:13 -0500 Subject: [PATCH 151/190] xdg-foreign: Fix crash on destroy of degenerate surface I am running a custom compiled version of chromium with a patch to get it up and running on sway git at the moment, and in that development build I compiled there is a bug where the browser will crash if you try to open a file select dialog. When this crash happens, chromium will not close, but instead will remain open and impossible to close unless you send a SIGKILL signal to the process. However, sway will crash to tty when you send the SIGKILL. I have a hunch that when chromium is opening the file select dialog it is creating some sort of a xdg toplevel surface. But it freezes before it fully initializes the surface. When the SIGKILL signal is given, sway/wlroots will try to free the xdg_toplevel surface but because it hasn't fully initialized due to the frozen window, it segfaults. Don't be fooled by the assert, the assert is not firing, the surface pointer is indeed NULL here. * thread #1, name = 'sway', stop reason = signal SIGSEGV: invalid address (fault address: 0x28) frame #0: 0x00007ffff78b9041 libwlroots.so.11`wlr_xdg_toplevel_set_parent(surface=0x0000000000000000, parent=0x0000000000000000) at wlr_xdg_toplevel.c:159:37 156 157 void wlr_xdg_toplevel_set_parent(struct wlr_xdg_surface *surface, 158 struct wlr_xdg_surface *parent) { -> 159 assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); 160 assert(!parent || parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); 161 162 if (surface->toplevel->parent) { (lldb) up error: sway {0x0003442a}: DIE has DW_AT_ranges(DW_FORM_sec_offset 0x67) attribute, but range extraction failed (invalid range list offset 0x67), please file a bug and attach the file at the start of this error message error: sway {0x0003442a}: DIE has DW_AT_ranges(DW_FORM_sec_offset 0x67) attribute, but range extraction failed (invalid range list offset 0x67), please file a bug and attach the file at the start of this error message frame #1: 0x00007ffff78e176e libwlroots.so.11`destroy_imported(imported=0x000055555626d570) at wlr_xdg_foreign_v1.c:154:3 151 wl_list_for_each_safe(child, child_tmp, &imported->children, link) { 152 struct wlr_xdg_surface *xdg_child = 153 wlr_xdg_surface_from_wlr_surface(child->surface); -> 154 wlr_xdg_toplevel_set_parent(xdg_child, NULL); 155 } 156 157 wl_list_remove(&imported->exported_destroyed.link); (lldb) up frame #2: 0x00007ffff78e1b9d libwlroots.so.11`xdg_imported_handle_resource_destroy(resource=0x00005555562555a0) at wlr_xdg_foreign_v1.c:280:2 277 struct wl_resource *resource) { 278 struct wlr_xdg_imported_v1 *imported = xdg_imported_from_resource(resource); 279 if (!imported) { -> 280 return; 281 } 282 283 destroy_imported(imported); (lldb) up frame #3: 0x00007ffff794989a libwayland-server.so.0`___lldb_unnamed_symbol211 + 154 libwayland-server.so.0`___lldb_unnamed_symbol211: -> 0x7ffff794989a <+154>: andl $0x1, %r13d 0x7ffff794989e <+158>: je 0x7ffff79498b0 ; <+176> 0x7ffff79498a0 <+160>: addq $0x8, %rsp 0x7ffff79498a4 <+164>: movl $0x1, %eax (lldb) up frame #4: 0x00007ffff794fec0 libwayland-server.so.0`___lldb_unnamed_symbol290 + 64 libwayland-server.so.0`___lldb_unnamed_symbol290: -> 0x7ffff794fec0 <+64>: cmpl $0x1, %eax 0x7ffff794fec3 <+67>: jne 0x7ffff794fed3 ; <+83> 0x7ffff794fec5 <+69>: addq $0x8, %rbx 0x7ffff794fec9 <+73>: cmpq %rbx, %r13 (lldb) up frame #5: 0x00007ffff79503e0 libwayland-server.so.0`___lldb_unnamed_symbol300 + 32 libwayland-server.so.0`___lldb_unnamed_symbol300: -> 0x7ffff79503e0 <+32>: cmpl $0x1, %eax 0x7ffff79503e3 <+35>: je 0x7ffff79503f0 ; <+48> 0x7ffff79503e5 <+37>: popq %rbx 0x7ffff79503e6 <+38>: popq %r12 (lldb) up frame #6: 0x00007ffff794a30e libwayland-server.so.0`wl_client_destroy + 126 libwayland-server.so.0`wl_client_destroy: -> 0x7ffff794a30e <+126>: movq %r12, %rdi 0x7ffff794a311 <+129>: callq 0x7ffff7950150 ; ___lldb_unnamed_symbol293 0x7ffff794a317 <+135>: movq 0x8(%rbp), %rdi 0x7ffff794a31b <+139>: callq *0xdc77(%rip) (lldb) up frame #7: 0x00007ffff794a3f7 libwayland-server.so.0`___lldb_unnamed_symbol214 + 119 libwayland-server.so.0`___lldb_unnamed_symbol214: -> 0x7ffff794a3f7 <+119>: movq 0x28(%rsp), %rax 0x7ffff794a3fc <+124>: subq %fs:0x28, %rax 0x7ffff794a405 <+133>: jne 0x7ffff794a727 ; <+935> 0x7ffff794a40b <+139>: addq $0x38, %rsp (lldb) up frame #8: 0x00007ffff794d1ca libwayland-server.so.0`wl_event_loop_dispatch + 202 libwayland-server.so.0`wl_event_loop_dispatch: -> 0x7ffff794d1ca <+202>: addq $0xc, %r15 0x7ffff794d1ce <+206>: cmpq %r15, %rbp 0x7ffff794d1d1 <+209>: jne 0x7ffff794d1b8 ; <+184> 0x7ffff794d1d3 <+211>: movq 0x8(%rsp), %rcx (lldb) up frame #9: 0x00007ffff794ad37 libwayland-server.so.0`wl_display_run + 39 libwayland-server.so.0`wl_display_run: -> 0x7ffff794ad37 <+39>: movl 0x8(%rbx), %eax 0x7ffff794ad3a <+42>: testl %eax, %eax 0x7ffff794ad3c <+44>: jne 0x7ffff794ad20 ; <+16> 0x7ffff794ad3e <+46>: popq %rbx (lldb) up frame #10: 0x000055555557689a sway`server_run(server=0x00005555555f26c0) at server.c:307:2 304 wlr_backend_destroy(server->backend); 305 return false; 306 } -> 307 308 return true; 309 } 310 (lldb) up frame #11: 0x0000555555575a93 sway`main(argc=3, argv=0x00007fffffffe978) at main.c:431:2 428 swaynag_show(&config->swaynag_config_errors); 429 } 430 -> 431 server_run(&server); 432 433 shutdown: 434 sway_log(SWAY_INFO, "Shutting down sway"); --- types/wlr_xdg_foreign_v1.c | 7 +++++-- types/wlr_xdg_foreign_v2.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/types/wlr_xdg_foreign_v1.c b/types/wlr_xdg_foreign_v1.c index 49216e684..bb7475174 100644 --- a/types/wlr_xdg_foreign_v1.c +++ b/types/wlr_xdg_foreign_v1.c @@ -33,7 +33,7 @@ static bool verify_is_toplevel(struct wl_resource *client_resource, if (wlr_surface_is_xdg_surface(surface)) { struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + if (xdg_surface == NULL || xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { wl_resource_post_error(client_resource, -1, "surface must be an xdg_toplevel"); return false; @@ -151,7 +151,10 @@ static void destroy_imported(struct wlr_xdg_imported_v1 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + + if (xdg_child != NULL) { + wlr_xdg_toplevel_set_parent(xdg_child, NULL); + } } wl_list_remove(&imported->exported_destroyed.link); diff --git a/types/wlr_xdg_foreign_v2.c b/types/wlr_xdg_foreign_v2.c index c9ef54966..7f7bff068 100644 --- a/types/wlr_xdg_foreign_v2.c +++ b/types/wlr_xdg_foreign_v2.c @@ -42,7 +42,7 @@ static bool verify_is_toplevel(struct wl_resource *client_resource, struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + if (xdg_surface == NULL || xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { wl_resource_post_error(client_resource, ZXDG_EXPORTER_V2_ERROR_INVALID_SURFACE, "surface must be an xdg_toplevel"); @@ -157,7 +157,10 @@ static void destroy_imported(struct wlr_xdg_imported_v2 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + + if (xdg_child != NULL) { + wlr_xdg_toplevel_set_parent(xdg_child, NULL); + } } wl_list_remove(&imported->exported_destroyed.link); From 05dd990e432436523ff8f2572c41e0d0e648d3a6 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:49 +0300 Subject: [PATCH 152/190] xdg-shell: rename surface role handlers --- include/types/wlr_xdg_shell.h | 4 ++-- types/xdg_shell/wlr_xdg_popup.c | 4 ++-- types/xdg_shell/wlr_xdg_surface.c | 4 ++-- types/xdg_shell/wlr_xdg_toplevel.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 8b2c66cc2..d8905bcff 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -19,8 +19,8 @@ struct wlr_xdg_surface *create_xdg_surface( void unmap_xdg_surface(struct wlr_xdg_surface *surface); void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface); void destroy_xdg_surface(struct wlr_xdg_surface *surface); -void handle_xdg_surface_commit(struct wlr_surface *wlr_surface); -void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface, +void xdg_surface_role_commit(struct wlr_surface *wlr_surface); +void xdg_surface_role_precommit(struct wlr_surface *wlr_surface, const struct wlr_surface_state *state); void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 3718ef749..c8d76ee1b 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -293,8 +293,8 @@ static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_popup_surface_role = { .name = "xdg_popup", - .commit = handle_xdg_surface_commit, - .precommit = handle_xdg_surface_precommit, + .commit = xdg_surface_role_commit, + .precommit = xdg_surface_role_precommit, }; void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index d54c058e0..62251d53f 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -305,7 +305,7 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, } } -void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { +void xdg_surface_role_commit(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface *surface = wlr_xdg_surface_from_wlr_surface(wlr_surface); if (surface == NULL) { @@ -338,7 +338,7 @@ void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { } } -void handle_xdg_surface_precommit(struct wlr_surface *wlr_surface, +void xdg_surface_role_precommit(struct wlr_surface *wlr_surface, const struct wlr_surface_state *state) { struct wlr_xdg_surface *surface = wlr_xdg_surface_from_wlr_surface(wlr_surface); diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index b5a7239b0..47a324d22 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -443,8 +443,8 @@ static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { const struct wlr_surface_role xdg_toplevel_surface_role = { .name = "xdg_toplevel", - .commit = handle_xdg_surface_commit, - .precommit = handle_xdg_surface_precommit, + .commit = xdg_surface_role_commit, + .precommit = xdg_surface_role_precommit, }; void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, From ee52c32915e20821c985c3b36498701e47c636a3 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:51 +0300 Subject: [PATCH 153/190] xdg-shell: fix create_xdg_popup() param type --- include/types/wlr_xdg_shell.h | 2 +- types/xdg_shell/wlr_xdg_popup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index d8905bcff..9a34c49c1 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -29,7 +29,7 @@ struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, struct wlr_xdg_surface *parent, - struct wlr_xdg_positioner_resource *positioner, int32_t id); + struct wlr_xdg_positioner_resource *positioner, uint32_t id); void handle_xdg_surface_popup_committed(struct wlr_xdg_surface *surface); struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index c8d76ee1b..de1987c9e 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -299,7 +299,7 @@ const struct wlr_surface_role xdg_popup_surface_role = { void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, struct wlr_xdg_surface *parent, - struct wlr_xdg_positioner_resource *positioner, int32_t id) { + struct wlr_xdg_positioner_resource *positioner, uint32_t id) { if (positioner->attrs.size.width == 0 || positioner->attrs.anchor_rect.width == 0) { wl_resource_post_error(xdg_surface->resource, From affe0d8713a7070844ed4d7558d02785e60ffd10 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:51 +0300 Subject: [PATCH 154/190] xdg-toplevel: fix functions' main argument type With this commit, `wlr_xdg_toplevel_*()` functions now expect a `wlr_xdg_toplevel` instead of a `wlr_xdg_surface`. --- include/types/wlr_xdg_shell.h | 12 +- include/wlr/types/wlr_xdg_shell.h | 38 ++-- tinywl/tinywl.c | 25 +-- types/wlr_xdg_decoration_v1.c | 21 +- types/wlr_xdg_foreign_v1.c | 4 +- types/wlr_xdg_foreign_v2.c | 4 +- types/xdg_shell/wlr_xdg_surface.c | 14 +- types/xdg_shell/wlr_xdg_toplevel.c | 320 ++++++++++++++--------------- 8 files changed, 212 insertions(+), 226 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 9a34c49c1..e3688a94b 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -36,11 +36,11 @@ struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, uint32_t id); -void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface); -void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, - struct wlr_xdg_surface_configure *configure); -void handle_xdg_toplevel_ack_configure(struct wlr_xdg_surface *surface, - struct wlr_xdg_surface_configure *configure); -void destroy_xdg_toplevel(struct wlr_xdg_surface *surface); +void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel); +struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( + struct wlr_xdg_toplevel *toplevel); +void handle_xdg_toplevel_ack_configure(struct wlr_xdg_toplevel *toplevel, + struct wlr_xdg_toplevel_configure *configure); +void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel); #endif diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 8d1a6fce6..e16d3218f 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -258,7 +258,7 @@ struct wlr_xdg_toplevel_show_window_menu_event { struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); -/** Returns the wlr_xdg_surface from an xdg_surface resource. +/** Get the corresponding wlr_xdg_surface from a resource. * * Aborts if the resource doesn't have the correct type. Returns NULL if the * resource is inert. @@ -267,7 +267,13 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wl_resource *resource); struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( struct wl_resource *resource); -struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( + +/** Get the corresponding wlr_xdg_toplevel from a resource. + * + * Aborts if the resource doesn't have the correct type. Returns NULL if the + * resource is inert. + */ +struct wlr_xdg_toplevel *wlr_xdg_toplevel_from_resource( struct wl_resource *resource); /** @@ -280,55 +286,55 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface); * Request that this toplevel surface be the given size. Returns the associated * configure serial. */ -uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_toplevel *toplevel, uint32_t width, uint32_t height); /** - * Request that this toplevel surface show itself in an activated or deactivated + * Request that this toplevel show itself in an activated or deactivated * state. Returns the associated configure serial. */ -uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_toplevel *toplevel, bool activated); /** - * Request that this toplevel surface consider itself maximized or not + * Request that this toplevel consider itself maximized or not * maximized. Returns the associated configure serial. */ -uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_toplevel *toplevel, bool maximized); /** - * Request that this toplevel surface consider itself fullscreen or not + * Request that this toplevel consider itself fullscreen or not * fullscreen. Returns the associated configure serial. */ -uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_toplevel *toplevel, bool fullscreen); /** - * Request that this toplevel surface consider itself to be resizing or not + * Request that this toplevel consider itself to be resizing or not * resizing. Returns the associated configure serial. */ -uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_toplevel *toplevel, bool resizing); /** - * Request that this toplevel surface consider itself in a tiled layout and some + * Request that this toplevel consider itself in a tiled layout and some * edges are adjacent to another part of the tiling grid. `tiled_edges` is a * bitfield of `enum wlr_edges`. Returns the associated configure serial. */ -uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_toplevel *toplevel, uint32_t tiled_edges); /** * Request that this xdg toplevel closes. */ -void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); +void wlr_xdg_toplevel_send_close(struct wlr_xdg_toplevel *toplevel); /** * Sets the parent of this toplevel. Parent can be NULL. */ -void wlr_xdg_toplevel_set_parent(struct wlr_xdg_surface *surface, - struct wlr_xdg_surface *parent); +void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, + struct wlr_xdg_toplevel *parent); /** * Request that this xdg popup closes. diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 6f628836c..a4fcc2626 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -78,7 +78,7 @@ struct tinywl_output { struct tinywl_view { struct wl_list link; struct tinywl_server *server; - struct wlr_xdg_surface *xdg_surface; + struct wlr_xdg_toplevel *xdg_toplevel; struct wlr_scene_node *scene_node; struct wl_listener map; struct wl_listener unmap; @@ -117,7 +117,8 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { */ struct wlr_xdg_surface *previous = wlr_xdg_surface_from_wlr_surface( seat->keyboard_state.focused_surface); - wlr_xdg_toplevel_set_activated(previous, false); + assert(previous->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + wlr_xdg_toplevel_set_activated(previous->toplevel, false); } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); /* Move the view to the front */ @@ -125,13 +126,13 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { wl_list_remove(&view->link); wl_list_insert(&server->views, &view->link); /* Activate the new surface */ - wlr_xdg_toplevel_set_activated(view->xdg_surface, true); + wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true); /* * Tell the seat to have the keyboard enter this surface. wlroots will keep * track of this and automatically send key events to the appropriate * clients without additional work on your part. */ - wlr_seat_keyboard_notify_enter(seat, view->xdg_surface->surface, + wlr_seat_keyboard_notify_enter(seat, view->xdg_toplevel->base->surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); } @@ -172,7 +173,7 @@ static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) { } struct tinywl_view *next_view = wl_container_of( server->views.prev, next_view, link); - focus_view(next_view, next_view->xdg_surface->surface); + focus_view(next_view, next_view->xdg_toplevel->base->surface); break; default: return false; @@ -381,14 +382,14 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { } struct wlr_box geo_box; - wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box); view->x = new_left - geo_box.x; view->y = new_top - geo_box.y; wlr_scene_node_set_position(view->scene_node, view->x, view->y); int new_width = new_right - new_left; int new_height = new_bottom - new_top; - wlr_xdg_toplevel_set_size(view->xdg_surface, new_width, new_height); + wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height); } static void process_cursor_motion(struct tinywl_server *server, uint32_t time) { @@ -581,7 +582,7 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data) { wl_list_insert(&view->server->views, &view->link); - focus_view(view, view->xdg_surface->surface); + focus_view(view, view->xdg_toplevel->base->surface); } static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) { @@ -612,7 +613,7 @@ static void begin_interactive(struct tinywl_view *view, struct tinywl_server *server = view->server; struct wlr_surface *focused_surface = server->seat->pointer_state.focused_surface; - if (view->xdg_surface->surface != + if (view->xdg_toplevel->base->surface != wlr_surface_get_root_surface(focused_surface)) { /* Deny move/resize requests from unfocused clients. */ return; @@ -625,7 +626,7 @@ static void begin_interactive(struct tinywl_view *view, server->grab_y = server->cursor->y - view->y; } else { struct wlr_box geo_box; - wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box); double border_x = (view->x + geo_box.x) + ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); @@ -691,9 +692,9 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { struct tinywl_view *view = calloc(1, sizeof(struct tinywl_view)); view->server = server; - view->xdg_surface = xdg_surface; + view->xdg_toplevel = xdg_surface->toplevel; view->scene_node = wlr_scene_xdg_surface_create( - &view->server->scene->node, view->xdg_surface); + &view->server->scene->node, view->xdg_toplevel->base); view->scene_node->data = view; xdg_surface->data = view->scene_node; diff --git a/types/wlr_xdg_decoration_v1.c b/types/wlr_xdg_decoration_v1.c index b6dd003ef..d0f969f45 100644 --- a/types/wlr_xdg_decoration_v1.c +++ b/types/wlr_xdg_decoration_v1.c @@ -173,11 +173,10 @@ static void decoration_manager_handle_get_toplevel_decoration( uint32_t id, struct wl_resource *toplevel_resource) { struct wlr_xdg_decoration_manager_v1 *manager = decoration_manager_from_resource(manager_resource); - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(toplevel_resource); - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(toplevel_resource); - if (wlr_surface_has_buffer(surface->surface)) { + if (wlr_surface_has_buffer(toplevel->base->surface)) { wl_resource_post_error(manager_resource, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER, "xdg_toplevel_decoration must not have a buffer at creation"); @@ -191,7 +190,7 @@ static void decoration_manager_handle_get_toplevel_decoration( return; } decoration->manager = manager; - decoration->surface = surface; + decoration->surface = toplevel->base; uint32_t version = wl_resource_get_version(manager_resource); decoration->resource = wl_resource_create(client, @@ -212,24 +211,26 @@ static void decoration_manager_handle_get_toplevel_decoration( wl_signal_init(&decoration->events.destroy); wl_signal_init(&decoration->events.request_mode); - wl_signal_add(&surface->events.destroy, &decoration->surface_destroy); + wl_signal_add(&toplevel->base->events.destroy, + &decoration->surface_destroy); decoration->surface_destroy.notify = toplevel_decoration_handle_surface_destroy; - wl_signal_add(&surface->events.configure, &decoration->surface_configure); + wl_signal_add(&toplevel->base->events.configure, + &decoration->surface_configure); decoration->surface_configure.notify = toplevel_decoration_handle_surface_configure; - wl_signal_add(&surface->events.ack_configure, + wl_signal_add(&toplevel->base->events.ack_configure, &decoration->surface_ack_configure); decoration->surface_ack_configure.notify = toplevel_decoration_handle_surface_ack_configure; - wl_signal_add(&surface->surface->events.commit, + wl_signal_add(&toplevel->base->surface->events.commit, &decoration->surface_commit); decoration->surface_commit.notify = toplevel_decoration_handle_surface_commit; wl_list_insert(&manager->decorations, &decoration->link); - if (surface->added) { + if (toplevel->base->added) { decoration->added = true; wlr_signal_emit_safe(&manager->events.new_toplevel_decoration, decoration); diff --git a/types/wlr_xdg_foreign_v1.c b/types/wlr_xdg_foreign_v1.c index bb7475174..c07959aaf 100644 --- a/types/wlr_xdg_foreign_v1.c +++ b/types/wlr_xdg_foreign_v1.c @@ -103,7 +103,7 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, struct wlr_xdg_surface *surface_child = wlr_xdg_surface_from_wlr_surface(wlr_surface_child); - wlr_xdg_toplevel_set_parent(surface_child, surface); + wlr_xdg_toplevel_set_parent(surface_child->toplevel, surface->toplevel); wl_signal_add(&surface_child->events.unmap, &child->xdg_surface_unmap); wl_signal_add(&surface_child->toplevel->events.set_parent, @@ -153,7 +153,7 @@ static void destroy_imported(struct wlr_xdg_imported_v1 *imported) { wlr_xdg_surface_from_wlr_surface(child->surface); if (xdg_child != NULL) { - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); } } diff --git a/types/wlr_xdg_foreign_v2.c b/types/wlr_xdg_foreign_v2.c index 7f7bff068..abd997352 100644 --- a/types/wlr_xdg_foreign_v2.c +++ b/types/wlr_xdg_foreign_v2.c @@ -109,7 +109,7 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, struct wlr_xdg_surface *surface_child = wlr_xdg_surface_from_wlr_surface(wlr_surface_child); - wlr_xdg_toplevel_set_parent(surface_child, surface); + wlr_xdg_toplevel_set_parent(surface_child->toplevel, surface->toplevel); wl_signal_add(&surface_child->events.unmap, &child->xdg_surface_unmap); wl_signal_add(&surface_child->toplevel->events.set_parent, @@ -159,7 +159,7 @@ static void destroy_imported(struct wlr_xdg_imported_v2 *imported) { wlr_xdg_surface_from_wlr_surface(child->surface); if (xdg_child != NULL) { - wlr_xdg_toplevel_set_parent(xdg_child, NULL); + wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); } } diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 62251d53f..3315456d9 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -130,7 +130,8 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, assert(0 && "not reached"); break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - handle_xdg_toplevel_ack_configure(surface, configure); + handle_xdg_toplevel_ack_configure(surface->toplevel, + configure->toplevel_configure); break; case WLR_XDG_SURFACE_ROLE_POPUP: break; @@ -164,7 +165,8 @@ static void surface_send_configure(void *user_data) { assert(0 && "not reached"); break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - send_xdg_toplevel_configure(surface, configure); + configure->toplevel_configure = + send_xdg_toplevel_configure(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: xdg_popup_send_configure(surface->popup->resource, @@ -319,7 +321,7 @@ void xdg_surface_role_commit(struct wlr_surface *wlr_surface) { // inert toplevel or popup return; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - handle_xdg_surface_toplevel_committed(surface); + handle_xdg_toplevel_committed(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: handle_xdg_surface_popup_committed(surface); @@ -493,12 +495,6 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { surface->client->ping_serial); } -void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { - assert(surface->toplevel); - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - xdg_toplevel_send_close(surface->toplevel->resource); -} - void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface) { if (surface == NULL) { return; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 47a324d22..d88e66598 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -8,38 +8,32 @@ #include "util/signal.h" void handle_xdg_toplevel_ack_configure( - struct wlr_xdg_surface *surface, - struct wlr_xdg_surface_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + struct wlr_xdg_toplevel *toplevel, + struct wlr_xdg_toplevel_configure *configure) { + toplevel->pending.maximized = configure->maximized; + toplevel->pending.fullscreen = configure->fullscreen; + toplevel->pending.resizing = configure->resizing; + toplevel->pending.activated = configure->activated; + toplevel->pending.tiled = configure->tiled; - struct wlr_xdg_toplevel_configure *acked = configure->toplevel_configure; - assert(acked != NULL); - - surface->toplevel->pending.maximized = acked->maximized; - surface->toplevel->pending.fullscreen = acked->fullscreen; - surface->toplevel->pending.resizing = acked->resizing; - surface->toplevel->pending.activated = acked->activated; - surface->toplevel->pending.tiled = acked->tiled; - - surface->toplevel->pending.width = acked->width; - surface->toplevel->pending.height = acked->height; + toplevel->pending.width = configure->width; + toplevel->pending.height = configure->height; } -void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, - struct wlr_xdg_surface_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - - configure->toplevel_configure = malloc(sizeof(*configure->toplevel_configure)); - if (configure->toplevel_configure == NULL) { +struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( + struct wlr_xdg_toplevel *toplevel) { + struct wlr_xdg_toplevel_configure *configure = + calloc(1, sizeof(*configure)); + if (configure == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); - wl_resource_post_no_memory(surface->toplevel->resource); - return; + wl_resource_post_no_memory(toplevel->resource); + return NULL; } - *configure->toplevel_configure = surface->toplevel->scheduled; + *configure = toplevel->scheduled; struct wl_array states; wl_array_init(&states); - if (surface->toplevel->scheduled.maximized) { + if (configure->maximized) { uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(WLR_ERROR, "Could not allocate state for maximized xdg_toplevel"); @@ -47,7 +41,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *s = XDG_TOPLEVEL_STATE_MAXIMIZED; } - if (surface->toplevel->scheduled.fullscreen) { + if (configure->fullscreen) { uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(WLR_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); @@ -55,7 +49,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *s = XDG_TOPLEVEL_STATE_FULLSCREEN; } - if (surface->toplevel->scheduled.resizing) { + if (configure->resizing) { uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(WLR_ERROR, "Could not allocate state for resizing xdg_toplevel"); @@ -63,7 +57,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *s = XDG_TOPLEVEL_STATE_RESIZING; } - if (surface->toplevel->scheduled.activated) { + if (configure->activated) { uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(WLR_ERROR, "Could not allocate state for activated xdg_toplevel"); @@ -71,8 +65,8 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *s = XDG_TOPLEVEL_STATE_ACTIVATED; } - if (surface->toplevel->scheduled.tiled) { - if (wl_resource_get_version(surface->resource) >= + if (configure->tiled) { + if (wl_resource_get_version(toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { const struct { enum wlr_edges edge; @@ -85,8 +79,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, }; for (size_t i = 0; i < sizeof(tiled)/sizeof(tiled[0]); ++i) { - if ((surface->toplevel->scheduled.tiled & - tiled[i].edge) == 0) { + if ((configure->tiled & tiled[i].edge) == 0) { continue; } @@ -98,7 +91,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *s = tiled[i].state; } - } else if (!surface->toplevel->scheduled.maximized) { + } else if (!configure->maximized) { // This version doesn't support tiling, best we can do is make the // toplevel maximized uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); @@ -111,36 +104,35 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } } - uint32_t width = surface->toplevel->scheduled.width; - uint32_t height = surface->toplevel->scheduled.height; - xdg_toplevel_send_configure(surface->toplevel->resource, width, height, - &states); + uint32_t width = configure->width; + uint32_t height = configure->height; + xdg_toplevel_send_configure(toplevel->resource, width, height, &states); wl_array_release(&states); - return; + return configure; error_out: wl_array_release(&states); - wl_resource_post_no_memory(surface->toplevel->resource); + free(configure); + wl_resource_post_no_memory(toplevel->resource); + return NULL; } -void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - - if (!surface->toplevel->added) { +void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel) { + if (!toplevel->added) { // on the first commit, send a configure request to tell the client it // is added - wlr_xdg_surface_schedule_configure(surface); - surface->toplevel->added = true; + wlr_xdg_surface_schedule_configure(toplevel->base); + toplevel->added = true; return; } - surface->toplevel->current = surface->toplevel->pending; + toplevel->current = toplevel->pending; } static const struct xdg_toplevel_interface xdg_toplevel_implementation; -struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( +struct wlr_xdg_toplevel *wlr_xdg_toplevel_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_toplevel_interface, &xdg_toplevel_implementation)); @@ -150,46 +142,45 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( static void handle_parent_unmap(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel *toplevel = wl_container_of(listener, toplevel, parent_unmap); - wlr_xdg_toplevel_set_parent(toplevel->base, - toplevel->parent->toplevel->parent); + wlr_xdg_toplevel_set_parent(toplevel, + toplevel->parent->toplevel->parent->toplevel); } -void wlr_xdg_toplevel_set_parent(struct wlr_xdg_surface *surface, - struct wlr_xdg_surface *parent) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - assert(!parent || parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - - if (surface->toplevel->parent) { - wl_list_remove(&surface->toplevel->parent_unmap.link); +void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, + struct wlr_xdg_toplevel *parent) { + if (toplevel->parent) { + wl_list_remove(&toplevel->parent_unmap.link); } - surface->toplevel->parent = parent; - if (surface->toplevel->parent) { - surface->toplevel->parent_unmap.notify = handle_parent_unmap; - wl_signal_add(&surface->toplevel->parent->events.unmap, - &surface->toplevel->parent_unmap); + if (parent) { + toplevel->parent = parent->base; + toplevel->parent_unmap.notify = handle_parent_unmap; + wl_signal_add(&toplevel->parent->events.unmap, + &toplevel->parent_unmap); + } else { + toplevel->parent = NULL; } - wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); + wlr_signal_emit_safe(&toplevel->events.set_parent, NULL); } static void xdg_toplevel_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - struct wlr_xdg_surface *parent = NULL; + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + struct wlr_xdg_toplevel *parent = NULL; if (parent_resource != NULL) { - parent = wlr_xdg_surface_from_toplevel_resource(parent_resource); + parent = wlr_xdg_toplevel_from_resource(parent_resource); } - wlr_xdg_toplevel_set_parent(surface, parent); + wlr_xdg_toplevel_set_parent(toplevel, parent); } static void xdg_toplevel_handle_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); char *tmp; tmp = strdup(title); @@ -197,15 +188,15 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client, return; } - free(surface->toplevel->title); - surface->toplevel->title = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface); + free(toplevel->title); + toplevel->title = tmp; + wlr_signal_emit_safe(&toplevel->events.set_title, NULL); } static void xdg_toplevel_handle_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); char *tmp; tmp = strdup(app_id); @@ -213,21 +204,21 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client, return; } - free(surface->toplevel->app_id); - surface->toplevel->app_id = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface); + free(toplevel->app_id); + toplevel->app_id = tmp; + wlr_signal_emit_safe(&toplevel->events.set_app_id, NULL); } static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, + if (!toplevel->base->configured) { + wl_resource_post_error(toplevel->base->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -239,26 +230,26 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, } struct wlr_xdg_toplevel_show_window_menu_event event = { - .surface = surface, + .surface = toplevel->base, .seat = seat, .serial = serial, .x = x, .y = y, }; - wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu, &event); + wlr_signal_emit_safe(&toplevel->events.request_show_window_menu, &event); } static void xdg_toplevel_handle_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, + if (!toplevel->base->configured) { + wl_resource_post_error(toplevel->base->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -270,24 +261,24 @@ static void xdg_toplevel_handle_move(struct wl_client *client, } struct wlr_xdg_toplevel_move_event event = { - .surface = surface, + .surface = toplevel->base, .seat = seat, .serial = serial, }; - wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event); + wlr_signal_emit_safe(&toplevel->events.request_move, &event); } static void xdg_toplevel_handle_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, + if (!toplevel->base->configured) { + wl_resource_post_error(toplevel->base->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -299,47 +290,47 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, } struct wlr_xdg_toplevel_resize_event event = { - .surface = surface, + .surface = toplevel->base, .seat = seat, .serial = serial, .edges = edges, }; - wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event); + wlr_signal_emit_safe(&toplevel->events.request_resize, &event); } static void xdg_toplevel_handle_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->pending.max_width = width; - surface->toplevel->pending.max_height = height; + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + toplevel->pending.max_width = width; + toplevel->pending.max_height = height; } static void xdg_toplevel_handle_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->pending.min_width = width; - surface->toplevel->pending.min_height = height; + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + toplevel->pending.min_width = width; + toplevel->pending.min_height = height; } static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->requested.maximized = true; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); - wlr_xdg_surface_schedule_configure(surface); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + toplevel->requested.maximized = true; + wlr_signal_emit_safe(&toplevel->events.request_maximize, NULL); + wlr_xdg_surface_schedule_configure(toplevel->base); } static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->requested.maximized = false; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); - wlr_xdg_surface_schedule_configure(surface); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + toplevel->requested.maximized = false; + wlr_signal_emit_safe(&toplevel->events.request_maximize, NULL); + wlr_xdg_surface_schedule_configure(toplevel->base); } static void handle_fullscreen_output_destroy(struct wl_listener *listener, @@ -350,9 +341,9 @@ static void handle_fullscreen_output_destroy(struct wl_listener *listener, wl_list_remove(&req->fullscreen_output_destroy.link); } -static void store_fullscreen_requested(struct wlr_xdg_surface *surface, +static void store_fullscreen_requested(struct wlr_xdg_toplevel *toplevel, bool fullscreen, struct wlr_output *output) { - struct wlr_xdg_toplevel_requested *req = &surface->toplevel->requested; + struct wlr_xdg_toplevel_requested *req = &toplevel->requested; req->fullscreen = fullscreen; if (req->fullscreen_output) { wl_list_remove(&req->fullscreen_output_destroy.link); @@ -368,49 +359,49 @@ static void store_fullscreen_requested(struct wlr_xdg_surface *surface, static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { output = wlr_output_from_resource(output_resource); } - store_fullscreen_requested(surface, true, output); + store_fullscreen_requested(toplevel, true, output); struct wlr_xdg_toplevel_set_fullscreen_event event = { - .surface = surface, + .surface = toplevel->base, .fullscreen = true, .output = output, }; - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); - wlr_xdg_surface_schedule_configure(surface); + wlr_signal_emit_safe(&toplevel->events.request_fullscreen, &event); + wlr_xdg_surface_schedule_configure(toplevel->base); } static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); - store_fullscreen_requested(surface, false, NULL); + store_fullscreen_requested(toplevel, false, NULL); struct wlr_xdg_toplevel_set_fullscreen_event event = { - .surface = surface, + .surface = toplevel->base, .fullscreen = false, .output = NULL, }; - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); - wlr_xdg_surface_schedule_configure(surface); + wlr_signal_emit_safe(&toplevel->events.request_fullscreen, &event); + wlr_xdg_surface_schedule_configure(toplevel->base); } static void xdg_toplevel_handle_set_minimized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - surface->toplevel->requested.minimized = true; - wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + toplevel->requested.minimized = true; + wlr_signal_emit_safe(&toplevel->events.request_minimize, NULL); } static void xdg_toplevel_handle_destroy(struct wl_client *client, @@ -436,9 +427,9 @@ static const struct xdg_toplevel_interface xdg_toplevel_implementation = { }; static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_toplevel_resource(resource); - destroy_xdg_toplevel(surface); + struct wlr_xdg_toplevel *toplevel = + wlr_xdg_toplevel_from_resource(resource); + destroy_xdg_toplevel(toplevel); } const struct wlr_surface_role xdg_toplevel_surface_role = { @@ -488,65 +479,56 @@ void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, return; } wl_resource_set_implementation(xdg_surface->toplevel->resource, - &xdg_toplevel_implementation, xdg_surface, + &xdg_toplevel_implementation, xdg_surface->toplevel, xdg_toplevel_handle_resource_destroy); xdg_surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; } -void destroy_xdg_toplevel(struct wlr_xdg_surface *xdg_surface) { - if (xdg_surface == NULL) { +void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { + if (toplevel == NULL) { return; } - assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - reset_xdg_surface(xdg_surface); + reset_xdg_surface(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, +void wlr_xdg_toplevel_send_close(struct wlr_xdg_toplevel *toplevel) { + xdg_toplevel_send_close(toplevel->resource); +} + +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_toplevel *toplevel, uint32_t width, uint32_t height) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.width = width; - surface->toplevel->scheduled.height = height; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.width = width; + toplevel->scheduled.height = height; + return wlr_xdg_surface_schedule_configure(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_toplevel *toplevel, bool activated) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.activated = activated; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.activated = activated; + return wlr_xdg_surface_schedule_configure(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_toplevel *toplevel, bool maximized) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.maximized = maximized; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.maximized = maximized; + return wlr_xdg_surface_schedule_configure(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_toplevel *toplevel, bool fullscreen) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.fullscreen = fullscreen; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.fullscreen = fullscreen; + return wlr_xdg_surface_schedule_configure(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_toplevel *toplevel, bool resizing) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.resizing = resizing; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.resizing = resizing; + return wlr_xdg_surface_schedule_configure(toplevel->base); } -uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, +uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_toplevel *toplevel, uint32_t tiled) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel->scheduled.tiled = tiled; - - return wlr_xdg_surface_schedule_configure(surface); + toplevel->scheduled.tiled = tiled; + return wlr_xdg_surface_schedule_configure(toplevel->base); } From 41412cadbef34e0c5d2f25e6b874c1ad4540ff01 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:52 +0300 Subject: [PATCH 155/190] xdg-popup: fix functions' main argument type With this commit, `wlr_xdg_popup_*()` functions now expect a `wlr_xdg_popup` instead of a `wlr_xdg_surface`. --- include/types/wlr_xdg_shell.h | 2 +- include/wlr/types/wlr_xdg_shell.h | 10 ++++- types/wlr_layer_shell_v1.c | 8 ++-- types/xdg_shell/wlr_xdg_popup.c | 75 ++++++++++++++++++------------- types/xdg_shell/wlr_xdg_surface.c | 21 +-------- 5 files changed, 58 insertions(+), 58 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index e3688a94b..f4e1ebe3b 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -30,7 +30,7 @@ struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, struct wlr_xdg_surface *parent, struct wlr_xdg_positioner_resource *positioner, uint32_t id); -void handle_xdg_surface_popup_committed(struct wlr_xdg_surface *surface); +void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index e16d3218f..736861e2d 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -265,7 +265,13 @@ struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); */ struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wl_resource *resource); -struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( + +/** Get the corresponding wlr_xdg_popup from a resource. + * + * Aborts if the resource doesn't have the correct type. Returns NULL if the + * resource is inert. + */ +struct wlr_xdg_popup *wlr_xdg_popup_from_resource( struct wl_resource *resource); /** Get the corresponding wlr_xdg_toplevel from a resource. @@ -339,7 +345,7 @@ void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, /** * Request that this xdg popup closes. **/ -void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface); +void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup); /** * Get the position for this popup in the surface parent's coordinate system. diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index b2c82955f..c8d3a1cb5 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -211,14 +211,12 @@ static void layer_surface_handle_get_popup(struct wl_client *client, struct wl_resource *popup_resource) { struct wlr_layer_surface_v1 *parent = layer_surface_from_resource(layer_resource); - struct wlr_xdg_surface *popup_surface = - wlr_xdg_surface_from_popup_resource(popup_resource); + struct wlr_xdg_popup *popup = + wlr_xdg_popup_from_resource(popup_resource); if (!parent) { return; } - assert(popup_surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - struct wlr_xdg_popup *popup = popup_surface->popup; popup->parent = parent->surface; wl_list_insert(&parent->popups, &popup->link); wlr_signal_emit_safe(&parent->events.new_popup, popup); @@ -265,7 +263,7 @@ static void layer_surface_unmap(struct wlr_layer_surface_v1 *surface) { struct wlr_xdg_popup *popup, *popup_tmp; wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) { - wlr_xdg_popup_destroy(popup->base); + wlr_xdg_popup_destroy(popup); } struct wlr_layer_surface_v1_configure *configure, *tmp; diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index de1987c9e..53e930bcd 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -196,25 +196,23 @@ struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( return xdg_grab; } -void handle_xdg_surface_popup_committed(struct wlr_xdg_surface *surface) { - assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - - if (!surface->popup->parent) { - wl_resource_post_error(surface->resource, +void handle_xdg_popup_committed(struct wlr_xdg_popup *popup) { + if (!popup->parent) { + wl_resource_post_error(popup->base->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_popup has no parent"); return; } - if (!surface->popup->committed) { - wlr_xdg_surface_schedule_configure(surface); - surface->popup->committed = true; + if (!popup->committed) { + wlr_xdg_surface_schedule_configure(popup->base); + popup->committed = true; } } static const struct xdg_popup_interface xdg_popup_implementation; -struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( +struct wlr_xdg_popup *wlr_xdg_popup_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_popup_interface, &xdg_popup_implementation)); @@ -224,35 +222,35 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( static void xdg_popup_handle_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_popup_resource(resource); - struct wlr_seat_client *seat_client = - wlr_seat_client_from_resource(seat_resource); - if (!surface) { + struct wlr_xdg_popup *popup = + wlr_xdg_popup_from_resource(resource); + if (!popup) { return; } - if (surface->popup->committed) { - wl_resource_post_error(surface->popup->resource, + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + if (popup->committed) { + wl_resource_post_error(popup->resource, XDG_POPUP_ERROR_INVALID_GRAB, "xdg_popup is already mapped"); return; } struct wlr_xdg_popup_grab *popup_grab = get_xdg_shell_popup_grab_from_seat( - surface->client->shell, seat_client->seat); + popup->base->client->shell, seat_client->seat); - if (!wl_list_empty(&surface->popups)) { - wl_resource_post_error(surface->client->resource, + if (!wl_list_empty(&popup->base->popups)) { + wl_resource_post_error(popup->base->client->resource, XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was not created on the topmost popup"); return; } - popup_grab->client = surface->client->client; - surface->popup->seat = seat_client->seat; + popup_grab->client = popup->base->client->client; + popup->seat = seat_client->seat; - wl_list_insert(&popup_grab->popups, &surface->popup->grab_link); + wl_list_insert(&popup_grab->popups, &popup->grab_link); wlr_seat_pointer_start_grab(seat_client->seat, &popup_grab->pointer_grab); @@ -264,11 +262,11 @@ static void xdg_popup_handle_grab(struct wl_client *client, static void xdg_popup_handle_destroy(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_popup_resource(resource); + struct wlr_xdg_popup *popup = + wlr_xdg_popup_from_resource(resource); - if (surface && !wl_list_empty(&surface->popups)) { - wl_resource_post_error(surface->client->resource, + if (popup && !wl_list_empty(&popup->base->popups)) { + wl_resource_post_error(popup->base->client->resource, XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was destroyed while it was not the topmost popup"); return; @@ -283,12 +281,12 @@ static const struct xdg_popup_interface xdg_popup_implementation = { }; static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_popup_resource(resource); - if (xdg_surface == NULL) { + struct wlr_xdg_popup *popup = + wlr_xdg_popup_from_resource(resource); + if (popup == NULL) { return; } - wlr_xdg_popup_destroy(xdg_surface); + wlr_xdg_popup_destroy(popup); } const struct wlr_surface_role xdg_popup_surface_role = { @@ -337,7 +335,7 @@ void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, return; } wl_resource_set_implementation(xdg_surface->popup->resource, - &xdg_popup_implementation, xdg_surface, + &xdg_popup_implementation, xdg_surface->popup, xdg_popup_handle_resource_destroy); xdg_surface->role = WLR_XDG_SURFACE_ROLE_POPUP; @@ -357,6 +355,21 @@ void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, } } +void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) { + if (popup == NULL) { + return; + } + + struct wlr_xdg_popup *child, *child_tmp; + wl_list_for_each_safe(child, child_tmp, &popup->base->popups, link) { + wlr_xdg_popup_destroy(child); + } + + xdg_popup_send_popup_done(popup->resource); + wl_resource_set_user_data(popup->resource, NULL); + reset_xdg_surface(popup->base); +} + void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, int *root_sx, int *root_sy) { struct wlr_box rect = popup->positioner.anchor_rect; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 3315456d9..081474dff 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -32,7 +32,7 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) { struct wlr_xdg_popup *popup, *popup_tmp; wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) { - wlr_xdg_popup_destroy(popup->base); + wlr_xdg_popup_destroy(popup); } // TODO: probably need to ungrab before this event @@ -324,7 +324,7 @@ void xdg_surface_role_commit(struct wlr_surface *wlr_surface) { handle_xdg_toplevel_committed(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: - handle_xdg_surface_popup_committed(surface); + handle_xdg_popup_committed(surface->popup); break; } @@ -495,23 +495,6 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { surface->client->ping_serial); } -void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface) { - if (surface == NULL) { - return; - } - assert(surface->popup); - assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - - struct wlr_xdg_popup *popup, *popup_tmp; - wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) { - wlr_xdg_popup_destroy(popup->base); - } - - xdg_popup_send_popup_done(surface->popup->resource); - wl_resource_set_user_data(surface->popup->resource, NULL); - reset_xdg_surface(surface); -} - void wlr_xdg_popup_get_position(struct wlr_xdg_popup *popup, double *popup_sx, double *popup_sy) { struct wlr_xdg_surface *parent = From 70d4a30be36aa576828c61cda4008247ebc911c1 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:52 +0300 Subject: [PATCH 156/190] xdg-shell: remove "xdg" from docs --- include/wlr/types/wlr_xdg_shell.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 736861e2d..247bad152 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -332,7 +332,7 @@ uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_toplevel *toplevel, uint32_t tiled_edges); /** - * Request that this xdg toplevel closes. + * Request that this toplevel closes. */ void wlr_xdg_toplevel_send_close(struct wlr_xdg_toplevel *toplevel); @@ -343,7 +343,7 @@ void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, struct wlr_xdg_toplevel *parent); /** - * Request that this xdg popup closes. + * Request that this popup closes. **/ void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup); From 27c8865a4d92c785a8298022a21cf989206e4436 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:53 +0300 Subject: [PATCH 157/190] xdg-shell: unify function arguments' names `wlr_xdg_surface`s are now named "surface" everywhere, and `wlr_surface`s are called "wlr_surface". --- include/types/wlr_xdg_shell.h | 8 +-- types/xdg_shell/wlr_xdg_popup.c | 52 +++++++-------- types/xdg_shell/wlr_xdg_surface.c | 102 ++++++++++++++--------------- types/xdg_shell/wlr_xdg_toplevel.c | 56 ++++++++-------- 4 files changed, 109 insertions(+), 109 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index f4e1ebe3b..7613a15d0 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -14,10 +14,10 @@ extern const struct wlr_surface_role xdg_toplevel_surface_role; extern const struct wlr_surface_role xdg_popup_surface_role; struct wlr_xdg_surface *create_xdg_surface( - struct wlr_xdg_client *client, struct wlr_surface *surface, + struct wlr_xdg_client *client, struct wlr_surface *wlr_surface, uint32_t id); void unmap_xdg_surface(struct wlr_xdg_surface *surface); -void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface); +void reset_xdg_surface(struct wlr_xdg_surface *surface); void destroy_xdg_surface(struct wlr_xdg_surface *surface); void xdg_surface_role_commit(struct wlr_surface *wlr_surface); void xdg_surface_role_precommit(struct wlr_surface *wlr_surface, @@ -27,14 +27,14 @@ void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( struct wl_resource *resource); -void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, +void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, struct wlr_xdg_positioner_resource *positioner, uint32_t id); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat); -void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, +void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id); void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel); struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 53e930bcd..7066893aa 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -295,63 +295,63 @@ const struct wlr_surface_role xdg_popup_surface_role = { .precommit = xdg_surface_role_precommit, }; -void create_xdg_popup(struct wlr_xdg_surface *xdg_surface, +void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, struct wlr_xdg_positioner_resource *positioner, uint32_t id) { if (positioner->attrs.size.width == 0 || positioner->attrs.anchor_rect.width == 0) { - wl_resource_post_error(xdg_surface->resource, + wl_resource_post_error(surface->resource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "positioner object is not complete"); return; } - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) { - wl_resource_post_error(xdg_surface->resource, + if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "xdg-surface has already been constructed"); return; } - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_popup_surface_role, - xdg_surface, xdg_surface->resource, XDG_WM_BASE_ERROR_ROLE)) { + if (!wlr_surface_set_role(surface->surface, &xdg_popup_surface_role, + surface, surface->resource, XDG_WM_BASE_ERROR_ROLE)) { return; } - assert(xdg_surface->popup == NULL); - xdg_surface->popup = calloc(1, sizeof(struct wlr_xdg_popup)); - if (!xdg_surface->popup) { - wl_resource_post_no_memory(xdg_surface->resource); + assert(surface->popup == NULL); + surface->popup = calloc(1, sizeof(struct wlr_xdg_popup)); + if (!surface->popup) { + wl_resource_post_no_memory(surface->resource); return; } - xdg_surface->popup->base = xdg_surface; + surface->popup->base = surface; - xdg_surface->popup->resource = wl_resource_create( - xdg_surface->client->client, &xdg_popup_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (xdg_surface->popup->resource == NULL) { - free(xdg_surface->popup); - wl_resource_post_no_memory(xdg_surface->resource); + surface->popup->resource = wl_resource_create( + surface->client->client, &xdg_popup_interface, + wl_resource_get_version(surface->resource), id); + if (surface->popup->resource == NULL) { + free(surface->popup); + wl_resource_post_no_memory(surface->resource); return; } - wl_resource_set_implementation(xdg_surface->popup->resource, - &xdg_popup_implementation, xdg_surface->popup, + wl_resource_set_implementation(surface->popup->resource, + &xdg_popup_implementation, surface->popup, xdg_popup_handle_resource_destroy); - xdg_surface->role = WLR_XDG_SURFACE_ROLE_POPUP; + surface->role = WLR_XDG_SURFACE_ROLE_POPUP; // positioner properties - memcpy(&xdg_surface->popup->positioner, &positioner->attrs, + memcpy(&surface->popup->positioner, &positioner->attrs, sizeof(struct wlr_xdg_positioner)); - xdg_surface->popup->geometry = + surface->popup->geometry = wlr_xdg_positioner_get_geometry(&positioner->attrs); if (parent) { - xdg_surface->popup->parent = parent->surface; - wl_list_insert(&parent->popups, &xdg_surface->popup->link); - wlr_signal_emit_safe(&parent->events.new_popup, xdg_surface->popup); + surface->popup->parent = parent->surface; + wl_list_insert(&parent->popups, &surface->popup->link); + wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); } else { - wl_list_init(&xdg_surface->popup->link); + wl_list_init(&surface->popup->link); } } diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 081474dff..7db308c07 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -364,102 +364,102 @@ static void xdg_surface_handle_surface_destroy(struct wl_listener *listener, } struct wlr_xdg_surface *create_xdg_surface( - struct wlr_xdg_client *client, struct wlr_surface *surface, + struct wlr_xdg_client *client, struct wlr_surface *wlr_surface, uint32_t id) { - struct wlr_xdg_surface *xdg_surface = + struct wlr_xdg_surface *surface = calloc(1, sizeof(struct wlr_xdg_surface)); - if (xdg_surface == NULL) { + if (surface == NULL) { wl_client_post_no_memory(client->client); return NULL; } - xdg_surface->client = client; - xdg_surface->role = WLR_XDG_SURFACE_ROLE_NONE; - xdg_surface->surface = surface; - xdg_surface->resource = wl_resource_create(client->client, + surface->client = client; + surface->role = WLR_XDG_SURFACE_ROLE_NONE; + surface->surface = wlr_surface; + surface->resource = wl_resource_create(client->client, &xdg_surface_interface, wl_resource_get_version(client->resource), id); - if (xdg_surface->resource == NULL) { - free(xdg_surface); + if (surface->resource == NULL) { + free(surface); wl_client_post_no_memory(client->client); return NULL; } - if (wlr_surface_has_buffer(xdg_surface->surface)) { - wl_resource_destroy(xdg_surface->resource); - free(xdg_surface); + if (wlr_surface_has_buffer(surface->surface)) { + wl_resource_destroy(surface->resource); + free(surface); wl_resource_post_error(client->resource, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, "xdg_surface must not have a buffer at creation"); return NULL; } - wl_list_init(&xdg_surface->configure_list); - wl_list_init(&xdg_surface->popups); + wl_list_init(&surface->configure_list); + wl_list_init(&surface->popups); - wl_signal_init(&xdg_surface->events.destroy); - wl_signal_init(&xdg_surface->events.ping_timeout); - wl_signal_init(&xdg_surface->events.new_popup); - wl_signal_init(&xdg_surface->events.map); - wl_signal_init(&xdg_surface->events.unmap); - wl_signal_init(&xdg_surface->events.configure); - wl_signal_init(&xdg_surface->events.ack_configure); + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.new_popup); + wl_signal_init(&surface->events.map); + wl_signal_init(&surface->events.unmap); + wl_signal_init(&surface->events.configure); + wl_signal_init(&surface->events.ack_configure); - wl_signal_add(&xdg_surface->surface->events.destroy, - &xdg_surface->surface_destroy); - xdg_surface->surface_destroy.notify = xdg_surface_handle_surface_destroy; + wl_signal_add(&surface->surface->events.destroy, + &surface->surface_destroy); + surface->surface_destroy.notify = xdg_surface_handle_surface_destroy; - wl_signal_add(&xdg_surface->surface->events.commit, - &xdg_surface->surface_commit); - xdg_surface->surface_commit.notify = xdg_surface_handle_surface_commit; + wl_signal_add(&surface->surface->events.commit, + &surface->surface_commit); + surface->surface_commit.notify = xdg_surface_handle_surface_commit; - wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", xdg_surface, - xdg_surface->resource); - wl_resource_set_implementation(xdg_surface->resource, - &xdg_surface_implementation, xdg_surface, + wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", surface, + surface->resource); + wl_resource_set_implementation(surface->resource, + &xdg_surface_implementation, surface, xdg_surface_handle_resource_destroy); - wl_list_insert(&client->surfaces, &xdg_surface->link); + wl_list_insert(&client->surfaces, &surface->link); - return xdg_surface; + return surface; } -void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) { - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) { - unmap_xdg_surface(xdg_surface); +void reset_xdg_surface(struct wlr_xdg_surface *surface) { + if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { + unmap_xdg_surface(surface); } - if (xdg_surface->added) { - wlr_signal_emit_safe(&xdg_surface->events.destroy, xdg_surface); - xdg_surface->added = false; + if (surface->added) { + wlr_signal_emit_safe(&surface->events.destroy, surface); + surface->added = false; } - switch (xdg_surface->role) { + switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - wl_resource_set_user_data(xdg_surface->toplevel->resource, NULL); - xdg_surface->toplevel->resource = NULL; + wl_resource_set_user_data(surface->toplevel->resource, NULL); + surface->toplevel->resource = NULL; struct wlr_xdg_toplevel_requested *req = - &xdg_surface->toplevel->requested; + &surface->toplevel->requested; if (req->fullscreen_output) { wl_list_remove(&req->fullscreen_output_destroy.link); } - free(xdg_surface->toplevel); - xdg_surface->toplevel = NULL; + free(surface->toplevel); + surface->toplevel = NULL; break; case WLR_XDG_SURFACE_ROLE_POPUP: - wl_resource_set_user_data(xdg_surface->popup->resource, NULL); - xdg_surface->popup->resource = NULL; + wl_resource_set_user_data(surface->popup->resource, NULL); + surface->popup->resource = NULL; - wl_list_remove(&xdg_surface->popup->link); + wl_list_remove(&surface->popup->link); - free(xdg_surface->popup); - xdg_surface->popup = NULL; + free(surface->popup); + surface->popup = NULL; break; case WLR_XDG_SURFACE_ROLE_NONE: // This space is intentionally left blank break; } - xdg_surface->role = WLR_XDG_SURFACE_ROLE_NONE; + surface->role = WLR_XDG_SURFACE_ROLE_NONE; } void destroy_xdg_surface(struct wlr_xdg_surface *surface) { diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index d88e66598..376ab49c1 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -438,51 +438,51 @@ const struct wlr_surface_role xdg_toplevel_surface_role = { .precommit = xdg_surface_role_precommit, }; -void create_xdg_toplevel(struct wlr_xdg_surface *xdg_surface, +void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id) { - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_toplevel_surface_role, - xdg_surface, xdg_surface->resource, XDG_WM_BASE_ERROR_ROLE)) { + if (!wlr_surface_set_role(surface->surface, &xdg_toplevel_surface_role, + surface, surface->resource, XDG_WM_BASE_ERROR_ROLE)) { return; } - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) { - wl_resource_post_error(xdg_surface->resource, + if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "xdg-surface has already been constructed"); return; } - assert(xdg_surface->toplevel == NULL); - xdg_surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel)); - if (xdg_surface->toplevel == NULL) { - wl_resource_post_no_memory(xdg_surface->resource); + assert(surface->toplevel == NULL); + surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel)); + if (surface->toplevel == NULL) { + wl_resource_post_no_memory(surface->resource); return; } - xdg_surface->toplevel->base = xdg_surface; + surface->toplevel->base = surface; - wl_signal_init(&xdg_surface->toplevel->events.request_maximize); - wl_signal_init(&xdg_surface->toplevel->events.request_fullscreen); - wl_signal_init(&xdg_surface->toplevel->events.request_minimize); - wl_signal_init(&xdg_surface->toplevel->events.request_move); - wl_signal_init(&xdg_surface->toplevel->events.request_resize); - wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); - wl_signal_init(&xdg_surface->toplevel->events.set_parent); - wl_signal_init(&xdg_surface->toplevel->events.set_title); - wl_signal_init(&xdg_surface->toplevel->events.set_app_id); + wl_signal_init(&surface->toplevel->events.request_maximize); + wl_signal_init(&surface->toplevel->events.request_fullscreen); + wl_signal_init(&surface->toplevel->events.request_minimize); + wl_signal_init(&surface->toplevel->events.request_move); + wl_signal_init(&surface->toplevel->events.request_resize); + wl_signal_init(&surface->toplevel->events.request_show_window_menu); + wl_signal_init(&surface->toplevel->events.set_parent); + wl_signal_init(&surface->toplevel->events.set_title); + wl_signal_init(&surface->toplevel->events.set_app_id); - xdg_surface->toplevel->resource = wl_resource_create( - xdg_surface->client->client, &xdg_toplevel_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (xdg_surface->toplevel->resource == NULL) { - free(xdg_surface->toplevel); - wl_resource_post_no_memory(xdg_surface->resource); + surface->toplevel->resource = wl_resource_create( + surface->client->client, &xdg_toplevel_interface, + wl_resource_get_version(surface->resource), id); + if (surface->toplevel->resource == NULL) { + free(surface->toplevel); + wl_resource_post_no_memory(surface->resource); return; } - wl_resource_set_implementation(xdg_surface->toplevel->resource, - &xdg_toplevel_implementation, xdg_surface->toplevel, + wl_resource_set_implementation(surface->toplevel->resource, + &xdg_toplevel_implementation, surface->toplevel, xdg_toplevel_handle_resource_destroy); - xdg_surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; + surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; } void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { From 1e4c1a3b58d77f91223571160cdb2db12ad9386b Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:53 +0300 Subject: [PATCH 158/190] xdg-toplevel: change parent type to xdg-toplevel This commit changes wlr_xdg_toplevel::parent type from wlr_xdg_surface to wlr_xdg_toplevel. --- include/wlr/types/wlr_xdg_shell.h | 2 +- types/xdg_shell/wlr_xdg_toplevel.c | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 247bad152..2fee14538 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -125,7 +125,7 @@ struct wlr_xdg_toplevel { struct wlr_xdg_surface *base; bool added; - struct wlr_xdg_surface *parent; + struct wlr_xdg_toplevel *parent; struct wl_listener parent_unmap; struct wlr_xdg_toplevel_state current, pending; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 376ab49c1..842e37c27 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -142,8 +142,7 @@ struct wlr_xdg_toplevel *wlr_xdg_toplevel_from_resource( static void handle_parent_unmap(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel *toplevel = wl_container_of(listener, toplevel, parent_unmap); - wlr_xdg_toplevel_set_parent(toplevel, - toplevel->parent->toplevel->parent->toplevel); + wlr_xdg_toplevel_set_parent(toplevel, toplevel->parent->parent); } void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, @@ -151,14 +150,12 @@ void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, if (toplevel->parent) { wl_list_remove(&toplevel->parent_unmap.link); } - + + toplevel->parent = parent; if (parent) { - toplevel->parent = parent->base; toplevel->parent_unmap.notify = handle_parent_unmap; - wl_signal_add(&toplevel->parent->events.unmap, + wl_signal_add(&toplevel->parent->base->events.unmap, &toplevel->parent_unmap); - } else { - toplevel->parent = NULL; } wlr_signal_emit_safe(&toplevel->events.set_parent, NULL); From e59aa3e0e7e142825fbd16887475285fafceb7ba Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:54 +0300 Subject: [PATCH 159/190] xdg-toplevel: change object type in event structs This commit replaces wlr_xdg_toplevel_*_event::surface with a toplevel field. --- include/wlr/types/wlr_xdg_shell.h | 8 ++++---- types/xdg_shell/wlr_xdg_toplevel.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 2fee14538..a54d27235 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -231,26 +231,26 @@ struct wlr_xdg_surface { }; struct wlr_xdg_toplevel_move_event { - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; struct wlr_seat_client *seat; uint32_t serial; }; struct wlr_xdg_toplevel_resize_event { - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; struct wlr_seat_client *seat; uint32_t serial; uint32_t edges; }; struct wlr_xdg_toplevel_set_fullscreen_event { - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; bool fullscreen; struct wlr_output *output; }; struct wlr_xdg_toplevel_show_window_menu_event { - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; struct wlr_seat_client *seat; uint32_t serial; uint32_t x, y; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 842e37c27..e1f9a91df 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -227,7 +227,7 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, } struct wlr_xdg_toplevel_show_window_menu_event event = { - .surface = toplevel->base, + .toplevel = toplevel, .seat = seat, .serial = serial, .x = x, @@ -258,7 +258,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client, } struct wlr_xdg_toplevel_move_event event = { - .surface = toplevel->base, + .toplevel = toplevel, .seat = seat, .serial = serial, }; @@ -287,7 +287,7 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, } struct wlr_xdg_toplevel_resize_event event = { - .surface = toplevel->base, + .toplevel = toplevel, .seat = seat, .serial = serial, .edges = edges, @@ -367,7 +367,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, true, output); struct wlr_xdg_toplevel_set_fullscreen_event event = { - .surface = toplevel->base, + .toplevel = toplevel, .fullscreen = true, .output = output, }; @@ -384,7 +384,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, false, NULL); struct wlr_xdg_toplevel_set_fullscreen_event event = { - .surface = toplevel->base, + .toplevel = toplevel, .fullscreen = false, .output = NULL, }; From c35d14ecfaf785cbf557c6106372ea68e0b8011e Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:55 +0300 Subject: [PATCH 160/190] xdg-shell: extract role-specific unmap logic --- include/types/wlr_xdg_shell.h | 3 ++- types/xdg_shell/wlr_xdg_popup.c | 21 +++++++++++++++++ types/xdg_shell/wlr_xdg_surface.c | 38 +++--------------------------- types/xdg_shell/wlr_xdg_toplevel.c | 25 ++++++++++++++++---- 4 files changed, 46 insertions(+), 41 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 7613a15d0..0c2b5cd5e 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -30,17 +30,18 @@ struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, struct wlr_xdg_positioner_resource *positioner, uint32_t id); +void unmap_xdg_popup(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat); void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id); +void unmap_xdg_toplevel(struct wlr_xdg_toplevel *toplevel); void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel); struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( struct wlr_xdg_toplevel *toplevel); void handle_xdg_toplevel_ack_configure(struct wlr_xdg_toplevel *toplevel, struct wlr_xdg_toplevel_configure *configure); -void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel); #endif diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 7066893aa..17b71cd49 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -355,6 +355,27 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, } } +void unmap_xdg_popup(struct wlr_xdg_popup *popup) { + if (popup->seat != NULL) { + struct wlr_xdg_popup_grab *grab = + get_xdg_shell_popup_grab_from_seat( + popup->base->client->shell, popup->seat); + + wl_list_remove(&popup->grab_link); + + if (wl_list_empty(&grab->popups)) { + if (grab->seat->pointer_state.grab == &grab->pointer_grab) { + wlr_seat_pointer_end_grab(grab->seat); + } + if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { + wlr_seat_keyboard_end_grab(grab->seat); + } + } + + popup->seat = NULL; + } +} + void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) { if (popup == NULL) { return; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 7db308c07..ff8d0d979 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -42,34 +42,10 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - if (surface->toplevel->parent) { - wl_list_remove(&surface->toplevel->parent_unmap.link); - surface->toplevel->parent = NULL; - } - free(surface->toplevel->title); - surface->toplevel->title = NULL; - free(surface->toplevel->app_id); - surface->toplevel->app_id = NULL; + unmap_xdg_toplevel(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: - if (surface->popup->seat != NULL) { - struct wlr_xdg_popup_grab *grab = - get_xdg_shell_popup_grab_from_seat(surface->client->shell, - surface->popup->seat); - - wl_list_remove(&surface->popup->grab_link); - - if (wl_list_empty(&grab->popups)) { - if (grab->seat->pointer_state.grab == &grab->pointer_grab) { - wlr_seat_pointer_end_grab(grab->seat); - } - if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { - wlr_seat_keyboard_end_grab(grab->seat); - } - } - - surface->popup->seat = NULL; - } + unmap_xdg_popup(surface->popup); break; case WLR_XDG_SURFACE_ROLE_NONE: assert(false && "not reached"); @@ -436,21 +412,13 @@ void reset_xdg_surface(struct wlr_xdg_surface *surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: wl_resource_set_user_data(surface->toplevel->resource, NULL); - surface->toplevel->resource = NULL; - struct wlr_xdg_toplevel_requested *req = - &surface->toplevel->requested; - if (req->fullscreen_output) { - wl_list_remove(&req->fullscreen_output_destroy.link); - } free(surface->toplevel); surface->toplevel = NULL; break; case WLR_XDG_SURFACE_ROLE_POPUP: - wl_resource_set_user_data(surface->popup->resource, NULL); - surface->popup->resource = NULL; - wl_list_remove(&surface->popup->link); + wl_resource_set_user_data(surface->popup->resource, NULL); free(surface->popup); surface->popup = NULL; break; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index e1f9a91df..8bbec9356 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -426,7 +426,10 @@ static const struct xdg_toplevel_interface xdg_toplevel_implementation = { static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(resource); - destroy_xdg_toplevel(toplevel); + if (toplevel == NULL) { + return; + } + reset_xdg_surface(toplevel->base); } const struct wlr_surface_role xdg_toplevel_surface_role = { @@ -482,11 +485,23 @@ void create_xdg_toplevel(struct wlr_xdg_surface *surface, surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; } -void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { - if (toplevel == NULL) { - return; +void unmap_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { + if (toplevel->parent) { + wl_list_remove(&toplevel->parent_unmap.link); + toplevel->parent = NULL; } - reset_xdg_surface(toplevel->base); + free(toplevel->title); + toplevel->title = NULL; + free(toplevel->app_id); + toplevel->app_id = NULL; + + if (toplevel->requested.fullscreen_output) { + wl_list_remove(&toplevel->requested.fullscreen_output_destroy.link); + toplevel->requested.fullscreen_output = NULL; + } + toplevel->requested.fullscreen = false; + toplevel->requested.maximized = false; + toplevel->requested.minimized = false; } void wlr_xdg_toplevel_send_close(struct wlr_xdg_toplevel *toplevel) { From d2b36b7bd1847ff9e3748bff5edbbf9b2ea8a71a Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:55 +0300 Subject: [PATCH 161/190] xdg-shell: fix potential use-after-free --- types/xdg_shell/wlr_xdg_popup.c | 1 + types/xdg_shell/wlr_xdg_toplevel.c | 1 + 2 files changed, 2 insertions(+) diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 17b71cd49..6f887fca9 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -331,6 +331,7 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, wl_resource_get_version(surface->resource), id); if (surface->popup->resource == NULL) { free(surface->popup); + surface->popup = NULL; wl_resource_post_no_memory(surface->resource); return; } diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 8bbec9356..ed7ecadd9 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -475,6 +475,7 @@ void create_xdg_toplevel(struct wlr_xdg_surface *surface, wl_resource_get_version(surface->resource), id); if (surface->toplevel->resource == NULL) { free(surface->toplevel); + surface->toplevel = NULL; wl_resource_post_no_memory(surface->resource); return; } From 88f30404386ce305b436b3877a56034eada3060f Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:56 +0300 Subject: [PATCH 162/190] xdg-popup: destroy popup-less grab This also fixes a seat destruction segfaulting if xdg-shell was destroyed first. --- include/types/wlr_xdg_shell.h | 2 -- types/xdg_shell/wlr_xdg_popup.c | 26 +++++++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 0c2b5cd5e..c0f977984 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -32,8 +32,6 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_positioner_resource *positioner, uint32_t id); void unmap_xdg_popup(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); -struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( - struct wlr_xdg_shell *shell, struct wlr_seat *seat); void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 6f887fca9..6fca33169 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -148,15 +148,15 @@ static const struct wlr_touch_grab_interface xdg_touch_grab_impl = { .cancel = xdg_touch_grab_cancel }; -static void xdg_popup_grab_handle_seat_destroy( - struct wl_listener *listener, void *data) { - struct wlr_xdg_popup_grab *xdg_grab = - wl_container_of(listener, xdg_grab, seat_destroy); +static void destroy_xdg_popup_grab(struct wlr_xdg_popup_grab *xdg_grab) { + if (xdg_grab == NULL) { + return; + } wl_list_remove(&xdg_grab->seat_destroy.link); - struct wlr_xdg_popup *popup, *next; - wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &xdg_grab->popups, grab_link) { destroy_xdg_surface(popup->base); } @@ -164,7 +164,14 @@ static void xdg_popup_grab_handle_seat_destroy( free(xdg_grab); } -struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( +static void xdg_popup_grab_handle_seat_destroy( + struct wl_listener *listener, void *data) { + struct wlr_xdg_popup_grab *xdg_grab = + wl_container_of(listener, xdg_grab, seat_destroy); + destroy_xdg_popup_grab(xdg_grab); +} + +static struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat) { struct wlr_xdg_popup_grab *xdg_grab; wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { @@ -371,6 +378,11 @@ void unmap_xdg_popup(struct wlr_xdg_popup *popup) { if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { wlr_seat_keyboard_end_grab(grab->seat); } + if (grab->seat->touch_state.grab == &grab->touch_grab) { + wlr_seat_touch_end_grab(grab->seat); + } + + destroy_xdg_popup_grab(grab); } popup->seat = NULL; From fd3a2a0906cc95a98c76cdf49a2f17cd23cc09e3 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:56 +0300 Subject: [PATCH 163/190] xdg-surface: minor consistency renaming --- types/xdg_shell/wlr_xdg_surface.c | 33 +++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index ff8d0d979..eb986104f 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -489,19 +489,17 @@ struct wlr_surface *wlr_xdg_surface_surface_at( struct wlr_surface *wlr_xdg_surface_popup_surface_at( struct wlr_xdg_surface *surface, double sx, double sy, double *sub_x, double *sub_y) { - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->mapped) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &surface->popups, link) { + if (!popup->base->mapped) { continue; } double popup_sx, popup_sy; - wlr_xdg_popup_get_position(popup_state, &popup_sx, &popup_sy); + wlr_xdg_popup_get_position(popup, &popup_sx, &popup_sy); - struct wlr_surface *sub = wlr_xdg_surface_surface_at(popup, - sx - popup_sx, - sy - popup_sy, + struct wlr_surface *sub = wlr_xdg_surface_surface_at( + popup->base, sx - popup_sx, sy - popup_sy, sub_x, sub_y); if (sub != NULL) { return sub; @@ -526,28 +524,25 @@ static void xdg_surface_iterator(struct wlr_surface *surface, static void xdg_surface_for_each_popup_surface(struct wlr_xdg_surface *surface, int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->configured || !popup->mapped) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &surface->popups, link) { + if (!popup->base->configured || !popup->base->mapped) { continue; } double popup_sx, popup_sy; - wlr_xdg_popup_get_position(popup_state, &popup_sx, &popup_sy); + wlr_xdg_popup_get_position(popup, &popup_sx, &popup_sy); struct xdg_surface_iterator_data data = { .user_iterator = iterator, .user_data = user_data, .x = x + popup_sx, .y = y + popup_sy, }; - wlr_surface_for_each_surface(popup->surface, xdg_surface_iterator, - &data); + wlr_surface_for_each_surface(popup->base->surface, + xdg_surface_iterator, &data); - xdg_surface_for_each_popup_surface(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); + xdg_surface_for_each_popup_surface(popup->base, + x + popup_sx, y + popup_sy, iterator, user_data); } } From 34a71eae313f55840e728500f7594fee4468226f Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:57 +0300 Subject: [PATCH 164/190] xdg-shell: drop wlr_xdg_toplevel_set_fullscreen_event Instead, compositors can read relevant values from wlr_xdg_toplevel.requested. --- include/wlr/types/wlr_xdg_shell.h | 6 ------ types/xdg_shell/wlr_xdg_toplevel.c | 16 ++-------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index a54d27235..4fcd6dd41 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -243,12 +243,6 @@ struct wlr_xdg_toplevel_resize_event { uint32_t edges; }; -struct wlr_xdg_toplevel_set_fullscreen_event { - struct wlr_xdg_toplevel *toplevel; - bool fullscreen; - struct wlr_output *output; -}; - struct wlr_xdg_toplevel_show_window_menu_event { struct wlr_xdg_toplevel *toplevel; struct wlr_seat_client *seat; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index ed7ecadd9..ad2f0501f 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -366,13 +366,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, true, output); - struct wlr_xdg_toplevel_set_fullscreen_event event = { - .toplevel = toplevel, - .fullscreen = true, - .output = output, - }; - - wlr_signal_emit_safe(&toplevel->events.request_fullscreen, &event); + wlr_signal_emit_safe(&toplevel->events.request_fullscreen, NULL); wlr_xdg_surface_schedule_configure(toplevel->base); } @@ -383,13 +377,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, false, NULL); - struct wlr_xdg_toplevel_set_fullscreen_event event = { - .toplevel = toplevel, - .fullscreen = false, - .output = NULL, - }; - - wlr_signal_emit_safe(&toplevel->events.request_fullscreen, &event); + wlr_signal_emit_safe(&toplevel->events.request_fullscreen, NULL); wlr_xdg_surface_schedule_configure(toplevel->base); } From 6ed3b02775e7f3622ffb1376480366ab76498b97 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:58 +0300 Subject: [PATCH 165/190] xdg-toplevel: fix `requested` doc `requested` is also checked on state change requests. --- include/wlr/types/wlr_xdg_shell.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 4fcd6dd41..d4a9f62bd 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -134,8 +134,8 @@ struct wlr_xdg_toplevel { struct wlr_xdg_toplevel_configure scheduled; // Properties that the client has requested. Intended to be checked - // by the compositor on surface map and handled accordingly - // (e.g. a client might want to start already in a fullscreen state). + // by the compositor on surface map and state change requests (such as + // xdg_toplevel::set_fullscreen) and handled accordingly. struct wlr_xdg_toplevel_requested requested; char *title; From 7ed60c54a0b7c10a0f70f54320e270691d40d673 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 8 Jan 2022 22:52:59 +0300 Subject: [PATCH 166/190] xdg-surface: avoid emitting signals with their owner object https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/1008#note_1139647 --- types/xdg_shell/wlr_xdg_shell.c | 2 +- types/xdg_shell/wlr_xdg_surface.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/xdg_shell/wlr_xdg_shell.c b/types/xdg_shell/wlr_xdg_shell.c index 0480d5f35..0b1302622 100644 --- a/types/xdg_shell/wlr_xdg_shell.c +++ b/types/xdg_shell/wlr_xdg_shell.c @@ -84,7 +84,7 @@ static int xdg_client_ping_timeout(void *user_data) { struct wlr_xdg_surface *surface; wl_list_for_each(surface, &client->surfaces, link) { - wlr_signal_emit_safe(&surface->events.ping_timeout, surface); + wlr_signal_emit_safe(&surface->events.ping_timeout, NULL); } client->ping_serial = 0; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index eb986104f..a9f7aa82e 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -37,7 +37,7 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) { // TODO: probably need to ungrab before this event if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, surface); + wlr_signal_emit_safe(&surface->events.unmap, NULL); } switch (surface->role) { @@ -312,7 +312,7 @@ void xdg_surface_role_commit(struct wlr_surface *wlr_surface) { if (surface->configured && wlr_surface_has_buffer(surface->surface) && !surface->mapped) { surface->mapped = true; - wlr_signal_emit_safe(&surface->events.map, surface); + wlr_signal_emit_safe(&surface->events.map, NULL); } } @@ -405,7 +405,7 @@ void reset_xdg_surface(struct wlr_xdg_surface *surface) { } if (surface->added) { - wlr_signal_emit_safe(&surface->events.destroy, surface); + wlr_signal_emit_safe(&surface->events.destroy, NULL); surface->added = false; } From c1a2c09ade789e5667bbe2dc04c6781d37fdab83 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 2 Feb 2022 20:54:29 +0300 Subject: [PATCH 167/190] xdg-popup: send invalid_positioner to the right resource --- types/xdg_shell/wlr_xdg_popup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 6fca33169..d923e923e 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -307,7 +307,7 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_positioner_resource *positioner, uint32_t id) { if (positioner->attrs.size.width == 0 || positioner->attrs.anchor_rect.width == 0) { - wl_resource_post_error(surface->resource, + wl_resource_post_error(surface->client->resource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "positioner object is not complete"); return; From 252b2348bd62170d97c4e81fb2050f757b56d67e Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 5 Feb 2022 16:32:38 +0100 Subject: [PATCH 168/190] wlr_cursor: constify map to region box arguments --- include/wlr/types/wlr_cursor.h | 4 ++-- types/wlr_cursor.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 739549c33..7dd73c48e 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -192,13 +192,13 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, /** * Maps this cursor to an arbitrary region on the associated wlr_output_layout. */ -void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box); +void wlr_cursor_map_to_region(struct wlr_cursor *cur, const struct wlr_box *box); /** * Maps inputs from this input device to an arbitrary region on the associated * wlr_output_layout. */ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_box *box); + struct wlr_input_device *dev, const struct wlr_box *box); #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 034628cf0..3160ca03b 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -865,7 +865,7 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, } void wlr_cursor_map_to_region(struct wlr_cursor *cur, - struct wlr_box *box) { + const struct wlr_box *box) { if (box) { if (wlr_box_empty(box)) { wlr_log(WLR_ERROR, "cannot map cursor to an empty region"); @@ -878,7 +878,7 @@ void wlr_cursor_map_to_region(struct wlr_cursor *cur, } void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_box *box) { + struct wlr_input_device *dev, const struct wlr_box *box) { struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { wlr_log(WLR_ERROR, "Cannot map device \"%s\" to geometry (not found in" From 35b3d67e5f0c12ae8d3174a268b0af73724ecc3e Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Thu, 17 Feb 2022 16:46:17 -0500 Subject: [PATCH 169/190] Fixed compiling with FFmpeg 5.0 --- examples/dmabuf-capture.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c index 4d05b78ba..58bf64195 100644 --- a/examples/dmabuf-capture.c +++ b/examples/dmabuf-capture.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 199309L +#include #include #include #include @@ -619,12 +620,12 @@ static int init_encoding(struct capture_context *ctx) { } /* Find encoder */ - AVCodec *out_codec = avcodec_find_encoder_by_name(ctx->encoder_name); + const AVCodec *out_codec = avcodec_find_encoder_by_name(ctx->encoder_name); if (!out_codec) { av_log(ctx, AV_LOG_ERROR, "Codec not found (not compiled in lavc?)!\n"); return AVERROR(EINVAL); } - ctx->avf->oformat->video_codec = out_codec->id; + ctx->avf->oformat = av_guess_format(ctx->encoder_name, NULL, NULL); ctx->is_software_encoder = !(out_codec->capabilities & AV_CODEC_CAP_HARDWARE); ctx->avctx = avcodec_alloc_context3(out_codec); From db6661502da7c6574d94d8f94a6d0f847fe10188 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 11 Feb 2022 20:49:30 +0300 Subject: [PATCH 170/190] CONTRIBUTING.md: update construction/destruction functions' description wlroots doesn't really follow the rule of keeping `create`/`destroy` and `init`/`finish` functions in pairs, so the relevant doc section is updated accordingly. --- CONTRIBUTING.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5b474e0c..63e279b53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -186,16 +186,23 @@ all of the characters, and replace any invalid characters with an underscore. ### Construction/Destruction Functions -For functions that are responsible for constructing and destructing an object, -they should be written as a pair of one of two forms: -* `init`/`finish`: These initialize/deinitialize a type, but are **NOT** -responsible for allocating it. They should accept a pointer to some -pre-allocated memory (e.g. a member of a struct). -* `create`/`destroy`: These also initialize/deinitialize, but will return a -pointer to a `malloc`ed chunk of memory, and will `free` it in `destroy`. +Functions that are responsible for constructing objects should take one of the +two following forms: -A destruction function should always be able to accept a NULL pointer or a -zeroed value and exit cleanly; this simplifies error handling a lot. +* `init`: for functions which accept a pointer to a pre-allocated object (e.g. +a member of a struct) and initialize it. +* `create`: for functions which allocate the memory for an object, initialize +it, and return a pointer. + +Likewise, functions that are responsible for destructing objects should take +one of the two following forms: + +* `finish`: for functions which accept a pointer to an object and deinitialize +it. Such functions should always be able to accept an already deinitialized +object. +* `destroy`: for functions which accept a pointer to an object, deinitialize +it, and free the memory. Such functions should always be able to accept a NULL +pointer. ### Error Codes From cff4abc5b15f2303a6e754b3e4bacd2bdef5811e Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Sun, 20 Feb 2022 17:47:15 +0100 Subject: [PATCH 171/190] output: clear buffer created for test When calling wlr_output_test an empty buffer might be created. This implicitly changes the pending state of the output. Ensure that such a change is only temporarily and clear such an empty buffer before returning the test result. --- types/output/output.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/types/output/output.c b/types/output/output.c index 0062013f7..1c0241fe5 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -639,6 +639,9 @@ static bool output_basic_test(struct wlr_output *output) { } bool wlr_output_test(struct wlr_output *output) { + bool had_buffer = output->pending.committed & WLR_OUTPUT_STATE_BUFFER; + bool success; + if (!output_basic_test(output)) { return false; } @@ -648,7 +651,13 @@ bool wlr_output_test(struct wlr_output *output) { if (!output->impl->test) { return true; } - return output->impl->test(output); + + success = output->impl->test(output); + + if (!had_buffer) { + output_clear_back_buffer(output); + } + return success; } bool wlr_output_commit(struct wlr_output *output) { From 7d560df90e7ee684dc26306f44a0b3c7f8cf2702 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Thu, 27 Jan 2022 10:00:57 -0500 Subject: [PATCH 172/190] backend/headless: remove unused wlr_headless_input_device --- backend/headless/backend.c | 13 ---- backend/headless/input_device.c | 108 -------------------------------- backend/headless/meson.build | 1 - include/backend/headless.h | 7 --- include/wlr/backend/headless.h | 9 +-- 5 files changed, 1 insertion(+), 137 deletions(-) delete mode 100644 backend/headless/input_device.c diff --git a/backend/headless/backend.c b/backend/headless/backend.c index b77881051..e44595de6 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -25,12 +25,6 @@ static bool backend_start(struct wlr_backend *wlr_backend) { &output->wlr_output); } - struct wlr_headless_input_device *input_device; - wl_list_for_each(input_device, &backend->input_devices, link) { - wlr_signal_emit_safe(&backend->backend.events.new_input, - &input_device->wlr_input_device); - } - backend->started = true; return true; } @@ -49,12 +43,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wlr_output_destroy(&output->wlr_output); } - struct wlr_headless_input_device *input_device, *input_device_tmp; - wl_list_for_each_safe(input_device, input_device_tmp, - &backend->input_devices, link) { - wlr_input_device_destroy(&input_device->wlr_input_device); - } - wlr_backend_finish(wlr_backend); free(backend); @@ -92,7 +80,6 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { backend->display = display; wl_list_init(&backend->outputs); - wl_list_init(&backend->input_devices); backend->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &backend->display_destroy); diff --git a/backend/headless/input_device.c b/backend/headless/input_device.c deleted file mode 100644 index 4df01aff8..000000000 --- a/backend/headless/input_device.c +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "backend/headless.h" -#include "util/signal.h" - -static void input_device_destroy(struct wlr_input_device *wlr_dev) { - struct wlr_headless_input_device *dev = - wl_container_of(wlr_dev, dev, wlr_input_device); - wl_list_remove(&dev->link); - free(dev); -} - -static const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy, -}; - -bool wlr_input_device_is_headless(struct wlr_input_device *wlr_dev) { - return wlr_dev->impl == &input_device_impl; -} - -struct wlr_input_device *wlr_headless_add_input_device( - struct wlr_backend *wlr_backend, enum wlr_input_device_type type) { - struct wlr_headless_backend *backend = - headless_backend_from_backend(wlr_backend); - - struct wlr_headless_input_device *device = - calloc(1, sizeof(struct wlr_headless_input_device)); - if (device == NULL) { - return NULL; - } - device->backend = backend; - - int vendor = 0; - int product = 0; - const char *name = "headless"; - struct wlr_input_device *wlr_device = &device->wlr_input_device; - wlr_input_device_init(wlr_device, type, &input_device_impl, name, vendor, - product); - - switch (type) { - case WLR_INPUT_DEVICE_KEYBOARD: - wlr_device->keyboard = calloc(1, sizeof(struct wlr_keyboard)); - if (wlr_device->keyboard == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_keyboard"); - goto error; - } - wlr_keyboard_init(wlr_device->keyboard, NULL); - break; - case WLR_INPUT_DEVICE_POINTER: - wlr_device->pointer = calloc(1, sizeof(struct wlr_pointer)); - if (wlr_device->pointer == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer"); - goto error; - } - wlr_pointer_init(wlr_device->pointer, NULL); - break; - case WLR_INPUT_DEVICE_TOUCH: - wlr_device->touch = calloc(1, sizeof(struct wlr_touch)); - if (wlr_device->touch == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_touch"); - goto error; - } - wlr_touch_init(wlr_device->touch, NULL); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - wlr_device->tablet = calloc(1, sizeof(struct wlr_tablet)); - if (wlr_device->tablet == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet"); - goto error; - } - wlr_tablet_init(wlr_device->tablet, NULL); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - wlr_device->tablet_pad = calloc(1, sizeof(struct wlr_tablet_pad)); - if (wlr_device->tablet_pad == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad"); - goto error; - } - wlr_tablet_pad_init(wlr_device->tablet_pad, NULL); - break; - case WLR_INPUT_DEVICE_SWITCH: - wlr_device->switch_device = calloc(1, sizeof(struct wlr_switch)); - if (wlr_device->switch_device == NULL) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_switch"); - goto error; - } - wlr_switch_init(wlr_device->switch_device, NULL); - } - - wl_list_insert(&backend->input_devices, &device->link); - - if (backend->started) { - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_device); - } - - return wlr_device; -error: - free(device); - return NULL; -} diff --git a/backend/headless/meson.build b/backend/headless/meson.build index e38ce1333..950c07160 100644 --- a/backend/headless/meson.build +++ b/backend/headless/meson.build @@ -1,5 +1,4 @@ wlr_files += files( 'backend.c', - 'input_device.c', 'output.c', ) diff --git a/include/backend/headless.h b/include/backend/headless.h index e126ac4ef..047509009 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -11,7 +11,6 @@ struct wlr_headless_backend { struct wl_display *display; struct wl_list outputs; size_t last_output_num; - struct wl_list input_devices; struct wl_listener display_destroy; bool started; }; @@ -26,12 +25,6 @@ struct wlr_headless_output { int frame_delay; // ms }; -struct wlr_headless_input_device { - struct wlr_input_device wlr_input_device; - struct wl_list link; - struct wlr_headless_backend *backend; -}; - struct wlr_headless_backend *headless_backend_from_backend( struct wlr_backend *wlr_backend); diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index 07dac9b84..f47354830 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -25,15 +25,8 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); */ struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend, unsigned int width, unsigned int height); -/** - * Creates a new input device. The caller is responsible for manually raising - * any event signals on the new input device if it wants to simulate input - * events. - */ -struct wlr_input_device *wlr_headless_add_input_device( - struct wlr_backend *backend, enum wlr_input_device_type type); + bool wlr_backend_is_headless(struct wlr_backend *backend); -bool wlr_input_device_is_headless(struct wlr_input_device *device); bool wlr_output_is_headless(struct wlr_output *output); #endif From 71577e351e7954467e2376ac7bb92edc4ce53159 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 4 Feb 2022 09:26:57 -0500 Subject: [PATCH 173/190] types/wlr_input_device: default vendor and product id to 0 vendor and product id are set when needed by the libinput backend --- backend/libinput/events.c | 7 +++---- backend/wayland/seat.c | 5 +---- backend/x11/backend.c | 2 +- backend/x11/output.c | 4 ++-- include/wlr/interfaces/wlr_input_device.h | 8 +++----- types/wlr_input_device.c | 7 +++---- types/wlr_virtual_keyboard_v1.c | 3 +-- types/wlr_virtual_pointer_v1.c | 3 +-- 8 files changed, 15 insertions(+), 24 deletions(-) diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 67598998b..1f28b94ac 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -48,8 +48,6 @@ static struct wlr_input_device *allocate_device( struct wlr_libinput_backend *backend, struct libinput_device *libinput_dev, struct wl_list *wlr_devices, enum wlr_input_device_type type) { - int vendor = libinput_device_get_id_vendor(libinput_dev); - int product = libinput_device_get_id_product(libinput_dev); const char *name = libinput_device_get_name(libinput_dev); struct wlr_libinput_input_device *dev = calloc(1, sizeof(struct wlr_libinput_input_device)); @@ -66,8 +64,9 @@ static struct wlr_input_device *allocate_device( wl_list_insert(wlr_devices, &dev->link); dev->handle = libinput_dev; libinput_device_ref(libinput_dev); - wlr_input_device_init(wlr_dev, type, &input_device_impl, - name, vendor, product); + wlr_input_device_init(wlr_dev, type, &input_device_impl, name); + wlr_dev->vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_dev->product = libinput_device_get_id_product(libinput_dev); return wlr_dev; } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 76c25fe5a..d22d5e634 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -466,8 +466,6 @@ struct wlr_wl_input_device *create_wl_input_device( struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - unsigned int vendor = 0, product = 0; - const char *type_name = "unknown"; switch (type) { @@ -495,8 +493,7 @@ struct wlr_wl_input_device *create_wl_input_device( char name[name_size]; (void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name); - wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, - product); + wlr_input_device_init(wlr_dev, type, &input_device_impl, name); wl_list_insert(&seat->backend->devices, &dev->link); return dev; } diff --git a/backend/x11/backend.c b/backend/x11/backend.c index ae20559cb..70fc0478d 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -639,7 +639,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, #endif wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD, - &input_device_impl, "X11 keyboard", 0, 0); + &input_device_impl, "X11 keyboard"); wlr_keyboard_init(&x11->keyboard, &keyboard_impl); x11->keyboard_dev.keyboard = &x11->keyboard; diff --git a/backend/x11/output.c b/backend/x11/output.c index b87b08dc5..d500795f9 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -574,13 +574,13 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_enabled(wlr_output, true); wlr_input_device_init(&output->pointer_dev, WLR_INPUT_DEVICE_POINTER, - &input_device_impl, "X11 pointer", 0, 0); + &input_device_impl, "X11 pointer"); wlr_pointer_init(&output->pointer, &pointer_impl); output->pointer_dev.pointer = &output->pointer; output->pointer_dev.output_name = strdup(wlr_output->name); wlr_input_device_init(&output->touch_dev, WLR_INPUT_DEVICE_TOUCH, - &input_device_impl, "X11 touch", 0, 0); + &input_device_impl, "X11 touch"); wlr_touch_init(&output->touch, &touch_impl); output->touch_dev.touch = &output->touch; output->touch_dev.output_name = strdup(wlr_output->name); diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h index 05248bf60..04d5644fa 100644 --- a/include/wlr/interfaces/wlr_input_device.h +++ b/include/wlr/interfaces/wlr_input_device.h @@ -15,11 +15,9 @@ struct wlr_input_device_impl { void (*destroy)(struct wlr_input_device *wlr_device); }; -void wlr_input_device_init( - struct wlr_input_device *wlr_device, - enum wlr_input_device_type type, - const struct wlr_input_device_impl *impl, - const char *name, int vendor, int product); +void wlr_input_device_init(struct wlr_input_device *wlr_device, + enum wlr_input_device_type type, const struct wlr_input_device_impl *impl, + const char *name); void wlr_input_device_destroy(struct wlr_input_device *dev); #endif diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 1364aa3d9..7f9654e52 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -15,13 +15,12 @@ void wlr_input_device_init(struct wlr_input_device *dev, enum wlr_input_device_type type, - const struct wlr_input_device_impl *impl, - const char *name, int vendor, int product) { + const struct wlr_input_device_impl *impl, const char *name) { dev->type = type; dev->impl = impl; dev->name = strdup(name); - dev->vendor = vendor; - dev->product = product; + dev->vendor = 0; + dev->product = 0; wl_signal_init(&dev->events.destroy); } diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index db643ef34..3b195ab34 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -207,8 +207,7 @@ static void virtual_keyboard_manager_create_virtual_keyboard( virtual_keyboard, virtual_keyboard_destroy_resource); wlr_input_device_init(&virtual_keyboard->input_device, - WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "virtual keyboard", - 0x0, 0x0); + WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "virtual keyboard"); struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat); diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index a9d1fd7bc..bb1b31dde 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -270,8 +270,7 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( virtual_pointer, virtual_pointer_destroy_resource); wlr_input_device_init(&virtual_pointer->input_device, - WLR_INPUT_DEVICE_POINTER, &input_device_impl, "virtual pointer", - 0x0, 0x0); + WLR_INPUT_DEVICE_POINTER, &input_device_impl, "virtual pointer"); struct wlr_virtual_pointer_v1_new_pointer_event event = { .new_pointer = virtual_pointer, From fd80329c53ed00b9411095b60e9d0611c016ec03 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 8 Feb 2022 11:20:44 -0500 Subject: [PATCH 174/190] interfaces/wlr_input_device: introduce wlr_input_device_finish This function releases the wlr_input_device allocated memory (it's name and it's output name), and signals its destroy event. --- include/wlr/interfaces/wlr_input_device.h | 7 +++++++ types/wlr_input_device.c | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h index 04d5644fa..de5273930 100644 --- a/include/wlr/interfaces/wlr_input_device.h +++ b/include/wlr/interfaces/wlr_input_device.h @@ -18,6 +18,13 @@ struct wlr_input_device_impl { void wlr_input_device_init(struct wlr_input_device *wlr_device, enum wlr_input_device_type type, const struct wlr_input_device_impl *impl, const char *name); + +/** + * Cleans up all of the provided wlr_input_device resources and signals the + * destroy event. + */ +void wlr_input_device_finish(struct wlr_input_device *wlr_device); + void wlr_input_device_destroy(struct wlr_input_device *dev); #endif diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 7f9654e52..50afdaff9 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -25,6 +25,17 @@ void wlr_input_device_init(struct wlr_input_device *dev, wl_signal_init(&dev->events.destroy); } +void wlr_input_device_finish(struct wlr_input_device *wlr_device) { + if (!wlr_device) { + return; + } + + wlr_signal_emit_safe(&wlr_device->events.destroy, wlr_device); + + free(wlr_device->name); + free(wlr_device->output_name); +} + void wlr_input_device_destroy(struct wlr_input_device *dev) { if (!dev) { return; From 130c3bcf6361a76a889790e1907b78c607053659 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 11 Feb 2022 09:06:26 -0500 Subject: [PATCH 175/190] types/wlr_input_device: call the specialized input device destroy function on destroy In case the `wlr_input_device` is not owned by a specialized input device, the function will finish the wlr_input_device and call it's implementation destroy function if an implementation has been supplied, or simply free it. --- include/wlr/interfaces/wlr_input_device.h | 6 ++++++ types/wlr_input_device.c | 20 +++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h index de5273930..ab3148076 100644 --- a/include/wlr/interfaces/wlr_input_device.h +++ b/include/wlr/interfaces/wlr_input_device.h @@ -25,6 +25,12 @@ void wlr_input_device_init(struct wlr_input_device *wlr_device, */ void wlr_input_device_finish(struct wlr_input_device *wlr_device); +/** + * Calls the specialized input device destroy function. + * If the wlr_input_device is not owned by a specialized input device, the + * function will finish the wlr_input_device, and either call its implementation + * destroy function if one has been given, or free the wlr_input_device. + */ void wlr_input_device_destroy(struct wlr_input_device *dev); #endif diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 50afdaff9..8056556b9 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -41,8 +41,6 @@ void wlr_input_device_destroy(struct wlr_input_device *dev) { return; } - wlr_signal_emit_safe(&dev->events.destroy, dev); - if (dev->_device) { switch (dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: @@ -63,17 +61,13 @@ void wlr_input_device_destroy(struct wlr_input_device *dev) { case WLR_INPUT_DEVICE_TABLET_PAD: wlr_tablet_pad_destroy(dev->tablet_pad); break; - default: - wlr_log(WLR_DEBUG, "Warning: leaking memory %p %p %d", - dev->_device, dev, dev->type); - break; + } + } else { + wlr_input_device_finish(dev); + if (dev->impl && dev->impl->destroy) { + dev->impl->destroy(dev); + } else { + free(dev); } } - free(dev->name); - free(dev->output_name); - if (dev->impl && dev->impl->destroy) { - dev->impl->destroy(dev); - } else { - free(dev); - } } From a1978b1299952586a2fd016aab682c7fdbe735ee Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 28 Jan 2022 13:55:28 -0500 Subject: [PATCH 176/190] types/wlr_keyboard: add base wlr_input_device wlr_keyboard owns its base wlr_input_device. It will be initialized when the keyboard is initialized, and finished when the keyboard is destroyed. --- backend/libinput/keyboard.c | 5 +- backend/wayland/seat.c | 4 +- backend/x11/backend.c | 9 +- backend/x11/input_device.c | 7 +- include/backend/x11.h | 1 - include/wlr/interfaces/wlr_keyboard.h | 2 +- include/wlr/types/wlr_keyboard.h | 3 + include/wlr/types/wlr_keyboard_group.h | 2 - include/wlr/types/wlr_virtual_keyboard_v1.h | 2 +- types/wlr_keyboard.c | 8 +- types/wlr_keyboard_group.c | 13 +-- types/wlr_virtual_keyboard_v1.c | 95 +++++++++------------ 12 files changed, 66 insertions(+), 85 deletions(-) diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c index d5207f542..be5faf3e1 100644 --- a/backend/libinput/keyboard.c +++ b/backend/libinput/keyboard.c @@ -49,7 +49,10 @@ struct wlr_keyboard *create_libinput_keyboard( libinput_device_ref(libinput_dev); libinput_device_led_update(libinput_dev, 0); struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard; - wlr_keyboard_init(wlr_kb, &impl); + const char *name = libinput_device_get_name(libinput_dev); + wlr_keyboard_init(wlr_kb, &impl, name); + wlr_kb->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_kb->base.product = libinput_device_get_id_product(libinput_dev); return wlr_kb; } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d22d5e634..90a999505 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -785,14 +785,14 @@ void create_wl_keyboard(struct wlr_wl_seat *seat) { } struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard)); if (!wlr_dev->keyboard) { wlr_log_errno(WLR_ERROR, "Allocation failed"); wlr_input_device_destroy(wlr_dev); return; } - wlr_keyboard_init(wlr_dev->keyboard, NULL); + + wlr_keyboard_init(wlr_dev->keyboard, NULL, wlr_dev->name); wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 70fc0478d..3f2a9f016 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -165,7 +165,7 @@ static bool backend_start(struct wlr_backend *backend) { wlr_log(WLR_INFO, "Starting X11 backend"); - wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard_dev); + wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard.base); for (size_t i = 0; i < x11->requested_outputs; ++i) { wlr_x11_output_create(&x11->backend); @@ -186,7 +186,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_output_destroy(&output->wlr_output); } - wlr_input_device_destroy(&x11->keyboard_dev); + wlr_keyboard_destroy(&x11->keyboard); wlr_backend_finish(backend); @@ -638,10 +638,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } #endif - wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD, - &input_device_impl, "X11 keyboard"); - wlr_keyboard_init(&x11->keyboard, &keyboard_impl); - x11->keyboard_dev.keyboard = &x11->keyboard; + wlr_keyboard_init(&x11->keyboard, &keyboard_impl, "x11-keyboard"); x11->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &x11->display_destroy); diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index f9541b062..94b705245 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -336,5 +336,10 @@ void update_x11_pointer_position(struct wlr_x11_output *output, } bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) { - return wlr_dev->impl == &input_device_impl; + switch (wlr_dev->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + return wlr_dev->keyboard->impl == &keyboard_impl; + default: + return wlr_dev->impl == &input_device_impl; + } } diff --git a/include/backend/x11.h b/include/backend/x11.h index fadcbedc3..b5c430fba 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -81,7 +81,6 @@ struct wlr_x11_backend { struct wl_list outputs; // wlr_x11_output::link struct wlr_keyboard keyboard; - struct wlr_input_device keyboard_dev; int drm_fd; struct wlr_drm_format_set dri3_formats; diff --git a/include/wlr/interfaces/wlr_keyboard.h b/include/wlr/interfaces/wlr_keyboard.h index 5d537827c..4bcef57b2 100644 --- a/include/wlr/interfaces/wlr_keyboard.h +++ b/include/wlr/interfaces/wlr_keyboard.h @@ -18,7 +18,7 @@ struct wlr_keyboard_impl { }; void wlr_keyboard_init(struct wlr_keyboard *keyboard, - const struct wlr_keyboard_impl *impl); + const struct wlr_keyboard_impl *impl, const char *name); void wlr_keyboard_destroy(struct wlr_keyboard *keyboard); void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, struct wlr_event_keyboard_key *event); diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index ea16c4320..b3be053a5 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #define WLR_LED_COUNT 3 @@ -48,6 +49,8 @@ struct wlr_keyboard_modifiers { }; struct wlr_keyboard { + struct wlr_input_device base; + const struct wlr_keyboard_impl *impl; struct wlr_keyboard_group *group; diff --git a/include/wlr/types/wlr_keyboard_group.h b/include/wlr/types/wlr_keyboard_group.h index cb73899a7..3906d9489 100644 --- a/include/wlr/types/wlr_keyboard_group.h +++ b/include/wlr/types/wlr_keyboard_group.h @@ -11,11 +11,9 @@ #include #include -#include struct wlr_keyboard_group { struct wlr_keyboard keyboard; - struct wlr_input_device *input_device; struct wl_list devices; // keyboard_group_device::link struct wl_list keys; // keyboard_group_key::link diff --git a/include/wlr/types/wlr_virtual_keyboard_v1.h b/include/wlr/types/wlr_virtual_keyboard_v1.h index a3f4e4521..8be6158dc 100644 --- a/include/wlr/types/wlr_virtual_keyboard_v1.h +++ b/include/wlr/types/wlr_virtual_keyboard_v1.h @@ -26,7 +26,7 @@ struct wlr_virtual_keyboard_manager_v1 { }; struct wlr_virtual_keyboard_v1 { - struct wlr_input_device input_device; + struct wlr_keyboard keyboard; struct wl_resource *resource; struct wlr_seat *seat; bool has_keymap; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index c54e33c6c..062c08a09 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -114,7 +115,10 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, } void wlr_keyboard_init(struct wlr_keyboard *kb, - const struct wlr_keyboard_impl *impl) { + const struct wlr_keyboard_impl *impl, const char *name) { + wlr_input_device_init(&kb->base, WLR_INPUT_DEVICE_KEYBOARD, NULL, name); + kb->base.keyboard = kb; + kb->impl = impl; wl_signal_init(&kb->events.key); wl_signal_init(&kb->events.modifiers); @@ -134,6 +138,8 @@ void wlr_keyboard_destroy(struct wlr_keyboard *kb) { return; } wlr_signal_emit_safe(&kb->events.destroy, kb); + wlr_input_device_finish(&kb->base); + xkb_state_unref(kb->xkb_state); xkb_keymap_unref(kb->keymap); free(kb->keymap_string); diff --git a/types/wlr_keyboard_group.c b/types/wlr_keyboard_group.c index d614f58db..35fc54702 100644 --- a/types/wlr_keyboard_group.c +++ b/types/wlr_keyboard_group.c @@ -60,16 +60,7 @@ struct wlr_keyboard_group *wlr_keyboard_group_create(void) { return NULL; } - group->input_device = calloc(1, sizeof(struct wlr_input_device)); - if (!group->input_device) { - wlr_log(WLR_ERROR, "Failed to allocate wlr_input_device for group"); - free(group); - return NULL; - } - wl_signal_init(&group->input_device->events.destroy); - group->input_device->keyboard = &group->keyboard; - - wlr_keyboard_init(&group->keyboard, &impl); + wlr_keyboard_init(&group->keyboard, &impl, "keyboard-group"); wl_list_init(&group->devices); wl_list_init(&group->keys); @@ -335,9 +326,7 @@ void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) { wlr_keyboard_group_remove_keyboard(group, device->keyboard); } wlr_keyboard_destroy(&group->keyboard); - wl_list_remove(&group->input_device->events.destroy.listener_list); wl_list_remove(&group->events.enter.listener_list); wl_list_remove(&group->events.leave.listener_list); - free(group->input_device); free(group); } diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 3b195ab34..dc549aa72 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -11,26 +11,40 @@ #include "util/time.h" #include "virtual-keyboard-unstable-v1-protocol.h" - -static void keyboard_led_update(struct wlr_keyboard *wlr_kb, uint32_t leds) { - // unsupported by virtual keyboard protocol +/** + * Send release event for each pressed key to bring the keyboard back to + * neutral state. + * + * This may be needed for virtual keyboards. For physical devices, kernel + * or libinput will deal with the removal of devices. + */ +static void keyboard_release_pressed_keys(struct wlr_keyboard *keyboard) { + size_t orig_num_keycodes = keyboard->num_keycodes; + for (size_t i = 0; i < orig_num_keycodes; ++i) { + assert(keyboard->num_keycodes == orig_num_keycodes - i); + struct wlr_event_keyboard_key event = { + .time_msec = get_current_time_msec(), + .keycode = keyboard->keycodes[orig_num_keycodes - i - 1], + .update_state = false, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }; + wlr_keyboard_notify_key(keyboard, &event); // updates num_keycodes + } } static void keyboard_destroy(struct wlr_keyboard *wlr_kb) { - // safe to ignore - keyboard will be destroyed only iff associated virtual - // keyboard is torn down, no need to tear down the keyboard separately + struct wlr_virtual_keyboard_v1 *keyboard = + (struct wlr_virtual_keyboard_v1 *)wlr_kb; + + keyboard_release_pressed_keys(&keyboard->keyboard); + wl_resource_set_user_data(keyboard->resource, NULL); + wlr_signal_emit_safe(&keyboard->events.destroy, keyboard); + wl_list_remove(&keyboard->link); + free(keyboard); } static const struct wlr_keyboard_impl keyboard_impl = { .destroy = keyboard_destroy, - .led_update = keyboard_led_update -}; - -static void input_device_destroy(struct wlr_input_device *dev) { -} - -static const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy }; static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl; @@ -44,10 +58,11 @@ static struct wlr_virtual_keyboard_v1 *virtual_keyboard_from_resource( struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard( struct wlr_input_device *wlr_dev) { - if (wlr_dev->impl != &input_device_impl) { + if (wlr_dev->type != WLR_INPUT_DEVICE_KEYBOARD + || wlr_dev->keyboard->impl != &keyboard_impl) { return NULL; } - return (struct wlr_virtual_keyboard_v1 *)wlr_dev; + return (struct wlr_virtual_keyboard_v1 *)wlr_dev->keyboard; } static void virtual_keyboard_keymap(struct wl_client *client, @@ -70,7 +85,7 @@ static void virtual_keyboard_keymap(struct wl_client *client, if (!keymap) { goto keymap_fail; } - wlr_keyboard_set_keymap(keyboard->input_device.keyboard, keymap); + wlr_keyboard_set_keymap(&keyboard->keyboard, keymap); keyboard->has_keymap = true; xkb_keymap_unref(keymap); xkb_context_unref(context); @@ -101,7 +116,7 @@ static void virtual_keyboard_key(struct wl_client *client, .update_state = false, .state = state, }; - wlr_keyboard_notify_key(keyboard->input_device.keyboard, &event); + wlr_keyboard_notify_key(&keyboard->keyboard, &event); } static void virtual_keyboard_modifiers(struct wl_client *client, @@ -115,39 +130,16 @@ static void virtual_keyboard_modifiers(struct wl_client *client, "Cannot send a modifier state before defining a keymap"); return; } - wlr_keyboard_notify_modifiers(keyboard->input_device.keyboard, + wlr_keyboard_notify_modifiers(&keyboard->keyboard, mods_depressed, mods_latched, mods_locked, group); } -/** - * Send release event for each pressed key to bring the keyboard back to - * neutral state. - * - * This may be needed for virtual keyboards. For physical devices, kernel - * or libinput will deal with the removal of devices. - */ -static void keyboard_release_pressed_keys(struct wlr_keyboard *keyboard) { - size_t orig_num_keycodes = keyboard->num_keycodes; - for (size_t i = 0; i < orig_num_keycodes; ++i) { - assert(keyboard->num_keycodes == orig_num_keycodes - i); - struct wlr_event_keyboard_key event = { - .time_msec = get_current_time_msec(), - .keycode = keyboard->keycodes[orig_num_keycodes - i - 1], - .update_state = false, - .state = WL_KEYBOARD_KEY_STATE_RELEASED, - }; - wlr_keyboard_notify_key(keyboard, &event); // updates num_keycodes - } -} - static void virtual_keyboard_destroy_resource(struct wl_resource *resource) { struct wlr_virtual_keyboard_v1 *keyboard = virtual_keyboard_from_resource(resource); - keyboard_release_pressed_keys(keyboard->input_device.keyboard); - wlr_signal_emit_safe(&keyboard->events.destroy, keyboard); - wl_list_remove(&keyboard->link); - wlr_input_device_destroy(&keyboard->input_device); - free(keyboard); + if (keyboard != NULL) { + wlr_keyboard_destroy(&keyboard->keyboard); + } } static void virtual_keyboard_destroy(struct wl_client *client, @@ -184,20 +176,13 @@ static void virtual_keyboard_manager_create_virtual_keyboard( return; } - struct wlr_keyboard* keyboard = calloc(1, sizeof(struct wlr_keyboard)); - if (!keyboard) { - wlr_log(WLR_ERROR, "Cannot allocate wlr_keyboard"); - free(virtual_keyboard); - wl_client_post_no_memory(client); - return; - } - wlr_keyboard_init(keyboard, &keyboard_impl); + wlr_keyboard_init(&virtual_keyboard->keyboard, &keyboard_impl, + "virtual-keyboard"); struct wl_resource *keyboard_resource = wl_resource_create(client, &zwp_virtual_keyboard_v1_interface, wl_resource_get_version(resource), id); if (!keyboard_resource) { - free(keyboard); free(virtual_keyboard); wl_client_post_no_memory(client); return; @@ -206,12 +191,8 @@ static void virtual_keyboard_manager_create_virtual_keyboard( wl_resource_set_implementation(keyboard_resource, &virtual_keyboard_impl, virtual_keyboard, virtual_keyboard_destroy_resource); - wlr_input_device_init(&virtual_keyboard->input_device, - WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "virtual keyboard"); - struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat); - virtual_keyboard->input_device.keyboard = keyboard; virtual_keyboard->resource = keyboard_resource; virtual_keyboard->seat = seat_client->seat; wl_signal_init(&virtual_keyboard->events.destroy); From d5480efc7a03641600df411dea93308e5edc8b27 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 31 Jan 2022 10:20:01 -0500 Subject: [PATCH 177/190] types/wlr_pointer: add base wlr_input_device wlr_pointer owns its wlr_input_device. It will be initialized when the pointer is initialized, and finished when the pointer is destroyed. --- backend/libinput/pointer.c | 5 +- backend/wayland/seat.c | 8 +++- backend/x11/input_device.c | 8 ++-- backend/x11/output.c | 11 ++--- include/backend/x11.h | 3 +- include/wlr/interfaces/wlr_pointer.h | 2 +- include/wlr/types/wlr_pointer.h | 2 + include/wlr/types/wlr_virtual_pointer_v1.h | 3 +- types/wlr_pointer.c | 7 ++- types/wlr_virtual_pointer_v1.c | 55 +++++++++------------- 10 files changed, 53 insertions(+), 51 deletions(-) diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 520f98dcf..305c43d9c 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -16,7 +16,10 @@ struct wlr_pointer *create_libinput_pointer( wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer"); return NULL; } - wlr_pointer_init(wlr_pointer, NULL); + const char *name = libinput_device_get_name(libinput_dev); + wlr_pointer_init(wlr_pointer, NULL, name); + wlr_pointer->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_pointer->base.product = libinput_device_get_id_product(libinput_dev); return wlr_pointer; } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 90a999505..633e585a8 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -532,6 +532,10 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) { zwp_relative_pointer_v1_destroy(pointer->relative_pointer); } + wlr_input_device_finish(&pointer->input_device->wlr_input_device); + wl_list_remove(&pointer->input_device->link); + free(pointer->input_device); + wl_list_remove(&pointer->output_destroy.link); free(pointer); } @@ -705,7 +709,7 @@ static void pointer_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_wl_pointer *pointer = wl_container_of(listener, pointer, output_destroy); - wlr_input_device_destroy(&pointer->input_device->wlr_input_device); + wlr_pointer_destroy(&pointer->wlr_pointer); } void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { @@ -743,7 +747,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { struct wlr_input_device *wlr_dev = &dev->wlr_input_device; wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->output_name = strdup(output->wlr_output.name); - wlr_pointer_init(wlr_dev->pointer, &pointer_impl); + wlr_pointer_init(wlr_dev->pointer, &pointer_impl, wlr_dev->name); if (backend->zwp_pointer_gestures_v1) { uint32_t version = zwp_pointer_gestures_v1_get_version( diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index 94b705245..5ca3e956f 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -33,7 +33,7 @@ static void send_key_event(struct wlr_x11_backend *x11, uint32_t key, static void send_button_event(struct wlr_x11_output *output, uint32_t key, enum wlr_button_state st, xcb_timestamp_t time) { struct wlr_event_pointer_button ev = { - .device = &output->pointer_dev, + .device = &output->pointer.base, .time_msec = time, .button = key, .state = st, @@ -45,7 +45,7 @@ static void send_button_event(struct wlr_x11_output *output, uint32_t key, static void send_axis_event(struct wlr_x11_output *output, int32_t delta, xcb_timestamp_t time) { struct wlr_event_pointer_axis ev = { - .device = &output->pointer_dev, + .device = &output->pointer.base, .time_msec = time, .source = WLR_AXIS_SOURCE_WHEEL, .orientation = WLR_AXIS_ORIENTATION_VERTICAL, @@ -60,7 +60,7 @@ static void send_axis_event(struct wlr_x11_output *output, int32_t delta, static void send_pointer_position_event(struct wlr_x11_output *output, int16_t x, int16_t y, xcb_timestamp_t time) { struct wlr_event_pointer_motion_absolute ev = { - .device = &output->pointer_dev, + .device = &output->pointer.base, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, @@ -339,6 +339,8 @@ bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) { switch (wlr_dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: return wlr_dev->keyboard->impl == &keyboard_impl; + case WLR_INPUT_DEVICE_POINTER: + return wlr_dev->pointer->impl == &pointer_impl; default: return wlr_dev->impl == &input_device_impl; } diff --git a/backend/x11/output.c b/backend/x11/output.c index d500795f9..19eb5d55e 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -76,7 +76,7 @@ static void output_destroy(struct wlr_output *wlr_output) { pixman_region32_fini(&output->exposed); - wlr_input_device_destroy(&output->pointer_dev); + wlr_pointer_destroy(&output->pointer); wlr_input_device_destroy(&output->touch_dev); struct wlr_x11_buffer *buffer, *buffer_tmp; @@ -573,11 +573,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_enabled(wlr_output, true); - wlr_input_device_init(&output->pointer_dev, WLR_INPUT_DEVICE_POINTER, - &input_device_impl, "X11 pointer"); - wlr_pointer_init(&output->pointer, &pointer_impl); - output->pointer_dev.pointer = &output->pointer; - output->pointer_dev.output_name = strdup(wlr_output->name); + wlr_pointer_init(&output->pointer, &pointer_impl, "x11-pointer"); + output->pointer.base.output_name = strdup(wlr_output->name); wlr_input_device_init(&output->touch_dev, WLR_INPUT_DEVICE_TOUCH, &input_device_impl, "X11 touch"); @@ -587,7 +584,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wl_list_init(&output->touchpoints); wlr_signal_emit_safe(&x11->backend.events.new_output, wlr_output); - wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer_dev); + wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer.base); wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch_dev); // Start the rendering loop by requesting the compositor to render a frame diff --git a/include/backend/x11.h b/include/backend/x11.h index b5c430fba..ee4846549 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f @@ -35,7 +35,6 @@ struct wlr_x11_output { xcb_present_event_t present_event_id; struct wlr_pointer pointer; - struct wlr_input_device pointer_dev; struct wlr_touch touch; struct wlr_input_device touch_dev; diff --git a/include/wlr/interfaces/wlr_pointer.h b/include/wlr/interfaces/wlr_pointer.h index fd3ab1023..e39500175 100644 --- a/include/wlr/interfaces/wlr_pointer.h +++ b/include/wlr/interfaces/wlr_pointer.h @@ -16,7 +16,7 @@ struct wlr_pointer_impl { }; void wlr_pointer_init(struct wlr_pointer *pointer, - const struct wlr_pointer_impl *impl); + const struct wlr_pointer_impl *impl, const char *name); void wlr_pointer_destroy(struct wlr_pointer *pointer); #endif diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index bcfb2ad3d..a58507189 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -17,6 +17,8 @@ struct wlr_pointer_impl; struct wlr_pointer { + struct wlr_input_device base; + const struct wlr_pointer_impl *impl; struct { diff --git a/include/wlr/types/wlr_virtual_pointer_v1.h b/include/wlr/types/wlr_virtual_pointer_v1.h index ede9bebf5..307d61586 100644 --- a/include/wlr/types/wlr_virtual_pointer_v1.h +++ b/include/wlr/types/wlr_virtual_pointer_v1.h @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -28,7 +27,7 @@ struct wlr_virtual_pointer_manager_v1 { }; struct wlr_virtual_pointer_v1 { - struct wlr_input_device input_device; + struct wlr_pointer pointer; struct wl_resource *resource; /* Vertical and horizontal */ struct wlr_event_pointer_axis axis_event[2]; diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index a6590e73d..d6237c736 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -1,11 +1,15 @@ #include #include #include +#include #include #include void wlr_pointer_init(struct wlr_pointer *pointer, - const struct wlr_pointer_impl *impl) { + const struct wlr_pointer_impl *impl, const char *name) { + wlr_input_device_init(&pointer->base, WLR_INPUT_DEVICE_POINTER, NULL, name); + pointer->base.pointer = pointer; + pointer->impl = impl; wl_signal_init(&pointer->events.motion); wl_signal_init(&pointer->events.motion_absolute); @@ -26,6 +30,7 @@ void wlr_pointer_destroy(struct wlr_pointer *pointer) { if (!pointer) { return; } + wlr_input_device_finish(&pointer->base); if (pointer->impl && pointer->impl->destroy) { pointer->impl->destroy(pointer); } else { diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index bb1b31dde..6215bbfff 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,17 +8,18 @@ #include "util/signal.h" #include "wlr-virtual-pointer-unstable-v1-protocol.h" -static void input_device_destroy(struct wlr_input_device *dev) { - struct wlr_virtual_pointer_v1 *pointer = - (struct wlr_virtual_pointer_v1 *)dev; - wl_resource_set_user_data(pointer->resource, NULL); - wlr_signal_emit_safe(&pointer->events.destroy, pointer); - wl_list_remove(&pointer->link); - free(pointer); +static void pointer_destroy(struct wlr_pointer *pointer) { + struct wlr_virtual_pointer_v1 *virtual_pointer = + (struct wlr_virtual_pointer_v1 *)pointer; + + wl_resource_set_user_data(virtual_pointer->resource, NULL); + wlr_signal_emit_safe(&virtual_pointer->events.destroy, virtual_pointer); + wl_list_remove(&virtual_pointer->link); + free(virtual_pointer); } -static const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy +static const struct wlr_pointer_impl pointer_impl = { + .destroy = pointer_destroy, }; static const struct zwlr_virtual_pointer_v1_interface virtual_pointer_impl; @@ -37,7 +39,7 @@ static void virtual_pointer_motion(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; struct wlr_event_pointer_motion event = { .device = wlr_dev, .time_msec = time, @@ -46,7 +48,7 @@ static void virtual_pointer_motion(struct wl_client *client, .unaccel_dx = wl_fixed_to_double(dx), .unaccel_dy = wl_fixed_to_double(dy), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &event); + wlr_signal_emit_safe(&pointer->pointer.events.motion, &event); } static void virtual_pointer_motion_absolute(struct wl_client *client, @@ -60,7 +62,7 @@ static void virtual_pointer_motion_absolute(struct wl_client *client, if (x_extent == 0 || y_extent == 0) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; struct wlr_event_pointer_motion_absolute event = { .device = wlr_dev, .time_msec = time, @@ -78,7 +80,7 @@ static void virtual_pointer_button(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; struct wlr_event_pointer_button event = { .device = wlr_dev, .time_msec = time, @@ -102,7 +104,7 @@ static void virtual_pointer_axis(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; pointer->axis_event[pointer->axis].device = wlr_dev; @@ -118,7 +120,7 @@ static void virtual_pointer_frame(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; for (size_t i = 0; i < sizeof(pointer->axis_valid) / sizeof(pointer->axis_valid[0]); @@ -148,7 +150,7 @@ static void virtual_pointer_axis_source(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis_event[pointer->axis].device = wlr_dev; pointer->axis_event[pointer->axis].source = source; } @@ -166,7 +168,7 @@ static void virtual_pointer_axis_stop(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; pointer->axis_event[pointer->axis].device = wlr_dev; @@ -190,7 +192,7 @@ static void virtual_pointer_axis_discrete(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->input_device; + struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; pointer->axis_event[pointer->axis].device = wlr_dev; @@ -204,7 +206,7 @@ static void virtual_pointer_destroy_resource(struct wl_resource *resource) { struct wlr_virtual_pointer_v1 *pointer = virtual_pointer_from_resource(resource); if (pointer != NULL) { - wlr_input_device_destroy(&pointer->input_device); + wlr_pointer_destroy(&pointer->pointer); } } @@ -247,20 +249,13 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( return; } - struct wlr_pointer *pointer = calloc(1, sizeof(struct wlr_pointer)); - if (!pointer) { - wlr_log(WLR_ERROR, "Cannot allocate wlr_pointer"); - free(virtual_pointer); - wl_client_post_no_memory(client); - return; - } - wlr_pointer_init(pointer, NULL); + wlr_pointer_init(&virtual_pointer->pointer, &pointer_impl, + "virtual-pointer"); struct wl_resource *pointer_resource = wl_resource_create(client, &zwlr_virtual_pointer_v1_interface, wl_resource_get_version(resource), id); if (!pointer_resource) { - free(pointer); free(virtual_pointer); wl_client_post_no_memory(client); return; @@ -269,9 +264,6 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( wl_resource_set_implementation(pointer_resource, &virtual_pointer_impl, virtual_pointer, virtual_pointer_destroy_resource); - wlr_input_device_init(&virtual_pointer->input_device, - WLR_INPUT_DEVICE_POINTER, &input_device_impl, "virtual pointer"); - struct wlr_virtual_pointer_v1_new_pointer_event event = { .new_pointer = virtual_pointer, }; @@ -287,7 +279,6 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( event.suggested_output = wlr_output; } - virtual_pointer->input_device.pointer = pointer; virtual_pointer->resource = pointer_resource; wl_signal_init(&virtual_pointer->events.destroy); From 0f3b38365d07bb3e65b5ce2ec265453115276d1d Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 31 Jan 2022 10:53:58 -0500 Subject: [PATCH 178/190] types/wlr_switch: add base wlr_input_device wlr_switch owns its wlr_input_device. It will be initialized when the switch is initialized, and finished when the switch is destroyed. --- backend/libinput/switch.c | 7 +++++-- include/wlr/interfaces/wlr_switch.h | 2 +- include/wlr/types/wlr_switch.h | 2 ++ types/wlr_switch.c | 8 +++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c index a9c33d3ab..9562e185b 100644 --- a/backend/libinput/switch.c +++ b/backend/libinput/switch.c @@ -16,8 +16,11 @@ struct wlr_switch *create_libinput_switch( wlr_log(WLR_ERROR, "Unable to allocate wlr_switch"); return NULL; } - wlr_switch_init(wlr_switch, NULL); - wlr_log(WLR_DEBUG, "Created switch for device %s", libinput_device_get_name(libinput_dev)); + const char *name = libinput_device_get_name(libinput_dev); + wlr_switch_init(wlr_switch, NULL, name); + wlr_log(WLR_DEBUG, "Created switch for device %s", name); + wlr_switch->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_switch->base.product = libinput_device_get_id_product(libinput_dev); return wlr_switch; } diff --git a/include/wlr/interfaces/wlr_switch.h b/include/wlr/interfaces/wlr_switch.h index 83a1365b5..cce55f98f 100644 --- a/include/wlr/interfaces/wlr_switch.h +++ b/include/wlr/interfaces/wlr_switch.h @@ -16,7 +16,7 @@ struct wlr_switch_impl { }; void wlr_switch_init(struct wlr_switch *switch_device, - struct wlr_switch_impl *impl); + struct wlr_switch_impl *impl, const char *name); void wlr_switch_destroy(struct wlr_switch *switch_device); #endif diff --git a/include/wlr/types/wlr_switch.h b/include/wlr/types/wlr_switch.h index 93db04c5f..a0b9562f7 100644 --- a/include/wlr/types/wlr_switch.h +++ b/include/wlr/types/wlr_switch.h @@ -16,6 +16,8 @@ struct wlr_switch_impl; struct wlr_switch { + struct wlr_input_device base; + struct wlr_switch_impl *impl; struct { diff --git a/types/wlr_switch.c b/types/wlr_switch.c index 248997a06..44a004e25 100644 --- a/types/wlr_switch.c +++ b/types/wlr_switch.c @@ -1,11 +1,16 @@ #include #include #include +#include #include #include void wlr_switch_init(struct wlr_switch *switch_device, - struct wlr_switch_impl *impl) { + struct wlr_switch_impl *impl, const char *name) { + wlr_input_device_init(&switch_device->base, WLR_INPUT_DEVICE_SWITCH, NULL, + name); + switch_device->base.switch_device = switch_device; + switch_device->impl = impl; wl_signal_init(&switch_device->events.toggle); } @@ -14,6 +19,7 @@ void wlr_switch_destroy(struct wlr_switch *switch_device) { if (!switch_device) { return; } + wlr_input_device_finish(&switch_device->base); if (switch_device->impl && switch_device->impl->destroy) { switch_device->impl->destroy(switch_device); } else { From a662743610a61df07c6616230e66e78456ecdafb Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 1 Feb 2022 10:25:28 -0500 Subject: [PATCH 179/190] types/wlr_tablet_pad: add base wlr_input_device wlr_tablet_pad owns its wlr_input_device. It will be initialized when the tablet pad is initialized, and finished when the tablet pad is destroyed. --- backend/libinput/tablet_pad.c | 5 ++++- backend/wayland/tablet_v2.c | 2 +- include/wlr/interfaces/wlr_tablet_pad.h | 2 +- include/wlr/types/wlr_tablet_pad.h | 2 ++ types/wlr_tablet_pad.c | 7 ++++++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index c9ec30ae8..2f1da363d 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -75,7 +75,10 @@ struct wlr_tablet_pad *create_libinput_tablet_pad( wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad"); return NULL; } - wlr_tablet_pad_init(wlr_tablet_pad, NULL); + const char *name = libinput_device_get_name(libinput_dev); + wlr_tablet_pad_init(wlr_tablet_pad, NULL, name); + wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_tablet_pad->base.product = libinput_device_get_id_product(libinput_dev); wlr_tablet_pad->button_count = libinput_device_tablet_pad_get_num_buttons(libinput_dev); diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index cda651011..34056314b 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -453,7 +453,7 @@ static void handle_pad_added(void *data, zwp_tablet_pad_v2_destroy(id); return; } - wlr_tablet_pad_init(wlr_dev->tablet_pad, NULL); + wlr_tablet_pad_init(wlr_dev->tablet_pad, NULL, wlr_dev->name); zwp_tablet_pad_v2_add_listener(id, &tablet_pad_listener, dev); } diff --git a/include/wlr/interfaces/wlr_tablet_pad.h b/include/wlr/interfaces/wlr_tablet_pad.h index 86bbe9c39..b35f162e0 100644 --- a/include/wlr/interfaces/wlr_tablet_pad.h +++ b/include/wlr/interfaces/wlr_tablet_pad.h @@ -16,7 +16,7 @@ struct wlr_tablet_pad_impl { }; void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, - struct wlr_tablet_pad_impl *impl); + struct wlr_tablet_pad_impl *impl, const char *name); void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad); #endif diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h index 6cd1b70e4..f30809cf0 100644 --- a/include/wlr/types/wlr_tablet_pad.h +++ b/include/wlr/types/wlr_tablet_pad.h @@ -22,6 +22,8 @@ struct wlr_tablet_pad_impl; struct wlr_tablet_pad { + struct wlr_input_device base; + struct wlr_tablet_pad_impl *impl; struct { diff --git a/types/wlr_tablet_pad.c b/types/wlr_tablet_pad.c index 2bd996a66..7d5635f79 100644 --- a/types/wlr_tablet_pad.c +++ b/types/wlr_tablet_pad.c @@ -1,11 +1,15 @@ #include #include #include +#include #include #include void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, - struct wlr_tablet_pad_impl *impl) { + struct wlr_tablet_pad_impl *impl, const char *name) { + wlr_input_device_init(&pad->base, WLR_INPUT_DEVICE_TABLET_PAD, NULL, name); + pad->base.tablet_pad = pad; + pad->impl = impl; wl_signal_init(&pad->events.button); wl_signal_init(&pad->events.ring); @@ -27,6 +31,7 @@ void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad) { } wl_array_release(&pad->paths); + wlr_input_device_finish(&pad->base); if (pad->impl && pad->impl->destroy) { pad->impl->destroy(pad); } else { From 7dfee50350180e38c7c02b79c5a3ee454dc552fd Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 1 Feb 2022 11:32:39 -0500 Subject: [PATCH 180/190] types/wlr_tablet_tool: add base wlr_input_device wlr_tablet_tool owns its wlr_input_device. It will be initialized when the tablet tool is initialized, and finished when the tablet tool is destroyed. --- backend/libinput/tablet_tool.c | 6 +++++- backend/wayland/tablet_v2.c | 2 +- include/wlr/interfaces/wlr_tablet_tool.h | 2 +- include/wlr/types/wlr_tablet_tool.h | 2 ++ types/wlr_tablet_tool.c | 8 +++++++- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 60208a87a..31803e810 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -75,7 +75,11 @@ struct wlr_tablet *create_libinput_tablet( } struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet; - wlr_tablet_init(wlr_tablet, &tablet_impl); + const char *name = libinput_device_get_name(libinput_dev); + + wlr_tablet_init(wlr_tablet, &tablet_impl, name); + wlr_tablet->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_tablet->base.product = libinput_device_get_id_product(libinput_dev); struct udev_device *udev = libinput_device_get_udev_device(libinput_dev); char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *)); diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index 34056314b..4ddcce078 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -909,7 +909,7 @@ static void handle_tab_added(void *data, return; } zwp_tablet_v2_set_user_data(id, wlr_dev->tablet); - wlr_tablet_init(wlr_dev->tablet, NULL); + wlr_tablet_init(wlr_dev->tablet, NULL, wlr_dev->name); zwp_tablet_v2_add_listener(id, &tablet_listener, dev); } diff --git a/include/wlr/interfaces/wlr_tablet_tool.h b/include/wlr/interfaces/wlr_tablet_tool.h index 81e72d75e..de7430a2f 100644 --- a/include/wlr/interfaces/wlr_tablet_tool.h +++ b/include/wlr/interfaces/wlr_tablet_tool.h @@ -16,7 +16,7 @@ struct wlr_tablet_impl { }; void wlr_tablet_init(struct wlr_tablet *tablet, - const struct wlr_tablet_impl *impl); + const struct wlr_tablet_impl *impl, const char *name); void wlr_tablet_destroy(struct wlr_tablet *tablet); #endif diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index 75fc1ee80..b8b4000f7 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -60,6 +60,8 @@ struct wlr_tablet_tool { struct wlr_tablet_impl; struct wlr_tablet { + struct wlr_input_device base; + const struct wlr_tablet_impl *impl; struct { diff --git a/types/wlr_tablet_tool.c b/types/wlr_tablet_tool.c index 5c0037bd2..12278e938 100644 --- a/types/wlr_tablet_tool.c +++ b/types/wlr_tablet_tool.c @@ -1,11 +1,16 @@ #include #include #include +#include #include #include void wlr_tablet_init(struct wlr_tablet *tablet, - const struct wlr_tablet_impl *impl) { + const struct wlr_tablet_impl *impl, const char *name) { + wlr_input_device_init(&tablet->base, WLR_INPUT_DEVICE_TABLET_TOOL, NULL, + name); + tablet->base.tablet = tablet; + tablet->impl = impl; wl_signal_init(&tablet->events.axis); wl_signal_init(&tablet->events.proximity); @@ -25,6 +30,7 @@ void wlr_tablet_destroy(struct wlr_tablet *tablet) { } wl_array_release(&tablet->paths); + wlr_input_device_finish(&tablet->base); if (tablet->impl && tablet->impl->destroy) { tablet->impl->destroy(tablet); } else { From edfb332b24a2a1e014de10eba1c5bf2b84538d2f Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 1 Feb 2022 11:51:50 -0500 Subject: [PATCH 181/190] types/wlr_touch: add base wlr_input_device wlr_touch now owns its wlr_input_device. It will be initialized when the tablet tool is initialized, and finished when the touch is destroyed. --- backend/libinput/touch.c | 5 ++++- backend/wayland/seat.c | 2 +- backend/x11/input_device.c | 8 +++++--- backend/x11/output.c | 11 ++++------- include/backend/x11.h | 1 - include/wlr/interfaces/wlr_touch.h | 2 +- include/wlr/types/wlr_touch.h | 3 +++ types/wlr_touch.c | 7 ++++++- 8 files changed, 24 insertions(+), 15 deletions(-) diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c index ee987a91a..d1f996119 100644 --- a/backend/libinput/touch.c +++ b/backend/libinput/touch.c @@ -16,7 +16,10 @@ struct wlr_touch *create_libinput_touch( wlr_log(WLR_ERROR, "Unable to allocate wlr_touch"); return NULL; } - wlr_touch_init(wlr_touch, NULL); + const char *name = libinput_device_get_name(libinput_dev); + wlr_touch_init(wlr_touch, NULL, name); + wlr_touch->base.vendor = libinput_device_get_id_vendor(libinput_dev); + wlr_touch->base.product = libinput_device_get_id_product(libinput_dev); return wlr_touch; } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 633e585a8..6382347f1 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -819,7 +819,7 @@ void create_wl_touch(struct wlr_wl_seat *seat) { wlr_input_device_destroy(wlr_dev); return; } - wlr_touch_init(wlr_dev->touch, NULL); + wlr_touch_init(wlr_dev->touch, NULL, wlr_dev->name); wl_touch_add_listener(wl_touch, &touch_listener, dev); wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index 5ca3e956f..a020442a2 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -72,7 +72,7 @@ static void send_pointer_position_event(struct wlr_x11_output *output, static void send_touch_down_event(struct wlr_x11_output *output, int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) { struct wlr_event_touch_down ev = { - .device = &output->touch_dev, + .device = &output->touch.base, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, @@ -85,7 +85,7 @@ static void send_touch_down_event(struct wlr_x11_output *output, static void send_touch_motion_event(struct wlr_x11_output *output, int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) { struct wlr_event_touch_motion ev = { - .device = &output->touch_dev, + .device = &output->touch.base, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, @@ -98,7 +98,7 @@ static void send_touch_motion_event(struct wlr_x11_output *output, static void send_touch_up_event(struct wlr_x11_output *output, int32_t touch_id, xcb_timestamp_t time) { struct wlr_event_touch_up ev = { - .device = &output->touch_dev, + .device = &output->touch.base, .time_msec = time, .touch_id = touch_id, }; @@ -341,6 +341,8 @@ bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) { return wlr_dev->keyboard->impl == &keyboard_impl; case WLR_INPUT_DEVICE_POINTER: return wlr_dev->pointer->impl == &pointer_impl; + case WLR_INPUT_DEVICE_TOUCH: + return wlr_dev->touch->impl == &touch_impl; default: return wlr_dev->impl == &input_device_impl; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 19eb5d55e..0900a60a1 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -77,7 +77,7 @@ static void output_destroy(struct wlr_output *wlr_output) { pixman_region32_fini(&output->exposed); wlr_pointer_destroy(&output->pointer); - wlr_input_device_destroy(&output->touch_dev); + wlr_touch_destroy(&output->touch); struct wlr_x11_buffer *buffer, *buffer_tmp; wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) { @@ -576,16 +576,13 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_pointer_init(&output->pointer, &pointer_impl, "x11-pointer"); output->pointer.base.output_name = strdup(wlr_output->name); - wlr_input_device_init(&output->touch_dev, WLR_INPUT_DEVICE_TOUCH, - &input_device_impl, "X11 touch"); - wlr_touch_init(&output->touch, &touch_impl); - output->touch_dev.touch = &output->touch; - output->touch_dev.output_name = strdup(wlr_output->name); + wlr_touch_init(&output->touch, &touch_impl, "x11-touch"); + output->touch.base.output_name = strdup(wlr_output->name); wl_list_init(&output->touchpoints); wlr_signal_emit_safe(&x11->backend.events.new_output, wlr_output); wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer.base); - wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch_dev); + wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch.base); // Start the rendering loop by requesting the compositor to render a frame wlr_output_schedule_frame(wlr_output); diff --git a/include/backend/x11.h b/include/backend/x11.h index ee4846549..2c0393556 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -37,7 +37,6 @@ struct wlr_x11_output { struct wlr_pointer pointer; struct wlr_touch touch; - struct wlr_input_device touch_dev; struct wl_list touchpoints; // wlr_x11_touchpoint::link struct wl_list buffers; // wlr_x11_buffer::link diff --git a/include/wlr/interfaces/wlr_touch.h b/include/wlr/interfaces/wlr_touch.h index e4ea6a781..2b95d2bf8 100644 --- a/include/wlr/interfaces/wlr_touch.h +++ b/include/wlr/interfaces/wlr_touch.h @@ -16,7 +16,7 @@ struct wlr_touch_impl { }; void wlr_touch_init(struct wlr_touch *touch, - const struct wlr_touch_impl *impl); + const struct wlr_touch_impl *impl, const char *name); void wlr_touch_destroy(struct wlr_touch *touch); #endif diff --git a/include/wlr/types/wlr_touch.h b/include/wlr/types/wlr_touch.h index ca7cf2a64..b2c097e8f 100644 --- a/include/wlr/types/wlr_touch.h +++ b/include/wlr/types/wlr_touch.h @@ -10,11 +10,14 @@ #define WLR_TYPES_WLR_TOUCH_H #include +#include #include struct wlr_touch_impl; struct wlr_touch { + struct wlr_input_device base; + const struct wlr_touch_impl *impl; struct { diff --git a/types/wlr_touch.c b/types/wlr_touch.c index 9edfdaeee..a0949933f 100644 --- a/types/wlr_touch.c +++ b/types/wlr_touch.c @@ -1,11 +1,15 @@ #include #include #include +#include #include #include void wlr_touch_init(struct wlr_touch *touch, - const struct wlr_touch_impl *impl) { + const struct wlr_touch_impl *impl, const char *name) { + wlr_input_device_init(&touch->base, WLR_INPUT_DEVICE_TOUCH, NULL, name); + touch->base.touch = touch; + touch->impl = impl; wl_signal_init(&touch->events.down); wl_signal_init(&touch->events.up); @@ -15,6 +19,7 @@ void wlr_touch_init(struct wlr_touch *touch, } void wlr_touch_destroy(struct wlr_touch *touch) { + wlr_input_device_finish(&touch->base); if (touch && touch->impl && touch->impl->destroy) { touch->impl->destroy(touch); } else { From b5b15b26258bc5e29736b3eb0268fa460acc9dd0 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 5 Feb 2022 10:29:42 +0300 Subject: [PATCH 182/190] xdg-{toplevel,popup}: extract destructors --- include/types/wlr_xdg_shell.h | 2 ++ types/xdg_shell/wlr_xdg_popup.c | 6 ++++++ types/xdg_shell/wlr_xdg_surface.c | 8 ++------ types/xdg_shell/wlr_xdg_toplevel.c | 5 +++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index c0f977984..1ad6b0aee 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -31,11 +31,13 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, struct wlr_xdg_positioner_resource *positioner, uint32_t id); void unmap_xdg_popup(struct wlr_xdg_popup *popup); +void destroy_xdg_popup(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id); void unmap_xdg_toplevel(struct wlr_xdg_toplevel *toplevel); +void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel); void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel); struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( struct wlr_xdg_toplevel *toplevel); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index d923e923e..eba829ccb 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -389,6 +389,12 @@ void unmap_xdg_popup(struct wlr_xdg_popup *popup) { } } +void destroy_xdg_popup(struct wlr_xdg_popup *popup) { + wl_list_remove(&popup->link); + wl_resource_set_user_data(popup->resource, NULL); + free(popup); +} + void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) { if (popup == NULL) { return; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index a9f7aa82e..e65c6afd9 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -411,15 +411,11 @@ void reset_xdg_surface(struct wlr_xdg_surface *surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - wl_resource_set_user_data(surface->toplevel->resource, NULL); - free(surface->toplevel); + destroy_xdg_toplevel(surface->toplevel); surface->toplevel = NULL; break; case WLR_XDG_SURFACE_ROLE_POPUP: - wl_list_remove(&surface->popup->link); - - wl_resource_set_user_data(surface->popup->resource, NULL); - free(surface->popup); + destroy_xdg_popup(surface->popup); surface->popup = NULL; break; case WLR_XDG_SURFACE_ROLE_NONE: diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index ad2f0501f..ed304cfcd 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -493,6 +493,11 @@ void unmap_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { toplevel->requested.minimized = false; } +void destroy_xdg_toplevel(struct wlr_xdg_toplevel *toplevel) { + wl_resource_set_user_data(toplevel->resource, NULL); + free(toplevel); +} + void wlr_xdg_toplevel_send_close(struct wlr_xdg_toplevel *toplevel) { xdg_toplevel_send_close(toplevel->resource); } From 5879e77d689ede8a1001daef2a71f14399ef3ef7 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 6 Feb 2022 23:39:50 +0300 Subject: [PATCH 183/190] xdg-positioner: rename structs To be consistent with other wlr_xdg_* structs, wlr_xdg_positioner_resource is renamed to wlr_xdg_positioner and made public, and wlr_xdg_positioner is renamed to wlr_xdg_positioner_rules. Functions which operated on wlr_xdg_positioner were renamed and updated accordingly. --- include/types/wlr_xdg_shell.h | 9 +- include/wlr/types/wlr_xdg_shell.h | 38 +++++--- types/xdg_shell/wlr_xdg_popup.c | 47 +++++---- types/xdg_shell/wlr_xdg_positioner.c | 136 +++++++++++---------------- types/xdg_shell/wlr_xdg_surface.c | 4 +- 5 files changed, 109 insertions(+), 125 deletions(-) diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index 1ad6b0aee..cfed6ee1d 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -5,11 +5,6 @@ #include #include "xdg-shell-protocol.h" -struct wlr_xdg_positioner_resource { - struct wl_resource *resource; - struct wlr_xdg_positioner attrs; -}; - extern const struct wlr_surface_role xdg_toplevel_surface_role; extern const struct wlr_surface_role xdg_popup_surface_role; @@ -24,12 +19,10 @@ void xdg_surface_role_precommit(struct wlr_surface *wlr_surface, const struct wlr_surface_state *state); void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id); -struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( - struct wl_resource *resource); void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, - struct wlr_xdg_positioner_resource *positioner, uint32_t id); + struct wlr_xdg_positioner *positioner, uint32_t id); void unmap_xdg_popup(struct wlr_xdg_popup *popup); void destroy_xdg_popup(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index d4a9f62bd..72cd6f27a 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -49,7 +49,7 @@ struct wlr_xdg_client { struct wl_event_source *ping_timer; }; -struct wlr_xdg_positioner { +struct wlr_xdg_positioner_rules { struct wlr_box anchor_rect; enum xdg_positioner_anchor anchor; enum xdg_positioner_gravity gravity; @@ -64,6 +64,11 @@ struct wlr_xdg_positioner { } offset; }; +struct wlr_xdg_positioner { + struct wl_resource *resource; + struct wlr_xdg_positioner_rules rules; +}; + struct wlr_xdg_popup { struct wlr_xdg_surface *base; struct wl_list link; @@ -77,7 +82,7 @@ struct wlr_xdg_popup { // geometry of the parent surface struct wlr_box geometry; - struct wlr_xdg_positioner positioner; + struct wlr_xdg_positioner_rules positioner_rules; struct wl_list grab_link; // wlr_xdg_popup_grab::popups }; @@ -276,6 +281,13 @@ struct wlr_xdg_popup *wlr_xdg_popup_from_resource( struct wlr_xdg_toplevel *wlr_xdg_toplevel_from_resource( struct wl_resource *resource); +/** Get the corresponding wlr_xdg_positioner from a resource. + * + * Aborts if the resource doesn't have the correct type. + */ +struct wlr_xdg_positioner *wlr_xdg_positioner_from_resource( + struct wl_resource *resource); + /** * Send a ping to the surface. If the surface does not respond in a reasonable * amount of time, the ping_timeout event will be emitted. @@ -346,12 +358,12 @@ void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup); */ void wlr_xdg_popup_get_position(struct wlr_xdg_popup *popup, double *popup_sx, double *popup_sy); + /** - * Get the geometry for this positioner based on the anchor rect, gravity, and - * size of this positioner. + * Get the geometry based on positioner rules. */ -struct wlr_box wlr_xdg_positioner_get_geometry( - struct wlr_xdg_positioner *positioner); +void wlr_xdg_positioner_rules_get_geometry( + struct wlr_xdg_positioner_rules *rules, struct wlr_box *box); /** * Get the anchor point for this popup in the toplevel parent's coordinate system. @@ -375,16 +387,18 @@ void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, const struct wlr_box *toplevel_sx_box); /** - Invert the right/left anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the x direction. + Invert the top/bottom anchor and gravity for those positioner rules. + This can be used to "flip" the positioner around the anchor rect in + the x direction. */ -void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner); +void wlr_xdg_positioner_rules_invert_x(struct wlr_xdg_positioner_rules *rules); /** - Invert the top/bottom anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the y direction. + Invert the top/bottom anchor and gravity for those positioner rules. + This can be used to "flip" the positioner around the anchor rect in + the y direction. */ -void wlr_positioner_invert_y(struct wlr_xdg_positioner *positioner); +void wlr_xdg_positioner_rules_invert_y(struct wlr_xdg_positioner_rules *rules); /** * Find a surface within this xdg-surface tree at the given surface-local diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index eba829ccb..e1e9653a5 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -304,9 +304,9 @@ const struct wlr_surface_role xdg_popup_surface_role = { void create_xdg_popup(struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent, - struct wlr_xdg_positioner_resource *positioner, uint32_t id) { - if (positioner->attrs.size.width == 0 || - positioner->attrs.anchor_rect.width == 0) { + struct wlr_xdg_positioner *positioner, uint32_t id) { + if (positioner->rules.size.width == 0 || + positioner->rules.anchor_rect.width == 0) { wl_resource_post_error(surface->client->resource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "positioner object is not complete"); @@ -348,11 +348,10 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, surface->role = WLR_XDG_SURFACE_ROLE_POPUP; - // positioner properties - memcpy(&surface->popup->positioner, &positioner->attrs, - sizeof(struct wlr_xdg_positioner)); - surface->popup->geometry = - wlr_xdg_positioner_get_geometry(&positioner->attrs); + memcpy(&surface->popup->positioner_rules, + &positioner->rules, sizeof(positioner->rules)); + wlr_xdg_positioner_rules_get_geometry( + &positioner->rules, &surface->popup->geometry); if (parent) { surface->popup->parent = parent->surface; @@ -412,8 +411,8 @@ void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) { void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, int *root_sx, int *root_sy) { - struct wlr_box rect = popup->positioner.anchor_rect; - enum xdg_positioner_anchor anchor = popup->positioner.anchor; + struct wlr_box rect = popup->positioner_rules.anchor_rect; + enum xdg_positioner_anchor anchor = popup->positioner_rules.anchor; int sx = 0, sy = 0; if (anchor == XDG_POSITIONER_ANCHOR_NONE) { @@ -511,22 +510,22 @@ static bool xdg_popup_unconstrain_flip(struct wlr_xdg_popup *popup, } bool flip_x = offset_x && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X); bool flip_y = offset_y && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y); if (flip_x) { - wlr_positioner_invert_x(&popup->positioner); + wlr_xdg_positioner_rules_invert_x(&popup->positioner_rules); } if (flip_y) { - wlr_positioner_invert_y(&popup->positioner); + wlr_xdg_positioner_rules_invert_y(&popup->positioner_rules); } - popup->geometry = - wlr_xdg_positioner_get_geometry(&popup->positioner); + wlr_xdg_positioner_rules_get_geometry( + &popup->positioner_rules, &popup->geometry); xdg_popup_box_constraints(popup, toplevel_sx_box, &offset_x, &offset_y); @@ -538,14 +537,14 @@ static bool xdg_popup_unconstrain_flip(struct wlr_xdg_popup *popup, // revert the positioner back if it didn't fix it and go to the next part if (offset_x && flip_x) { - wlr_positioner_invert_x(&popup->positioner); + wlr_xdg_positioner_rules_invert_x(&popup->positioner_rules); } if (offset_y && flip_y) { - wlr_positioner_invert_y(&popup->positioner); + wlr_xdg_positioner_rules_invert_y(&popup->positioner_rules); } - popup->geometry = - wlr_xdg_positioner_get_geometry(&popup->positioner); + wlr_xdg_positioner_rules_get_geometry( + &popup->positioner_rules, &popup->geometry); return false; } @@ -561,11 +560,11 @@ static bool xdg_popup_unconstrain_slide(struct wlr_xdg_popup *popup, } bool slide_x = offset_x && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); bool slide_y = offset_y && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); if (slide_x) { @@ -604,11 +603,11 @@ static bool xdg_popup_unconstrain_resize(struct wlr_xdg_popup *popup, } bool resize_x = offset_x && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); bool resize_y = offset_y && - (popup->positioner.constraint_adjustment & + (popup->positioner_rules.constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); if (resize_x) { diff --git a/types/xdg_shell/wlr_xdg_positioner.c b/types/xdg_shell/wlr_xdg_positioner.c index aa149cc2a..d4c6f03a3 100644 --- a/types/xdg_shell/wlr_xdg_positioner.c +++ b/types/xdg_shell/wlr_xdg_positioner.c @@ -4,7 +4,7 @@ static const struct xdg_positioner_interface xdg_positioner_implementation; -struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( +struct wlr_xdg_positioner *wlr_xdg_positioner_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_positioner_interface, &xdg_positioner_implementation)); @@ -13,8 +13,8 @@ struct wlr_xdg_positioner_resource *get_xdg_positioner_from_resource( static void xdg_positioner_handle_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, @@ -23,15 +23,15 @@ static void xdg_positioner_handle_set_size(struct wl_client *client, return; } - positioner->attrs.size.width = width; - positioner->attrs.size.height = height; + positioner->rules.size.width = width; + positioner->rules.size.height = height; } static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); if (width < 0 || height < 0) { wl_resource_post_error(resource, @@ -40,16 +40,16 @@ static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, return; } - positioner->attrs.anchor_rect.x = x; - positioner->attrs.anchor_rect.y = y; - positioner->attrs.anchor_rect.width = width; - positioner->attrs.anchor_rect.height = height; + positioner->rules.anchor_rect.x = x; + positioner->rules.anchor_rect.y = y; + positioner->rules.anchor_rect.width = width; + positioner->rules.anchor_rect.height = height; } static void xdg_positioner_handle_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { wl_resource_post_error(resource, @@ -58,13 +58,13 @@ static void xdg_positioner_handle_set_anchor(struct wl_client *client, return; } - positioner->attrs.anchor = anchor; + positioner->rules.anchor = anchor; } static void xdg_positioner_handle_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { wl_resource_post_error(resource, @@ -73,25 +73,25 @@ static void xdg_positioner_handle_set_gravity(struct wl_client *client, return; } - positioner->attrs.gravity = gravity; + positioner->rules.gravity = gravity; } static void xdg_positioner_handle_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); - positioner->attrs.constraint_adjustment = constraint_adjustment; + positioner->rules.constraint_adjustment = constraint_adjustment; } static void xdg_positioner_handle_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); - positioner->attrs.offset.x = x; - positioner->attrs.offset.y = y; + positioner->rules.offset.x = x; + positioner->rules.offset.y = y; } static void xdg_positioner_handle_destroy(struct wl_client *client, @@ -113,14 +113,13 @@ static const struct xdg_positioner_interface static void xdg_positioner_handle_resource_destroy( struct wl_resource *resource) { - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); free(positioner); } void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id) { - struct wlr_xdg_positioner_resource *positioner = - calloc(1, sizeof(struct wlr_xdg_positioner_resource)); + struct wlr_xdg_positioner *positioner = calloc(1, sizeof(*positioner)); if (positioner == NULL) { wl_client_post_no_memory(client->client); return; @@ -171,60 +170,40 @@ static bool positioner_gravity_has_edge(enum xdg_positioner_gravity gravity, (enum xdg_positioner_anchor)edge); } -struct wlr_box wlr_xdg_positioner_get_geometry( - struct wlr_xdg_positioner *positioner) { - struct wlr_box geometry = { - .x = positioner->offset.x, - .y = positioner->offset.y, - .width = positioner->size.width, - .height = positioner->size.height, - }; +void wlr_xdg_positioner_rules_get_geometry( + struct wlr_xdg_positioner_rules *rules, struct wlr_box *box) { + box->x = rules->offset.x; + box->y = rules->offset.y; + box->width = rules->size.width; + box->height = rules->size.height; - if (positioner_anchor_has_edge(positioner->anchor, - XDG_POSITIONER_ANCHOR_TOP)) { - geometry.y += positioner->anchor_rect.y; - } else if (positioner_anchor_has_edge(positioner->anchor, - XDG_POSITIONER_ANCHOR_BOTTOM)) { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height; + if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_TOP)) { + box->y += rules->anchor_rect.y; + } else if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_BOTTOM)) { + box->y += rules->anchor_rect.y + rules->anchor_rect.height; } else { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + box->y += rules->anchor_rect.y + rules->anchor_rect.height / 2; } - if (positioner_anchor_has_edge(positioner->anchor, - XDG_POSITIONER_ANCHOR_LEFT)) { - geometry.x += positioner->anchor_rect.x; - } else if (positioner_anchor_has_edge(positioner->anchor, - XDG_POSITIONER_ANCHOR_RIGHT)) { - geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; + if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_LEFT)) { + box->x += rules->anchor_rect.x; + } else if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_RIGHT)) { + box->x += rules->anchor_rect.x + rules->anchor_rect.width; } else { - geometry.x += - positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + box->x += rules->anchor_rect.x + rules->anchor_rect.width / 2; } - if (positioner_gravity_has_edge(positioner->gravity, - XDG_POSITIONER_GRAVITY_TOP)) { - geometry.y -= geometry.height; - } else if (!positioner_gravity_has_edge(positioner->gravity, - XDG_POSITIONER_GRAVITY_BOTTOM)) { - geometry.y -= geometry.height / 2; + if (positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_TOP)) { + box->y -= box->height; + } else if (!positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_BOTTOM)) { + box->y -= box->height / 2; } - if (positioner_gravity_has_edge(positioner->gravity, - XDG_POSITIONER_GRAVITY_LEFT)) { - geometry.x -= geometry.width; - } else if (!positioner_gravity_has_edge(positioner->gravity, - XDG_POSITIONER_GRAVITY_RIGHT)) { - geometry.x -= geometry.width / 2; + if (positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_LEFT)) { + box->x -= box->width; + } else if (!positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_RIGHT)) { + box->x -= box->width / 2; } - - if (positioner->constraint_adjustment == - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) { - return geometry; - } - - return geometry; } static enum xdg_positioner_anchor positioner_anchor_invert_x( @@ -281,13 +260,12 @@ static enum xdg_positioner_gravity positioner_gravity_invert_y( (enum xdg_positioner_anchor)gravity); } - -void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner) { - positioner->anchor = positioner_anchor_invert_x(positioner->anchor); - positioner->gravity = positioner_gravity_invert_x(positioner->gravity); +void wlr_xdg_positioner_rules_invert_x(struct wlr_xdg_positioner_rules *rules) { + rules->anchor = positioner_anchor_invert_x(rules->anchor); + rules->gravity = positioner_gravity_invert_x(rules->gravity); } -void wlr_positioner_invert_y(struct wlr_xdg_positioner *positioner) { - positioner->anchor = positioner_anchor_invert_y(positioner->anchor); - positioner->gravity = positioner_gravity_invert_y(positioner->gravity); +void wlr_xdg_positioner_rules_invert_y(struct wlr_xdg_positioner_rules *rules) { + rules->anchor = positioner_anchor_invert_y(rules->anchor); + rules->gravity = positioner_gravity_invert_y(rules->gravity); } diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index e65c6afd9..73ed66c92 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -186,8 +186,8 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, if (xdg_surface == NULL) { return; // TODO: create an inert xdg_popup } - struct wlr_xdg_positioner_resource *positioner = - get_xdg_positioner_from_resource(positioner_resource); + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(positioner_resource); create_xdg_popup(xdg_surface, parent, positioner, id); } From 511f137f8fb245e4877d83a0846294091373eba1 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Mon, 7 Feb 2022 14:22:48 +0300 Subject: [PATCH 184/190] xdg-positioner: rewrite unconstraining, untie from xdg-popup --- include/wlr/types/wlr_xdg_shell.h | 25 +-- types/xdg_shell/wlr_xdg_popup.c | 213 ++------------------ types/xdg_shell/wlr_xdg_positioner.c | 286 +++++++++++++++++++++++---- 3 files changed, 261 insertions(+), 263 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 72cd6f27a..48bfbb975 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -363,13 +363,14 @@ void wlr_xdg_popup_get_position(struct wlr_xdg_popup *popup, * Get the geometry based on positioner rules. */ void wlr_xdg_positioner_rules_get_geometry( - struct wlr_xdg_positioner_rules *rules, struct wlr_box *box); + const struct wlr_xdg_positioner_rules *rules, struct wlr_box *box); /** - * Get the anchor point for this popup in the toplevel parent's coordinate system. + * Unconstrain the box from the constraint area according to positioner rules. */ -void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, - int *toplevel_sx, int *toplevel_sy); +void wlr_xdg_positioner_rules_unconstrain_box( + const struct wlr_xdg_positioner_rules *rules, + const struct wlr_box *constraint, struct wlr_box *box); /** * Convert the given coordinates in the popup coordinate system to the toplevel @@ -384,21 +385,7 @@ void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, * surface coordinate system. */ void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box); - -/** - Invert the top/bottom anchor and gravity for those positioner rules. - This can be used to "flip" the positioner around the anchor rect in - the x direction. - */ -void wlr_xdg_positioner_rules_invert_x(struct wlr_xdg_positioner_rules *rules); - -/** - Invert the top/bottom anchor and gravity for those positioner rules. - This can be used to "flip" the positioner around the anchor rect in - the y direction. - */ -void wlr_xdg_positioner_rules_invert_y(struct wlr_xdg_positioner_rules *rules); + const struct wlr_box *toplevel_space_box); /** * Find a surface within this xdg-surface tree at the given surface-local diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index e1e9653a5..973a339be 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -409,45 +409,6 @@ void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) { reset_xdg_surface(popup->base); } -void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, - int *root_sx, int *root_sy) { - struct wlr_box rect = popup->positioner_rules.anchor_rect; - enum xdg_positioner_anchor anchor = popup->positioner_rules.anchor; - int sx = 0, sy = 0; - - if (anchor == XDG_POSITIONER_ANCHOR_NONE) { - sx = (rect.x + rect.width) / 2; - sy = (rect.y + rect.height) / 2; - } else if (anchor == XDG_POSITIONER_ANCHOR_TOP) { - sx = (rect.x + rect.width) / 2; - sy = rect.y; - } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM) { - sx = (rect.x + rect.width) / 2; - sy = rect.y + rect.height; - } else if (anchor == XDG_POSITIONER_ANCHOR_LEFT) { - sx = rect.x; - sy = (rect.y + rect.height) / 2; - } else if (anchor == XDG_POSITIONER_ANCHOR_RIGHT) { - sx = rect.x + rect.width; - sy = (rect.y + rect.height) / 2; - } else if (anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT) { - sx = rect.x; - sy = rect.y; - } else if (anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT) { - sx = rect.x + rect.width; - sy = rect.y; - } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT) { - sx = rect.x; - sy = rect.y + rect.height; - } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { - sx = rect.x + rect.width; - sy = rect.y + rect.height; - } - - *root_sx = sx; - *root_sy = sy; -} - void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) { struct wlr_surface *parent = popup->parent; @@ -471,167 +432,17 @@ void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, *toplevel_sy = popup_sy; } -static void xdg_popup_box_constraints(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box, int *offset_x, int *offset_y) { - int popup_width = popup->geometry.width; - int popup_height = popup->geometry.height; - int anchor_sx = 0, anchor_sy = 0; - wlr_xdg_popup_get_anchor_point(popup, &anchor_sx, &anchor_sy); - int popup_sx = 0, popup_sy = 0; - wlr_xdg_popup_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &popup_sx, &popup_sy); - *offset_x = 0, *offset_y = 0; - - if (popup_sx < toplevel_sx_box->x) { - *offset_x = toplevel_sx_box->x - popup_sx; - } else if (popup_sx + popup_width > - toplevel_sx_box->x + toplevel_sx_box->width) { - *offset_x = toplevel_sx_box->x + toplevel_sx_box->width - - (popup_sx + popup_width); - } - - if (popup_sy < toplevel_sx_box->y) { - *offset_y = toplevel_sx_box->y - popup_sy; - } else if (popup_sy + popup_height > - toplevel_sx_box->y + toplevel_sx_box->height) { - *offset_y = toplevel_sx_box->y + toplevel_sx_box->height - - (popup_sy + popup_height); - } -} - -static bool xdg_popup_unconstrain_flip(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool flip_x = offset_x && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X); - - bool flip_y = offset_y && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y); - - if (flip_x) { - wlr_xdg_positioner_rules_invert_x(&popup->positioner_rules); - } - if (flip_y) { - wlr_xdg_positioner_rules_invert_y(&popup->positioner_rules); - } - - wlr_xdg_positioner_rules_get_geometry( - &popup->positioner_rules, &popup->geometry); - - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - // no longer constrained - return true; - } - - // revert the positioner back if it didn't fix it and go to the next part - if (offset_x && flip_x) { - wlr_xdg_positioner_rules_invert_x(&popup->positioner_rules); - } - if (offset_y && flip_y) { - wlr_xdg_positioner_rules_invert_y(&popup->positioner_rules); - } - - wlr_xdg_positioner_rules_get_geometry( - &popup->positioner_rules, &popup->geometry); - - return false; -} - -static bool xdg_popup_unconstrain_slide(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool slide_x = offset_x && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); - - bool slide_y = offset_y && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - - if (slide_x) { - popup->geometry.x += offset_x; - } - - if (slide_y) { - popup->geometry.y += offset_y; - } - - int toplevel_x = 0, toplevel_y = 0; - wlr_xdg_popup_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &toplevel_x, &toplevel_y); - - if (slide_x && toplevel_x < toplevel_sx_box->x) { - popup->geometry.x += toplevel_sx_box->x - toplevel_x; - } - if (slide_y && toplevel_y < toplevel_sx_box->y) { - popup->geometry.y += toplevel_sx_box->y - toplevel_y; - } - - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - -static bool xdg_popup_unconstrain_resize(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box) { - int offset_x, offset_y; - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool resize_x = offset_x && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); - - bool resize_y = offset_y && - (popup->positioner_rules.constraint_adjustment & - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); - - if (resize_x) { - popup->geometry.width -= offset_x; - } - if (resize_y) { - popup->geometry.height -= offset_y; - } - - xdg_popup_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, - const struct wlr_box *toplevel_sx_box) { - if (xdg_popup_unconstrain_flip(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_unconstrain_slide(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_unconstrain_resize(popup, toplevel_sx_box)) { - return; - } + const struct wlr_box *toplevel_space_box) { + int toplevel_sx, toplevel_sy; + wlr_xdg_popup_get_toplevel_coords(popup, + 0, 0, &toplevel_sx, &toplevel_sy); + struct wlr_box popup_constraint = { + .x = toplevel_space_box->x - toplevel_sx, + .y = toplevel_space_box->y - toplevel_sy, + .width = toplevel_space_box->width, + .height = toplevel_space_box->height, + }; + wlr_xdg_positioner_rules_unconstrain_box(&popup->positioner_rules, + &popup_constraint, &popup->geometry); } diff --git a/types/xdg_shell/wlr_xdg_positioner.c b/types/xdg_shell/wlr_xdg_positioner.c index d4c6f03a3..6fa1ed991 100644 --- a/types/xdg_shell/wlr_xdg_positioner.c +++ b/types/xdg_shell/wlr_xdg_positioner.c @@ -1,5 +1,6 @@ #include #include +#include #include "types/wlr_xdg_shell.h" static const struct xdg_positioner_interface xdg_positioner_implementation; @@ -139,74 +140,79 @@ void create_xdg_positioner(struct wlr_xdg_client *client, uint32_t id) { positioner, xdg_positioner_handle_resource_destroy); } -static bool positioner_anchor_has_edge(enum xdg_positioner_anchor anchor, - enum xdg_positioner_anchor edge) { - switch (edge) { +static uint32_t xdg_positioner_anchor_to_wlr_edges( + enum xdg_positioner_anchor anchor) { + switch (anchor) { + case XDG_POSITIONER_ANCHOR_NONE: + return WLR_EDGE_NONE; case XDG_POSITIONER_ANCHOR_TOP: - return anchor == XDG_POSITIONER_ANCHOR_TOP || - anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT || - anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT; + return WLR_EDGE_TOP; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return WLR_EDGE_TOP | WLR_EDGE_LEFT; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return WLR_EDGE_TOP | WLR_EDGE_RIGHT; case XDG_POSITIONER_ANCHOR_BOTTOM: - return anchor == XDG_POSITIONER_ANCHOR_BOTTOM || - anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT || - anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT; + return WLR_EDGE_BOTTOM; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; case XDG_POSITIONER_ANCHOR_LEFT: - return anchor == XDG_POSITIONER_ANCHOR_LEFT || - anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT || - anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT; + return WLR_EDGE_LEFT; case XDG_POSITIONER_ANCHOR_RIGHT: - return anchor == XDG_POSITIONER_ANCHOR_RIGHT || - anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT || - anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT; - default: - abort(); // unreachable + return WLR_EDGE_RIGHT; } + + abort(); // Unreachable } -static bool positioner_gravity_has_edge(enum xdg_positioner_gravity gravity, - enum xdg_positioner_gravity edge) { - // gravity and edge enums are the same - return positioner_anchor_has_edge((enum xdg_positioner_anchor)gravity, - (enum xdg_positioner_anchor)edge); +static uint32_t xdg_positioner_gravity_to_wlr_edges( + enum xdg_positioner_gravity gravity) { + // Gravity and edge enums are the same + return xdg_positioner_anchor_to_wlr_edges((enum xdg_positioner_anchor)gravity); } void wlr_xdg_positioner_rules_get_geometry( - struct wlr_xdg_positioner_rules *rules, struct wlr_box *box) { + const struct wlr_xdg_positioner_rules *rules, struct wlr_box *box) { box->x = rules->offset.x; box->y = rules->offset.y; box->width = rules->size.width; box->height = rules->size.height; - if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_TOP)) { + uint32_t edges = xdg_positioner_anchor_to_wlr_edges(rules->anchor); + + if (edges & WLR_EDGE_TOP) { box->y += rules->anchor_rect.y; - } else if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_BOTTOM)) { + } else if (edges & WLR_EDGE_BOTTOM) { box->y += rules->anchor_rect.y + rules->anchor_rect.height; } else { box->y += rules->anchor_rect.y + rules->anchor_rect.height / 2; } - if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_LEFT)) { + if (edges & WLR_EDGE_LEFT) { box->x += rules->anchor_rect.x; - } else if (positioner_anchor_has_edge(rules->anchor, XDG_POSITIONER_ANCHOR_RIGHT)) { + } else if (edges & WLR_EDGE_RIGHT) { box->x += rules->anchor_rect.x + rules->anchor_rect.width; } else { box->x += rules->anchor_rect.x + rules->anchor_rect.width / 2; } - if (positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_TOP)) { + edges = xdg_positioner_gravity_to_wlr_edges(rules->gravity); + + if (edges & WLR_EDGE_TOP) { box->y -= box->height; - } else if (!positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_BOTTOM)) { + } else if (~edges & WLR_EDGE_BOTTOM) { box->y -= box->height / 2; } - if (positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_LEFT)) { + if (edges & WLR_EDGE_LEFT) { box->x -= box->width; - } else if (!positioner_gravity_has_edge(rules->gravity, XDG_POSITIONER_GRAVITY_RIGHT)) { + } else if (~edges & WLR_EDGE_RIGHT) { box->x -= box->width / 2; } } -static enum xdg_positioner_anchor positioner_anchor_invert_x( +static enum xdg_positioner_anchor xdg_positioner_anchor_invert_x( enum xdg_positioner_anchor anchor) { switch (anchor) { case XDG_POSITIONER_ANCHOR_LEFT: @@ -226,14 +232,14 @@ static enum xdg_positioner_anchor positioner_anchor_invert_x( } } -static enum xdg_positioner_gravity positioner_gravity_invert_x( +static enum xdg_positioner_gravity xdg_positioner_gravity_invert_x( enum xdg_positioner_gravity gravity) { // gravity and edge enums are the same - return (enum xdg_positioner_gravity)positioner_anchor_invert_x( + return (enum xdg_positioner_gravity)xdg_positioner_anchor_invert_x( (enum xdg_positioner_anchor)gravity); } -static enum xdg_positioner_anchor positioner_anchor_invert_y( +static enum xdg_positioner_anchor xdg_positioner_anchor_invert_y( enum xdg_positioner_anchor anchor) { switch (anchor) { case XDG_POSITIONER_ANCHOR_TOP: @@ -253,19 +259,213 @@ static enum xdg_positioner_anchor positioner_anchor_invert_y( } } -static enum xdg_positioner_gravity positioner_gravity_invert_y( +static enum xdg_positioner_gravity xdg_positioner_gravity_invert_y( enum xdg_positioner_gravity gravity) { // gravity and edge enums are the same - return (enum xdg_positioner_gravity)positioner_anchor_invert_y( + return (enum xdg_positioner_gravity)xdg_positioner_anchor_invert_y( (enum xdg_positioner_anchor)gravity); } -void wlr_xdg_positioner_rules_invert_x(struct wlr_xdg_positioner_rules *rules) { - rules->anchor = positioner_anchor_invert_x(rules->anchor); - rules->gravity = positioner_gravity_invert_x(rules->gravity); +/** + * Distances from each edge of the box to the corresponding edge of + * the anchor rect. Each distance is positive if the edge is outside + * the anchor rect, and negative if the edge is inside it. + */ +struct constraint_offsets { + int top; + int bottom; + int left; + int right; +}; + +static bool is_unconstrained(const struct constraint_offsets *offsets) { + return offsets->top <= 0 && offsets->bottom <= 0 && + offsets->left <= 0 && offsets->right <= 0; } -void wlr_xdg_positioner_rules_invert_y(struct wlr_xdg_positioner_rules *rules) { - rules->anchor = positioner_anchor_invert_y(rules->anchor); - rules->gravity = positioner_gravity_invert_y(rules->gravity); +static void get_constrained_box_offsets(const struct wlr_box *constraint, + const struct wlr_box *box, struct constraint_offsets *offsets) { + offsets->left = constraint->x - box->x; + offsets->right = box->x + box->width - constraint->x - constraint->width; + offsets->top = constraint->y - box->y; + offsets->bottom = box->y + box->height - constraint->y - constraint->height; +} + +static bool xdg_positioner_rules_unconstrain_by_flip( + const struct wlr_xdg_positioner_rules *rules, + const struct wlr_box *constraint, struct wlr_box *box, + struct constraint_offsets *offsets) { + // If none of the edges are constrained, no need to flip. + // If both edges are constrained, the box is bigger than + // the anchor rect and flipping won't help anyway. + bool flip_x = ((offsets->left > 0) ^ (offsets->right > 0)) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X); + bool flip_y = ((offsets->top > 0) ^ (offsets->bottom > 0)) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y); + + if (!flip_x && !flip_y) { + return false; + } + + struct wlr_xdg_positioner_rules flipped = *rules; + if (flip_x) { + flipped.anchor = xdg_positioner_anchor_invert_x(flipped.anchor); + flipped.gravity = xdg_positioner_gravity_invert_x(flipped.gravity); + } + if (flip_y) { + flipped.anchor = xdg_positioner_anchor_invert_y(flipped.anchor); + flipped.gravity = xdg_positioner_gravity_invert_y(flipped.gravity); + } + + struct wlr_box flipped_box; + wlr_xdg_positioner_rules_get_geometry(&flipped, &flipped_box); + struct constraint_offsets flipped_offsets; + get_constrained_box_offsets(constraint, &flipped_box, &flipped_offsets); + + // Only apply flipping if it helps + if (flipped_offsets.left <= 0 && flipped_offsets.right <= 0) { + box->x = flipped_box.x; + offsets->left = flipped_offsets.left; + offsets->right = flipped_offsets.right; + } + if (flipped_offsets.top <= 0 && flipped_offsets.bottom <= 0) { + box->y = flipped_box.y; + offsets->top = flipped_offsets.top; + offsets->bottom = flipped_offsets.bottom; + } + + return is_unconstrained(offsets); +} + +static bool xdg_positioner_rules_unconstrain_by_slide( + const struct wlr_xdg_positioner_rules *rules, + const struct wlr_box *constraint, struct wlr_box *box, + struct constraint_offsets *offsets) { + uint32_t gravity = xdg_positioner_gravity_to_wlr_edges(rules->gravity); + + // We can only slide if there is gravity on this axis + bool slide_x = (offsets->left > 0 || offsets->right > 0) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) && + (gravity & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)); + bool slide_y = (offsets->top > 0 || offsets->bottom > 0) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) && + (gravity & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)); + + if (!slide_x && !slide_y) { + return false; + } + + if (slide_x) { + if (offsets->left > 0 && offsets->right > 0) { + // The protocol states: "First try to slide towards the direction of + // the gravity [...] Then try to slide towards the opposite direction + // of the gravity". The only situation where this order matters is when + // the box is bigger than the anchor rect and completely includes it. + // In this case, the second slide will fail immediately, so simply + // slide towards the direction of the gravity. + if (gravity & WLR_EDGE_LEFT) { + box->x -= offsets->right; + } else if (gravity & WLR_EDGE_RIGHT) { + box->x += offsets->left; + } + } else { + // If at least one edge is already unconstrained, the order of slide + // attempts doesn't matter. Slide for the minimal distance needed to + // satisfy the requirement of constraining one edge or unconstraining + // another. + int abs_left = offsets->left > 0 ? offsets->left : -offsets->left; + int abs_right = offsets->right > 0 ? offsets->right : -offsets->right; + if (abs_left < abs_right) { + box->x += offsets->left; + } else { + box->x -= offsets->right; + } + } + } + if (slide_y) { + if (offsets->top > 0 && offsets->bottom > 0) { + if (gravity & WLR_EDGE_TOP) { + box->y -= offsets->bottom; + } else if (gravity & WLR_EDGE_BOTTOM) { + box->y += offsets->top; + } + } else { + int abs_top = offsets->top > 0 ? offsets->top : -offsets->top; + int abs_bottom = offsets->bottom > 0 ? offsets->bottom : -offsets->bottom; + if (abs_top < abs_bottom) { + box->y += offsets->top; + } else { + box->y -= offsets->bottom; + } + } + } + + get_constrained_box_offsets(constraint, box, offsets); + return is_unconstrained(offsets); +} + +static bool xdg_positioner_rules_unconstrain_by_resize( + const struct wlr_xdg_positioner_rules *rules, + const struct wlr_box *constraint, struct wlr_box *box, + struct constraint_offsets *offsets) { + bool resize_x = (offsets->left > 0 || offsets->right > 0) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); + bool resize_y = (offsets->top > 0 || offsets->bottom > 0) && + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); + + if (!resize_x && !resize_y) { + return false; + } + + if (offsets->left < 0) { + offsets->left = 0; + } + if (offsets->right < 0) { + offsets->right = 0; + } + if (offsets->top < 0) { + offsets->top = 0; + } + if (offsets->bottom < 0) { + offsets->bottom = 0; + } + + // Try to satisfy the constraints by clipping the box. + struct wlr_box resized_box = *box; + if (resize_x) { + resized_box.x += offsets->left; + resized_box.width -= offsets->left + offsets->right; + } + if (resize_y) { + resized_box.y += offsets->top; + resized_box.height -= offsets->top + offsets->bottom; + } + + if (wlr_box_empty(&resized_box)) { + return false; + } + + *box = resized_box; + get_constrained_box_offsets(constraint, box, offsets); + return is_unconstrained(offsets); +} + +void wlr_xdg_positioner_rules_unconstrain_box( + const struct wlr_xdg_positioner_rules *rules, + const struct wlr_box *constraint, struct wlr_box *box) { + struct constraint_offsets offsets; + get_constrained_box_offsets(constraint, box, &offsets); + if (is_unconstrained(&offsets)) { + // Already unconstrained + return; + } + if (xdg_positioner_rules_unconstrain_by_flip(rules, constraint, box, &offsets)) { + return; + } + if (xdg_positioner_rules_unconstrain_by_slide(rules, constraint, box, &offsets)) { + return; + } + if (xdg_positioner_rules_unconstrain_by_resize(rules, constraint, box, &offsets)) { + return; + } } From f1181c34ed3c3dd80299d634de062c4f2d731bac Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 9 Feb 2022 10:36:34 -0500 Subject: [PATCH 185/190] types/wlr_tablet_pad: constify impl --- include/wlr/interfaces/wlr_tablet_pad.h | 2 +- include/wlr/types/wlr_tablet_pad.h | 2 +- types/wlr_tablet_pad.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wlr/interfaces/wlr_tablet_pad.h b/include/wlr/interfaces/wlr_tablet_pad.h index b35f162e0..ff5c93594 100644 --- a/include/wlr/interfaces/wlr_tablet_pad.h +++ b/include/wlr/interfaces/wlr_tablet_pad.h @@ -16,7 +16,7 @@ struct wlr_tablet_pad_impl { }; void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, - struct wlr_tablet_pad_impl *impl, const char *name); + const struct wlr_tablet_pad_impl *impl, const char *name); void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad); #endif diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h index f30809cf0..249233537 100644 --- a/include/wlr/types/wlr_tablet_pad.h +++ b/include/wlr/types/wlr_tablet_pad.h @@ -24,7 +24,7 @@ struct wlr_tablet_pad_impl; struct wlr_tablet_pad { struct wlr_input_device base; - struct wlr_tablet_pad_impl *impl; + const struct wlr_tablet_pad_impl *impl; struct { struct wl_signal button; diff --git a/types/wlr_tablet_pad.c b/types/wlr_tablet_pad.c index 7d5635f79..861d1addb 100644 --- a/types/wlr_tablet_pad.c +++ b/types/wlr_tablet_pad.c @@ -6,7 +6,7 @@ #include void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, - struct wlr_tablet_pad_impl *impl, const char *name) { + const struct wlr_tablet_pad_impl *impl, const char *name) { wlr_input_device_init(&pad->base, WLR_INPUT_DEVICE_TABLET_PAD, NULL, name); pad->base.tablet_pad = pad; From 1acc931cf0f4de6b4402a70f1343f14df4d83347 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 9 Feb 2022 15:53:42 -0500 Subject: [PATCH 186/190] types/wlr_switch: constify impl --- include/wlr/interfaces/wlr_switch.h | 2 +- include/wlr/types/wlr_switch.h | 2 +- types/wlr_switch.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wlr/interfaces/wlr_switch.h b/include/wlr/interfaces/wlr_switch.h index cce55f98f..fbf5e6cb9 100644 --- a/include/wlr/interfaces/wlr_switch.h +++ b/include/wlr/interfaces/wlr_switch.h @@ -16,7 +16,7 @@ struct wlr_switch_impl { }; void wlr_switch_init(struct wlr_switch *switch_device, - struct wlr_switch_impl *impl, const char *name); + const struct wlr_switch_impl *impl, const char *name); void wlr_switch_destroy(struct wlr_switch *switch_device); #endif diff --git a/include/wlr/types/wlr_switch.h b/include/wlr/types/wlr_switch.h index a0b9562f7..31811ec33 100644 --- a/include/wlr/types/wlr_switch.h +++ b/include/wlr/types/wlr_switch.h @@ -18,7 +18,7 @@ struct wlr_switch_impl; struct wlr_switch { struct wlr_input_device base; - struct wlr_switch_impl *impl; + const struct wlr_switch_impl *impl; struct { struct wl_signal toggle; diff --git a/types/wlr_switch.c b/types/wlr_switch.c index 44a004e25..629fa5ee9 100644 --- a/types/wlr_switch.c +++ b/types/wlr_switch.c @@ -6,7 +6,7 @@ #include void wlr_switch_init(struct wlr_switch *switch_device, - struct wlr_switch_impl *impl, const char *name) { + const struct wlr_switch_impl *impl, const char *name) { wlr_input_device_init(&switch_device->base, WLR_INPUT_DEVICE_SWITCH, NULL, name); switch_device->base.switch_device = switch_device; From 19f7e5d2b4f6ae8d50eff2c219ca9bfed885eb57 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 8 Feb 2022 15:32:40 -0500 Subject: [PATCH 187/190] backend/x11: remove wlr_input_device_impl --- backend/x11/backend.c | 2 +- backend/x11/input_device.c | 22 +++++++--------------- backend/x11/output.c | 4 ++-- include/backend/x11.h | 8 +++----- 4 files changed, 13 insertions(+), 23 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 3f2a9f016..dbee4379f 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -638,7 +638,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } #endif - wlr_keyboard_init(&x11->keyboard, &keyboard_impl, "x11-keyboard"); + wlr_keyboard_init(&x11->keyboard, &x11_keyboard_impl, "x11-keyboard"); x11->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &x11->display_destroy); diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index a020442a2..a2d7ef536 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -286,19 +286,11 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11, } } -static void input_device_destroy(struct wlr_input_device *wlr_device) { - // Don't free the input device, it's on the stack -} - -const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy, -}; - static void keyboard_destroy(struct wlr_keyboard *wlr_keyboard) { // Don't free the keyboard, it's on the stack } -const struct wlr_keyboard_impl keyboard_impl = { +const struct wlr_keyboard_impl x11_keyboard_impl = { .destroy = keyboard_destroy, }; @@ -306,7 +298,7 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) { // Don't free the pointer, it's on the stack } -const struct wlr_pointer_impl pointer_impl = { +const struct wlr_pointer_impl x11_pointer_impl = { .destroy = pointer_destroy, }; @@ -314,7 +306,7 @@ static void touch_destroy(struct wlr_touch *wlr_touch) { // Don't free the touch, it's on the stack } -const struct wlr_touch_impl touch_impl = { +const struct wlr_touch_impl x11_touch_impl = { .destroy = touch_destroy, }; @@ -338,12 +330,12 @@ void update_x11_pointer_position(struct wlr_x11_output *output, bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) { switch (wlr_dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: - return wlr_dev->keyboard->impl == &keyboard_impl; + return wlr_dev->keyboard->impl == &x11_keyboard_impl; case WLR_INPUT_DEVICE_POINTER: - return wlr_dev->pointer->impl == &pointer_impl; + return wlr_dev->pointer->impl == &x11_pointer_impl; case WLR_INPUT_DEVICE_TOUCH: - return wlr_dev->touch->impl == &touch_impl; + return wlr_dev->touch->impl == &x11_touch_impl; default: - return wlr_dev->impl == &input_device_impl; + return false; } } diff --git a/backend/x11/output.c b/backend/x11/output.c index 0900a60a1..7037c36cc 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -573,10 +573,10 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_enabled(wlr_output, true); - wlr_pointer_init(&output->pointer, &pointer_impl, "x11-pointer"); + wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer"); output->pointer.base.output_name = strdup(wlr_output->name); - wlr_touch_init(&output->touch, &touch_impl, "x11-touch"); + wlr_touch_init(&output->touch, &x11_touch_impl, "x11-touch"); output->touch.base.output_name = strdup(wlr_output->name); wl_list_init(&output->touchpoints); diff --git a/include/backend/x11.h b/include/backend/x11.h index 2c0393556..572fce189 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -127,10 +126,9 @@ struct wlr_x11_backend *get_x11_backend_from_backend( struct wlr_x11_output *get_x11_output_from_window_id( struct wlr_x11_backend *x11, xcb_window_t window); -extern const struct wlr_keyboard_impl keyboard_impl; -extern const struct wlr_pointer_impl pointer_impl; -extern const struct wlr_touch_impl touch_impl; -extern const struct wlr_input_device_impl input_device_impl; +extern const struct wlr_keyboard_impl x11_keyboard_impl; +extern const struct wlr_pointer_impl x11_pointer_impl; +extern const struct wlr_touch_impl x11_touch_impl; void handle_x11_xinput_event(struct wlr_x11_backend *x11, xcb_ge_generic_event_t *event); From 887516d004ca5c5f35e99fd36f4b30f649f1c2f8 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 9 Feb 2022 14:08:20 -0500 Subject: [PATCH 188/190] backend/wayland: remove wlr_input_device_impl --- backend/wayland/backend.c | 2 +- backend/wayland/seat.c | 85 ++++++++++++++++++++----------------- backend/wayland/tablet_v2.c | 8 +++- include/backend/wayland.h | 3 ++ 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 1df753b93..a5b297ba2 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -444,7 +444,7 @@ static void backend_destroy(struct wlr_backend *backend) { struct wlr_wl_input_device *input_device, *tmp_input_device; wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) { - wlr_input_device_destroy(&input_device->wlr_input_device); + destroy_wl_input_device(input_device); } struct wlr_wl_buffer *buffer, *tmp_buffer; diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 6382347f1..ae669c4d8 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include "pointer-gestures-unstable-v1-client-protocol.h" @@ -22,6 +24,10 @@ #include "util/signal.h" #include "util/time.h" +static const struct wlr_pointer_impl pointer_impl; +static const struct wlr_keyboard_impl keyboard_impl; +static const struct wlr_touch_impl touch_impl; + static struct wlr_wl_pointer *output_get_pointer( struct wlr_wl_output *output, const struct wl_pointer *wl_pointer) { @@ -431,26 +437,21 @@ static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_de return dev->seat; } -static void input_device_destroy(struct wlr_input_device *wlr_dev) { - struct wlr_wl_input_device *dev = - get_wl_input_device_from_input_device(wlr_dev); - if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) { - struct wlr_wl_seat *seat = input_device_get_seat(wlr_dev); - wl_keyboard_release(seat->keyboard); - seat->keyboard = NULL; - } - // We can't destroy pointer here because we might have multiple devices - // exposing it to compositor. - wl_list_remove(&dev->link); - free(dev); -} - -static const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy, -}; - bool wlr_input_device_is_wl(struct wlr_input_device *dev) { - return dev->impl == &input_device_impl; + switch (dev->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + return dev->keyboard->impl == &keyboard_impl; + case WLR_INPUT_DEVICE_POINTER: + return dev->pointer->impl == &pointer_impl; + case WLR_INPUT_DEVICE_TOUCH: + return dev->touch->impl == &touch_impl; + case WLR_INPUT_DEVICE_TABLET_TOOL: + return dev->tablet->impl == &tablet_impl; + case WLR_INPUT_DEVICE_TABLET_PAD: + return dev->tablet_pad->impl == &tablet_pad_impl; + default: + return false; + } } struct wlr_wl_input_device *create_wl_input_device( @@ -493,12 +494,24 @@ struct wlr_wl_input_device *create_wl_input_device( char name[name_size]; (void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name); - wlr_input_device_init(wlr_dev, type, &input_device_impl, name); + wlr_input_device_init(wlr_dev, type, NULL, name); wl_list_insert(&seat->backend->devices, &dev->link); return dev; } -static const struct wlr_pointer_impl pointer_impl; +void destroy_wl_input_device(struct wlr_wl_input_device *dev) { + /** + * TODO remove the redundant wlr_input_device from wlr_wl_input_device + * wlr_wl_input_device::wlr_input_device is not owned by its input device + * type, which means we have 2 wlr_input_device to cleanup + */ + wlr_input_device_finish(&dev->wlr_input_device); + if (dev->wlr_input_device._device) { + wlr_input_device_destroy(&dev->wlr_input_device); + } + wl_list_remove(&dev->link); + free(dev); +} struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer) { assert(wlr_pointer->impl == &pointer_impl); @@ -532,10 +545,6 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) { zwp_relative_pointer_v1_destroy(pointer->relative_pointer); } - wlr_input_device_finish(&pointer->input_device->wlr_input_device); - wl_list_remove(&pointer->input_device->link); - free(pointer->input_device); - wl_list_remove(&pointer->output_destroy.link); free(pointer); } @@ -709,7 +718,7 @@ static void pointer_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_wl_pointer *pointer = wl_container_of(listener, pointer, output_destroy); - wlr_pointer_destroy(&pointer->wlr_pointer); + destroy_wl_input_device(pointer->input_device); } void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { @@ -741,13 +750,14 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { } pointer->input_device = dev; - wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); - pointer->output_destroy.notify = pointer_handle_output_destroy; - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->output_name = strdup(output->wlr_output.name); - wlr_pointer_init(wlr_dev->pointer, &pointer_impl, wlr_dev->name); + + wlr_pointer_init(&pointer->wlr_pointer, &pointer_impl, wlr_dev->name); + + wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); + pointer->output_destroy.notify = pointer_handle_output_destroy; if (backend->zwp_pointer_gestures_v1) { uint32_t version = zwp_pointer_gestures_v1_get_version( @@ -792,11 +802,11 @@ void create_wl_keyboard(struct wlr_wl_seat *seat) { wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard)); if (!wlr_dev->keyboard) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - wlr_input_device_destroy(wlr_dev); + destroy_wl_input_device(dev); return; } - wlr_keyboard_init(wlr_dev->keyboard, NULL, wlr_dev->name); + wlr_keyboard_init(wlr_dev->keyboard, &keyboard_impl, wlr_dev->name); wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); @@ -816,16 +826,15 @@ void create_wl_touch(struct wlr_wl_seat *seat) { wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); if (!wlr_dev->touch) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - wlr_input_device_destroy(wlr_dev); + destroy_wl_input_device(dev); return; } - wlr_touch_init(wlr_dev->touch, NULL, wlr_dev->name); + wlr_touch_init(wlr_dev->touch, &touch_impl, wlr_dev->name); wl_touch_add_listener(wl_touch, &touch_listener, dev); wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); } - static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_seat *seat = data; @@ -860,7 +869,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wlr_log(WLR_DEBUG, "dropping pointer %s", pointer->input_device->wlr_input_device.name); struct wlr_wl_output *output = pointer->output; - wlr_input_device_destroy(&device->wlr_input_device); + destroy_wl_input_device(device); assert(seat->active_pointer != pointer); assert(output->cursor.pointer != pointer); } @@ -891,7 +900,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, if (device->seat != seat) { continue; } - wlr_input_device_destroy(&device->wlr_input_device); + destroy_wl_input_device(device); } assert(seat->keyboard == NULL); // free'ed by input_device_destroy } @@ -910,7 +919,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, struct wlr_wl_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { if (device->wlr_input_device.type == WLR_INPUT_DEVICE_TOUCH) { - wlr_input_device_destroy(&device->wlr_input_device); + destroy_wl_input_device(device); } } diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index 4ddcce078..d24bf3409 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -426,6 +426,8 @@ static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { .removed = handle_tablet_pad_removed, }; +const struct wlr_tablet_pad_impl tablet_pad_impl = {0}; + static void handle_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) { @@ -453,7 +455,7 @@ static void handle_pad_added(void *data, zwp_tablet_pad_v2_destroy(id); return; } - wlr_tablet_pad_init(wlr_dev->tablet_pad, NULL, wlr_dev->name); + wlr_tablet_pad_init(wlr_dev->tablet_pad, &tablet_pad_impl, wlr_dev->name); zwp_tablet_pad_v2_add_listener(id, &tablet_pad_listener, dev); } @@ -887,6 +889,8 @@ static const struct zwp_tablet_v2_listener tablet_listener = { .removed = handle_tablet_removed, }; +const struct wlr_tablet_impl tablet_impl = {0}; + static void handle_tab_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) { @@ -909,7 +913,7 @@ static void handle_tab_added(void *data, return; } zwp_tablet_v2_set_user_data(id, wlr_dev->tablet); - wlr_tablet_init(wlr_dev->tablet, NULL, wlr_dev->name); + wlr_tablet_init(wlr_dev->tablet, &tablet_impl, wlr_dev->name); zwp_tablet_v2_add_listener(id, &tablet_listener, dev); } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 4e5d36361..668b69aed 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -134,9 +134,12 @@ struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_seat *seat, enum wlr_input_device_type type); bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); +void destroy_wl_input_device(struct wlr_wl_input_device *dev); void destroy_wl_buffer(struct wlr_wl_buffer *buffer); extern const struct wl_seat_listener seat_listener; +extern const struct wlr_tablet_pad_impl tablet_pad_impl; +extern const struct wlr_tablet_impl tablet_impl; struct wlr_wl_tablet_seat *wl_add_tablet_seat( struct zwp_tablet_manager_v2 *manager, From 91ba28e020092089eb9cc960530355de68c60a3d Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 9 Feb 2022 16:03:12 -0500 Subject: [PATCH 189/190] backend/libinput: remove wlr_input_device_impl --- backend/libinput/backend.c | 2 +- backend/libinput/events.c | 46 ++++++++++++++++++++++------------ backend/libinput/keyboard.c | 9 +++---- backend/libinput/pointer.c | 5 ++-- backend/libinput/switch.c | 4 ++- backend/libinput/tablet_pad.c | 4 ++- backend/libinput/tablet_tool.c | 9 +++---- backend/libinput/touch.c | 4 ++- include/backend/libinput.h | 16 +++++++++++- 9 files changed, 64 insertions(+), 35 deletions(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 4191f3507..8023807fd 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -145,7 +145,7 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) { struct wlr_libinput_input_device *dev, *tmp; wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) { - wlr_input_device_destroy(&dev->wlr_input_device); + destroy_libinput_input_device(dev); } free(*wlr_devices_ptr); } diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 1f28b94ac..67ca49d51 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -10,12 +10,6 @@ #include "util/array.h" #include "util/signal.h" -static struct wlr_libinput_input_device *get_libinput_device_from_device( - struct wlr_input_device *wlr_dev) { - assert(wlr_input_device_is_libinput(wlr_dev)); - return (struct wlr_libinput_input_device *)wlr_dev; -} - struct wlr_input_device *get_appropriate_device( enum wlr_input_device_type desired_type, struct libinput_device *libinput_dev) { @@ -32,18 +26,23 @@ struct wlr_input_device *get_appropriate_device( return NULL; } -static void input_device_destroy(struct wlr_input_device *wlr_dev) { - struct wlr_libinput_input_device *dev = - get_libinput_device_from_device(wlr_dev); +void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) +{ + /** + * TODO remove the redundant wlr_input_device from wlr_libinput_input_device + * wlr_libinput_input_device::wlr_input_device is not owned by its input + * device type, which means we have 2 wlr_input_device to cleanup + */ + if (dev->wlr_input_device._device) { + wlr_input_device_destroy(&dev->wlr_input_device); + } + wlr_input_device_finish(&dev->wlr_input_device); + libinput_device_unref(dev->handle); wl_list_remove(&dev->link); free(dev); } -static const struct wlr_input_device_impl input_device_impl = { - .destroy = input_device_destroy, -}; - static struct wlr_input_device *allocate_device( struct wlr_libinput_backend *backend, struct libinput_device *libinput_dev, struct wl_list *wlr_devices, @@ -64,14 +63,29 @@ static struct wlr_input_device *allocate_device( wl_list_insert(wlr_devices, &dev->link); dev->handle = libinput_dev; libinput_device_ref(libinput_dev); - wlr_input_device_init(wlr_dev, type, &input_device_impl, name); + wlr_input_device_init(wlr_dev, type, NULL, name); wlr_dev->vendor = libinput_device_get_id_vendor(libinput_dev); wlr_dev->product = libinput_device_get_id_product(libinput_dev); return wlr_dev; } bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) { - return wlr_dev->impl == &input_device_impl; + switch (wlr_dev->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + return wlr_dev->keyboard->impl == &libinput_keyboard_impl; + case WLR_INPUT_DEVICE_POINTER: + return wlr_dev->pointer->impl == &libinput_pointer_impl; + case WLR_INPUT_DEVICE_TOUCH: + return wlr_dev->touch->impl == &libinput_touch_impl; + case WLR_INPUT_DEVICE_TABLET_TOOL: + return wlr_dev->tablet->impl == &libinput_tablet_impl; + case WLR_INPUT_DEVICE_TABLET_PAD: + return wlr_dev->tablet_pad->impl == &libinput_tablet_pad_impl; + case WLR_INPUT_DEVICE_SWITCH: + return wlr_dev->switch_device->impl == &libinput_switch_impl; + default: + return false; + } } static void handle_device_added(struct wlr_libinput_backend *backend, @@ -216,7 +230,7 @@ static void handle_device_removed(struct wlr_libinput_backend *backend, } struct wlr_libinput_input_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { - wlr_input_device_destroy(&dev->wlr_input_device); + destroy_libinput_input_device(dev); } size_t i = 0; struct wl_list **ptr; diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c index be5faf3e1..9127217a8 100644 --- a/backend/libinput/keyboard.c +++ b/backend/libinput/keyboard.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include "backend/libinput.h" @@ -12,11 +11,9 @@ struct wlr_libinput_keyboard { struct libinput_device *libinput_dev; }; -static const struct wlr_keyboard_impl impl; - static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard( struct wlr_keyboard *wlr_kb) { - assert(wlr_kb->impl == &impl); + assert(wlr_kb->impl == &libinput_keyboard_impl); return (struct wlr_libinput_keyboard *)wlr_kb; } @@ -33,7 +30,7 @@ static void keyboard_destroy(struct wlr_keyboard *wlr_kb) { free(kb); } -static const struct wlr_keyboard_impl impl = { +const struct wlr_keyboard_impl libinput_keyboard_impl = { .destroy = keyboard_destroy, .led_update = keyboard_set_leds }; @@ -50,7 +47,7 @@ struct wlr_keyboard *create_libinput_keyboard( libinput_device_led_update(libinput_dev, 0); struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard; const char *name = libinput_device_get_name(libinput_dev); - wlr_keyboard_init(wlr_kb, &impl, name); + wlr_keyboard_init(wlr_kb, &libinput_keyboard_impl, name); wlr_kb->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_kb->base.product = libinput_device_get_id_product(libinput_dev); return wlr_kb; diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 305c43d9c..706ace7b5 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -2,12 +2,13 @@ #include #include #include -#include #include #include #include "backend/libinput.h" #include "util/signal.h" +const struct wlr_pointer_impl libinput_pointer_impl = {0}; + struct wlr_pointer *create_libinput_pointer( struct libinput_device *libinput_dev) { assert(libinput_dev); @@ -17,7 +18,7 @@ struct wlr_pointer *create_libinput_pointer( return NULL; } const char *name = libinput_device_get_name(libinput_dev); - wlr_pointer_init(wlr_pointer, NULL, name); + wlr_pointer_init(wlr_pointer, &libinput_pointer_impl, name); wlr_pointer->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_pointer->base.product = libinput_device_get_id_product(libinput_dev); return wlr_pointer; diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c index 9562e185b..0e710f090 100644 --- a/backend/libinput/switch.c +++ b/backend/libinput/switch.c @@ -8,6 +8,8 @@ #include "backend/libinput.h" #include "util/signal.h" +const struct wlr_switch_impl libinput_switch_impl; + struct wlr_switch *create_libinput_switch( struct libinput_device *libinput_dev) { assert(libinput_dev); @@ -17,7 +19,7 @@ struct wlr_switch *create_libinput_switch( return NULL; } const char *name = libinput_device_get_name(libinput_dev); - wlr_switch_init(wlr_switch, NULL, name); + wlr_switch_init(wlr_switch, &libinput_switch_impl, name); wlr_log(WLR_DEBUG, "Created switch for device %s", name); wlr_switch->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_switch->base.product = libinput_device_get_id_product(libinput_dev); diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index 2f1da363d..50b8ad6e7 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -66,6 +66,8 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, wl_list_insert(&pad->groups, &group->link); } +const struct wlr_tablet_pad_impl libinput_tablet_pad_impl; + struct wlr_tablet_pad *create_libinput_tablet_pad( struct libinput_device *libinput_dev) { assert(libinput_dev); @@ -76,7 +78,7 @@ struct wlr_tablet_pad *create_libinput_tablet_pad( return NULL; } const char *name = libinput_device_get_name(libinput_dev); - wlr_tablet_pad_init(wlr_tablet_pad, NULL, name); + wlr_tablet_pad_init(wlr_tablet_pad, &libinput_tablet_pad_impl, name); wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_tablet_pad->base.product = libinput_device_get_id_product(libinput_dev); diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 31803e810..373f87d7b 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -14,10 +14,8 @@ #include "util/array.h" #include "util/signal.h" -static const struct wlr_tablet_impl tablet_impl; - static bool tablet_is_libinput(struct wlr_tablet *tablet) { - return tablet->impl == &tablet_impl; + return tablet->impl == &libinput_tablet_impl; } struct wlr_libinput_tablet_tool { @@ -42,7 +40,6 @@ static void destroy_tool(struct wlr_libinput_tablet_tool *tool) { free(tool); } - static void destroy_tablet(struct wlr_tablet *wlr_tablet) { assert(tablet_is_libinput(wlr_tablet)); struct wlr_libinput_tablet *tablet = @@ -60,7 +57,7 @@ static void destroy_tablet(struct wlr_tablet *wlr_tablet) { free(tablet); } -static const struct wlr_tablet_impl tablet_impl = { +const struct wlr_tablet_impl libinput_tablet_impl = { .destroy = destroy_tablet, }; @@ -77,7 +74,7 @@ struct wlr_tablet *create_libinput_tablet( struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet; const char *name = libinput_device_get_name(libinput_dev); - wlr_tablet_init(wlr_tablet, &tablet_impl, name); + wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name); wlr_tablet->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_tablet->base.product = libinput_device_get_id_product(libinput_dev); diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c index d1f996119..2e22a97a3 100644 --- a/backend/libinput/touch.c +++ b/backend/libinput/touch.c @@ -8,6 +8,8 @@ #include "backend/libinput.h" #include "util/signal.h" +const struct wlr_touch_impl libinput_touch_impl; + struct wlr_touch *create_libinput_touch( struct libinput_device *libinput_dev) { assert(libinput_dev); @@ -17,7 +19,7 @@ struct wlr_touch *create_libinput_touch( return NULL; } const char *name = libinput_device_get_name(libinput_dev); - wlr_touch_init(wlr_touch, NULL, name); + wlr_touch_init(wlr_touch, &libinput_touch_impl, name); wlr_touch->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_touch->base.product = libinput_device_get_id_product(libinput_dev); return wlr_touch; diff --git a/include/backend/libinput.h b/include/backend/libinput.h index a6841d7e9..39e6dfe5a 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -5,7 +5,12 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include #include struct wlr_libinput_backend { @@ -39,6 +44,15 @@ struct wlr_input_device *get_appropriate_device( enum wlr_input_device_type desired_type, struct libinput_device *device); +void destroy_libinput_input_device(struct wlr_libinput_input_device *dev); + +extern const struct wlr_keyboard_impl libinput_keyboard_impl; +extern const struct wlr_pointer_impl libinput_pointer_impl; +extern const struct wlr_switch_impl libinput_switch_impl; +extern const struct wlr_tablet_impl libinput_tablet_impl; +extern const struct wlr_tablet_pad_impl libinput_tablet_pad_impl; +extern const struct wlr_touch_impl libinput_touch_impl; + struct wlr_keyboard *create_libinput_keyboard( struct libinput_device *device); void handle_keyboard_key(struct libinput_event *event, From e279266f714c7122e9ad97d56d047313f78cfdbe Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 9 Feb 2022 16:14:56 -0500 Subject: [PATCH 190/190] interfaces: remove wlr_input_device_impl --- backend/headless/backend.c | 1 - backend/libinput/events.c | 3 +- backend/wayland/backend.c | 1 - backend/wayland/seat.c | 3 +- backend/wayland/tablet_v2.c | 1 - backend/x11/backend.c | 1 - backend/x11/input_device.c | 1 - include/wlr/interfaces/wlr_input_device.h | 36 --------------------- include/wlr/types/wlr_input_device.h | 17 ++++++++-- include/wlr/types/wlr_virtual_keyboard_v1.h | 3 +- types/wlr_input_device.c | 11 ++----- types/wlr_keyboard.c | 3 +- types/wlr_pointer.c | 3 +- types/wlr_switch.c | 4 +-- types/wlr_tablet_pad.c | 3 +- types/wlr_tablet_tool.c | 4 +-- types/wlr_touch.c | 3 +- types/wlr_virtual_keyboard_v1.c | 1 + 18 files changed, 27 insertions(+), 72 deletions(-) delete mode 100644 include/wlr/interfaces/wlr_input_device.h diff --git a/backend/headless/backend.c b/backend/headless/backend.c index e44595de6..b14dda4a9 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include "backend/headless.h" diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 67ca49d51..e8d99f251 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "backend/libinput.h" #include "util/array.h" @@ -63,7 +62,7 @@ static struct wlr_input_device *allocate_device( wl_list_insert(wlr_devices, &dev->link); dev->handle = libinput_dev; libinput_device_ref(libinput_dev); - wlr_input_device_init(wlr_dev, type, NULL, name); + wlr_input_device_init(wlr_dev, type, name); wlr_dev->vendor = libinput_device_get_id_vendor(libinput_dev); wlr_dev->product = libinput_device_get_id_product(libinput_dev); return wlr_dev; diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index a5b297ba2..c0e99a228 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index ae669c4d8..28466bb33 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -494,7 +493,7 @@ struct wlr_wl_input_device *create_wl_input_device( char name[name_size]; (void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name); - wlr_input_device_init(wlr_dev, type, NULL, name); + wlr_input_device_init(wlr_dev, type, name); wl_list_insert(&seat->backend->devices, &dev->link); return dev; } diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index d24bf3409..95cdd119d 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "util/signal.h" #include "util/time.h" diff --git a/backend/x11/backend.c b/backend/x11/backend.c index dbee4379f..64bcf475b 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index a2d7ef536..f87f53a0d 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h deleted file mode 100644 index ab3148076..000000000 --- a/include/wlr/interfaces/wlr_input_device.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_INTERFACES_WLR_INPUT_DEVICE_H -#define WLR_INTERFACES_WLR_INPUT_DEVICE_H - -#include - -struct wlr_input_device_impl { - void (*destroy)(struct wlr_input_device *wlr_device); -}; - -void wlr_input_device_init(struct wlr_input_device *wlr_device, - enum wlr_input_device_type type, const struct wlr_input_device_impl *impl, - const char *name); - -/** - * Cleans up all of the provided wlr_input_device resources and signals the - * destroy event. - */ -void wlr_input_device_finish(struct wlr_input_device *wlr_device); - -/** - * Calls the specialized input device destroy function. - * If the wlr_input_device is not owned by a specialized input device, the - * function will finish the wlr_input_device, and either call its implementation - * destroy function if one has been given, or free the wlr_input_device. - */ -void wlr_input_device_destroy(struct wlr_input_device *dev); - -#endif diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index cbc877df6..1690a5b92 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -28,8 +28,6 @@ enum wlr_input_device_type { struct wlr_input_device_impl; struct wlr_input_device { - const struct wlr_input_device_impl *impl; - enum wlr_input_device_type type; unsigned int vendor, product; char *name; @@ -55,4 +53,19 @@ struct wlr_input_device { void *data; }; +void wlr_input_device_init(struct wlr_input_device *wlr_device, + enum wlr_input_device_type type, const char *name); + +/** + * Clean up all of the provided wlr_input_device resources + */ +void wlr_input_device_finish(struct wlr_input_device *wlr_device); + +/** + * Calls the specialized input device destroy function. + * If the wlr_input_device is not owned by a specialized input device, the + * function will finish the wlr_input_device and free it. + */ +void wlr_input_device_destroy(struct wlr_input_device *dev); + #endif diff --git a/include/wlr/types/wlr_virtual_keyboard_v1.h b/include/wlr/types/wlr_virtual_keyboard_v1.h index 8be6158dc..a818f1416 100644 --- a/include/wlr/types/wlr_virtual_keyboard_v1.h +++ b/include/wlr/types/wlr_virtual_keyboard_v1.h @@ -10,8 +10,7 @@ #define WLR_TYPES_WLR_VIRTUAL_KEYBOARD_V1_H #include -#include -#include +#include struct wlr_virtual_keyboard_manager_v1 { struct wl_global *global; diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 8056556b9..6897febed 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -14,10 +13,8 @@ #include "util/signal.h" void wlr_input_device_init(struct wlr_input_device *dev, - enum wlr_input_device_type type, - const struct wlr_input_device_impl *impl, const char *name) { + enum wlr_input_device_type type, const char *name) { dev->type = type; - dev->impl = impl; dev->name = strdup(name); dev->vendor = 0; dev->product = 0; @@ -64,10 +61,6 @@ void wlr_input_device_destroy(struct wlr_input_device *dev) { } } else { wlr_input_device_finish(dev); - if (dev->impl && dev->impl->destroy) { - dev->impl->destroy(dev); - } else { - free(dev); - } + free(dev); } } diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index 062c08a09..afa689b12 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -116,7 +115,7 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, void wlr_keyboard_init(struct wlr_keyboard *kb, const struct wlr_keyboard_impl *impl, const char *name) { - wlr_input_device_init(&kb->base, WLR_INPUT_DEVICE_KEYBOARD, NULL, name); + wlr_input_device_init(&kb->base, WLR_INPUT_DEVICE_KEYBOARD, name); kb->base.keyboard = kb; kb->impl = impl; diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index d6237c736..caabec1b3 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -1,13 +1,12 @@ #include #include #include -#include #include #include void wlr_pointer_init(struct wlr_pointer *pointer, const struct wlr_pointer_impl *impl, const char *name) { - wlr_input_device_init(&pointer->base, WLR_INPUT_DEVICE_POINTER, NULL, name); + wlr_input_device_init(&pointer->base, WLR_INPUT_DEVICE_POINTER, name); pointer->base.pointer = pointer; pointer->impl = impl; diff --git a/types/wlr_switch.c b/types/wlr_switch.c index 629fa5ee9..42611da96 100644 --- a/types/wlr_switch.c +++ b/types/wlr_switch.c @@ -1,14 +1,12 @@ #include #include #include -#include #include #include void wlr_switch_init(struct wlr_switch *switch_device, const struct wlr_switch_impl *impl, const char *name) { - wlr_input_device_init(&switch_device->base, WLR_INPUT_DEVICE_SWITCH, NULL, - name); + wlr_input_device_init(&switch_device->base, WLR_INPUT_DEVICE_SWITCH, name); switch_device->base.switch_device = switch_device; switch_device->impl = impl; diff --git a/types/wlr_tablet_pad.c b/types/wlr_tablet_pad.c index 861d1addb..663ccd39e 100644 --- a/types/wlr_tablet_pad.c +++ b/types/wlr_tablet_pad.c @@ -1,13 +1,12 @@ #include #include #include -#include #include #include void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, const struct wlr_tablet_pad_impl *impl, const char *name) { - wlr_input_device_init(&pad->base, WLR_INPUT_DEVICE_TABLET_PAD, NULL, name); + wlr_input_device_init(&pad->base, WLR_INPUT_DEVICE_TABLET_PAD, name); pad->base.tablet_pad = pad; pad->impl = impl; diff --git a/types/wlr_tablet_tool.c b/types/wlr_tablet_tool.c index 12278e938..e50d29d1a 100644 --- a/types/wlr_tablet_tool.c +++ b/types/wlr_tablet_tool.c @@ -1,14 +1,12 @@ #include #include #include -#include #include #include void wlr_tablet_init(struct wlr_tablet *tablet, const struct wlr_tablet_impl *impl, const char *name) { - wlr_input_device_init(&tablet->base, WLR_INPUT_DEVICE_TABLET_TOOL, NULL, - name); + wlr_input_device_init(&tablet->base, WLR_INPUT_DEVICE_TABLET_TOOL, name); tablet->base.tablet = tablet; tablet->impl = impl; diff --git a/types/wlr_touch.c b/types/wlr_touch.c index a0949933f..366191101 100644 --- a/types/wlr_touch.c +++ b/types/wlr_touch.c @@ -1,13 +1,12 @@ #include #include #include -#include #include #include void wlr_touch_init(struct wlr_touch *touch, const struct wlr_touch_impl *impl, const char *name) { - wlr_input_device_init(&touch->base, WLR_INPUT_DEVICE_TOUCH, NULL, name); + wlr_input_device_init(&touch->base, WLR_INPUT_DEVICE_TOUCH, name); touch->base.touch = touch; touch->impl = impl; diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index dc549aa72..07eeb3678 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include