diff options
author | Mikhail Burakov <mburakov@mailbox.org> | 2023-06-04 15:37:25 +0200 |
---|---|---|
committer | Mikhail Burakov <mburakov@mailbox.org> | 2023-06-04 16:12:55 +0200 |
commit | 148d71e5e62f8079d3cc227134b301b7bc548763 (patch) | |
tree | e60aa392c75e67a5901910379fe523eabeba2383 | |
parent | 0fa6c1cdd3d6dbea880e0ee2051f28e763e5b5d8 (diff) |
Add implementation of window overlays
-rw-r--r-- | window.c | 148 | ||||
-rw-r--r-- | window.h | 7 |
2 files changed, 155 insertions, 0 deletions
@@ -17,11 +17,16 @@ #include "window.h" +#include <assert.h> #include <errno.h> +#include <fcntl.h> #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include <wayland-client.h> #include "frame.h" @@ -31,6 +36,8 @@ #include "toolbox/utils.h" #include "xdg-shell.h" +#define OVERLAY_BUFFERS_COUNT 2 + // TODO(mburakov): This would look like shit until Wayland guys finally fix // https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 @@ -42,7 +49,9 @@ struct Window { struct wl_display* wl_display; struct wl_registry* wl_registry; struct wl_compositor* wl_compositor; + struct wl_shm* wl_shm; struct wl_seat* wl_seat; + struct wl_subcompositor* wl_subcompositor; struct xdg_wm_base* xdg_wm_base; struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1; struct zwp_pointer_constraints_v1* zwp_pointer_constraints_v1; @@ -65,6 +74,18 @@ struct Window { bool was_closed; }; +struct Overlay { + int width; + int height; + int shm_fd; + void* shm_buffer; + struct wl_surface* wl_surface; + struct wl_subsurface* wl_subsurface; + struct wl_shm_pool* wl_shm_pool; + struct wl_buffer* wl_buffers[OVERLAY_BUFFERS_COUNT]; + size_t wl_buffer_current; +}; + static void OnWlRegistryGlobal(void* data, struct wl_registry* wl_registry, uint32_t name, const char* interface, uint32_t version) { @@ -77,7 +98,9 @@ static void OnWlRegistryGlobal(void* data, struct wl_registry* wl_registry, } struct Window* window = data; MAYBE_BIND(wl_compositor) + MAYBE_BIND(wl_shm) MAYBE_BIND(wl_seat) + MAYBE_BIND(wl_subcompositor) MAYBE_BIND(xdg_wm_base) MAYBE_BIND(zwp_linux_dmabuf_v1) MAYBE_BIND(zwp_pointer_constraints_v1) @@ -150,7 +173,10 @@ rollback_globals: if (window->zwp_linux_dmabuf_v1) zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1); if (window->xdg_wm_base) xdg_wm_base_destroy(window->xdg_wm_base); + if (window->wl_subcompositor) + wl_subcompositor_destroy(window->wl_subcompositor); if (window->wl_seat) wl_seat_destroy(window->wl_seat); + if (window->wl_shm) wl_shm_destroy(window->wl_shm); if (window->wl_compositor) wl_compositor_destroy(window->wl_compositor); rollback_wl_registry: wl_registry_destroy(window->wl_registry); @@ -516,7 +542,9 @@ static void DeinitWaylandGlobals(struct Window* window) { zwp_pointer_constraints_v1_destroy(window->zwp_pointer_constraints_v1); zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1); xdg_wm_base_destroy(window->xdg_wm_base); + wl_subcompositor_destroy(window->wl_subcompositor); wl_seat_destroy(window->wl_seat); + wl_shm_destroy(window->wl_shm); wl_compositor_destroy(window->wl_compositor); wl_registry_destroy(window->wl_registry); wl_display_disconnect(window->wl_display); @@ -650,3 +678,123 @@ void WindowDestroy(struct Window* window) { DeinitWaylandGlobals(window); free(window); } + +struct Overlay* OverlayCreate(const struct Window* window, int x, int y, + int width, int height) { + ssize_t stride = width * 4; + ssize_t buffer_size = stride * height; + ssize_t pool_size = OVERLAY_BUFFERS_COUNT * buffer_size; + if (pool_size > INT32_MAX || width < 0 || height < 0) { + LOG("Suspicious overlay size %ux%u", width, height); + return NULL; + } + + struct Overlay* overlay = malloc(sizeof(struct Overlay)); + if (!overlay) { + LOG("Failed to allocate overlay (%s)", strerror(errno)); + return NULL; + } + *overlay = (struct Overlay){ + .width = width, + .height = height, + .shm_fd = -1, + }; + + char name[64]; + static size_t counter = 0; + snprintf(name, sizeof(name), "/wl_shm-%d-%zu", getpid(), counter++); + overlay->shm_fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (overlay->shm_fd == -1) { + LOG("Failed to open shm (%s)", strerror(errno)); + goto rollback_overlay; + } + shm_unlink(name); + + if (ftruncate(overlay->shm_fd, pool_size) == -1) { + LOG("Failed to truncate shm (%s)", strerror(errno)); + goto rollback_shm_fd; + } + overlay->shm_buffer = mmap(NULL, (size_t)pool_size, PROT_READ | PROT_WRITE, + MAP_SHARED, overlay->shm_fd, 0); + if (!overlay->shm_buffer) { + LOG("Failed to mmap shm (%s)", strerror(errno)); + goto rollback_shm_fd; + } + + overlay->wl_surface = wl_compositor_create_surface(window->wl_compositor); + if (!overlay->wl_surface) { + LOG("Failed to create wl_surface (%s)", strerror(errno)); + goto rollback_shm_buffer; + } + + overlay->wl_subsurface = wl_subcompositor_get_subsurface( + window->wl_subcompositor, overlay->wl_surface, window->wl_surface); + if (!overlay->wl_subsurface) { + LOG("Failed to create wl_subsurface (%s)", strerror(errno)); + goto rollback_wl_surface; + } + wl_subsurface_place_above(overlay->wl_subsurface, window->wl_surface); + wl_subsurface_set_position(overlay->wl_subsurface, x, y); + + overlay->wl_shm_pool = + wl_shm_create_pool(window->wl_shm, overlay->shm_fd, (int32_t)pool_size); + if (!overlay->wl_shm_pool) { + LOG("Failed to create wl_shm_pool (%s)", strerror(errno)); + goto rollback_wl_subsurface; + } + + int i = 0; + for (; i < OVERLAY_BUFFERS_COUNT; i++) { + overlay->wl_buffers[i] = wl_shm_pool_create_buffer( + overlay->wl_shm_pool, (int)(i * buffer_size), overlay->width, + overlay->height, (int)stride, WL_SHM_FORMAT_ARGB8888); + if (!overlay->wl_buffers[i]) { + LOG("Failed to create wl_buffer (%s)", strerror(errno)); + goto rollback_wl_buffers; + } + } + return overlay; + +rollback_wl_buffers: + for (; i; i--) wl_buffer_destroy(overlay->wl_buffers[i - 1]); + wl_shm_pool_destroy(overlay->wl_shm_pool); +rollback_wl_subsurface: + wl_subsurface_destroy(overlay->wl_subsurface); +rollback_wl_surface: + wl_surface_destroy(overlay->wl_surface); +rollback_shm_buffer: + munmap(overlay->shm_buffer, (size_t)pool_size); +rollback_shm_fd: + close(overlay->shm_fd); +rollback_overlay: + free(overlay); + return NULL; +} + +void* OverlayLock(struct Overlay* overlay) { + ssize_t stride = overlay->width * 4; + ssize_t buffer_size = stride * overlay->height; + size_t next = (overlay->wl_buffer_current + 1) % OVERLAY_BUFFERS_COUNT; + return (uint8_t*)overlay->shm_buffer + (size_t)buffer_size * next; +} + +void OverlayUnlock(struct Overlay* overlay) { + size_t next = (overlay->wl_buffer_current + 1) % OVERLAY_BUFFERS_COUNT; + wl_surface_attach(overlay->wl_surface, overlay->wl_buffers[next], 0, 0); + wl_surface_damage(overlay->wl_surface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_commit(overlay->wl_surface); + overlay->wl_buffer_current = next; +} + +void OverlayDestroy(struct Overlay* overlay) { + for (int i = OVERLAY_BUFFERS_COUNT; i; i--) + wl_buffer_destroy(overlay->wl_buffers[i - 1]); + wl_shm_pool_destroy(overlay->wl_shm_pool); + wl_subsurface_destroy(overlay->wl_subsurface); + wl_surface_destroy(overlay->wl_surface); + ssize_t pool_size = + OVERLAY_BUFFERS_COUNT * overlay->width * overlay->height * 4; + munmap(overlay->shm_buffer, (size_t)(pool_size)); + close(overlay->shm_fd); + free(overlay); +} @@ -23,6 +23,7 @@ struct Window; struct Frame; +struct Overlay; struct WindowEventHandlers { void (*OnClose)(void* user); @@ -42,4 +43,10 @@ bool WindowAssignFrames(struct Window* window, size_t nframes, bool WindowShowFrame(struct Window* window, size_t index); void WindowDestroy(struct Window* window); +struct Overlay* OverlayCreate(const struct Window* window, int x, int y, + int width, int height); +void* OverlayLock(struct Overlay* overlay); +void OverlayUnlock(struct Overlay* overlay); +void OverlayDestroy(struct Overlay* overlay); + #endif // RECEIVER_WINDOW_H_ |