From 927ae621c9a3d46dbc401b8e9ea7bbed1bf2e97b Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Sun, 11 Oct 2026 21:53:42 +0300 Subject: initial: Yet Another Surface Library (YASL) 0.1.0 A minimal, modern desktop window surface library in C. Supports Wayland on Linux and Cocoa/Metal on macOS with presentation timing, fractional scaling, IME, and CSD. --- src/wayland/buffer.c | 551 +++++ src/wayland/clipboard.c | 621 +++++ src/wayland/clipboard.h | 41 + src/wayland/drag.c | 241 ++ src/wayland/ime.c | 174 ++ src/wayland/internal.h | 418 ++++ src/wayland/keyboard.c | 389 +++ src/wayland/pointer.c | 1291 ++++++++++ src/wayland/popup.c | 193 ++ .../protocols/commit-timing-v1-client-protocol.h | 294 +++ src/wayland/protocols/commit-timing-v1-protocol.c | 73 + .../protocols/cursor-shape-v1-client-protocol.h | 452 ++++ src/wayland/protocols/cursor-shape-v1-protocol.c | 75 + src/wayland/protocols/fifo-v1-client-protocol.h | 323 +++ src/wayland/protocols/fifo-v1-protocol.c | 71 + .../fractional-scale-v1-client-protocol.h | 264 +++ .../protocols/fractional-scale-v1-protocol.c | 74 + src/wayland/protocols/meson.build | 15 + .../protocols/presentation-time-client-protocol.h | 498 ++++ src/wayland/protocols/presentation-time-protocol.c | 84 + ...primary-selection-unstable-v1-client-protocol.h | 582 +++++ .../primary-selection-unstable-v1-protocol.c | 116 + src/wayland/protocols/tablet-v2-client-protocol.h | 2495 ++++++++++++++++++++ src/wayland/protocols/tablet-v2-protocol.c | 254 ++ .../protocols/tearing-control-v1-client-protocol.h | 298 +++ .../protocols/tearing-control-v1-protocol.c | 71 + .../text-input-unstable-v3-client-protocol.h | 1103 +++++++++ .../protocols/text-input-unstable-v3-protocol.c | 103 + src/wayland/protocols/viewporter-client-protocol.h | 394 ++++ src/wayland/protocols/viewporter-protocol.c | 75 + .../protocols/xdg-decoration-client-protocol.h | 400 ++++ src/wayland/protocols/xdg-decoration-protocol.c | 76 + src/wayland/protocols/xdg-shell-client-protocol.h | 2392 +++++++++++++++++++ src/wayland/protocols/xdg-shell-protocol.c | 184 ++ .../xdg-toplevel-drag-v1-client-protocol.h | 320 +++ .../protocols/xdg-toplevel-drag-v1-protocol.c | 74 + src/wayland/shell.c | 398 ++++ src/wayland/surface.c | 430 ++++ 38 files changed, 15907 insertions(+) create mode 100644 src/wayland/buffer.c create mode 100644 src/wayland/clipboard.c create mode 100644 src/wayland/clipboard.h create mode 100644 src/wayland/drag.c create mode 100644 src/wayland/ime.c create mode 100644 src/wayland/internal.h create mode 100644 src/wayland/keyboard.c create mode 100644 src/wayland/pointer.c create mode 100644 src/wayland/popup.c create mode 100644 src/wayland/protocols/commit-timing-v1-client-protocol.h create mode 100644 src/wayland/protocols/commit-timing-v1-protocol.c create mode 100644 src/wayland/protocols/cursor-shape-v1-client-protocol.h create mode 100644 src/wayland/protocols/cursor-shape-v1-protocol.c create mode 100644 src/wayland/protocols/fifo-v1-client-protocol.h create mode 100644 src/wayland/protocols/fifo-v1-protocol.c create mode 100644 src/wayland/protocols/fractional-scale-v1-client-protocol.h create mode 100644 src/wayland/protocols/fractional-scale-v1-protocol.c create mode 100644 src/wayland/protocols/meson.build create mode 100644 src/wayland/protocols/presentation-time-client-protocol.h create mode 100644 src/wayland/protocols/presentation-time-protocol.c create mode 100644 src/wayland/protocols/primary-selection-unstable-v1-client-protocol.h create mode 100644 src/wayland/protocols/primary-selection-unstable-v1-protocol.c create mode 100644 src/wayland/protocols/tablet-v2-client-protocol.h create mode 100644 src/wayland/protocols/tablet-v2-protocol.c create mode 100644 src/wayland/protocols/tearing-control-v1-client-protocol.h create mode 100644 src/wayland/protocols/tearing-control-v1-protocol.c create mode 100644 src/wayland/protocols/text-input-unstable-v3-client-protocol.h create mode 100644 src/wayland/protocols/text-input-unstable-v3-protocol.c create mode 100644 src/wayland/protocols/viewporter-client-protocol.h create mode 100644 src/wayland/protocols/viewporter-protocol.c create mode 100644 src/wayland/protocols/xdg-decoration-client-protocol.h create mode 100644 src/wayland/protocols/xdg-decoration-protocol.c create mode 100644 src/wayland/protocols/xdg-shell-client-protocol.h create mode 100644 src/wayland/protocols/xdg-shell-protocol.c create mode 100644 src/wayland/protocols/xdg-toplevel-drag-v1-client-protocol.h create mode 100644 src/wayland/protocols/xdg-toplevel-drag-v1-protocol.c create mode 100644 src/wayland/shell.c create mode 100644 src/wayland/surface.c (limited to 'src/wayland') diff --git a/src/wayland/buffer.c b/src/wayland/buffer.c new file mode 100644 index 0000000..492cfde --- /dev/null +++ b/src/wayland/buffer.c @@ -0,0 +1,551 @@ +#include "internal.h" +#include + +static long minor_faults(void) +{ + struct rusage usage; + return getrusage(RUSAGE_SELF, &usage) == 0 ? usage.ru_minflt : 0; +} + +void surface_update_opaque_region(struct yasl_surface *w) +{ + if (!w || !w->opaque || w->logical_width <= 0 || w->logical_height <= 0) + return; + struct wl_region *region = wl_compositor_create_region(w->conn->compositor); + if (!region) return; + wl_region_add(region, 0, 0, w->logical_width, w->logical_height); + wl_surface_set_opaque_region(w->surface, region); + wl_region_destroy(region); +} + +static const struct wl_buffer_listener buffer_listener; + +int device_px(int logical, uint32_t scale_120) +{ + int64_t px = ((int64_t)logical * scale_120 + YASL_SCALE_UNIT / 2) / YASL_SCALE_UNIT; + return px > 0 && px <= INT_MAX ? (int)px : -1; +} + +int logical_px_ceil(int device, uint32_t scale_120) +{ + return (int)(((int64_t)device * YASL_SCALE_UNIT + scale_120 - 1) / scale_120); +} + +bool buffer_size(int width, int height, size_t *bytes) +{ + if (width <= 0 || height <= 0 || width > INT32_MAX / 4 || + (size_t)height > INT32_MAX / ((size_t)width * 4)) + return false; + *bytes = (size_t)width * 4 * (size_t)height; + return true; +} + +void buffer_destroy(struct buffer *b) +{ + if (b->proxy) wl_buffer_destroy(b->proxy); + if (b->pool) wl_shm_pool_destroy(b->pool); + if (b->pixels) munmap(b->pixels, b->capacity); + *b = (struct buffer){0}; +} + +static bool fd_truncate(int fd, size_t bytes) +{ + int rc; + do { rc = ftruncate(fd, (off_t)bytes); } while (rc < 0 && errno == EINTR); + return rc == 0; +} + +int buffer_reserve(struct yasl_surface *w, struct buffer *b, size_t needed) +{ + if (needed <= b->capacity) return 0; + if (b->busy || needed > INT32_MAX) return -1; + size_t capacity = b->capacity <= INT32_MAX / 2 ? b->capacity * 2 : INT32_MAX; + if (capacity < needed) capacity = needed; + int fd = memfd_create("yasl_surface_buffer", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd < 0) return -1; + if (!fd_truncate(fd, capacity) || + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL) < 0) { + close(fd); + return -1; + } + uint32_t *pixels = mmap(NULL, capacity, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (pixels == MAP_FAILED) { + close(fd); + return -1; + } + struct wl_shm_pool *pool = wl_shm_create_pool(w->conn->shm, fd, (int32_t)capacity); + close(fd); + if (!pool) { + munmap(pixels, capacity); + return -1; + } + buffer_destroy(b); + b->pool = pool; + b->pixels = pixels; + b->capacity = capacity; + return 0; +} + +int buffer_prepare(struct yasl_surface *w, struct buffer *b, int width, int height, + const struct wl_buffer_listener *listener) +{ + if (b->proxy && !b->busy && b->width == width && b->height == height) return 0; + long faults_before = minor_faults(); + uint64_t t0 = yasl_loop_now_ns(); + size_t bytes; + if (!buffer_size(width, height, &bytes) || buffer_reserve(w, b, bytes) < 0) + return -1; + b->owner = w; + struct wl_buffer *proxy = wl_shm_pool_create_buffer(b->pool, 0, + width, height, width * 4, WL_SHM_FORMAT_ARGB8888); + if (!proxy) return -1; + if (b->proxy) wl_buffer_destroy(b->proxy); + b->proxy = proxy; + b->width = width; + b->height = height; + b->busy = false; + b->presented = false; + wl_buffer_add_listener(proxy, listener, b); + yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - t0); + long faults = minor_faults() - faults_before; + if (faults > 0) w->clock.resize_minflt += faults; + return 0; +} + +static void publish_surface_scale(struct yasl_surface *w) +{ + if (w->viewport) { + wp_viewport_set_destination(w->viewport, w->logical_width, w->logical_height); + } else if (w->scale_120 % YASL_SCALE_UNIT == 0 && + wl_proxy_get_version((struct wl_proxy *)w->surface) >= + WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) { + wl_surface_set_buffer_scale(w->surface, (int32_t)(w->scale_120 / YASL_SCALE_UNIT)); + } +} + +static void surface_request_scale(struct yasl_surface *w, uint32_t scale_120) +{ + if (!scale_120 || scale_120 == w->pending_scale_120) return; + w->pending_scale_120 = scale_120; + w->size_pending = true; + yasl_surface_schedule_redraw(w); +} + +int apply_pending_geometry(struct yasl_surface *w) +{ + if (!w->size_pending) return 0; + if (w->parent && w->pending_scale_120 == w->scale_120) { + w->size_pending = false; + return 0; + } + bool floating = !w->parent && !w->maximized && !w->fullscreen && !w->tiled; + int free_w = floating && w->floating_width > 0 ? w->floating_width : w->logical_width; + int free_h = floating && w->floating_height > 0 ? w->floating_height : w->logical_height; + int logical_w = !w->parent && w->req_width > 0 ? w->req_width : free_w; + int logical_h = !w->parent && w->req_height > 0 ? w->req_height : free_h; + if (!w->parent) { + if (logical_w < YASL_MIN_LOGICAL_PX) logical_w = YASL_MIN_LOGICAL_PX; + if (logical_h < YASL_MIN_LOGICAL_PX) logical_h = YASL_MIN_LOGICAL_PX; + } + if (!w->fullscreen) { + if (w->bound_width > 0 && logical_w > w->bound_width) + logical_w = w->bound_width; + if (w->bound_height > 0 && logical_h > w->bound_height) + logical_h = w->bound_height; + } + int width = device_px(logical_w, w->pending_scale_120); + int height = device_px(logical_h, w->pending_scale_120); + size_t bytes; + if (!buffer_size(width, height, &bytes)) { + return -1; + } + bool rescaled = w->scale_120 != w->pending_scale_120; + bool resized = width != w->width || height != w->height; + w->size_pending = false; + if (floating) { + w->floating_width = logical_w; + w->floating_height = logical_h; + } + if (!rescaled && !resized && logical_w == w->logical_width && logical_h == w->logical_height) + return 0; + + w->scale_120 = w->pending_scale_120; + w->scale_factor = (double)w->scale_120 / YASL_SCALE_UNIT; + w->width = width; + w->height = height; + w->logical_width = logical_w; + w->logical_height = logical_h; + surface_update_opaque_region(w); + if (resized || rescaled) { + for (int i = 0; i < NBUF; i++) + w->buffers[i].presented = false; + } + publish_surface_scale(w); + if (w->cbs->configure && (resized || rescaled)) + w->cbs->configure(w, (struct yasl_geometry){ + .size = { .x = width, .y = height }, .scale_120 = w->scale_120, + }, w->ud); + return 0; +} + +static void fractional_preferred_scale(void *data, + struct wp_fractional_scale_v1 *frac_scale, uint32_t scale) +{ + (void)frac_scale; + surface_request_scale(data, scale); +} + +static const struct wp_fractional_scale_v1_listener frac_scale_listener = { + .preferred_scale = fractional_preferred_scale, +}; + +static void surface_follow_refresh(struct yasl_surface *w) +{ + uint32_t refresh = 0; + for (const struct wl_conn_output *o = w->conn->outputs; o; o = o->next) + if ((o->mask & w->outputs) && o->refresh_ns && + (!refresh || o->refresh_ns < refresh)) + refresh = o->refresh_ns; + if (!refresh && w->conn->outputs) + refresh = w->conn->outputs->refresh_ns; + if (refresh) + w->clock.refresh_ns = refresh; +} + +void surface_follow_outputs(struct yasl_surface *w) +{ + surface_follow_refresh(w); + if (!w->frac_scale && !surface_gets_preferred_scale(w->surface)) + surface_request_scale(w, conn_output_scale_120(w->conn, w->outputs)); +} + +static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *output) +{ + (void)surface; + struct yasl_surface *w = data; + w->outputs |= conn_output_mask(w->conn, output); + surface_follow_outputs(w); +} + +static void surface_leave(void *data, struct wl_surface *surface, struct wl_output *output) +{ + (void)surface; + struct yasl_surface *w = data; + w->outputs &= ~conn_output_mask(w->conn, output); + surface_follow_outputs(w); +} + +static void surface_preferred_scale(void *data, struct wl_surface *surface, int32_t factor) +{ + (void)surface; + struct yasl_surface *w = data; + if (w->frac_scale || w->parent || factor <= 0) + return; + surface_request_scale(w, (uint32_t)factor * YASL_SCALE_UNIT); +} + +static void surface_preferred_transform(void *data, struct wl_surface *surface, + uint32_t transform) +{ + (void)data; (void)surface; (void)transform; +} + +static const struct wl_surface_listener surface_listener = { + .enter = surface_enter, + .leave = surface_leave, + .preferred_buffer_scale = surface_preferred_scale, + .preferred_buffer_transform = surface_preferred_transform, +}; + +static void buffer_release(void *data, struct wl_buffer *buffer) +{ + (void)buffer; + struct buffer *b = data; + b->busy = false; + if (b->owner && b->owner->want_draw) + yasl_surface_schedule_redraw(b->owner); +} + +static const struct wl_buffer_listener buffer_listener = { + .release = buffer_release, +}; + +static void frame_done(void *data, struct wl_callback *cb, uint32_t ms) +{ + struct yasl_surface *w = data; + wl_callback_destroy(cb); + w->frame_cb = NULL; + + uint64_t now = yasl_loop_now_ns(); + if (!w->conn->pres_clock_known) + yasl_clock_presented(&w->clock, yasl_clock_extend_ms(ms, now), w->sample_refresh); + + if (w->want_draw) + yasl_surface_schedule_redraw(w); +} + +static const struct wl_callback_listener frame_listener = { + .done = frame_done, +}; + +static void arm_frame(struct yasl_surface *w) +{ + if (!w->configured || w->closed || w->frame_cb) + return; + w->frame_cb = wl_surface_frame(w->surface); + if (!w->frame_cb) { surface_fail(w); return; } + w->sample_refresh = w->clock.last_present_ns && + yasl_loop_now_ns() - w->clock.last_present_ns < + (uint64_t)(w->clock.refresh_ns / 2); + if (wl_callback_add_listener(w->frame_cb, &frame_listener, w) < 0) { + wl_callback_destroy(w->frame_cb); + w->frame_cb = NULL; + surface_fail(w); + } +} + +int buffer_pick_free_index(const struct buffer *bufs, int cur) +{ + if (!bufs[cur ^ 1].busy) return cur ^ 1; + for (int i = 0; i < NBUF; i++) + if (i != cur && i != (cur ^ 1) && !bufs[i].busy) return i; + if (!bufs[cur].busy) return cur; + return -1; +} + +struct latency_feedback { + struct yasl_surface *window; + struct wp_presentation_feedback *proxy; + struct latency_feedback *next; +}; + +static void feedback_destroy(struct latency_feedback *feedback) +{ + struct latency_feedback **link = &feedback->window->latency_feedbacks; + while (*link && *link != feedback) link = &(*link)->next; + if (*link) *link = feedback->next; + wp_presentation_feedback_destroy(feedback->proxy); + free(feedback); +} + +void surface_feedback_destroy(struct yasl_surface *w) +{ + while (w->latency_feedbacks) feedback_destroy(w->latency_feedbacks); +} + +static void sync_output(void *data, struct wp_presentation_feedback *fb, + struct wl_output *output) +{ + (void)data; (void)fb; (void)output; +} + +static void presented(void *data, struct wp_presentation_feedback *fb, + uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec, + uint32_t refresh, uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) +{ + (void)seq_hi; (void)seq_lo; (void)flags; + struct latency_feedback *feedback = data; + struct yasl_surface *w = feedback->window; + if (w->conn->pres_clock_known) { + uint64_t ns = conn_pres_to_mono(w->conn, + (((uint64_t)tv_sec_hi << 32) | tv_sec_lo) * 1000000000ull + tv_nsec); + if (refresh) w->clock.refresh_ns = refresh; + w->clock.last_present_ns = ns; + } + (void)fb; + feedback_destroy(feedback); +} + +static void discarded(void *data, struct wp_presentation_feedback *fb) +{ + struct latency_feedback *feedback = data; + feedback->window->frames_skipped++; + (void)fb; + feedback_destroy(feedback); +} + +static const struct wp_presentation_feedback_listener feedback_listener = { + .sync_output = sync_output, + .presented = presented, + .discarded = discarded, +}; + +void surface_request_presentation_feedback(struct yasl_surface *w) +{ + if (!w || !w->conn->presentation) + return; + struct wp_presentation_feedback *fb = + wp_presentation_feedback(w->conn->presentation, w->surface); + struct latency_feedback *feedback = fb ? calloc(1, sizeof(*feedback)) : NULL; + if (!feedback) { + if (fb) wp_presentation_feedback_destroy(fb); + return; + } + feedback->window = w; + feedback->proxy = fb; + feedback->next = w->latency_feedbacks; + w->latency_feedbacks = feedback; + wp_presentation_feedback_add_listener(fb, &feedback_listener, feedback); +} + +static void commit_buffer(struct yasl_surface *w, int idx) +{ + wl_surface_attach(w->surface, w->buffers[idx].proxy, 0, 0); + + const struct yasl_damage_list *d = &w->damage; + if (d->n < 0 || !w->buffers[idx].presented) + wl_surface_damage_buffer(w->surface, 0, 0, w->width, w->height); + else + wl_damage_list(w->surface, d); + + if (!w->parent) { + surface_request_presentation_feedback(w); + if (w->conn->fifo_mgr && !w->fifo) + w->fifo = wp_fifo_manager_v1_get_fifo(w->conn->fifo_mgr, w->surface); + if (w->conn->commit_timing_mgr && !w->commit_timer) + w->commit_timer = wp_commit_timing_manager_v1_get_timer( + w->conn->commit_timing_mgr, w->surface); + } + if (w->fifo) { + wp_fifo_v1_wait_barrier(w->fifo); + wp_fifo_v1_set_barrier(w->fifo); + } + if (w->commit_timer && w->conn->pres_clock_known) { + uint64_t now = yasl_loop_now_ns(); + uint64_t next = yasl_clock_next_present_ns(&w->clock); + bool soon = next > now && next - now < (uint64_t)(w->clock.refresh_ns * 1.5); + next = conn_mono_to_pres(w->conn, next); + if (soon) + wp_commit_timer_v1_set_timestamp(w->commit_timer, + (uint32_t)(next / 1000000000ull >> 32), + (uint32_t)(next / 1000000000ull), + (uint32_t)(next % 1000000000ull)); + } + + if (w->has_pending_serial) { + xdg_surface_ack_configure(w->xdg_surface, w->pending_serial); + w->has_pending_serial = false; + } + wl_surface_commit(w->surface); + w->buffers[idx].busy = true; + w->buffers[idx].presented = true; +} + +bool yasl_surface_present(struct yasl_surface *w, const struct yasl_framebuffer *fb, + const struct yasl_damage_list *damage) +{ + if (!w || w->closed || !w->frame_active || w->frame_presented || !fb || + !damage || fb->pixels != w->frame.target.pixels || + fb->size.x != w->width || fb->size.y != w->height || + fb->buffer != w->cur) + return false; + + w->damage = *damage; + arm_frame(w); + if (w->closed) + return false; + commit_buffer(w, w->cur); + w->frame_presented = true; + return true; +} + +void surface_draw_frame(struct yasl_surface *w) +{ + if (w->closed || !w->configured) + return; + if (apply_pending_geometry(w) < 0) { + surface_fail(w); + return; + } + if (w->closed || !w->cbs->draw || w->frame_cb || !w->want_draw) + return; + + int idx = buffer_pick_free_index(w->buffers, w->cur); + if (idx < 0) { + w->frames_skipped++; + return; + } + if (buffer_prepare(w, &w->buffers[idx], w->width, w->height, &buffer_listener) < 0) { + w->frames_skipped++; + return; + } + w->cur = idx; + w->want_draw = false; + + if (w->parent) + memset(w->buffers[idx].pixels, 0, (size_t)w->width * (size_t)w->height * sizeof(uint32_t)); + w->damage = (struct yasl_damage_list){0}; + w->frame = (struct yasl_frame){ + .surface = w, + .target = { + .pixels = w->buffers[idx].pixels, + .size = { .x = w->width, .y = w->height }, + .buffer = idx, + .cleared = w->parent != NULL, + .damage = &w->damage, + .native_drawable = NULL, + .transaction = false, + }, + }; + w->frame_active = true; + w->frame_presented = false; + w->cbs->draw(w, &w->frame, w->ud); + w->frame_active = false; + if (!w->closed && !w->frame_presented) + w->frames_skipped++; +} + +int surface_init_scaling(struct yasl_surface *w) +{ + wl_surface_add_listener(w->surface, &surface_listener, w); + if (w->conn->viewporter) { + w->viewport = wp_viewporter_get_viewport(w->conn->viewporter, w->surface); + if (!w->viewport) return -1; + } + if (w->conn->scale_mgr && w->viewport && !w->parent) { + w->frac_scale = wp_fractional_scale_manager_v1_get_fractional_scale( + w->conn->scale_mgr, w->surface); + if (!w->frac_scale) return -1; + wp_fractional_scale_v1_add_listener(w->frac_scale, &frac_scale_listener, w); + } + return 0; +} + +void yasl_surface_set_title(struct yasl_surface *w, const char *title) +{ + if (!w || !w->toplevel || !title) return; + char *copy = yasl_utf8_sanitize_dup(title); + if (!copy) return; + xdg_toplevel_set_title(w->toplevel, copy); + free(copy); +} + +uint32_t yasl_surface_state(const struct yasl_surface *w) +{ + if (!w) return 0; + uint32_t s = 0; + if (w->fullscreen) s |= YASL_STATE_FULLSCREEN; + if (w->maximized) s |= YASL_STATE_MAXIMIZED; + if (w->activated) s |= YASL_STATE_ACTIVATED; + if (w->suspended) s |= YASL_STATE_SUSPENDED; + if (!w->server_decorated) s |= YASL_STATE_CSD; + return s; +} + +struct yasl_timing yasl_surface_timing(const struct yasl_surface *w) +{ + struct yasl_timing t = { + .refresh_ns = w->clock.refresh_ns, + .last_present_ns = w->clock.last_present_ns, + .next_present_ns = yasl_clock_next_present_ns(&w->clock), + .frames_skipped = w->frames_skipped, + }; + yasl_clock_resize_stats(&w->clock, &t.resize); + return t; +} + +uint64_t yasl_surface_frame_time_ns(struct yasl_surface *w, uint64_t now) +{ + return yasl_clock_frame_timestamp_ns(&w->clock, now); +} diff --git a/src/wayland/clipboard.c b/src/wayland/clipboard.c new file mode 100644 index 0000000..324644f --- /dev/null +++ b/src/wayland/clipboard.c @@ -0,0 +1,621 @@ +#define _GNU_SOURCE +#include "internal.h" +#include "clipboard.h" + +#define CLIPBOARD_TEXT_MAX (256u * 1024) + +struct offer { + struct offer *next; + struct wl_data_offer *proxy; + char *mime; + bool uri_list; + bool tab; +}; +struct primary_offer { + struct primary_offer *next; + struct zwp_primary_selection_offer_v1 *proxy; + char *mime; +}; +struct transfer { + struct transfer *next; + struct clipboard *owner; + struct offer *drop; + struct wl_surface *drop_surface; + int fd, id; + char *text; + size_t len, offset, capacity; + bool sending; + bool uri_list; +}; +struct clipboard { + struct wl_display *display; + struct wl_data_device_manager *manager; + struct wl_data_device *device; + struct zwp_primary_selection_device_manager_v1 *primary_manager; + struct zwp_primary_selection_device_v1 *primary_device; + struct zwp_primary_selection_source_v1 *primary_source; + struct wl_seat *seat; + struct wl_data_source *source; + struct offer *selection; + struct offer *pending_offers; + struct offer *drag_offer; + struct primary_offer *primary_selection; + struct primary_offer *primary_pending_offers; + struct yasl_loop *loop; + struct transfer *transfers; + char *text; + char *primary_text; + clipboard_receive_fn receive; + void *ud; + clipboard_drag_fn drag; + void *drag_ud; + clipboard_drop_fn drop; + void *drop_ud; + wl_fixed_t drag_x, drag_y; + struct wl_surface *drag_surface; +}; + +const char *clipboard_drag_mime(void) +{ + static char mime[64]; + if (!mime[0]) + snprintf(mime, sizeof(mime), "application/x-yasl-tab;pid=%ld", (long)getpid()); + return mime; +} + +static void drag_event(struct clipboard *c, enum yasl_drag_event ev, + wl_fixed_t x, wl_fixed_t y) +{ + if (c->drag) + c->drag(ev, c->drag_surface, wl_fixed_to_double(x), wl_fixed_to_double(y), + c->drag_ud); +} + +static bool offer_droppable(const struct offer *o) +{ + return o && !o->tab && (o->uri_list || o->mime); +} + +static void drop_event(struct clipboard *c, enum yasl_drop_event ev) +{ + if (c->drop && c->drag_surface) + c->drop(ev, c->drag_surface, wl_fixed_to_double(c->drag_x), + wl_fixed_to_double(c->drag_y), c->drop_ud); +} + +static void free_offer(struct offer *o); + +static void transfer_end(struct transfer *t, bool complete) +{ + struct transfer **p = &t->owner->transfers; + while (*p && *p != t) p = &(*p)->next; + if (*p) *p = t->next; + yasl_loop_del_fd(t->owner->loop, t->id); + close(t->fd); + if (t->drop) { + if (complete && wl_data_offer_get_version(t->drop->proxy) >= + WL_DATA_OFFER_FINISH_SINCE_VERSION) + wl_data_offer_finish(t->drop->proxy); + free_offer(t->drop); + wl_display_flush(t->owner->display); + } + free(t->text); + free(t); +} + +static void transfer_destroy(struct transfer *t) +{ + transfer_end(t, false); +} + +static int transfer_io(int fd, short events, void *ud) +{ + struct transfer *t = ud; + if (events & (POLLERR | POLLNVAL)) { transfer_destroy(t); return 0; } + if (t->sending) { + ssize_t n = write(fd, t->text + t->offset, t->len - t->offset); + if (n > 0) t->offset += (size_t)n; + if (t->offset == t->len || n == 0 || + (n < 0 && errno != EAGAIN && errno != EINTR)) transfer_destroy(t); + } else { + char buf[8192]; + ssize_t n = read(fd, buf, sizeof(buf)); + if (n > 0) { + size_t need = t->len + (size_t)n; + if (need > CLIPBOARD_TEXT_MAX) { transfer_destroy(t); return 0; } + if (need > t->capacity) { + size_t capacity = t->capacity ? t->capacity * 2 : sizeof(buf); + if (capacity > CLIPBOARD_TEXT_MAX) capacity = CLIPBOARD_TEXT_MAX; + char *text = realloc(t->text, capacity); + if (!text) { transfer_destroy(t); return 0; } + t->text = text; + t->capacity = capacity; + } + memcpy(t->text + t->len, buf, (size_t)n); + t->len += n; + } else if (n == 0) { + if (t->len) { + t->owner->receive(t->text, t->len, t->uri_list, + t->drop_surface, t->owner->ud); + } + transfer_end(t, true); + } else if (errno != EAGAIN && errno != EINTR) transfer_destroy(t); + } + return 0; +} + +static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool sending, + bool uri_list, const char *send_text) +{ + struct transfer *t = calloc(1, sizeof(*t)); + if (!t) { close(fd); return NULL; } + t->owner = c; t->fd = fd; t->sending = sending; t->uri_list = uri_list; + fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + if (sending) { + t->text = strdup(send_text ? send_text : ""); + if (!t->text) { close(fd); free(t); return NULL; } + t->len = strlen(t->text); + } + t->id = yasl_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t); + if (t->id < 0) { close(fd); free(t->text); free(t); return NULL; } + t->next = c->transfers; c->transfers = t; + return t; +} + +static struct transfer *start_transfer(struct clipboard *c, int fd, bool sending, bool uri_list) +{ + return start_transfer_text(c, fd, sending, uri_list, c->text); +} + +static const char *match_text_mime(const char *mime) +{ + if (!strcasecmp(mime, "text/plain;charset=utf-8")) return "text/plain;charset=utf-8"; + if (!strcasecmp(mime, "text/plain;charset=utf8")) return "text/plain;charset=utf8"; + if (!strcasecmp(mime, "text/plain")) return "text/plain"; + if (!strcasecmp(mime, "UTF8_STRING")) return "UTF8_STRING"; + if (!strcasecmp(mime, "STRING")) return "STRING"; + if (!strcasecmp(mime, "TEXT")) return "TEXT"; + return NULL; +} + +static void offer_keep_mime(char **slot, const char *mime) +{ + char *copy = strdup(mime); + if (!copy) return; + free(*slot); + *slot = copy; +} + +static void offer_mime(void *ud, struct wl_data_offer *proxy, const char *mime) +{ + (void)proxy; + struct offer *o = ud; + if (!strcmp(mime, clipboard_drag_mime())) o->tab = true; + if (!strcmp(mime, "text/uri-list")) o->uri_list = true; + const char *match = match_text_mime(mime); + if (match) { + if (!o->mime || !strcasecmp(match, "text/plain;charset=utf-8")) + offer_keep_mime(&o->mime, mime); + } +} +static void offer_source_actions(void *ud, struct wl_data_offer *proxy, uint32_t actions) +{ (void)ud; (void)proxy; (void)actions; } +static void offer_action(void *ud, struct wl_data_offer *proxy, uint32_t action) +{ (void)ud; (void)proxy; (void)action; } +static const struct wl_data_offer_listener offer_listener = { + .offer = offer_mime, + .source_actions = offer_source_actions, + .action = offer_action, +}; +static void free_offer(struct offer *o) +{ + if (o) { wl_data_offer_destroy(o->proxy); free(o->mime); free(o); } +} +static void take_pending_offer(struct clipboard *c, struct offer *o) +{ + if (!o) return; + struct offer **p = &c->pending_offers; + while (*p && *p != o) p = &(*p)->next; + if (*p) *p = o->next; + o->next = NULL; +} +static void clear_pending_offers(struct clipboard *c) +{ + while (c->pending_offers) { + struct offer *o = c->pending_offers; + c->pending_offers = o->next; + free_offer(o); + } +} +static void data_offer(void *ud, struct wl_data_device *device, struct wl_data_offer *proxy) +{ + (void)device; + struct clipboard *c = ud; + struct offer *o = calloc(1, sizeof(*o)); + if (!o) { wl_data_offer_destroy(proxy); return; } + o->proxy = proxy; + wl_data_offer_add_listener(proxy, &offer_listener, o); + o->next = c->pending_offers; + c->pending_offers = o; +} +static void selection(void *ud, struct wl_data_device *device, struct wl_data_offer *proxy) +{ + (void)device; + struct clipboard *c = ud; + struct offer *o = proxy ? wl_data_offer_get_user_data(proxy) : NULL; + take_pending_offer(c, o); + if (c->drag_offer == o) c->drag_offer = NULL; + if (c->selection != o) free_offer(c->selection); + c->selection = o; +} +static void drag_offer_enter(void *ud, struct wl_data_device *device, uint32_t serial, + struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *proxy) +{ + (void)device; + if (proxy) { + struct clipboard *c = ud; + struct offer *o = wl_data_offer_get_user_data(proxy); + take_pending_offer(c, o); + if (c->selection == o) c->selection = NULL; + if (c->drag_offer && c->drag_offer != o) free_offer(c->drag_offer); + c->drag_offer = o; + const char *mime = o && o->tab ? clipboard_drag_mime() + : o && o->uri_list ? "text/uri-list" + : o ? o->mime : NULL; + wl_data_offer_accept(proxy, serial, mime); + if (mime && wl_data_offer_get_version(proxy) >= 3) { + uint32_t action = o->tab ? WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE + : WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + wl_data_offer_set_actions(proxy, action, action); + } + c->drag_x = x; + c->drag_y = y; + c->drag_surface = surface; + if (o && o->tab) + drag_event(c, YASL_DRAG_OVER, x, y); + else if (offer_droppable(o)) + drop_event(c, YASL_DROP_OVER); + } +} +static void drag_offer_clear(void *ud, struct wl_data_device *device) +{ + (void)device; + struct clipboard *c = ud; + if (c->drag_offer && c->drag_offer->tab) + drag_event(c, YASL_DRAG_LEAVE, c->drag_x, c->drag_y); + else if (offer_droppable(c->drag_offer)) + drop_event(c, YASL_DROP_LEAVE); + free_offer(c->drag_offer); + c->drag_offer = NULL; + c->drag_surface = NULL; +} +static void drag_motion(void *ud, struct wl_data_device *device, uint32_t time, wl_fixed_t x, wl_fixed_t y) +{ + (void)device; (void)time; + struct clipboard *c = ud; + c->drag_x = x; + c->drag_y = y; + if (c->drag_offer && c->drag_offer->tab) + drag_event(c, YASL_DRAG_OVER, x, y); + else if (offer_droppable(c->drag_offer)) + drop_event(c, YASL_DROP_OVER); +} +static void drag_drop(void *ud, struct wl_data_device *device) +{ + (void)device; + struct clipboard *c = ud; + struct offer *o = c->drag_offer; + if (!o) return; + c->drag_offer = NULL; + bool v3 = wl_data_offer_get_version(o->proxy) >= 3; + if (o->tab) { + drag_event(c, YASL_DRAG_DROP, c->drag_x, c->drag_y); + if (v3) + wl_data_offer_finish(o->proxy); + } else if (offer_droppable(o)) { + drop_event(c, YASL_DROP_LEAVE); + int fds[2]; + if (pipe2(fds, O_CLOEXEC) == 0) { + wl_data_offer_receive(o->proxy, o->uri_list ? "text/uri-list" : o->mime, fds[1]); + close(fds[1]); + struct transfer *t = start_transfer(c, fds[0], false, o->uri_list); + if (t) { + t->drop = o; + t->drop_surface = c->drag_surface; + o = NULL; + } + wl_display_flush(c->display); + } + } + c->drag_surface = NULL; + free_offer(o); +} +static const struct wl_data_device_listener device_listener = { + .data_offer = data_offer, .selection = selection, .enter = drag_offer_enter, + .leave = drag_offer_clear, .motion = drag_motion, .drop = drag_drop +}; +static void source_target(void *ud, struct wl_data_source *s, const char *mime) { (void)ud; (void)s; (void)mime; } +static void source_send(void *ud, struct wl_data_source *s, const char *mime, int32_t fd) +{ (void)s; (void)mime; start_transfer(ud, fd, true, false); } +static void source_cancelled(void *ud, struct wl_data_source *s) +{ + struct clipboard *c = ud; + if (c->source == s) c->source = NULL; + wl_data_source_destroy(s); +} +static void source_dnd_drop_performed(void *ud, struct wl_data_source *s) { (void)ud; (void)s; } +static void source_dnd_finished(void *ud, struct wl_data_source *s) { (void)ud; (void)s; } +static void source_action(void *ud, struct wl_data_source *s, uint32_t action) { (void)ud; (void)s; (void)action; } +static const struct wl_data_source_listener source_listener = { + .target = source_target, .send = source_send, .cancelled = source_cancelled, + .dnd_drop_performed = source_dnd_drop_performed, + .dnd_finished = source_dnd_finished, .action = source_action, +}; + +static void free_primary_offer(struct primary_offer *o) +{ + if (o) { zwp_primary_selection_offer_v1_destroy(o->proxy); free(o->mime); free(o); } +} + +static void take_pending_primary_offer(struct clipboard *c, struct primary_offer *o) +{ + if (!o) return; + struct primary_offer **p = &c->primary_pending_offers; + while (*p && *p != o) p = &(*p)->next; + if (*p) *p = o->next; + o->next = NULL; +} + +static void clear_pending_primary_offers(struct clipboard *c) +{ + while (c->primary_pending_offers) { + struct primary_offer *o = c->primary_pending_offers; + c->primary_pending_offers = o->next; + free_primary_offer(o); + } +} + +static void primary_offer_mime(void *ud, struct zwp_primary_selection_offer_v1 *proxy, const char *mime) +{ + (void)proxy; + struct primary_offer *o = ud; + const char *match = match_text_mime(mime); + if (match) { + if (!o->mime || !strcasecmp(match, "text/plain;charset=utf-8")) + offer_keep_mime(&o->mime, mime); + } +} + +static const struct zwp_primary_selection_offer_v1_listener primary_offer_listener = { + .offer = primary_offer_mime, +}; + +static void primary_data_offer(void *ud, struct zwp_primary_selection_device_v1 *device, + struct zwp_primary_selection_offer_v1 *proxy) +{ + (void)device; + struct clipboard *c = ud; + struct primary_offer *o = calloc(1, sizeof(*o)); + if (!o) { zwp_primary_selection_offer_v1_destroy(proxy); return; } + o->proxy = proxy; + zwp_primary_selection_offer_v1_add_listener(proxy, &primary_offer_listener, o); + o->next = c->primary_pending_offers; + c->primary_pending_offers = o; +} + +static void primary_selection(void *ud, struct zwp_primary_selection_device_v1 *device, + struct zwp_primary_selection_offer_v1 *proxy) +{ + (void)device; + struct clipboard *c = ud; + struct primary_offer *o = proxy ? zwp_primary_selection_offer_v1_get_user_data(proxy) : NULL; + take_pending_primary_offer(c, o); + if (c->primary_selection != o) free_primary_offer(c->primary_selection); + c->primary_selection = o; +} + +static const struct zwp_primary_selection_device_v1_listener primary_device_listener = { + .data_offer = primary_data_offer, + .selection = primary_selection, +}; + +static void primary_source_send(void *ud, struct zwp_primary_selection_source_v1 *s, + const char *mime, int32_t fd) +{ + (void)s; (void)mime; + struct clipboard *c = ud; + start_transfer_text(c, fd, true, false, c->primary_text); +} + +static void primary_source_cancelled(void *ud, struct zwp_primary_selection_source_v1 *s) +{ + struct clipboard *c = ud; + if (c->primary_source == s) c->primary_source = NULL; + zwp_primary_selection_source_v1_destroy(s); +} + +static const struct zwp_primary_selection_source_v1_listener primary_source_listener = { + .send = primary_source_send, + .cancelled = primary_source_cancelled, +}; + +void clipboard_set_primary_manager(struct clipboard *c, + struct zwp_primary_selection_device_manager_v1 *mgr) +{ + if (!c) return; + c->primary_manager = mgr; + if (c->primary_device) { + zwp_primary_selection_device_v1_destroy(c->primary_device); + c->primary_device = NULL; + } + if (c->primary_manager && c->seat) { + c->primary_device = + zwp_primary_selection_device_manager_v1_get_device(c->primary_manager, c->seat); + if (c->primary_device) + zwp_primary_selection_device_v1_add_listener(c->primary_device, + &primary_device_listener, c); + } +} + +void clipboard_set_drag_handler(struct clipboard *c, clipboard_drag_fn fn, void *ud) +{ + if (!c) return; + c->drag = fn; + c->drag_ud = ud; +} + +void clipboard_set_drop_handler(struct clipboard *c, clipboard_drop_fn fn, void *ud) +{ + if (!c) return; + c->drop = fn; + c->drop_ud = ud; +} + +struct wl_data_device *clipboard_data_device(const struct clipboard *c) +{ + return c ? c->device : NULL; +} + +struct clipboard *clipboard_create(struct wl_display *display, struct wl_data_device_manager *manager, + struct wl_seat *seat, struct yasl_loop *loop, + clipboard_receive_fn receive, void *ud) +{ + if (!manager || !seat) return NULL; + struct clipboard *c = calloc(1, sizeof(*c)); + if (!c) return NULL; + c->display = display; c->manager = manager; c->loop = loop; c->receive = receive; c->ud = ud; + c->device = wl_data_device_manager_get_data_device(manager, seat); + if (!c->device) { free(c); return NULL; } + c->seat = seat; + wl_data_device_add_listener(c->device, &device_listener, c); + return c; +} + +bool clipboard_set_seat(struct clipboard *c, struct wl_seat *seat) +{ + if (!c || c->seat == seat) return false; + c->seat = seat; + drag_offer_clear(c, c->device); + if (c->device) { + wl_data_device_destroy(c->device); + c->device = NULL; + } + free_offer(c->selection); + c->selection = NULL; + clear_pending_offers(c); + if (c->source) { + wl_data_source_destroy(c->source); + c->source = NULL; + } + if (c->primary_device) { + zwp_primary_selection_device_v1_destroy(c->primary_device); + c->primary_device = NULL; + } + free_primary_offer(c->primary_selection); + c->primary_selection = NULL; + clear_pending_primary_offers(c); + if (c->primary_source) { + zwp_primary_selection_source_v1_destroy(c->primary_source); + c->primary_source = NULL; + } + if (!seat) return true; + if (c->manager) { + c->device = wl_data_device_manager_get_data_device(c->manager, seat); + if (c->device) + wl_data_device_add_listener(c->device, &device_listener, c); + } + if (c->primary_manager) { + c->primary_device = + zwp_primary_selection_device_manager_v1_get_device(c->primary_manager, seat); + if (c->primary_device) + zwp_primary_selection_device_v1_add_listener(c->primary_device, + &primary_device_listener, c); + } + return true; +} + +void clipboard_copy(struct clipboard *c, const char *text, uint32_t serial) +{ + if (!c || !c->device || !text || !serial) return; + char *copy = strdup(text); + if (!copy) return; + if (c->source) wl_data_source_destroy(c->source); + free(c->text); c->text = copy; + c->source = wl_data_device_manager_create_data_source(c->manager); + if (!c->source) return; + wl_data_source_add_listener(c->source, &source_listener, c); + wl_data_source_offer(c->source, "text/plain;charset=utf-8"); + wl_data_source_offer(c->source, "text/plain"); + wl_data_source_offer(c->source, "UTF8_STRING"); + wl_data_source_offer(c->source, "STRING"); + wl_data_source_offer(c->source, "TEXT"); + wl_data_device_set_selection(c->device, c->source, serial); +} + +void clipboard_paste(struct clipboard *c) +{ + if (!c || !c->device || !c->selection || !c->selection->mime) return; + int fds[2]; + if (pipe2(fds, O_CLOEXEC) < 0) return; + wl_data_offer_receive(c->selection->proxy, c->selection->mime, fds[1]); + close(fds[1]); + start_transfer(c, fds[0], false, false); + wl_display_flush(c->display); +} + +void clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial) +{ + if (!c || !text || !serial) return; + if (!c->primary_device || !c->primary_manager) { + clipboard_copy(c, text, serial); + return; + } + char *copy = strdup(text); + if (!copy) return; + if (c->primary_source) zwp_primary_selection_source_v1_destroy(c->primary_source); + free(c->primary_text); c->primary_text = copy; + c->primary_source = zwp_primary_selection_device_manager_v1_create_source(c->primary_manager); + if (!c->primary_source) return; + zwp_primary_selection_source_v1_add_listener(c->primary_source, &primary_source_listener, c); + zwp_primary_selection_source_v1_offer(c->primary_source, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(c->primary_source, "text/plain"); + zwp_primary_selection_source_v1_offer(c->primary_source, "UTF8_STRING"); + zwp_primary_selection_source_v1_offer(c->primary_source, "STRING"); + zwp_primary_selection_source_v1_offer(c->primary_source, "TEXT"); + zwp_primary_selection_device_v1_set_selection(c->primary_device, c->primary_source, serial); +} + +void clipboard_paste_primary(struct clipboard *c) +{ + if (!c) return; + if (c->primary_device && c->primary_selection && c->primary_selection->mime) { + int fds[2]; + if (pipe2(fds, O_CLOEXEC) < 0) return; + zwp_primary_selection_offer_v1_receive(c->primary_selection->proxy, + c->primary_selection->mime, fds[1]); + close(fds[1]); + start_transfer(c, fds[0], false, false); + wl_display_flush(c->display); + return; + } + clipboard_paste(c); +} + +void clipboard_destroy(struct clipboard *c) +{ + if (!c) return; + while (c->transfers) + transfer_destroy(c->transfers); + free_offer(c->selection); + clear_pending_offers(c); + free_offer(c->drag_offer); + free_primary_offer(c->primary_selection); + clear_pending_primary_offers(c); + if (c->primary_source) zwp_primary_selection_source_v1_destroy(c->primary_source); + if (c->primary_device) zwp_primary_selection_device_v1_destroy(c->primary_device); + free(c->primary_text); + if (c->source) wl_data_source_destroy(c->source); + if (c->device) wl_data_device_destroy(c->device); + free(c->text); free(c); +} diff --git a/src/wayland/clipboard.h b/src/wayland/clipboard.h new file mode 100644 index 0000000..6ea75c6 --- /dev/null +++ b/src/wayland/clipboard.h @@ -0,0 +1,41 @@ +#ifndef YASL_WAYLAND_CLIPBOARD_H +#define YASL_WAYLAND_CLIPBOARD_H + +#include +#include +#include +#include "yasl/yasl.h" + +struct wl_display; +struct wl_data_device_manager; +struct wl_seat; +struct wl_surface; +struct wl_data_device; +struct clipboard; +struct zwp_primary_selection_device_manager_v1; + +typedef void (*clipboard_receive_fn)(const char *, size_t, bool uri_list, + struct wl_surface *on, void *); + +struct clipboard *clipboard_create(struct wl_display *, struct wl_data_device_manager *, + struct wl_seat *, struct yasl_loop *, + clipboard_receive_fn, void *); +void clipboard_destroy(struct clipboard *); +bool clipboard_set_seat(struct clipboard *, struct wl_seat *); +void clipboard_set_primary_manager(struct clipboard *, struct zwp_primary_selection_device_manager_v1 *); +void clipboard_copy(struct clipboard *, const char *, uint32_t); +void clipboard_paste(struct clipboard *); +void clipboard_copy_primary(struct clipboard *, const char *, uint32_t); +void clipboard_paste_primary(struct clipboard *); + +typedef void (*clipboard_drag_fn)(enum yasl_drag_event, struct wl_surface *on, + double x, double y, void *); +void clipboard_set_drag_handler(struct clipboard *, clipboard_drag_fn, void *); + +typedef void (*clipboard_drop_fn)(enum yasl_drop_event, struct wl_surface *on, + double x, double y, void *); +void clipboard_set_drop_handler(struct clipboard *, clipboard_drop_fn, void *); +const char *clipboard_drag_mime(void); +struct wl_data_device *clipboard_data_device(const struct clipboard *); + +#endif diff --git a/src/wayland/drag.c b/src/wayland/drag.c new file mode 100644 index 0000000..107ec52 --- /dev/null +++ b/src/wayland/drag.c @@ -0,0 +1,241 @@ +#include "internal.h" + +static void icon_clear(struct drag_icon *icon) +{ + if (icon->viewport) wp_viewport_destroy(icon->viewport); + if (icon->surface) wl_surface_destroy(icon->surface); + if (icon->buffer) wl_buffer_destroy(icon->buffer); + if (icon->pool) wl_shm_pool_destroy(icon->pool); + if (icon->mapping) munmap(icon->mapping, icon->size); + if (icon->pool) close(icon->fd); + *icon = (struct drag_icon){0}; +} + +static bool icon_create(struct yasl_display *c, const struct yasl_drag_image *image) +{ + struct drag_icon *icon = &c->drag.icon; + size_t bytes; + if (!image->pixels || !buffer_size(image->size.x, image->size.y, &bytes)) + return false; + int fd = memfd_create("yasl_drag_icon", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd < 0) + return false; + void *mapping = MAP_FAILED; + if (ftruncate(fd, (off_t)bytes) == 0 && + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK) == 0) + mapping = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) { + close(fd); + return false; + } + memcpy(mapping, image->pixels, bytes); + icon->mapping = mapping; + icon->size = bytes; + icon->pool = wl_shm_create_pool(c->shm, fd, (int32_t)bytes); + if (!icon->pool) { + close(fd); + icon_clear(icon); + return false; + } + icon->fd = fd; + icon->buffer = wl_shm_pool_create_buffer(icon->pool, 0, image->size.x, + image->size.y, image->size.x * 4, WL_SHM_FORMAT_ARGB8888); + icon->surface = wl_compositor_create_surface(c->compositor); + if (!icon->buffer || !icon->surface) { + icon_clear(icon); + return false; + } + return true; +} + +static void icon_show(struct yasl_display *c, const struct yasl_drag_image *image) +{ + struct drag_icon *icon = &c->drag.icon; + uint32_t scale = c->drag.scale_120; + if (c->viewporter) { + icon->viewport = wp_viewporter_get_viewport(c->viewporter, icon->surface); + if (icon->viewport) + wp_viewport_set_destination(icon->viewport, + yasl_scale_to_logical(image->size.x, scale), + yasl_scale_to_logical(image->size.y, scale)); + } else if (scale % YASL_SCALE_UNIT == 0 && + wl_proxy_get_version((struct wl_proxy *)icon->surface) >= + WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) { + wl_surface_set_buffer_scale(icon->surface, (int32_t)(scale / YASL_SCALE_UNIT)); + } + if (wl_proxy_get_version((struct wl_proxy *)icon->surface) >= + WL_SURFACE_OFFSET_SINCE_VERSION) + wl_surface_offset(icon->surface, + -yasl_scale_to_logical(image->hotspot.x, scale), + -yasl_scale_to_logical(image->hotspot.y, scale)); + wl_surface_attach(icon->surface, icon->buffer, 0, 0); + wl_surface_damage_buffer(icon->surface, 0, 0, image->size.x, image->size.y); + wl_surface_commit(icon->surface); +} + +static void drag_clear(struct yasl_display *c, bool ended) +{ + struct conn_drag *d = &c->drag; + if (d->toplevel) { + if (ended) + xdg_toplevel_drag_v1_destroy(d->toplevel); + else + wl_proxy_destroy((struct wl_proxy *)d->toplevel); + } + if (d->source) + wl_data_source_destroy(d->source); + icon_clear(&d->icon); + *d = (struct conn_drag){0}; +} + +static void drag_finish(struct yasl_display *c, enum yasl_drag_end how, bool ended) +{ + const struct yasl_drag_listener *l = c->drag.listener; + void *ud = c->drag.ud; + drag_clear(c, ended); + if (l && l->end) + l->end(ud, how); +} + +void conn_drag_end(struct yasl_display *c) +{ + if (c && c->drag.source) + drag_finish(c, YASL_DRAG_CANCELLED, false); +} + +static void source_target(void *ud, struct wl_data_source *s, const char *mime) { (void)ud; (void)s; (void)mime; } +static void source_send(void *ud, struct wl_data_source *s, const char *mime, int32_t fd) { (void)ud; (void)s; (void)mime; close(fd); } +static void source_action(void *ud, struct wl_data_source *s, uint32_t action) { (void)ud; (void)s; (void)action; } + +static void source_cancelled(void *ud, struct wl_data_source *s) +{ + (void)s; + struct yasl_display *c = ud; + bool released = c->drag.dropped || !c->drag.carrying; + drag_finish(c, released ? YASL_DRAG_DROPPED : YASL_DRAG_CANCELLED, true); +} + +static void source_dropped(void *ud, struct wl_data_source *s) +{ + (void)s; + ((struct yasl_display *)ud)->drag.dropped = true; +} + +static void source_finished(void *ud, struct wl_data_source *s) +{ + (void)s; + drag_finish(ud, YASL_DRAG_DROPPED, true); +} + +static const struct wl_data_source_listener source_listener = { + .target = source_target, + .send = source_send, + .cancelled = source_cancelled, + .dnd_drop_performed = source_dropped, + .dnd_finished = source_finished, + .action = source_action, +}; + +static struct seat *drag_seat(struct yasl_display *c, struct yasl_surface *origin) +{ + struct yasl_surface *root = surface_root(origin); + struct seat *active = conn_active_seat(c); + if (active && active->press_serial && + surface_root(active->press_surface) == root) + return active; + for (struct seat *s = c->seats; s; s = s->next) + if (s->press_serial && surface_root(s->press_surface) == root) + return s; + return NULL; +} + +bool yasl_display_drag_start(struct yasl_display *c, struct yasl_surface *origin, + const struct yasl_drag_image *image, + const struct yasl_drag_listener *l, void *ud) +{ + if (!c || !origin || origin->conn != c || !l || c->drag.source) + return false; + struct seat *seat = drag_seat(c, origin); + if (!seat) + return false; + struct wl_data_device *device = clipboard_data_device(seat->clipboard); + if (!device || wl_data_device_get_version(device) < 3) + return false; + c->drag.scale_120 = origin->scale_120; + if (image && !icon_create(c, image)) + return false; + struct wl_data_source *s = wl_data_device_manager_create_data_source(c->data_manager); + if (!s) { + icon_clear(&c->drag.icon); + return false; + } + c->drag.source = s; + c->drag.seat = seat; + c->drag.listener = l; + c->drag.ud = ud; + wl_data_source_add_listener(s, &source_listener, c); + wl_data_source_offer(s, clipboard_drag_mime()); + wl_data_source_set_actions(s, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + if (c->toplevel_drag_mgr) + c->drag.toplevel = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag( + c->toplevel_drag_mgr, s); + wl_data_device_start_drag(device, s, seat->press_surface->surface, + c->drag.icon.surface, seat->press_serial); + if (image) + icon_show(c, image); + wl_display_flush(c->wl); + return true; +} + +void yasl_display_drag_cancel(struct yasl_display *c) +{ + if (c && c->drag.source) + drag_clear(c, false); +} + +bool yasl_surface_drag_carry(struct yasl_surface *w, struct yasl_vector2i offset) +{ + struct yasl_display *c = w ? w->conn : NULL; + if (!c || !c->drag.source || !c->drag.toplevel || !w->toplevel) + return false; + uint32_t scale = c->drag.scale_120; + xdg_toplevel_drag_v1_attach(c->drag.toplevel, w->toplevel, + yasl_scale_to_logical(offset.x, scale), + yasl_scale_to_logical(offset.y, scale)); + c->drag.carrying = true; + return true; +} + +bool yasl_surface_place_under_pointer(struct yasl_surface *w, struct yasl_vector2i at) +{ + (void)w; + (void)at; + return false; +} + +static struct yasl_vector2i drag_device_pos(const struct yasl_surface *w, double x, double y) +{ + double dx = x * w->scale_factor, dy = y * w->scale_factor; + return (struct yasl_vector2i){ + .x = (int)(dx < 0 ? dx - 0.5 : dx + 0.5), + .y = (int)(dy < 0 ? dy - 0.5 : dy + 0.5), + }; +} + +void conn_drop_target(struct yasl_display *c, enum yasl_drop_event ev, + struct wl_surface *on, double x, double y) +{ + struct yasl_surface *w = conn_surface_for(c, on); + if (!w || w->parent || !w->cbs->drop) + return; + w->cbs->drop(w, ev, drag_device_pos(w, x, y), w->ud); +} + +void conn_drag_target(struct yasl_display *c, enum yasl_drag_event ev, + struct wl_surface *on, double x, double y) +{ + struct yasl_surface *w = conn_surface_for(c, on); + if (!w || w->parent || !w->cbs->drag) + return; + w->cbs->drag(w, ev, drag_device_pos(w, x, y), w->ud); +} diff --git a/src/wayland/ime.c b/src/wayland/ime.c new file mode 100644 index 0000000..9da019c --- /dev/null +++ b/src/wayland/ime.c @@ -0,0 +1,174 @@ +#include "internal.h" + +#define IME_TEXT_MAX (256u * 1024) + +static void show_preedit(struct yasl_surface *w, char *text, int begin, int end) +{ + bool changed = (text || w->ime_shown) && + (!text || !w->ime_shown || strcmp(text, w->ime_shown) || + begin != w->ime_shown_begin || end != w->ime_shown_end); + free(w->ime_shown); + w->ime_shown = text; + w->ime_shown_begin = begin; + w->ime_shown_end = end; + if (changed) + yasl_surface_schedule_redraw(w); +} + +void ime_reset(struct yasl_surface *w) +{ + free(w->ime_preedit); + w->ime_preedit = NULL; + free(w->ime_commit); + w->ime_commit = NULL; + show_preedit(w, NULL, -1, -1); +} + +void ime_send_caret(struct yasl_surface *w) +{ + struct seat *seat = w->ime_seat; + if (!seat || !seat->text_input) + return; + uint32_t scale = w->scale_120 ? w->scale_120 : YASL_SCALE_UNIT; + zwp_text_input_v3_set_cursor_rectangle(seat->text_input, + yasl_scale_to_logical(w->ime_caret.x, scale), + yasl_scale_to_logical(w->ime_caret.y, scale), + yasl_scale_to_logical(w->ime_caret.width, scale), + yasl_scale_to_logical(w->ime_caret.height, scale)); + zwp_text_input_v3_commit(seat->text_input); +} + +const char *yasl_surface_ime_preedit(const struct yasl_surface *w) +{ + return w ? w->ime_shown : NULL; +} + +bool yasl_surface_ime_preedit_cursor(const struct yasl_surface *w, int *begin, int *end) +{ + if (!w || !w->ime_shown || w->ime_shown_begin < 0) + return false; + *begin = w->ime_shown_begin; + *end = w->ime_shown_end; + return true; +} + +void yasl_surface_set_ime_caret(struct yasl_surface *w, struct yasl_rect2i caret) +{ + if (!w || (w->ime_caret.x == caret.x && w->ime_caret.y == caret.y && + w->ime_caret.width == caret.width && w->ime_caret.height == caret.height)) + return; + w->ime_caret = caret; + ime_send_caret(w); +} + +static void text_input_enter(void *data, struct zwp_text_input_v3 *text_input, + struct wl_surface *surface) +{ + struct seat *s = data; + struct yasl_surface *w = surface_root(conn_surface_for(s->conn, surface)); + s->ime_focus = w; + if (!w) return; + zwp_text_input_v3_enable(text_input); + zwp_text_input_v3_set_content_type(text_input, + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL); + w->ime_seat = s; + ime_send_caret(w); +} + +static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input, + struct wl_surface *surface) +{ + (void)surface; + struct seat *s = data; + struct yasl_surface *w = s->ime_focus; + s->ime_focus = NULL; + if (!w) return; + zwp_text_input_v3_disable(text_input); + zwp_text_input_v3_commit(text_input); + if (w->ime_seat == s) + w->ime_seat = NULL; + ime_reset(w); +} + +static void text_input_preedit_string(void *data, + struct zwp_text_input_v3 *text_input, const char *text, + int32_t cursor_begin, int32_t cursor_end) +{ + (void)text_input; + struct yasl_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + free(w->ime_preedit); + w->ime_preedit = text ? strndup(text, IME_TEXT_MAX) : NULL; + int len = w->ime_preedit ? (int)strlen(w->ime_preedit) : 0; + bool shown = cursor_begin >= 0 && cursor_end >= cursor_begin && + cursor_end <= len; + w->ime_cursor_begin = shown ? cursor_begin : -1; + w->ime_cursor_end = shown ? cursor_end : -1; +} + +static void text_input_commit_string(void *data, + struct zwp_text_input_v3 *text_input, const char *text) +{ + (void)text_input; + struct yasl_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + free(w->ime_commit); + w->ime_commit = (text && text[0]) ? strndup(text, IME_TEXT_MAX) : NULL; +} + +static void text_input_delete_surrounding_text(void *data, + struct zwp_text_input_v3 *text_input, uint32_t before_length, + uint32_t after_length) +{ + (void)data; (void)text_input; (void)before_length; (void)after_length; +} + +static void text_input_done(void *data, struct zwp_text_input_v3 *text_input, + uint32_t serial) +{ + (void)text_input; (void)serial; + struct yasl_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + if (w->ime_commit) { + struct yasl_input_event ev = { + .kind = YASL_INPUT_TEXT, + .surface = w, + .text = { .text = w->ime_commit, .len = strlen(w->ime_commit) }, + }; + input_queue_push(&w->input, &ev); + free(w->ime_commit); + w->ime_commit = NULL; + } + char *preedit = w->ime_preedit && w->ime_preedit[0] ? w->ime_preedit : NULL; + if (!preedit) + free(w->ime_preedit); + w->ime_preedit = NULL; + show_preedit(w, preedit, preedit ? w->ime_cursor_begin : -1, + preedit ? w->ime_cursor_end : -1); + w->ime_cursor_begin = w->ime_cursor_end = -1; +} + +static void text_input_action(void *data, struct zwp_text_input_v3 *text_input, + uint32_t action, uint32_t serial) +{ (void)data; (void)text_input; (void)action; (void)serial; } + +static void text_input_language(void *data, struct zwp_text_input_v3 *text_input, + const char *language) +{ (void)data; (void)text_input; (void)language; } + +static void text_input_preedit_hint(void *data, struct zwp_text_input_v3 *text_input, + uint32_t start, uint32_t end, uint32_t hint) +{ (void)data; (void)text_input; (void)start; (void)end; (void)hint; } + +const struct zwp_text_input_v3_listener text_input_listener = { + .action = text_input_action, + .language = text_input_language, + .preedit_hint = text_input_preedit_hint, + .enter = text_input_enter, + .leave = text_input_leave, + .preedit_string = text_input_preedit_string, + .commit_string = text_input_commit_string, + .delete_surrounding_text = text_input_delete_surrounding_text, + .done = text_input_done, +}; diff --git a/src/wayland/internal.h b/src/wayland/internal.h new file mode 100644 index 0000000..dc85943 --- /dev/null +++ b/src/wayland/internal.h @@ -0,0 +1,418 @@ +#ifndef YASL_WAYLAND_INTERNAL_H +#define YASL_WAYLAND_INTERNAL_H + +#define _GNU_SOURCE + +#include "yasl/yasl.h" +#include "yasl/timing.h" +#include "clipboard.h" + +#include +#include +#include "protocols/xdg-shell-client-protocol.h" +#include "protocols/xdg-decoration-client-protocol.h" +#include "protocols/cursor-shape-v1-client-protocol.h" +#include "protocols/fractional-scale-v1-client-protocol.h" +#include "protocols/viewporter-client-protocol.h" +#include "protocols/tablet-v2-client-protocol.h" +#include "protocols/text-input-unstable-v3-client-protocol.h" +#include "protocols/tearing-control-v1-client-protocol.h" +#include "protocols/presentation-time-client-protocol.h" +#include "protocols/fifo-v1-client-protocol.h" +#include "protocols/commit-timing-v1-client-protocol.h" +#include "protocols/xdg-toplevel-drag-v1-client-protocol.h" +#include "protocols/primary-selection-unstable-v1-client-protocol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 3 + +struct yasl_surface; +struct tablet_tool; +struct tablet_device; +struct tablet_pad; + +struct buffer { + struct yasl_surface *owner; + struct wl_shm_pool *pool; + struct wl_buffer *proxy; + uint32_t *pixels; + size_t capacity; + int width, height; + bool busy; + bool presented; +}; + +struct wl_conn_output { + struct yasl_display *conn; + struct wl_output *proxy; + struct wl_conn_output *next; + uint64_t mask; + uint32_t name; + int32_t scale, pending_scale; + uint32_t refresh_ns, pending_refresh_ns; +}; + +struct pending_press { + struct yasl_surface *surface; + struct yasl_vector2i pos; + int button; + bool release; +}; + +struct press_queue { + struct pending_press ev[8]; + int n; +}; + +struct drag_icon { + struct wl_surface *surface; + struct wl_buffer *buffer; + struct wl_shm_pool *pool; + struct wp_viewport *viewport; + void *mapping; + size_t size; + int fd; +}; + +struct conn_drag { + struct wl_data_source *source; + struct xdg_toplevel_drag_v1 *toplevel; + struct drag_icon icon; + const struct yasl_drag_listener *listener; + void *ud; + uint32_t scale_120; + struct seat *seat; + bool dropped; + bool carrying; +}; + +#define SEAT_TOUCH_POINTS 10 + +struct touch_point { + struct yasl_surface *surface; + int32_t id; + double x, y; + bool active; + bool down, moved, up; +}; + +struct seat { + struct yasl_display *conn; + struct seat *next; + struct wl_seat *proxy; + uint32_t name; + struct wl_keyboard *keyboard; + struct wl_pointer *pointer; + struct wl_touch *touch; + struct wp_cursor_shape_device_v1 *cursor_shape_dev; + struct wl_surface *cursor_surface; + struct wp_viewport *cursor_viewport; + struct zwp_tablet_seat_v2 *tablet_seat; + struct tablet_tool *tablet_tools; + struct tablet_device *tablet_devices; + struct tablet_pad *tablet_pads; + struct zwp_text_input_v3 *text_input; + struct clipboard *clipboard; + + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + xkb_mod_mask_t input_mod_masks[8]; + xkb_mod_index_t mod_shift, mod_alt, mod_ctrl, mod_super; + bool input_mods_ready; + uint64_t repeat_started_ns; + int repeat_fd, repeat_watch; + int32_t repeat_rate, repeat_delay; + uint32_t repeat_key; + bool repeat_held; + + struct yasl_surface *pointer_focus; + struct yasl_surface *keyboard_focus; + struct yasl_surface *tablet_focus; + struct yasl_surface *ime_focus; + struct yasl_surface *focus_leaving; + uint32_t input_serial; + uint32_t press_serial; + struct yasl_surface *press_surface; + + uint32_t pointer_serial; + int cursor_shape; + struct yasl_vector2i pointer_pos; + uint64_t pointer_buttons; + double axis_v, axis_h, frame_v; + int frame_v120; + int axis_discrete_v, axis_discrete_h; + int axis_value120_v, axis_value120_h; + bool axis_has_v120_v, axis_has_v120_h; + bool axis_smooth; + bool motion_pending; + struct press_queue ptr_presses; + struct yasl_surface *ptr_left; + struct yasl_vector2i ptr_left_pos; + bool ptr_left_motion; + + struct tablet_tool *tool; + struct press_queue tool_presses; + struct yasl_vector2i tool_pos; + uint64_t tool_buttons; + struct yasl_pointer_pen pen; + int tool_wheel; + bool tool_motion; + + struct touch_point touch_points[SEAT_TOUCH_POINTS]; + struct touch_point *touch_primary; + bool touch_pressed; + bool touch_scrolling; + double touch_scroll_y, touch_scroll_rest; +}; + +#define YASL_QUEUE_CAP 256 +struct input_queue { + struct yasl_input_event events[YASL_QUEUE_CAP]; + int head; + int tail; + int count; +}; + +static inline void input_queue_push(struct input_queue *q, const struct yasl_input_event *ev) +{ + if (q->count >= YASL_QUEUE_CAP) return; + q->events[q->tail] = *ev; + q->tail = (q->tail + 1) % YASL_QUEUE_CAP; + q->count++; +} + +static inline bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev) +{ + if (q->count <= 0) return false; + *ev = q->events[q->head]; + q->head = (q->head + 1) % YASL_QUEUE_CAP; + q->count--; + return true; +} + +static inline void input_queue_clear(struct input_queue *q) +{ + q->head = q->tail = q->count = 0; +} + +struct yasl_display { + struct wl_display *wl; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shm *shm; + struct wl_conn_output *outputs; + uint64_t output_masks; + struct xdg_wm_base *wm_base; + struct zxdg_decoration_manager_v1 *decor_mgr; + struct wp_fractional_scale_manager_v1 *scale_mgr; + struct wp_viewporter *viewporter; + struct seat *seats; + struct seat *active_seat; + struct wl_data_device_manager *data_manager; + struct zwp_primary_selection_device_manager_v1 *primary_selection_mgr; + struct wp_cursor_shape_manager_v1 *cursor_shape_mgr; + struct wl_cursor_theme *cursor_theme; + const char *cursor_theme_name; + int cursor_size, cursor_theme_scale; + struct zwp_tablet_manager_v2 *tablet_mgr; + struct zwp_text_input_manager_v3 *text_input_mgr; + struct wp_tearing_control_manager_v1 *tearing_mgr; + struct wp_presentation *presentation; + struct wp_fifo_manager_v1 *fifo_mgr; + struct wp_commit_timing_manager_v1 *commit_timing_mgr; + struct xkb_context *xkb_ctx; + struct yasl_loop *loop; + const struct yasl_display_cbs *cbs; + void *ud; + char *app_id; + clockid_t pres_clock; + bool pres_clock_known; + struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr; + struct conn_drag drag; + struct yasl_surface *surfaces; + struct yasl_surface *paste_target; + int watch; + int depth; + struct yasl_surface *dead; + bool reading; + bool lost; +}; + +struct yasl_surface { + struct yasl_display *conn; + struct yasl_surface *conn_next; + struct yasl_surface *dead_next; + struct yasl_surface *parent; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *toplevel; + struct xdg_popup *popup; + struct zxdg_toplevel_decoration_v1 *toplevel_decor; + bool server_decorated; + struct wp_fractional_scale_v1 *frac_scale; + struct wp_viewport *viewport; + + char *ime_preedit; + char *ime_commit; + char *ime_shown; + int ime_cursor_begin, ime_cursor_end; + int ime_shown_begin, ime_shown_end; + struct yasl_rect2i ime_caret; + struct seat *ime_seat; + struct wp_tearing_control_v1 *tearing_control; + struct latency_feedback *latency_feedbacks; + struct wp_fifo_v1 *fifo; + struct wp_commit_timer_v1 *commit_timer; + struct wl_callback *frame_cb; + const struct yasl_surface_cbs *cbs; + void *ud; + uint64_t frames_skipped; + + struct yasl_frame_clock clock; + struct input_queue input; + + struct buffer buffers[NBUF]; + struct yasl_frame frame; + struct yasl_damage_list damage; + bool frame_active; + bool frame_presented; + + int floating_width, floating_height; + struct yasl_rect2i content; + int cur; + int width, height; + int logical_width, logical_height; + int req_width, req_height; + int bound_width, bound_height; + uint32_t scale_120; + uint32_t pending_scale_120; + uint32_t pending_serial; + double scale_factor; + uint64_t outputs; + + bool tiled; + bool size_pending; + bool sample_refresh; + bool has_pending_serial; + bool configured; + bool closed; + bool destroyed; + bool opaque; + bool fullscreen; + bool maximized; + bool activated; + bool suspended; + bool want_draw; +}; + +char *yasl_utf8_sanitize_dup(const char *str); +bool yasl_utf8_validate(const char *str, size_t len); + +int device_px(int logical, uint32_t scale_120); +bool buffer_size(int width, int height, size_t *bytes); +int buffer_reserve(struct yasl_surface *w, struct buffer *b, size_t needed); +void buffer_destroy(struct buffer *b); +int buffer_pick_free_index(const struct buffer *bufs, int cur); +int buffer_prepare(struct yasl_surface *w, struct buffer *b, int width, int height, + const struct wl_buffer_listener *listener); +int apply_pending_geometry(struct yasl_surface *w); +int logical_px_ceil(int device, uint32_t scale_120); + +static inline void wl_damage_list(struct wl_surface *s, const struct yasl_damage_list *d) +{ + if (d->n < 0) { + wl_surface_damage_buffer(s, d->bounds.x, d->bounds.y, + d->bounds.width, d->bounds.height); + return; + } + for (int i = 0; i < d->n; i++) + wl_surface_damage_buffer(s, d->rects[i].x, d->rects[i].y, + d->rects[i].width, d->rects[i].height); +} + +void surface_update_opaque_region(struct yasl_surface *w); +int surface_init_scaling(struct yasl_surface *w); + +static inline bool surface_gets_preferred_scale(struct wl_surface *s) +{ + return wl_proxy_get_version((struct wl_proxy *)s) >= + WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION; +} + +uint64_t conn_output_mask(const struct yasl_display *c, const struct wl_output *proxy); +uint32_t conn_output_scale_120(const struct yasl_display *c, uint64_t outputs); +void conn_destroy_outputs(struct yasl_display *c); +void surface_follow_outputs(struct yasl_surface *w); +uint64_t conn_pres_to_mono(const struct yasl_display *c, uint64_t ns); +uint64_t conn_mono_to_pres(const struct yasl_display *c, uint64_t ns); +void surface_draw_frame(struct yasl_surface *w); +void surface_fail(struct yasl_surface *w); +void display_enter(struct yasl_display *c); +void display_leave(struct yasl_display *c); + +struct yasl_surface *conn_surface_for(struct yasl_display *c, struct wl_surface *s); + +static inline struct yasl_surface *surface_root(struct yasl_surface *w) +{ + while (w && w->parent) + w = w->parent; + return w; +} + +void conn_drag_end(struct yasl_display *c); +void conn_drop_target(struct yasl_display *c, enum yasl_drop_event ev, + struct wl_surface *on, double x, double y); +void conn_drag_target(struct yasl_display *c, enum yasl_drag_event ev, + struct wl_surface *on, double x, double y); + +void seat_bind(struct yasl_display *c, struct wl_registry *registry, + uint32_t name, uint32_t version); +bool seat_remove(struct yasl_display *c, uint32_t name); +void seat_destroy(struct seat *s); +struct seat *conn_active_seat(const struct yasl_display *c); +void seat_note_input(struct seat *s, uint32_t serial); +void seat_forget_surface(struct seat *s, struct yasl_surface *w); +void seat_clipboard_ensure(struct seat *s); +int display_input_init(struct yasl_display *c); +extern const struct wl_seat_listener seat_listener; + +void keyboard_repeat_stop(struct seat *s); +void keyboard_repeat_sync(struct seat *s); +int keyboard_repeat_init(struct seat *s); +void keyboard_settle_focus(struct yasl_display *c); +bool conn_keyboard_on(const struct yasl_display *c, const struct yasl_surface *w, + const struct seat *except); +extern const struct wl_keyboard_listener keyboard_listener; +int seat_modifiers(const struct seat *s); + +void surface_init_cursor(struct yasl_display *c); +void seat_destroy_tablet(struct seat *s); +void seat_pointer_reset(struct seat *s); + +extern const struct zwp_text_input_v3_listener text_input_listener; +void ime_reset(struct yasl_surface *w); +void ime_send_caret(struct yasl_surface *w); + +int surface_init_shell(struct yasl_surface *w, const char *title); +extern const struct xdg_surface_listener shell_surface_listener; +extern const struct wl_registry_listener registry_listener; + +void surface_feedback_destroy(struct yasl_surface *w); +void surface_request_presentation_feedback(struct yasl_surface *w); + +#endif diff --git a/src/wayland/keyboard.c b/src/wayland/keyboard.c new file mode 100644 index 0000000..7283d58 --- /dev/null +++ b/src/wayland/keyboard.c @@ -0,0 +1,389 @@ +#include "internal.h" + +#define XKB_EVDEV_OFFSET 8 +#define KEYMAP_MAX_BYTES (8u * 1024 * 1024) + +void keyboard_repeat_stop(struct seat *s) +{ + if (!s->repeat_held) return; + s->repeat_held = false; + if (s->repeat_fd >= 0) { + struct itimerspec off = {0}; + timerfd_settime(s->repeat_fd, 0, &off, NULL); + } +} + +void keyboard_repeat_sync(struct seat *s) +{ + if (s->repeat_fd < 0) return; + struct itimerspec timer = {0}; + if (s->repeat_held && s->repeat_rate > 0) { + uint64_t interval = 1000000000ull / (uint32_t)s->repeat_rate; + if (!interval) interval = 1; + uint64_t delay_ns = (uint64_t)s->repeat_delay * 1000000ull; + if (!delay_ns) delay_ns = 1; + timer.it_value = (struct timespec){ (time_t)(delay_ns / 1000000000ull), (long)(delay_ns % 1000000000ull) }; + timer.it_interval = (struct timespec){ (time_t)(interval / 1000000000ull), (long)(interval % 1000000000ull) }; + } + timerfd_settime(s->repeat_fd, 0, &timer, NULL); +} + +static const char *const input_mod_names[8] = { + XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_ALT, + XKB_MOD_NAME_CTRL, XKB_MOD_NAME_LOGO, + "Hyper", "Meta", + XKB_MOD_NAME_CAPS, XKB_MOD_NAME_NUM +}; + +static bool mod_active(const struct seat *s, const char *name) +{ + return xkb_state_mod_name_is_active(s->xkb_state, name, XKB_STATE_MODS_EFFECTIVE) > 0; +} + +static void resolve_input_mod_masks(struct seat *s) +{ + memset(s->input_mod_masks, 0, sizeof(s->input_mod_masks)); + if (!s->xkb_keymap) return; + struct xkb_state *probe = xkb_state_new(s->xkb_keymap); + if (!probe) return; + for (unsigned real = 0; real < 8; real++) { + xkb_state_update_mask(probe, 1u << real, 0, 0, 0, 0, 0); + for (unsigned i = 0; i < 8; i++) { + if (xkb_state_mod_name_is_active(probe, input_mod_names[i], + XKB_STATE_MODS_EFFECTIVE) > 0) + s->input_mod_masks[i] |= 1u << real; + } + } + xkb_state_unref(probe); + s->input_mods_ready = true; +} + +static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, + uint32_t format, int32_t fd, uint32_t size) +{ + (void)keyboard; + struct seat *s = data; + keyboard_repeat_stop(s); + s->input_mods_ready = false; + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + struct stat st; + if (size == 0 || size > KEYMAP_MAX_BYTES || + fstat(fd, &st) < 0 || st.st_size < 0 || (uint64_t)st.st_size < size) { + close(fd); + return; + } + char *map_str = malloc(size); + if (!map_str) { + close(fd); + return; + } + size_t off = 0; + while (off < size) { + ssize_t n = pread(fd, map_str + off, size - off, (off_t)off); + if (n > 0) off += (size_t)n; + else if (n == 0 || errno != EINTR) break; + } + close(fd); + if (off < size) { + free(map_str); + return; + } + + if (s->xkb_keymap) + xkb_keymap_unref(s->xkb_keymap); + if (s->xkb_state) + xkb_state_unref(s->xkb_state); + s->xkb_state = NULL; + + s->xkb_keymap = xkb_keymap_new_from_buffer(s->conn->xkb_ctx, map_str, size, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + free(map_str); + + if (s->xkb_keymap) { + s->xkb_state = xkb_state_new(s->xkb_keymap); + s->mod_shift = xkb_keymap_mod_get_index(s->xkb_keymap, XKB_MOD_NAME_SHIFT); + s->mod_alt = xkb_keymap_mod_get_index(s->xkb_keymap, XKB_MOD_NAME_ALT); + s->mod_ctrl = xkb_keymap_mod_get_index(s->xkb_keymap, XKB_MOD_NAME_CTRL); + s->mod_super = xkb_keymap_mod_get_index(s->xkb_keymap, XKB_MOD_NAME_LOGO); + resolve_input_mod_masks(s); + } +} + +static void keyboard_reset_keys(struct seat *s, struct yasl_surface *w) +{ + (void)w; + keyboard_repeat_stop(s); +} + +bool conn_keyboard_on(const struct yasl_display *c, const struct yasl_surface *w, + const struct seat *except) +{ + for (const struct seat *s = c->seats; s; s = s->next) + if (s != except && s->keyboard_focus == w) + return true; + return false; +} + +static void push_focus(struct yasl_surface *w, bool focused) +{ + struct yasl_input_event ev = { + .kind = YASL_INPUT_FOCUS, + .surface = w, + .focus = { .focused = focused }, + }; + input_queue_push(&w->input, &ev); +} + +static void keyboard_enter(void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + (void)keyboard; (void)serial; (void)keys; + struct seat *s = data; + struct yasl_surface *w = surface_root(conn_surface_for(s->conn, surface)); + bool same_window = w && w == s->focus_leaving; + if (same_window) + s->focus_leaving = NULL; + if (!w) { + s->keyboard_focus = NULL; + return; + } + bool focused = conn_keyboard_on(s->conn, w, s); + s->keyboard_focus = w; + keyboard_reset_keys(s, w); + if (!same_window && !focused) + push_focus(w, true); +} + +static void seat_settle_focus(struct seat *s) +{ + struct yasl_surface *w = s->focus_leaving; + if (!w) + return; + s->focus_leaving = NULL; + if (!conn_keyboard_on(s->conn, w, NULL)) + push_focus(w, false); +} + +void keyboard_settle_focus(struct yasl_display *c) +{ + for (struct seat *s = c->seats; s; s = s->next) + seat_settle_focus(s); +} + +static void keyboard_leave(void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface) +{ + (void)keyboard; (void)serial; (void)surface; + struct seat *s = data; + struct yasl_surface *w = s->keyboard_focus; + s->keyboard_focus = NULL; + if (!w) return; + keyboard_reset_keys(s, w); + seat_settle_focus(s); + s->focus_leaving = w; +} + +static unsigned input_modifiers(struct seat *s) +{ + if (!s->input_mods_ready) + resolve_input_mod_masks(s); + + unsigned mods = 0; + xkb_mod_mask_t reported = 0; + for (unsigned i = 0; i < 8; i++) { + xkb_mod_mask_t mask = s->input_mod_masks[i]; + if (mask && (mask & ~reported) && mod_active(s, input_mod_names[i])) { + mods |= 1u << i; + reported |= mask; + } + } + return mods; +} + +static uint32_t key_codepoint_at_level(struct seat *s, uint32_t key, xkb_layout_index_t layout, xkb_level_index_t level) +{ + const xkb_keysym_t *syms; + int n = xkb_keymap_key_get_syms_by_level(s->xkb_keymap, key + XKB_EVDEV_OFFSET, layout, level, &syms); + return n == 1 ? xkb_keysym_to_utf32(syms[0]) : 0; +} + +static struct yasl_key_event xkb_key_event(struct seat *s, uint32_t key, + enum yasl_key_action action) +{ + uint32_t code = key + XKB_EVDEV_OFFSET; + xkb_keysym_t sym = xkb_state_key_get_one_sym(s->xkb_state, code); + xkb_layout_index_t layout = xkb_state_key_get_layout(s->xkb_state, code); + + struct yasl_key_event k = { + .key = sym, + .keypad = key >= KEY_KP0 && key <= KEY_KPCOMMA, + .action = action, + .mods = input_modifiers(s), + .codepoint = key_codepoint_at_level(s, key, layout, 0), + .shifted = key_codepoint_at_level(s, key, layout, 1), + .base = key, + .text = xkb_state_key_get_utf32(s->xkb_state, code), + }; + if (!k.codepoint) k.codepoint = xkb_keysym_to_utf32(sym); + return k; +} + +static bool keyboard_dispatch_key(struct seat *s, struct yasl_surface *w, uint32_t key, + enum yasl_key_action action) +{ + if (!s->xkb_state || !w->cbs) return false; + + struct yasl_key_event k = xkb_key_event(s, key, action); + struct yasl_input_event ev = { + .kind = YASL_INPUT_KEY, + .surface = w, + .key = k, + }; + input_queue_push(&w->input, &ev); + return action != YASL_KEY_RELEASE; +} + +static void keyboard_key(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + (void)keyboard; (void)time; + struct seat *s = data; + struct yasl_surface *w = s->keyboard_focus; + if (!w) return; + seat_note_input(s, serial); + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { + if (s->repeat_held && key == s->repeat_key) keyboard_repeat_stop(s); + keyboard_dispatch_key(s, w, key, YASL_KEY_RELEASE); + return; + } + if (state != WL_KEYBOARD_KEY_STATE_PRESSED || !s->xkb_keymap) return; + bool repeatable = xkb_keymap_key_repeats(s->xkb_keymap, key + XKB_EVDEV_OFFSET); + if (repeatable) keyboard_repeat_stop(s); + if (keyboard_dispatch_key(s, w, key, YASL_KEY_PRESS) && repeatable) { + s->repeat_key = key; + s->repeat_held = true; + s->repeat_started_ns = yasl_loop_now_ns(); + keyboard_repeat_sync(s); + } +} + +static int keyboard_repeat_ready(int fd, short revents, void *data) +{ + struct seat *s = data; + uint64_t count; + if (!(revents & POLLIN) || read(fd, &count, sizeof(count)) != sizeof(count)) return 0; + + struct yasl_surface *w = s->keyboard_focus; + if (!w) { + keyboard_repeat_stop(s); + return 0; + } + if (count > 32) count = 32; + while (count-- && s->repeat_held && s->repeat_rate > 0) { + if (!keyboard_dispatch_key(s, w, s->repeat_key, YASL_KEY_REPEAT)) + keyboard_repeat_stop(s); + } + return 0; +} + +static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + (void)keyboard; (void)serial; + struct seat *s = data; + if (s->xkb_state) { + xkb_state_update_mask(s->xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); + } +} + +static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + (void)keyboard; + struct seat *s = data; + s->repeat_rate = rate > 0 ? rate : 0; + s->repeat_delay = delay > 0 ? delay : 0; + keyboard_repeat_sync(s); +} + +const struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info, +}; + +int keyboard_repeat_init(struct seat *s) +{ + if (s->repeat_fd >= 0) return 0; + s->repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (s->repeat_fd < 0) return -1; + s->repeat_watch = yasl_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN, + keyboard_repeat_ready, s); + if (s->repeat_watch <= 0) { + s->repeat_watch = 0; + close(s->repeat_fd); + s->repeat_fd = -1; + return -1; + } + keyboard_repeat_sync(s); + return 0; +} + +static bool mod_index_active(const struct seat *s, xkb_mod_index_t mod) +{ + return mod != XKB_MOD_INVALID && + xkb_state_mod_index_is_active(s->xkb_state, mod, + XKB_STATE_MODS_EFFECTIVE) > 0; +} + +int seat_modifiers(const struct seat *s) +{ + if (!s || !s->xkb_state) return 0; + int mods = 0; + if (mod_index_active(s, s->mod_shift)) mods |= YASL_MOD_SHIFT; + if (mod_index_active(s, s->mod_alt)) mods |= YASL_MOD_ALT; + if (mod_index_active(s, s->mod_ctrl)) mods |= YASL_MOD_CTRL; + if (mod_index_active(s, s->mod_super)) mods |= YASL_MOD_SUPER; + return mods; +} + +int yasl_display_modifiers(const struct yasl_display *c) +{ + return c ? seat_modifiers(conn_active_seat(c)) : 0; +} + +void yasl_display_copy(struct yasl_display *c, enum yasl_selection sel, const char *text) +{ + struct seat *s = c ? conn_active_seat(c) : NULL; + if (!s || !s->clipboard) + return; + if (sel == YASL_PRIMARY) + clipboard_copy_primary(s->clipboard, text, s->input_serial); + else + clipboard_copy(s->clipboard, text, s->input_serial); +} + +void yasl_display_paste(struct yasl_display *c, enum yasl_selection sel, struct yasl_surface *target) +{ + struct seat *s = c ? conn_active_seat(c) : NULL; + if (!s || !s->clipboard) + return; + c->paste_target = target; + if (sel == YASL_PRIMARY) + clipboard_paste_primary(s->clipboard); + else + clipboard_paste(s->clipboard); +} + +bool yasl_surface_input_poll(struct yasl_surface *w, struct yasl_input_event *ev) +{ + return w && ev && input_queue_pop(&w->input, ev); +} diff --git a/src/wayland/pointer.c b/src/wayland/pointer.c new file mode 100644 index 0000000..37e72f3 --- /dev/null +++ b/src/wayland/pointer.c @@ -0,0 +1,1291 @@ +#include "internal.h" + +#include +#include +#include + +#define SCROLL_PX_PER_LINE 10.0 + +struct tablet_tool { + struct tablet_tool *next; + struct seat *seat; + struct zwp_tablet_tool_v2 *proxy; + struct wp_cursor_shape_device_v1 *shape_dev; + uint32_t proximity_serial; + bool eraser; +}; + +struct tablet_device { + struct tablet_device *next; + struct zwp_tablet_v2 *proxy; +}; + +struct tablet_pad { + struct tablet_pad *next; + struct zwp_tablet_pad_v2 *proxy; +}; + +static int device_px_round(double v) +{ + return (int)(v < 0 ? v - 0.5 : v + 0.5); +} + +static struct yasl_vector2i device_from_fixed(const struct yasl_surface *w, + wl_fixed_t x, wl_fixed_t y) +{ + return (struct yasl_vector2i){ + .x = device_px_round(wl_fixed_to_double(x) * w->scale_factor), + .y = device_px_round(wl_fixed_to_double(y) * w->scale_factor), + }; +} + +static int motion_button(uint64_t buttons) +{ + for (int b = 0; b <= 7; b++) + if (buttons & (1ull << b)) + return b; + return 3; +} + +void seat_note_input(struct seat *s, uint32_t serial) +{ + s->input_serial = serial; + s->conn->active_seat = s; +} + +struct seat *conn_active_seat(const struct yasl_display *c) +{ + return c->active_seat ? c->active_seat : c->seats; +} + +static void push_mouse(struct seat *s, struct yasl_surface *w, struct yasl_mouse_event ev) +{ + ev.mods = (unsigned)seat_modifiers(s); + struct yasl_input_event input_ev = { + .kind = YASL_INPUT_MOUSE, + .surface = w, + .mouse = ev, + }; + input_queue_push(&surface_root(w)->input, &input_ev); +} + +static void report_mouse(struct seat *s, struct yasl_surface *w, struct yasl_vector2i pos, + int button, enum yasl_pointer_kind kind) +{ + push_mouse(s, w, (struct yasl_mouse_event){ + .pos = pos, .button = button, .kind = kind, + }); +} + +static void report_wheel(struct seat *s, struct yasl_surface *w, struct yasl_vector2i pos, + int button, int lines, float delta) +{ + push_mouse(s, w, (struct yasl_mouse_event){ + .pos = pos, .button = button, .kind = YASL_PTR_SCROLL, + .scroll_lines = lines, .scroll_delta = delta, + }); +} + +static bool cursor_theme_for(struct yasl_display *c, int scale) +{ + if (c->cursor_theme && c->cursor_theme_scale == scale) + return true; + struct wl_cursor_theme *theme = wl_cursor_theme_load(c->cursor_theme_name, + c->cursor_size * scale, c->shm); + if (!theme) + return c->cursor_theme != NULL; + if (c->cursor_theme) + wl_cursor_theme_destroy(c->cursor_theme); + c->cursor_theme = theme; + c->cursor_theme_scale = scale; + return true; +} + +static bool seat_cursor_surface(struct seat *s) +{ + struct yasl_display *c = s->conn; + if (s->cursor_surface) + return true; + s->cursor_surface = wl_compositor_create_surface(c->compositor); + if (!s->cursor_surface) + return false; + if (c->viewporter) + s->cursor_viewport = wp_viewporter_get_viewport(c->viewporter, s->cursor_surface); + return true; +} + +static void set_cursor_theme_fallback(struct seat *s, struct yasl_surface *w, + enum yasl_cursor shape) +{ + struct yasl_display *c = s->conn; + int scale = (int)((w->scale_120 + YASL_SCALE_UNIT - 1) / YASL_SCALE_UNIT); + if (scale < 1) scale = 1; + if (!seat_cursor_surface(s) || !cursor_theme_for(c, scale)) return; + static const char *names[][2] = { + {"default", "left_ptr"}, + {"text", "xterm"}, + {"pointer", "hand2"}, + {"crosshair", "crosshair"}, + {"move", "move"}, + {"nwse-resize", "nw-resize"}, + {"nesw-resize", "ne-resize"}, + {"ew-resize", "ew-resize"}, + {"ns-resize", "ns-resize"}, + }; + int idx = shape < YASL_CURSOR_NONE ? (int)shape : 0; + struct wl_cursor *cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][0]); + if (!cursor) cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][1]); + if (!cursor || !cursor->image_count) return; + struct wl_cursor_image *img = cursor->images[0]; + struct wl_buffer *buffer = wl_cursor_image_get_buffer(img); + if (!buffer) return; + + int theme_scale = c->cursor_theme_scale; + if (s->cursor_viewport) { + wp_viewport_set_destination(s->cursor_viewport, + logical_px_ceil((int)img->width, (uint32_t)theme_scale * YASL_SCALE_UNIT), + logical_px_ceil((int)img->height, (uint32_t)theme_scale * YASL_SCALE_UNIT)); + } else { + if (img->width % (uint32_t)theme_scale || img->height % (uint32_t)theme_scale) + theme_scale = 1; + wl_surface_set_buffer_scale(s->cursor_surface, theme_scale); + } + int shown = s->cursor_viewport ? c->cursor_theme_scale : theme_scale; + wl_pointer_set_cursor(s->pointer, s->pointer_serial, s->cursor_surface, + (int32_t)img->hotspot_x / shown, (int32_t)img->hotspot_y / shown); + wl_surface_attach(s->cursor_surface, buffer, 0, 0); + wl_surface_damage_buffer(s->cursor_surface, 0, 0, + (int32_t)img->width, (int32_t)img->height); + wl_surface_commit(s->cursor_surface); +} + +static uint32_t cursor_shape_of(enum yasl_cursor shape) +{ + switch (shape) { + case YASL_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT; + case YASL_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER; + case YASL_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR; + case YASL_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE; + case YASL_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE; + case YASL_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE; + case YASL_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE; + case YASL_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE; + default: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT; + } +} + +static void seat_set_cursor(struct seat *s, struct yasl_surface *w, enum yasl_cursor shape) +{ + if (!s->pointer || !s->pointer_serial || s->pointer_focus != w || + s->cursor_shape == (int)shape) + return; + if (shape == YASL_CURSOR_NONE) + wl_pointer_set_cursor(s->pointer, s->pointer_serial, NULL, 0, 0); + else if (s->cursor_shape_dev) + wp_cursor_shape_device_v1_set_shape(s->cursor_shape_dev, + s->pointer_serial, cursor_shape_of(shape)); + else + set_cursor_theme_fallback(s, w, shape); + s->cursor_shape = shape; +} + +static void tool_set_cursor(struct tablet_tool *t, enum yasl_cursor shape) +{ + if (!t->proximity_serial) + return; + if (shape == YASL_CURSOR_NONE) + zwp_tablet_tool_v2_set_cursor(t->proxy, t->proximity_serial, NULL, 0, 0); + else if (t->shape_dev) + wp_cursor_shape_device_v1_set_shape(t->shape_dev, t->proximity_serial, + cursor_shape_of(shape)); +} + +void yasl_surface_set_cursor(struct yasl_surface *w, enum yasl_cursor shape) +{ + if (!w || !w->conn) return; + for (struct seat *s = w->conn->seats; s; s = s->next) { + seat_set_cursor(s, w, shape); + if (s->tool && s->tablet_focus == w) + tool_set_cursor(s->tool, shape); + } +} + +static void press_queue_flush(struct seat *s, struct press_queue *q, + struct yasl_surface *only, uint64_t *buttons, + struct yasl_mouse_event like) +{ + int kept = 0; + for (int i = 0; i < q->n; i++) { + struct pending_press p = q->ev[i]; + if (only && p.surface != only) { + q->ev[kept++] = p; + continue; + } + if (!p.surface) continue; + if (p.release) *buttons &= ~(1ull << p.button); + else *buttons |= 1ull << p.button; + struct yasl_mouse_event ev = like; + ev.pos = p.pos; + ev.button = p.button; + ev.kind = p.release ? YASL_PTR_RELEASE : YASL_PTR_PRESS; + push_mouse(s, p.surface, ev); + } + q->n = kept; +} + +static void press_queue_push(struct press_queue *q, struct yasl_surface *w, + struct yasl_vector2i pos, int button, bool release) +{ + if (q->n == (int)(sizeof(q->ev) / sizeof(q->ev[0]))) { + memmove(q->ev, q->ev + 1, sizeof(q->ev[0]) * (size_t)(q->n - 1)); + q->n--; + } + q->ev[q->n++] = (struct pending_press){ + .surface = w, .pos = pos, .button = button, .release = release, + }; +} + +static void press_queue_forget(struct press_queue *q, struct yasl_surface *w) +{ + for (int i = 0; i < q->n; i++) + if (q->ev[i].surface == w) + q->ev[i].surface = NULL; +} + +void seat_pointer_reset(struct seat *s) +{ + s->pointer_buttons = 0; + s->pointer_serial = 0; + s->motion_pending = false; + s->axis_v = s->axis_h = s->frame_v = 0; + s->frame_v120 = 0; + s->axis_discrete_v = s->axis_discrete_h = 0; + s->axis_value120_v = s->axis_value120_h = 0; + s->axis_has_v120_v = s->axis_has_v120_h = false; + s->axis_smooth = false; + s->cursor_shape = -1; +} + +static void pointer_frame(void *data, struct wl_pointer *pointer); + +static void pointer_event_done(struct seat *s) +{ + if (s->pointer && wl_pointer_get_version(s->pointer) < WL_POINTER_FRAME_SINCE_VERSION) + pointer_frame(s, s->pointer); +} + +static void flush_pending_motion(struct seat *s, struct yasl_surface *w) +{ + if (!s->motion_pending) return; + s->motion_pending = false; + report_mouse(s, w, s->pointer_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION); +} + +static void pointer_enter(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + (void)pointer; + struct seat *s = data; + struct yasl_surface *w = conn_surface_for(s->conn, surface); + s->pointer_focus = w; + if (!w) return; + s->pointer_pos = device_from_fixed(w, surface_x, surface_y); + s->pointer_serial = serial; + s->cursor_shape = -1; + seat_set_cursor(s, w, w->parent ? YASL_CURSOR_ARROW : YASL_CURSOR_TEXT); + s->motion_pending = true; + pointer_event_done(s); +} + +static void pointer_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) +{ + (void)pointer; (void)serial; (void)surface; + struct seat *s = data; + struct yasl_surface *w = s->pointer_focus; + s->pointer_focus = NULL; + if (!w) return; + if (s->ptr_left) + pointer_frame(s, s->pointer); + s->ptr_left = w; + s->ptr_left_pos = s->pointer_pos; + s->ptr_left_motion = s->motion_pending; + s->motion_pending = false; + pointer_event_done(s); +} + +static void pointer_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + (void)pointer; (void)time; + struct seat *s = data; + struct yasl_surface *w = s->pointer_focus; + if (!w) return; + s->pointer_pos = device_from_fixed(w, surface_x, surface_y); + s->motion_pending = true; + pointer_event_done(s); +} + +static void pointer_button(void *data, struct wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + (void)pointer; (void)time; + struct seat *s = data; + struct yasl_surface *w = s->pointer_focus; + if (!w) return; + int b; + switch (button) { + case BTN_LEFT: b = 0; break; + case BTN_MIDDLE: b = 1; break; + case BTN_RIGHT: b = 2; break; + case BTN_BACK: b = 3; break; + case BTN_FORWARD: b = 4; break; + default: return; + } + seat_note_input(s, serial); + bool release = state == WL_POINTER_BUTTON_STATE_RELEASED; + if (!release) { + s->press_serial = serial; + s->press_surface = w; + } + press_queue_push(&s->ptr_presses, w, s->pointer_pos, b, release); + pointer_event_done(s); +} + +static void pointer_axis(void *data, struct wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ + (void)pointer; (void)time; + struct seat *s = data; + if (!s->pointer_focus) return; + double v = wl_fixed_to_double(value); + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s->axis_v += v; + s->frame_v += v; + } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s->axis_h += v; + } + pointer_event_done(s); +} + +static void pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) +{ + (void)pointer; + struct seat *s = data; + if (axis_source == WL_POINTER_AXIS_SOURCE_FINGER || + axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) + s->axis_smooth = true; +} + +static void pointer_axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis) +{ + (void)pointer; (void)time; + struct seat *s = data; + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s->axis_value120_v = 0; + s->axis_has_v120_v = false; + } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s->axis_value120_h = 0; + s->axis_has_v120_h = false; + } +} + +static void pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) +{ + (void)pointer; + struct seat *s = data; + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + s->axis_discrete_v += discrete; + else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + s->axis_discrete_h += discrete; +} + +static void pointer_axis_value120(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t value120) +{ + (void)pointer; + struct seat *s = data; + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s->axis_value120_v += value120; + s->frame_v120 += value120; + s->axis_has_v120_v = true; + } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s->axis_value120_h += value120; + s->axis_has_v120_h = true; + } +} + +static void pointer_frame_vertical(struct seat *s, struct yasl_surface *w) +{ + if (s->axis_has_v120_v) { + int discrete = s->axis_value120_v / 120; + s->axis_value120_v -= discrete * 120; + float delta = -(float)s->frame_v120 / 120.0f; + int btn = discrete ? (discrete < 0 ? 4 : 5) : (delta > 0 ? 4 : 5); + if (discrete || delta != 0.0f) + report_wheel(s, w, s->pointer_pos, btn, -discrete, delta); + s->axis_v = 0; + } else if (s->axis_discrete_v) { + report_wheel(s, w, s->pointer_pos, s->axis_discrete_v > 0 ? 5 : 4, -s->axis_discrete_v, 0.0f); + s->axis_v = 0; + } else if (s->frame_v != 0.0) { + int lines = -(int)(s->axis_v / SCROLL_PX_PER_LINE); + s->axis_v += (double)lines * SCROLL_PX_PER_LINE; + float delta = (float)(-s->frame_v / SCROLL_PX_PER_LINE); + report_wheel(s, w, s->pointer_pos, delta > 0 ? 4 : 5, lines, delta); + } + s->frame_v = 0; + s->frame_v120 = 0; +} + +static void pointer_frame_horizontal(struct seat *s, struct yasl_surface *w) +{ + if (s->axis_has_v120_h) { + int discrete = s->axis_value120_h / 120; + s->axis_value120_h -= discrete * 120; + if (discrete) + report_wheel(s, w, s->pointer_pos, discrete > 0 ? 7 : 6, discrete, 0.0f); + s->axis_h = 0; + } else if (s->axis_discrete_h) { + report_wheel(s, w, s->pointer_pos, s->axis_discrete_h > 0 ? 7 : 6, s->axis_discrete_h, 0.0f); + s->axis_h = 0; + } else if (s->axis_h) { + int steps = (int)(s->axis_h / SCROLL_PX_PER_LINE); + if (steps != 0) { + s->axis_h -= (double)steps * SCROLL_PX_PER_LINE; + report_wheel(s, w, s->pointer_pos, steps > 0 ? 7 : 6, steps, 0.0f); + } + } +} + +static void pointer_frame(void *data, struct wl_pointer *pointer) +{ + (void)pointer; + struct seat *s = data; + struct yasl_surface *left = s->ptr_left; + if (left) { + s->ptr_left = NULL; + if (s->ptr_left_motion) + report_mouse(s, left, s->ptr_left_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION); + press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_mouse_event){0}); + report_mouse(s, left, s->ptr_left_pos, 3, YASL_PTR_LEAVE); + struct yasl_vector2i pos = s->pointer_pos; + bool motion = s->motion_pending; + uint32_t serial = s->pointer_focus ? s->pointer_serial : 0; + int shape = s->pointer_focus ? s->cursor_shape : -1; + seat_pointer_reset(s); + s->pointer_pos = pos; + s->motion_pending = motion; + s->pointer_serial = serial; + s->cursor_shape = shape; + } + struct yasl_surface *w = s->pointer_focus; + if (!w) { + s->ptr_presses.n = 0; + return; + } + + flush_pending_motion(s, w); + press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_mouse_event){0}); + + if (s->axis_smooth) { + if (!s->axis_has_v120_v) s->axis_value120_v = 0; + if (!s->axis_has_v120_h) s->axis_value120_h = 0; + s->axis_smooth = false; + } + pointer_frame_vertical(s, w); + pointer_frame_horizontal(s, w); + + s->axis_discrete_v = 0; + s->axis_discrete_h = 0; + s->axis_has_v120_v = false; + s->axis_has_v120_h = false; +} + +static void pointer_axis_relative_direction(void *data, struct wl_pointer *pointer, uint32_t axis, uint32_t direction) +{ (void)data; (void)pointer; (void)axis; (void)direction; } +static void pointer_warp(void *data, struct wl_pointer *pointer, wl_fixed_t x, wl_fixed_t y) +{ (void)data; (void)pointer; (void)x; (void)y; } + +static const struct wl_pointer_listener pointer_listener = { + .axis_relative_direction = pointer_axis_relative_direction, + .warp = pointer_warp, + .enter = pointer_enter, + .leave = pointer_leave, + .motion = pointer_motion, + .button = pointer_button, + .axis = pointer_axis, + .frame = pointer_frame, + .axis_source = pointer_axis_source, + .axis_stop = pointer_axis_stop, + .axis_discrete = pointer_axis_discrete, + .axis_value120 = pointer_axis_value120, +}; + +static struct touch_point *touch_find(struct seat *s, int32_t id) +{ + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) + if (s->touch_points[i].active && s->touch_points[i].id == id) + return &s->touch_points[i]; + return NULL; +} + +static struct yasl_vector2i touch_pos(const struct touch_point *p) +{ + double scale = p->surface->scale_factor; + return (struct yasl_vector2i){ + .x = device_px_round(p->x * scale), .y = device_px_round(p->y * scale), + }; +} + +static int touch_count(const struct seat *s) +{ + int n = 0; + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) + if (s->touch_points[i].active && !s->touch_points[i].up) + n++; + return n; +} + +static double touch_centroid_y(const struct seat *s, const struct yasl_surface *on) +{ + double sum = 0; + int n = 0; + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { + const struct touch_point *p = &s->touch_points[i]; + if (p->active && !p->up && p->surface == on) { + sum += p->y; + n++; + } + } + return n ? sum / n : 0; +} + +static void touch_report(struct seat *s, struct touch_point *p, int button, + enum yasl_pointer_kind kind) +{ + push_mouse(s, p->surface, (struct yasl_mouse_event){ + .pos = touch_pos(p), .button = button, .kind = kind, + .device = YASL_PTR_DEV_TOUCH, + }); +} + +static void touch_down(void *data, struct wl_touch *touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + (void)touch; (void)time; + struct seat *s = data; + struct yasl_surface *w = conn_surface_for(s->conn, surface); + if (!w || touch_find(s, id)) return; + struct touch_point *p = NULL; + for (int i = 0; i < SEAT_TOUCH_POINTS && !p; i++) + if (!s->touch_points[i].active) + p = &s->touch_points[i]; + if (!p) return; + seat_note_input(s, serial); + s->press_serial = serial; + s->press_surface = w; + *p = (struct touch_point){ + .surface = w, .id = id, .active = true, .down = true, + .x = wl_fixed_to_double(x), .y = wl_fixed_to_double(y), + }; +} + +static void touch_up(void *data, struct wl_touch *touch, uint32_t serial, uint32_t time, int32_t id) +{ + (void)touch; (void)serial; (void)time; + struct touch_point *p = touch_find(data, id); + if (p) p->up = true; +} + +static void touch_motion(void *data, struct wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + (void)touch; (void)time; + struct touch_point *p = touch_find(data, id); + if (!p) return; + p->x = wl_fixed_to_double(x); + p->y = wl_fixed_to_double(y); + p->moved = true; +} + +static void touch_frame(void *data, struct wl_touch *touch) +{ + (void)touch; + struct seat *s = data; + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { + struct touch_point *p = &s->touch_points[i]; + if (p->active && p->down && !s->touch_primary && !s->touch_scrolling) { + s->touch_primary = p; + s->touch_pressed = true; + touch_report(s, p, 0, YASL_PTR_PRESS); + } + } + struct touch_point *primary = s->touch_primary; + if (primary && !s->touch_scrolling && touch_count(s) >= 2) { + if (s->touch_pressed) + touch_report(s, primary, 0, YASL_PTR_RELEASE); + s->touch_pressed = false; + s->touch_scrolling = true; + s->touch_scroll_y = touch_centroid_y(s, primary->surface); + s->touch_scroll_rest = 0; + } else if (s->touch_scrolling && primary && touch_count(s) >= 2) { + double y = touch_centroid_y(s, primary->surface); + double dy = y - s->touch_scroll_y; + s->touch_scroll_y = y; + if (dy != 0.0) { + double lines = dy / SCROLL_PX_PER_LINE; + s->touch_scroll_rest += lines; + int whole = (int)s->touch_scroll_rest; + s->touch_scroll_rest -= whole; + push_mouse(s, primary->surface, (struct yasl_mouse_event){ + .pos = touch_pos(primary), .button = lines > 0 ? 4 : 5, + .kind = YASL_PTR_SCROLL, .scroll_lines = whole, + .scroll_delta = (float)lines, .device = YASL_PTR_DEV_TOUCH, + }); + } + } else if (primary && primary->moved && s->touch_pressed) { + touch_report(s, primary, 0, YASL_PTR_MOTION); + } + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { + struct touch_point *p = &s->touch_points[i]; + if (!p->active) continue; + if (p->up) { + if (p == s->touch_primary) { + if (s->touch_pressed) + touch_report(s, p, 0, YASL_PTR_RELEASE); + s->touch_pressed = false; + s->touch_primary = NULL; + } + *p = (struct touch_point){0}; + } else { + p->down = p->moved = false; + } + } + if (!touch_count(s)) + s->touch_scrolling = false; +} + +static void touch_cancel(void *data, struct wl_touch *touch) +{ + (void)touch; + struct seat *s = data; + if (s->touch_primary && s->touch_pressed) + touch_report(s, s->touch_primary, 0, YASL_PTR_RELEASE); + memset(s->touch_points, 0, sizeof(s->touch_points)); + s->touch_primary = NULL; + s->touch_pressed = false; + s->touch_scrolling = false; +} + +static void touch_shape(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t major, wl_fixed_t minor) +{ (void)data; (void)touch; (void)id; (void)major; (void)minor; } +static void touch_orientation(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t orientation) +{ (void)data; (void)touch; (void)id; (void)orientation; } + +static const struct wl_touch_listener touch_listener = { + .shape = touch_shape, .orientation = touch_orientation, + .down = touch_down, .up = touch_up, .motion = touch_motion, + .frame = touch_frame, .cancel = touch_cancel, +}; + +static struct yasl_mouse_event tool_event(const struct seat *s) +{ + return (struct yasl_mouse_event){ + .device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN, + .pen = s->pen, + }; +} + +static void tablet_tool_proximity_in(void *data, + struct zwp_tablet_tool_v2 *tool, uint32_t serial, + struct zwp_tablet_v2 *tablet, struct wl_surface *surface) +{ + (void)tool; (void)tablet; + struct tablet_tool *t = data; + struct seat *s = t->seat; + struct yasl_surface *w = conn_surface_for(s->conn, surface); + s->tablet_focus = w; + s->tool = t; + s->tool_buttons = 0; + s->pen = (struct yasl_pointer_pen){0}; + t->proximity_serial = serial; + if (!w) return; + if (s->conn->cursor_shape_mgr && !t->shape_dev) + t->shape_dev = wp_cursor_shape_manager_v1_get_tablet_tool_v2( + s->conn->cursor_shape_mgr, t->proxy); + tool_set_cursor(t, w->parent ? YASL_CURSOR_ARROW : YASL_CURSOR_TEXT); + s->tool_motion = true; +} + +static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool) +{ + (void)tool; + struct tablet_tool *t = data; + struct seat *s = t->seat; + struct yasl_surface *w = s->tablet_focus; + if (w) { + press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s)); + struct yasl_mouse_event ev = tool_event(s); + ev.pos = s->tool_pos; + ev.button = 3; + ev.kind = YASL_PTR_LEAVE; + push_mouse(s, w, ev); + } + s->tool_presses.n = 0; + s->tablet_focus = NULL; + s->tool = NULL; + s->tool_motion = false; + t->proximity_serial = 0; +} + +static void tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial) +{ + (void)tool; + struct seat *s = ((struct tablet_tool *)data)->seat; + struct yasl_surface *w = s->tablet_focus; + if (!w) return; + seat_note_input(s, serial); + s->press_serial = serial; + s->press_surface = w; + press_queue_push(&s->tool_presses, w, s->tool_pos, 0, false); +} + +static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool) +{ + (void)tool; + struct seat *s = ((struct tablet_tool *)data)->seat; + struct yasl_surface *w = s->tablet_focus; + if (!w) return; + press_queue_push(&s->tool_presses, w, s->tool_pos, 0, true); +} + +static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_fixed_t x, wl_fixed_t y) +{ + (void)tool; + struct seat *s = ((struct tablet_tool *)data)->seat; + struct yasl_surface *w = s->tablet_focus; + if (!w) return; + s->tool_pos = device_from_fixed(w, x, y); + s->tool_motion = true; +} + +static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t serial, uint32_t button, uint32_t state) +{ + (void)tool; + struct seat *s = ((struct tablet_tool *)data)->seat; + struct yasl_surface *w = s->tablet_focus; + if (!w) return; + seat_note_input(s, serial); + int b; + switch (button) { + case BTN_STYLUS: b = 2; break; + case BTN_STYLUS2: b = 1; break; + case BTN_STYLUS3: b = 3; break; + default: return; + } + bool release = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED; + press_queue_push(&s->tool_presses, w, s->tool_pos, b, release); +} + +static void tool_pressure(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) +{ + (void)t; + struct seat *s = ((struct tablet_tool *)d)->seat; + s->pen.pressure = v > 65535 ? 65535 : (uint16_t)v; + s->tool_motion = true; +} + +static int8_t tilt_degrees(wl_fixed_t v) +{ + double d = wl_fixed_to_double(v); + return (int8_t)(d < -90 ? -90 : d > 90 ? 90 : lround(d)); +} + +static void tool_tilt(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t x, wl_fixed_t y) +{ + (void)t; + struct seat *s = ((struct tablet_tool *)d)->seat; + s->pen.tilt_x = tilt_degrees(x); + s->pen.tilt_y = tilt_degrees(y); + s->tool_motion = true; +} + +static void tool_wheel(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg, int32_t clicks) +{ + (void)t; (void)deg; + ((struct tablet_tool *)d)->seat->tool_wheel += clicks; +} + +static void tool_frame(void *d, struct zwp_tablet_tool_v2 *t, uint32_t time) +{ + (void)t; (void)time; + struct seat *s = ((struct tablet_tool *)d)->seat; + struct yasl_surface *w = s->tablet_focus; + if (!w) { + s->tool_presses.n = 0; + s->tool_wheel = 0; + return; + } + struct yasl_mouse_event like = tool_event(s); + if (s->tool_motion) { + struct yasl_mouse_event ev = like; + ev.pos = s->tool_pos; + ev.button = motion_button(s->tool_buttons); + ev.kind = YASL_PTR_MOTION; + push_mouse(s, w, ev); + s->tool_motion = false; + } + press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like); + if (s->tool_wheel) { + report_wheel(s, w, s->tool_pos, s->tool_wheel > 0 ? 5 : 4, -s->tool_wheel, 0.0f); + s->tool_wheel = 0; + } +} + +static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *tool) +{ + struct tablet_tool *t = data; + struct seat *s = t->seat; + if (s->tool == t) { + s->tool = NULL; + s->tablet_focus = NULL; + s->tool_presses.n = 0; + } + struct tablet_tool **link = &s->tablet_tools; + while (*link && *link != t) + link = &(*link)->next; + if (*link) + *link = t->next; + if (t->shape_dev) + wp_cursor_shape_device_v1_destroy(t->shape_dev); + zwp_tablet_tool_v2_destroy(tool); + free(t); +} + +static void tool_type(void *d, struct zwp_tablet_tool_v2 *t, uint32_t type) +{ + (void)t; + ((struct tablet_tool *)d)->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER; +} + +static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; } +static void tool_hardware_id_wacom(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; } +static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) { (void)d; (void)t; (void)cap; } +static void tool_done(void *d, struct zwp_tablet_tool_v2 *t) { (void)d; (void)t; } +static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) { (void)d; (void)t; (void)v; } +static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) { (void)d; (void)t; (void)deg; } +static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) { (void)d; (void)t; (void)pos; } + +static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { + .type = tool_type, .hardware_serial = tool_hardware_serial, + .hardware_id_wacom = tool_hardware_id_wacom, .capability = tool_capability, + .done = tool_done, .removed = tablet_tool_removed, + .proximity_in = tablet_tool_proximity_in, .proximity_out = tablet_tool_proximity_out, + .down = tablet_tool_down, .up = tablet_tool_up, .motion = tablet_tool_motion, + .pressure = tool_pressure, .distance = tool_distance, .tilt = tool_tilt, + .rotation = tool_rotation, .slider = tool_slider, .wheel = tool_wheel, + .button = tablet_tool_button, .frame = tool_frame, +}; + +static void tablet_name(void *data, struct zwp_tablet_v2 *tablet, const char *name) { (void)data; (void)tablet; (void)name; } +static void tablet_id(void *data, struct zwp_tablet_v2 *tablet, uint32_t vid, uint32_t pid) { (void)data; (void)tablet; (void)vid; (void)pid; } +static void tablet_path(void *data, struct zwp_tablet_v2 *tablet, const char *path) { (void)data; (void)tablet; (void)path; } +static void tablet_done(void *data, struct zwp_tablet_v2 *tablet) { (void)data; (void)tablet; } +static void tablet_bustype(void *data, struct zwp_tablet_v2 *tablet, uint32_t bustype) { (void)data; (void)tablet; (void)bustype; } + +static void tablet_removed(void *data, struct zwp_tablet_v2 *tablet) +{ + struct seat *s = data; + struct tablet_device **link = &s->tablet_devices; + while (*link && (*link)->proxy != tablet) + link = &(*link)->next; + if (*link) { + struct tablet_device *removed = *link; + *link = removed->next; + free(removed); + } + zwp_tablet_v2_destroy(tablet); +} + +static const struct zwp_tablet_v2_listener tablet_listener = { + .name = tablet_name, .id = tablet_id, .path = tablet_path, + .done = tablet_done, .removed = tablet_removed, .bustype = tablet_bustype, +}; + +static void tablet_pad_group(void *data, struct zwp_tablet_pad_v2 *pad, struct zwp_tablet_pad_group_v2 *group) { (void)data; (void)pad; (void)group; } +static void tablet_pad_path(void *data, struct zwp_tablet_pad_v2 *pad, const char *path) { (void)data; (void)pad; (void)path; } +static void tablet_pad_buttons(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t buttons) { (void)data; (void)pad; (void)buttons; } +static void tablet_pad_done(void *data, struct zwp_tablet_pad_v2 *pad) { (void)data; (void)pad; } +static void tablet_pad_button(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t time, uint32_t button, uint32_t state) { (void)data; (void)pad; (void)time; (void)button; (void)state; } +static void tablet_pad_enter(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { (void)data; (void)pad; (void)serial; (void)tablet; (void)surface; } +static void tablet_pad_leave(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t serial, struct wl_surface *surface) { (void)data; (void)pad; (void)serial; (void)surface; } + +static void tablet_pad_removed(void *data, struct zwp_tablet_pad_v2 *pad) +{ + struct seat *s = data; + struct tablet_pad **link = &s->tablet_pads; + while (*link && (*link)->proxy != pad) + link = &(*link)->next; + if (*link) { + struct tablet_pad *removed = *link; + *link = removed->next; + free(removed); + } + zwp_tablet_pad_v2_destroy(pad); +} + +static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { + .group = tablet_pad_group, .path = tablet_pad_path, .buttons = tablet_pad_buttons, + .done = tablet_pad_done, .button = tablet_pad_button, .enter = tablet_pad_enter, + .leave = tablet_pad_leave, .removed = tablet_pad_removed, +}; + +void seat_destroy_tablet(struct seat *s) +{ + while (s->tablet_tools) + tablet_tool_removed(s->tablet_tools, s->tablet_tools->proxy); + while (s->tablet_pads) + tablet_pad_removed(s, s->tablet_pads->proxy); + while (s->tablet_devices) + tablet_removed(s, s->tablet_devices->proxy); + if (s->tablet_seat) { + zwp_tablet_seat_v2_destroy(s->tablet_seat); + s->tablet_seat = NULL; + } +} + +static void tablet_seat_tablet_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_v2 *tablet) +{ + (void)tablet_seat; + struct seat *s = data; + struct tablet_device *owned = calloc(1, sizeof(*owned)); + if (!owned) { zwp_tablet_v2_destroy(tablet); return; } + owned->proxy = tablet; + owned->next = s->tablet_devices; + s->tablet_devices = owned; + zwp_tablet_v2_add_listener(tablet, &tablet_listener, s); +} + +static void tablet_seat_tool_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_tool_v2 *tool) +{ + (void)tablet_seat; + struct seat *s = data; + struct tablet_tool *owned = calloc(1, sizeof(*owned)); + if (!owned) { zwp_tablet_tool_v2_destroy(tool); return; } + owned->proxy = tool; + owned->seat = s; + owned->next = s->tablet_tools; + s->tablet_tools = owned; + zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, owned); +} + +static void tablet_seat_pad_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_pad_v2 *pad) +{ + (void)tablet_seat; + struct seat *s = data; + struct tablet_pad *owned = calloc(1, sizeof(*owned)); + if (!owned) { zwp_tablet_pad_v2_destroy(pad); return; } + owned->proxy = pad; + owned->next = s->tablet_pads; + s->tablet_pads = owned; + zwp_tablet_pad_v2_add_listener(pad, &tablet_pad_listener, s); +} + +static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { + .tablet_added = tablet_seat_tablet_added, + .tool_added = tablet_seat_tool_added, + .pad_added = tablet_seat_pad_added, +}; + +static void clipboard_received(const char *text, size_t len, bool uri_list, + struct wl_surface *on, void *ud) +{ + struct seat *s = ud; + struct yasl_display *c = s->conn; + struct yasl_surface *w = on ? surface_root(conn_surface_for(c, on)) : NULL; + if (!w) + w = c->paste_target ? c->paste_target : s->keyboard_focus; + if (!len || !w) return; + struct yasl_input_event ev = { + .surface = w, + .kind = uri_list ? YASL_INPUT_DROP_FILES : YASL_INPUT_PASTE, + }; + if (uri_list) { + ev.drop_files.files = text; + ev.drop_files.len = len; + } else { + ev.paste.text = text; + ev.paste.len = len; + } + input_queue_push(&w->input, &ev); +} + +static void clipboard_drag(enum yasl_drag_event ev, struct wl_surface *on, + double x, double y, void *ud) +{ + struct seat *s = ud; + conn_drag_target(s->conn, ev, on, x, y); +} + +static void clipboard_drop_hover(enum yasl_drop_event ev, struct wl_surface *on, + double x, double y, void *ud) +{ + struct seat *s = ud; + conn_drop_target(s->conn, ev, on, x, y); +} + +void seat_clipboard_ensure(struct seat *s) +{ + struct yasl_display *c = s->conn; + if (!c->data_manager || !s->proxy) + return; + if (!s->clipboard) { + s->clipboard = clipboard_create(c->wl, c->data_manager, s->proxy, + c->loop, clipboard_received, s); + if (!s->clipboard) + return; + clipboard_set_drag_handler(s->clipboard, clipboard_drag, s); + clipboard_set_drop_handler(s->clipboard, clipboard_drop_hover, s); + } + if (c->primary_selection_mgr) + clipboard_set_primary_manager(s->clipboard, c->primary_selection_mgr); +} + +static void seat_drop_pointer(struct seat *s) +{ + if (s->cursor_shape_dev) { + wp_cursor_shape_device_v1_destroy(s->cursor_shape_dev); + s->cursor_shape_dev = NULL; + } + if (s->pointer) { + if (wl_pointer_get_version(s->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) + wl_pointer_release(s->pointer); + else + wl_pointer_destroy(s->pointer); + s->pointer = NULL; + } + seat_pointer_reset(s); + s->pointer_focus = s->ptr_left = NULL; + s->ptr_presses.n = 0; +} + +static void seat_drop_keyboard(struct seat *s) +{ + keyboard_repeat_stop(s); + if (s->keyboard) { + if (wl_keyboard_get_version(s->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) + wl_keyboard_release(s->keyboard); + else + wl_keyboard_destroy(s->keyboard); + s->keyboard = NULL; + } + s->repeat_rate = 0; + struct yasl_surface *w = s->keyboard_focus; + s->keyboard_focus = NULL; + if (w && !s->focus_leaving) + s->focus_leaving = w; +} + +static void seat_drop_touch(struct seat *s) +{ + if (s->touch) { + touch_cancel(s, s->touch); + if (wl_touch_get_version(s->touch) >= WL_TOUCH_RELEASE_SINCE_VERSION) + wl_touch_release(s->touch); + else + wl_touch_destroy(s->touch); + s->touch = NULL; + } +} + +static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps) +{ + struct seat *s = data; + struct yasl_display *c = s->conn; + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + if (!s->keyboard) { + s->keyboard = wl_seat_get_keyboard(proxy); + if (s->keyboard) + wl_keyboard_add_listener(s->keyboard, &keyboard_listener, s); + if (s->keyboard && wl_keyboard_get_version(s->keyboard) < + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { + s->repeat_rate = 25; + s->repeat_delay = 600; + } + } + } else if (s->keyboard) { + seat_drop_keyboard(s); + } + + if (caps & WL_SEAT_CAPABILITY_POINTER) { + if (!s->pointer) { + s->pointer = wl_seat_get_pointer(proxy); + if (s->pointer) + wl_pointer_add_listener(s->pointer, &pointer_listener, s); + if (s->pointer && c->cursor_shape_mgr) + s->cursor_shape_dev = wp_cursor_shape_manager_v1_get_pointer( + c->cursor_shape_mgr, s->pointer); + } + } else if (s->pointer) { + seat_drop_pointer(s); + } + + if (caps & WL_SEAT_CAPABILITY_TOUCH) { + if (!s->touch) { + s->touch = wl_seat_get_touch(proxy); + if (s->touch) + wl_touch_add_listener(s->touch, &touch_listener, s); + } + } else if (s->touch) { + seat_drop_touch(s); + } + + if (c->tablet_mgr && !s->tablet_seat) { + s->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(c->tablet_mgr, proxy); + if (s->tablet_seat) + zwp_tablet_seat_v2_add_listener(s->tablet_seat, &tablet_seat_listener, s); + } + + if (c->text_input_mgr && !s->text_input) { + s->text_input = zwp_text_input_manager_v3_get_text_input(c->text_input_mgr, proxy); + if (s->text_input) + zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s); + } + + seat_clipboard_ensure(s); +} + +static void seat_name(void *data, struct wl_seat *seat, const char *name) +{ (void)data; (void)seat; (void)name; } + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_capabilities, + .name = seat_name, +}; + +void seat_bind(struct yasl_display *c, struct wl_registry *registry, + uint32_t name, uint32_t version) +{ + struct seat *s = calloc(1, sizeof(*s)); + if (!s) return; + s->conn = c; + s->name = name; + s->repeat_fd = -1; + s->cursor_shape = -1; + s->proxy = wl_registry_bind(registry, name, &wl_seat_interface, + version < 8 ? version : 8); + if (!s->proxy) { + free(s); + return; + } + s->next = c->seats; + c->seats = s; + wl_seat_add_listener(s->proxy, &seat_listener, s); + keyboard_repeat_init(s); +} + +void seat_forget_surface(struct seat *s, struct yasl_surface *w) +{ + struct yasl_surface **refs[] = { + &s->pointer_focus, &s->keyboard_focus, + &s->tablet_focus, &s->ime_focus, &s->focus_leaving, &s->ptr_left, + &s->press_surface, + }; + for (size_t i = 0; i < sizeof(refs) / sizeof(refs[0]); i++) + if (*refs[i] == w) + *refs[i] = NULL; + press_queue_forget(&s->ptr_presses, w); + press_queue_forget(&s->tool_presses, w); + for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { + if (s->touch_points[i].active && s->touch_points[i].surface == w) { + if (s->touch_primary == &s->touch_points[i]) { + s->touch_primary = NULL; + s->touch_pressed = false; + } + s->touch_points[i] = (struct touch_point){0}; + } + } +} + +void seat_destroy(struct seat *s) +{ + struct yasl_display *c = s->conn; + for (struct seat **link = &c->seats; *link; link = &(*link)->next) { + if (*link == s) { + *link = s->next; + break; + } + } + if (c->active_seat == s) + c->active_seat = NULL; + for (struct yasl_surface *w = c->surfaces; w; w = w->conn_next) { + if (w->ime_seat == s) { + w->ime_seat = NULL; + ime_reset(w); + } + } + if (c->drag.seat == s) + conn_drag_end(c); + if (s->text_input) + zwp_text_input_v3_destroy(s->text_input); + seat_destroy_tablet(s); + seat_drop_pointer(s); + seat_drop_keyboard(s); + struct yasl_surface *left = s->focus_leaving; + if (left && !conn_keyboard_on(c, left, NULL)) { + struct yasl_input_event ev = { + .kind = YASL_INPUT_FOCUS, + .surface = left, + .focus = { .focused = false }, + }; + input_queue_push(&left->input, &ev); + } + seat_drop_touch(s); + clipboard_destroy(s->clipboard); + if (s->repeat_watch > 0) yasl_loop_del_fd(c->loop, s->repeat_watch); + if (s->repeat_fd >= 0) close(s->repeat_fd); + if (s->cursor_viewport) wp_viewport_destroy(s->cursor_viewport); + if (s->cursor_surface) wl_surface_destroy(s->cursor_surface); + if (s->xkb_state) xkb_state_unref(s->xkb_state); + if (s->xkb_keymap) xkb_keymap_unref(s->xkb_keymap); + if (s->proxy) { + if (wl_seat_get_version(s->proxy) >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(s->proxy); + else + wl_seat_destroy(s->proxy); + } + free(s); +} + +bool seat_remove(struct yasl_display *c, uint32_t name) +{ + for (struct seat *s = c->seats; s; s = s->next) { + if (s->name == name) { + seat_destroy(s); + return true; + } + } + return false; +} + +int display_input_init(struct yasl_display *c) +{ + for (struct seat *s = c->seats; s; s = s->next) { + keyboard_repeat_init(s); + seat_clipboard_ensure(s); + } + return 0; +} + +void surface_init_cursor(struct yasl_display *c) +{ + if (c->cursor_shape_mgr) + return; + const char *env_size = getenv("XCURSOR_SIZE"); + int size = env_size ? atoi(env_size) : 0; + c->cursor_theme_name = getenv("XCURSOR_THEME"); + c->cursor_size = size > 0 && size <= 512 ? size : 24; + cursor_theme_for(c, 1); +} diff --git a/src/wayland/popup.c b/src/wayland/popup.c new file mode 100644 index 0000000..e809a43 --- /dev/null +++ b/src/wayland/popup.c @@ -0,0 +1,193 @@ +#include "internal.h" + +static void popup_configure(void *data, struct xdg_popup *popup, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + (void)data; (void)popup; (void)x; (void)y; (void)width; (void)height; +} + +static void popup_done(void *data, struct xdg_popup *popup) +{ + (void)popup; + surface_fail(data); +} + +static void popup_repositioned(void *data, struct xdg_popup *popup, uint32_t token) +{ + (void)data; (void)popup; (void)token; +} + +static const struct xdg_popup_listener popup_listener = { + .configure = popup_configure, + .popup_done = popup_done, + .repositioned = popup_repositioned, +}; + +static bool popup_spec_valid(const struct yasl_popup_spec *spec) +{ + return spec && spec->size.x > 0 && spec->size.y > 0 && + spec->content_offset.x >= 0 && spec->content_offset.y >= 0 && + spec->content_size.x >= 0 && spec->content_size.y >= 0 && + spec->content_offset.x + spec->content_size.x <= spec->size.x && + spec->content_offset.y + spec->content_size.y <= spec->size.y; +} + +static bool popup_apply_spec(struct yasl_surface *w, const struct yasl_popup_spec *spec) +{ + uint32_t scale = w->parent->scale_120; + struct yasl_vector2i logical = { + .x = logical_px_ceil(spec->size.x, scale), + .y = logical_px_ceil(spec->size.y, scale), + }; + int width = device_px(logical.x, scale); + int height = device_px(logical.y, scale); + size_t bytes; + if (logical.x <= 0 || logical.y <= 0 || !buffer_size(width, height, &bytes)) + return false; + struct yasl_vector2i content = spec->content_size; + if (!content.x) content.x = spec->size.x - spec->content_offset.x; + if (!content.y) content.y = spec->size.y - spec->content_offset.y; + bool rescaled = scale != w->scale_120; + w->scale_120 = w->pending_scale_120 = scale; + w->scale_factor = (double)scale / YASL_SCALE_UNIT; + w->width = width; + w->height = height; + w->logical_width = logical.x; + w->logical_height = logical.y; + w->content = (struct yasl_rect2i){ + .x = spec->content_offset.x, .y = spec->content_offset.y, + .width = content.x, .height = content.y + }; + for (int i = 0; i < NBUF; i++) + w->buffers[i].presented = false; + if (w->viewport) + wp_viewport_set_destination(w->viewport, logical.x, logical.y); + else if ((rescaled || !w->configured) && scale % YASL_SCALE_UNIT == 0 && + wl_proxy_get_version((struct wl_proxy *)w->surface) >= + WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) + wl_surface_set_buffer_scale(w->surface, (int32_t)(scale / YASL_SCALE_UNIT)); + return true; +} + +static void popup_set_geometry(struct yasl_surface *w) +{ + uint32_t scale = w->scale_120; + int gx = yasl_scale_to_logical(w->content.x, scale); + int gy = yasl_scale_to_logical(w->content.y, scale); + int gw = yasl_scale_to_logical(w->content.width, scale); + int gh = yasl_scale_to_logical(w->content.height, scale); + if (gw < 1) gw = 1; + if (gh < 1) gh = 1; + if (gx + gw > w->logical_width) + gx = w->logical_width - gw > 0 ? w->logical_width - gw : 0; + if (gy + gh > w->logical_height) + gy = w->logical_height - gh > 0 ? w->logical_height - gh : 0; + xdg_surface_set_window_geometry(w->xdg_surface, gx, gy, gw, gh); +} + +static struct xdg_positioner *popup_positioner(struct yasl_surface *w, + const struct yasl_popup_spec *spec) +{ + struct yasl_surface *parent = w->parent; + struct xdg_positioner *pos = xdg_wm_base_create_positioner(w->conn->wm_base); + if (!pos) + return NULL; + uint32_t scale = parent->scale_120; + int gw = yasl_scale_to_logical(w->content.width, scale); + int gh = yasl_scale_to_logical(w->content.height, scale); + xdg_positioner_set_size(pos, gw > 0 ? gw : 1, gh > 0 ? gh : 1); + struct yasl_vector2i at = { + .x = spec->anchor.x - parent->content.x, + .y = spec->anchor.y - parent->content.y, + }; + int aw = yasl_scale_to_logical(spec->anchor.width, scale); + int ah = yasl_scale_to_logical(spec->anchor.height, scale); + xdg_positioner_set_anchor_rect(pos, + yasl_scale_to_logical(at.x, scale), + yasl_scale_to_logical(at.y, scale), + aw > 0 ? aw : 1, ah > 0 ? ah : 1); + xdg_positioner_set_anchor(pos, spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT + : XDG_POSITIONER_ANCHOR_TOP_LEFT); + xdg_positioner_set_gravity(pos, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); + xdg_positioner_set_constraint_adjustment(pos, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); + if (xdg_positioner_get_version(pos) >= XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION) + xdg_positioner_set_reactive(pos); + return pos; +} + +struct yasl_surface *yasl_surface_create_popup(struct yasl_surface *parent, + const struct yasl_popup_spec *spec) +{ + struct yasl_display *c = parent ? parent->conn : NULL; + struct seat *seat = c ? conn_active_seat(c) : NULL; + if (!c || c->lost || parent->closed || !parent->xdg_surface || !seat || + !seat->input_serial || !popup_spec_valid(spec)) + return NULL; + + struct yasl_surface *w = calloc(1, sizeof(*w)); + if (!w) + return NULL; + w->conn = c; + w->conn_next = c->surfaces; + c->surfaces = w; + w->parent = parent; + yasl_surface_set_callbacks(w, NULL, NULL); + w->clock.refresh_ns = parent->clock.refresh_ns; + + w->surface = wl_compositor_create_surface(c->compositor); + if (!w->surface || surface_init_scaling(w) < 0) + goto err; + w->xdg_surface = xdg_wm_base_get_xdg_surface(c->wm_base, w->surface); + if (!w->xdg_surface) + goto err; + xdg_surface_add_listener(w->xdg_surface, &shell_surface_listener, w); + if (!popup_apply_spec(w, spec)) + goto err; + struct xdg_positioner *pos = popup_positioner(w, spec); + if (!pos) + goto err; + w->popup = xdg_surface_get_popup(w->xdg_surface, parent->xdg_surface, pos); + xdg_positioner_destroy(pos); + if (!w->popup) + goto err; + xdg_popup_add_listener(w->popup, &popup_listener, w); + popup_set_geometry(w); + xdg_popup_grab(w->popup, seat->proxy, seat->input_serial); + w->want_draw = true; + wl_surface_commit(w->surface); + return w; + +err: + yasl_surface_destroy(w); + return NULL; +} + +bool yasl_surface_popup_reposition(struct yasl_surface *w, const struct yasl_popup_spec *spec) +{ + if (!w || !w->popup || w->closed || !w->conn || w->conn->lost || + !popup_spec_valid(spec) || + xdg_popup_get_version(w->popup) < XDG_POPUP_REPOSITION_SINCE_VERSION) + return false; + struct yasl_popup_spec old = { + .size = { .x = w->width, .y = w->height }, + .content_offset = { .x = w->content.x, .y = w->content.y }, + .content_size = { .x = w->content.width, .y = w->content.height }, + }; + if (!popup_apply_spec(w, spec)) { + popup_apply_spec(w, &old); + return false; + } + struct xdg_positioner *pos = popup_positioner(w, spec); + if (!pos) + return false; + popup_set_geometry(w); + static uint32_t token; + xdg_popup_reposition(w->popup, pos, ++token); + xdg_positioner_destroy(pos); + yasl_surface_schedule_redraw(w); + return true; +} diff --git a/src/wayland/protocols/commit-timing-v1-client-protocol.h b/src/wayland/protocols/commit-timing-v1-client-protocol.h new file mode 100644 index 0000000..20dc94c --- /dev/null +++ b/src/wayland/protocols/commit-timing-v1-client-protocol.h @@ -0,0 +1,294 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef COMMIT_TIMING_V1_CLIENT_PROTOCOL_H +#define COMMIT_TIMING_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_commit_timing_v1 The commit_timing_v1 protocol + * @section page_ifaces_commit_timing_v1 Interfaces + * - @subpage page_iface_wp_commit_timing_manager_v1 - commit timing + * - @subpage page_iface_wp_commit_timer_v1 - Surface commit timer + * @section page_copyright_commit_timing_v1 Copyright + *
+ *
+ * Copyright © 2023 Valve Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_commit_timer_v1; +struct wp_commit_timing_manager_v1; + +#ifndef WP_COMMIT_TIMING_MANAGER_V1_INTERFACE +#define WP_COMMIT_TIMING_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_commit_timing_manager_v1 wp_commit_timing_manager_v1 + * @section page_iface_wp_commit_timing_manager_v1_desc Description + * + * When a compositor latches on to new content updates it will check for + * any number of requirements of the available content updates (such as + * fences of all buffers being signalled) to consider the update ready. + * + * This protocol provides a method for adding a time constraint to surface + * content. This constraint indicates to the compositor that a content + * update should be presented as closely as possible to, but not before, + * a specified time. + * + * This protocol does not change the Wayland property that content + * updates are applied in the order they are received, even when some + * content updates contain timestamps and others do not. + * + * To provide timestamps, this global factory interface must be used to + * acquire a wp_commit_timing_v1 object for a surface, which may then be + * used to provide timestamp information for commits. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_wp_commit_timing_manager_v1_api API + * See @ref iface_wp_commit_timing_manager_v1. + */ +/** + * @defgroup iface_wp_commit_timing_manager_v1 The wp_commit_timing_manager_v1 interface + * + * When a compositor latches on to new content updates it will check for + * any number of requirements of the available content updates (such as + * fences of all buffers being signalled) to consider the update ready. + * + * This protocol provides a method for adding a time constraint to surface + * content. This constraint indicates to the compositor that a content + * update should be presented as closely as possible to, but not before, + * a specified time. + * + * This protocol does not change the Wayland property that content + * updates are applied in the order they are received, even when some + * content updates contain timestamps and others do not. + * + * To provide timestamps, this global factory interface must be used to + * acquire a wp_commit_timing_v1 object for a surface, which may then be + * used to provide timestamp information for commits. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface wp_commit_timing_manager_v1_interface; +#endif +#ifndef WP_COMMIT_TIMER_V1_INTERFACE +#define WP_COMMIT_TIMER_V1_INTERFACE +/** + * @page page_iface_wp_commit_timer_v1 wp_commit_timer_v1 + * @section page_iface_wp_commit_timer_v1_desc Description + * + * An object to set a time constraint for a content update on a surface. + * @section page_iface_wp_commit_timer_v1_api API + * See @ref iface_wp_commit_timer_v1. + */ +/** + * @defgroup iface_wp_commit_timer_v1 The wp_commit_timer_v1 interface + * + * An object to set a time constraint for a content update on a surface. + */ +extern const struct wl_interface wp_commit_timer_v1_interface; +#endif + +#ifndef WP_COMMIT_TIMING_MANAGER_V1_ERROR_ENUM +#define WP_COMMIT_TIMING_MANAGER_V1_ERROR_ENUM +enum wp_commit_timing_manager_v1_error { + /** + * commit timer already exists for surface + */ + WP_COMMIT_TIMING_MANAGER_V1_ERROR_COMMIT_TIMER_EXISTS = 0, +}; +#endif /* WP_COMMIT_TIMING_MANAGER_V1_ERROR_ENUM */ + +#define WP_COMMIT_TIMING_MANAGER_V1_DESTROY 0 +#define WP_COMMIT_TIMING_MANAGER_V1_GET_TIMER 1 + + +/** + * @ingroup iface_wp_commit_timing_manager_v1 + */ +#define WP_COMMIT_TIMING_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_commit_timing_manager_v1 + */ +#define WP_COMMIT_TIMING_MANAGER_V1_GET_TIMER_SINCE_VERSION 1 + +/** @ingroup iface_wp_commit_timing_manager_v1 */ +static inline void +wp_commit_timing_manager_v1_set_user_data(struct wp_commit_timing_manager_v1 *wp_commit_timing_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_commit_timing_manager_v1, user_data); +} + +/** @ingroup iface_wp_commit_timing_manager_v1 */ +static inline void * +wp_commit_timing_manager_v1_get_user_data(struct wp_commit_timing_manager_v1 *wp_commit_timing_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_commit_timing_manager_v1); +} + +static inline uint32_t +wp_commit_timing_manager_v1_get_version(struct wp_commit_timing_manager_v1 *wp_commit_timing_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_commit_timing_manager_v1); +} + +/** + * @ingroup iface_wp_commit_timing_manager_v1 + * + * Informs the server that the client will no longer be using + * this protocol object. Existing objects created by this object + * are not affected. + */ +static inline void +wp_commit_timing_manager_v1_destroy(struct wp_commit_timing_manager_v1 *wp_commit_timing_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_commit_timing_manager_v1, + WP_COMMIT_TIMING_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_commit_timing_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_commit_timing_manager_v1 + * + * Establish a timing controller for a surface. + * + * Only one commit timer can be created for a surface, or a + * commit_timer_exists protocol error will be generated. + */ +static inline struct wp_commit_timer_v1 * +wp_commit_timing_manager_v1_get_timer(struct wp_commit_timing_manager_v1 *wp_commit_timing_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_commit_timing_manager_v1, + WP_COMMIT_TIMING_MANAGER_V1_GET_TIMER, &wp_commit_timer_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_commit_timing_manager_v1), 0, NULL, surface); + + return (struct wp_commit_timer_v1 *) id; +} + +#ifndef WP_COMMIT_TIMER_V1_ERROR_ENUM +#define WP_COMMIT_TIMER_V1_ERROR_ENUM +enum wp_commit_timer_v1_error { + /** + * timestamp contains an invalid value + */ + WP_COMMIT_TIMER_V1_ERROR_INVALID_TIMESTAMP = 0, + /** + * timestamp exists + */ + WP_COMMIT_TIMER_V1_ERROR_TIMESTAMP_EXISTS = 1, + /** + * the associated surface no longer exists + */ + WP_COMMIT_TIMER_V1_ERROR_SURFACE_DESTROYED = 2, +}; +#endif /* WP_COMMIT_TIMER_V1_ERROR_ENUM */ + +#define WP_COMMIT_TIMER_V1_SET_TIMESTAMP 0 +#define WP_COMMIT_TIMER_V1_DESTROY 1 + + +/** + * @ingroup iface_wp_commit_timer_v1 + */ +#define WP_COMMIT_TIMER_V1_SET_TIMESTAMP_SINCE_VERSION 1 +/** + * @ingroup iface_wp_commit_timer_v1 + */ +#define WP_COMMIT_TIMER_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_commit_timer_v1 */ +static inline void +wp_commit_timer_v1_set_user_data(struct wp_commit_timer_v1 *wp_commit_timer_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_commit_timer_v1, user_data); +} + +/** @ingroup iface_wp_commit_timer_v1 */ +static inline void * +wp_commit_timer_v1_get_user_data(struct wp_commit_timer_v1 *wp_commit_timer_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_commit_timer_v1); +} + +static inline uint32_t +wp_commit_timer_v1_get_version(struct wp_commit_timer_v1 *wp_commit_timer_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_commit_timer_v1); +} + +/** + * @ingroup iface_wp_commit_timer_v1 + * + * Provide a timing constraint for a surface content update. + * + * A set_timestamp request may be made before a wl_surface.commit to + * tell the compositor that the content is intended to be presented + * as closely as possible to, but not before, the specified time. + * The time is in the domain of the compositor's presentation clock. + * + * An invalid_timestamp error will be generated for invalid tv_nsec. + * + * If a timestamp already exists on the surface, a timestamp_exists + * error is generated. + * + * Requesting set_timestamp after the commit_timer object's surface is + * destroyed will generate a "surface_destroyed" error. + */ +static inline void +wp_commit_timer_v1_set_timestamp(struct wp_commit_timer_v1 *wp_commit_timer_v1, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_commit_timer_v1, + WP_COMMIT_TIMER_V1_SET_TIMESTAMP, NULL, wl_proxy_get_version((struct wl_proxy *) wp_commit_timer_v1), 0, tv_sec_hi, tv_sec_lo, tv_nsec); +} + +/** + * @ingroup iface_wp_commit_timer_v1 + * + * Informs the server that the client will no longer be using + * this protocol object. + * + * Existing timing constraints are not affected by the destruction. + */ +static inline void +wp_commit_timer_v1_destroy(struct wp_commit_timer_v1 *wp_commit_timer_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_commit_timer_v1, + WP_COMMIT_TIMER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_commit_timer_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/commit-timing-v1-protocol.c b/src/wayland/protocols/commit-timing-v1-protocol.c new file mode 100644 index 0000000..6755745 --- /dev/null +++ b/src/wayland/protocols/commit-timing-v1-protocol.c @@ -0,0 +1,73 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2023 Valve Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_commit_timer_v1_interface; + +static const struct wl_interface *commit_timing_v1_types[] = { + NULL, + NULL, + NULL, + &wp_commit_timer_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_commit_timing_manager_v1_requests[] = { + { "destroy", "", commit_timing_v1_types + 0 }, + { "get_timer", "no", commit_timing_v1_types + 3 }, +}; + +WL_PRIVATE const struct wl_interface wp_commit_timing_manager_v1_interface = { + "wp_commit_timing_manager_v1", 1, + 2, wp_commit_timing_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_commit_timer_v1_requests[] = { + { "set_timestamp", "uuu", commit_timing_v1_types + 0 }, + { "destroy", "", commit_timing_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_commit_timer_v1_interface = { + "wp_commit_timer_v1", 1, + 2, wp_commit_timer_v1_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/cursor-shape-v1-client-protocol.h b/src/wayland/protocols/cursor-shape-v1-client-protocol.h new file mode 100644 index 0000000..ff60edd --- /dev/null +++ b/src/wayland/protocols/cursor-shape-v1-client-protocol.h @@ -0,0 +1,452 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef CURSOR_SHAPE_V1_CLIENT_PROTOCOL_H +#define CURSOR_SHAPE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_cursor_shape_v1 The cursor_shape_v1 protocol + * @section page_ifaces_cursor_shape_v1 Interfaces + * - @subpage page_iface_wp_cursor_shape_manager_v1 - cursor shape manager + * - @subpage page_iface_wp_cursor_shape_device_v1 - cursor shape for a device + * @section page_copyright_cursor_shape_v1 Copyright + *
+ *
+ * Copyright 2018 The Chromium Authors
+ * Copyright 2023 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_pointer; +struct wp_cursor_shape_device_v1; +struct wp_cursor_shape_manager_v1; +struct zwp_tablet_tool_v2; + +#ifndef WP_CURSOR_SHAPE_MANAGER_V1_INTERFACE +#define WP_CURSOR_SHAPE_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_cursor_shape_manager_v1 wp_cursor_shape_manager_v1 + * @section page_iface_wp_cursor_shape_manager_v1_desc Description + * + * This global offers an alternative, optional way to set cursor images. This + * new way uses enumerated cursors instead of a wl_surface like + * wl_pointer.set_cursor does. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_wp_cursor_shape_manager_v1_api API + * See @ref iface_wp_cursor_shape_manager_v1. + */ +/** + * @defgroup iface_wp_cursor_shape_manager_v1 The wp_cursor_shape_manager_v1 interface + * + * This global offers an alternative, optional way to set cursor images. This + * new way uses enumerated cursors instead of a wl_surface like + * wl_pointer.set_cursor does. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface wp_cursor_shape_manager_v1_interface; +#endif +#ifndef WP_CURSOR_SHAPE_DEVICE_V1_INTERFACE +#define WP_CURSOR_SHAPE_DEVICE_V1_INTERFACE +/** + * @page page_iface_wp_cursor_shape_device_v1 wp_cursor_shape_device_v1 + * @section page_iface_wp_cursor_shape_device_v1_desc Description + * + * This interface allows clients to set the cursor shape. + * @section page_iface_wp_cursor_shape_device_v1_api API + * See @ref iface_wp_cursor_shape_device_v1. + */ +/** + * @defgroup iface_wp_cursor_shape_device_v1 The wp_cursor_shape_device_v1 interface + * + * This interface allows clients to set the cursor shape. + */ +extern const struct wl_interface wp_cursor_shape_device_v1_interface; +#endif + +#define WP_CURSOR_SHAPE_MANAGER_V1_DESTROY 0 +#define WP_CURSOR_SHAPE_MANAGER_V1_GET_POINTER 1 +#define WP_CURSOR_SHAPE_MANAGER_V1_GET_TABLET_TOOL_V2 2 + + +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + */ +#define WP_CURSOR_SHAPE_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + */ +#define WP_CURSOR_SHAPE_MANAGER_V1_GET_POINTER_SINCE_VERSION 1 +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + */ +#define WP_CURSOR_SHAPE_MANAGER_V1_GET_TABLET_TOOL_V2_SINCE_VERSION 1 + +/** @ingroup iface_wp_cursor_shape_manager_v1 */ +static inline void +wp_cursor_shape_manager_v1_set_user_data(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_cursor_shape_manager_v1, user_data); +} + +/** @ingroup iface_wp_cursor_shape_manager_v1 */ +static inline void * +wp_cursor_shape_manager_v1_get_user_data(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_cursor_shape_manager_v1); +} + +static inline uint32_t +wp_cursor_shape_manager_v1_get_version(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_manager_v1); +} + +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + * + * Destroy the cursor shape manager. + */ +static inline void +wp_cursor_shape_manager_v1_destroy(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_cursor_shape_manager_v1, + WP_CURSOR_SHAPE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + * + * Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. + * + * When the pointer capability is removed from the wl_seat, the + * wp_cursor_shape_device_v1 object becomes inert. + */ +static inline struct wp_cursor_shape_device_v1 * +wp_cursor_shape_manager_v1_get_pointer(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1, struct wl_pointer *pointer) +{ + struct wl_proxy *cursor_shape_device; + + cursor_shape_device = wl_proxy_marshal_flags((struct wl_proxy *) wp_cursor_shape_manager_v1, + WP_CURSOR_SHAPE_MANAGER_V1_GET_POINTER, &wp_cursor_shape_device_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_manager_v1), 0, NULL, pointer); + + return (struct wp_cursor_shape_device_v1 *) cursor_shape_device; +} + +/** + * @ingroup iface_wp_cursor_shape_manager_v1 + * + * Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. + * + * When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 + * object becomes inert. + */ +static inline struct wp_cursor_shape_device_v1 * +wp_cursor_shape_manager_v1_get_tablet_tool_v2(struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1, struct zwp_tablet_tool_v2 *tablet_tool) +{ + struct wl_proxy *cursor_shape_device; + + cursor_shape_device = wl_proxy_marshal_flags((struct wl_proxy *) wp_cursor_shape_manager_v1, + WP_CURSOR_SHAPE_MANAGER_V1_GET_TABLET_TOOL_V2, &wp_cursor_shape_device_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_manager_v1), 0, NULL, tablet_tool); + + return (struct wp_cursor_shape_device_v1 *) cursor_shape_device; +} + +#ifndef WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM +/** + * @ingroup iface_wp_cursor_shape_device_v1 + * cursor shapes + * + * This enum describes cursor shapes. + * + * The names are taken from the CSS W3C specification: + * https://w3c.github.io/csswg-drafts/css-ui/#cursor + * with a few additions. + * + * Note that there are some groups of cursor shapes that are related: + * The first group is drag-and-drop cursors which are used to indicate + * the selected action during dnd operations. The second group is resize + * cursors which are used to indicate resizing and moving possibilities + * on window borders. It is recommended that the shapes in these groups + * should use visually compatible images and metaphors. + */ +enum wp_cursor_shape_device_v1_shape { + /** + * default cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT = 1, + /** + * a context menu is available for the object under the cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU = 2, + /** + * help is available for the object under the cursor + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP = 3, + /** + * pointer that indicates a link or another interactive element + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER = 4, + /** + * progress indicator + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS = 5, + /** + * program is busy, user should wait + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT = 6, + /** + * a cell or set of cells may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL = 7, + /** + * simple crosshair + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR = 8, + /** + * text may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT = 9, + /** + * vertical text may be selected + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT = 10, + /** + * drag-and-drop: alias of/shortcut to something is to be created + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS = 11, + /** + * drag-and-drop: something is to be copied + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY = 12, + /** + * drag-and-drop: something is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE = 13, + /** + * drag-and-drop: the dragged item cannot be dropped at the current cursor location + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP = 14, + /** + * drag-and-drop: the requested action will not be carried out + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED = 15, + /** + * drag-and-drop: something can be grabbed + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB = 16, + /** + * drag-and-drop: something is being grabbed + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING = 17, + /** + * resizing: the east border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE = 18, + /** + * resizing: the north border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE = 19, + /** + * resizing: the north-east corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE = 20, + /** + * resizing: the north-west corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE = 21, + /** + * resizing: the south border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE = 22, + /** + * resizing: the south-east corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE = 23, + /** + * resizing: the south-west corner is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE = 24, + /** + * resizing: the west border is to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE = 25, + /** + * resizing: the east and west borders are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE = 26, + /** + * resizing: the north and south borders are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE = 27, + /** + * resizing: the north-east and south-west corners are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE = 28, + /** + * resizing: the north-west and south-east corners are to be moved + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE = 29, + /** + * resizing: that the item/column can be resized horizontally + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE = 30, + /** + * resizing: that the item/row can be resized vertically + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE = 31, + /** + * something can be scrolled in any direction + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL = 32, + /** + * something can be zoomed in + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN = 33, + /** + * something can be zoomed out + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT = 34, + /** + * drag-and-drop: the user will select which action will be carried out (non-css value) + * @since 2 + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK = 35, + /** + * resizing: something can be moved or resized in any direction (non-css value) + * @since 2 + */ + WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE = 36, +}; +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK_SINCE_VERSION 2 +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE_SINCE_VERSION 2 +#endif /* WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM */ + +#ifndef WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM +#define WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM +enum wp_cursor_shape_device_v1_error { + /** + * the specified shape value is invalid + */ + WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE = 1, +}; +#endif /* WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM */ + +#define WP_CURSOR_SHAPE_DEVICE_V1_DESTROY 0 +#define WP_CURSOR_SHAPE_DEVICE_V1_SET_SHAPE 1 + + +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_cursor_shape_device_v1 + */ +#define WP_CURSOR_SHAPE_DEVICE_V1_SET_SHAPE_SINCE_VERSION 1 + +/** @ingroup iface_wp_cursor_shape_device_v1 */ +static inline void +wp_cursor_shape_device_v1_set_user_data(struct wp_cursor_shape_device_v1 *wp_cursor_shape_device_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_cursor_shape_device_v1, user_data); +} + +/** @ingroup iface_wp_cursor_shape_device_v1 */ +static inline void * +wp_cursor_shape_device_v1_get_user_data(struct wp_cursor_shape_device_v1 *wp_cursor_shape_device_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_cursor_shape_device_v1); +} + +static inline uint32_t +wp_cursor_shape_device_v1_get_version(struct wp_cursor_shape_device_v1 *wp_cursor_shape_device_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_device_v1); +} + +/** + * @ingroup iface_wp_cursor_shape_device_v1 + * + * Destroy the cursor shape device. + * + * The device cursor shape remains unchanged. + */ +static inline void +wp_cursor_shape_device_v1_destroy(struct wp_cursor_shape_device_v1 *wp_cursor_shape_device_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_cursor_shape_device_v1, + WP_CURSOR_SHAPE_DEVICE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_device_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_cursor_shape_device_v1 + * + * Sets the device cursor to the specified shape. The compositor will + * change the cursor image based on the specified shape. + * + * The cursor actually changes only if the input device focus is one of + * the requesting client's surfaces. If any, the previous cursor image + * (surface or shape) is replaced. + * + * The "shape" argument must be a valid enum entry, otherwise the + * invalid_shape protocol error is raised. + * + * This is similar to the wl_pointer.set_cursor and + * zwp_tablet_tool_v2.set_cursor requests, but this request accepts a + * shape instead of contents in the form of a surface. Clients can mix + * set_cursor and set_shape requests. + * + * The serial parameter must match the latest wl_pointer.enter or + * zwp_tablet_tool_v2.proximity_in serial number sent to the client. + * Otherwise the request will be ignored. + */ +static inline void +wp_cursor_shape_device_v1_set_shape(struct wp_cursor_shape_device_v1 *wp_cursor_shape_device_v1, uint32_t serial, uint32_t shape) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_cursor_shape_device_v1, + WP_CURSOR_SHAPE_DEVICE_V1_SET_SHAPE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_cursor_shape_device_v1), 0, serial, shape); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/cursor-shape-v1-protocol.c b/src/wayland/protocols/cursor-shape-v1-protocol.c new file mode 100644 index 0000000..c76190d --- /dev/null +++ b/src/wayland/protocols/cursor-shape-v1-protocol.c @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright 2018 The Chromium Authors + * Copyright 2023 Simon Ser + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_pointer_interface; +extern const struct wl_interface wp_cursor_shape_device_v1_interface; +extern const struct wl_interface zwp_tablet_tool_v2_interface; + +static const struct wl_interface *cursor_shape_v1_types[] = { + NULL, + NULL, + &wp_cursor_shape_device_v1_interface, + &wl_pointer_interface, + &wp_cursor_shape_device_v1_interface, + &zwp_tablet_tool_v2_interface, +}; + +static const struct wl_message wp_cursor_shape_manager_v1_requests[] = { + { "destroy", "", cursor_shape_v1_types + 0 }, + { "get_pointer", "no", cursor_shape_v1_types + 2 }, + { "get_tablet_tool_v2", "no", cursor_shape_v1_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface wp_cursor_shape_manager_v1_interface = { + "wp_cursor_shape_manager_v1", 2, + 3, wp_cursor_shape_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_cursor_shape_device_v1_requests[] = { + { "destroy", "", cursor_shape_v1_types + 0 }, + { "set_shape", "uu", cursor_shape_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_cursor_shape_device_v1_interface = { + "wp_cursor_shape_device_v1", 2, + 2, wp_cursor_shape_device_v1_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/fifo-v1-client-protocol.h b/src/wayland/protocols/fifo-v1-client-protocol.h new file mode 100644 index 0000000..8c2eeec --- /dev/null +++ b/src/wayland/protocols/fifo-v1-client-protocol.h @@ -0,0 +1,323 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef FIFO_V1_CLIENT_PROTOCOL_H +#define FIFO_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_fifo_v1 The fifo_v1 protocol + * @section page_ifaces_fifo_v1 Interfaces + * - @subpage page_iface_wp_fifo_manager_v1 - protocol for fifo constraints + * - @subpage page_iface_wp_fifo_v1 - fifo interface + * @section page_copyright_fifo_v1 Copyright + *
+ *
+ * Copyright © 2023 Valve Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_fifo_manager_v1; +struct wp_fifo_v1; + +#ifndef WP_FIFO_MANAGER_V1_INTERFACE +#define WP_FIFO_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_fifo_manager_v1 wp_fifo_manager_v1 + * @section page_iface_wp_fifo_manager_v1_desc Description + * + * When a Wayland compositor considers applying a content update, + * it must ensure all the update's readiness constraints (fences, etc) + * are met. + * + * This protocol provides a way to use the completion of a display refresh + * cycle as an additional readiness constraint. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_wp_fifo_manager_v1_api API + * See @ref iface_wp_fifo_manager_v1. + */ +/** + * @defgroup iface_wp_fifo_manager_v1 The wp_fifo_manager_v1 interface + * + * When a Wayland compositor considers applying a content update, + * it must ensure all the update's readiness constraints (fences, etc) + * are met. + * + * This protocol provides a way to use the completion of a display refresh + * cycle as an additional readiness constraint. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface wp_fifo_manager_v1_interface; +#endif +#ifndef WP_FIFO_V1_INTERFACE +#define WP_FIFO_V1_INTERFACE +/** + * @page page_iface_wp_fifo_v1 wp_fifo_v1 + * @section page_iface_wp_fifo_v1_desc Description + * + * A fifo object for a surface that may be used to add + * display refresh constraints to content updates. + * @section page_iface_wp_fifo_v1_api API + * See @ref iface_wp_fifo_v1. + */ +/** + * @defgroup iface_wp_fifo_v1 The wp_fifo_v1 interface + * + * A fifo object for a surface that may be used to add + * display refresh constraints to content updates. + */ +extern const struct wl_interface wp_fifo_v1_interface; +#endif + +#ifndef WP_FIFO_MANAGER_V1_ERROR_ENUM +#define WP_FIFO_MANAGER_V1_ERROR_ENUM +/** + * @ingroup iface_wp_fifo_manager_v1 + * fatal presentation error + * + * These fatal protocol errors may be emitted in response to + * illegal requests. + */ +enum wp_fifo_manager_v1_error { + /** + * fifo manager already exists for surface + */ + WP_FIFO_MANAGER_V1_ERROR_ALREADY_EXISTS = 0, +}; +#endif /* WP_FIFO_MANAGER_V1_ERROR_ENUM */ + +#define WP_FIFO_MANAGER_V1_DESTROY 0 +#define WP_FIFO_MANAGER_V1_GET_FIFO 1 + + +/** + * @ingroup iface_wp_fifo_manager_v1 + */ +#define WP_FIFO_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_fifo_manager_v1 + */ +#define WP_FIFO_MANAGER_V1_GET_FIFO_SINCE_VERSION 1 + +/** @ingroup iface_wp_fifo_manager_v1 */ +static inline void +wp_fifo_manager_v1_set_user_data(struct wp_fifo_manager_v1 *wp_fifo_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fifo_manager_v1, user_data); +} + +/** @ingroup iface_wp_fifo_manager_v1 */ +static inline void * +wp_fifo_manager_v1_get_user_data(struct wp_fifo_manager_v1 *wp_fifo_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fifo_manager_v1); +} + +static inline uint32_t +wp_fifo_manager_v1_get_version(struct wp_fifo_manager_v1 *wp_fifo_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fifo_manager_v1); +} + +/** + * @ingroup iface_wp_fifo_manager_v1 + * + * Informs the server that the client will no longer be using + * this protocol object. Existing objects created by this object + * are not affected. + */ +static inline void +wp_fifo_manager_v1_destroy(struct wp_fifo_manager_v1 *wp_fifo_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fifo_manager_v1, + WP_FIFO_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fifo_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_fifo_manager_v1 + * + * Establish a fifo object for a surface that may be used to add + * display refresh constraints to content updates. + * + * Only one such object may exist for a surface and attempting + * to create more than one will result in an already_exists + * protocol error. If a surface is acted on by multiple software + * components, general best practice is that only the component + * performing wl_surface.attach operations should use this protocol. + */ +static inline struct wp_fifo_v1 * +wp_fifo_manager_v1_get_fifo(struct wp_fifo_manager_v1 *wp_fifo_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_fifo_manager_v1, + WP_FIFO_MANAGER_V1_GET_FIFO, &wp_fifo_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_fifo_manager_v1), 0, NULL, surface); + + return (struct wp_fifo_v1 *) id; +} + +#ifndef WP_FIFO_V1_ERROR_ENUM +#define WP_FIFO_V1_ERROR_ENUM +/** + * @ingroup iface_wp_fifo_v1 + * fatal error + * + * These fatal protocol errors may be emitted in response to + * illegal requests. + */ +enum wp_fifo_v1_error { + /** + * the associated surface no longer exists + */ + WP_FIFO_V1_ERROR_SURFACE_DESTROYED = 0, +}; +#endif /* WP_FIFO_V1_ERROR_ENUM */ + +#define WP_FIFO_V1_SET_BARRIER 0 +#define WP_FIFO_V1_WAIT_BARRIER 1 +#define WP_FIFO_V1_DESTROY 2 + + +/** + * @ingroup iface_wp_fifo_v1 + */ +#define WP_FIFO_V1_SET_BARRIER_SINCE_VERSION 1 +/** + * @ingroup iface_wp_fifo_v1 + */ +#define WP_FIFO_V1_WAIT_BARRIER_SINCE_VERSION 1 +/** + * @ingroup iface_wp_fifo_v1 + */ +#define WP_FIFO_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_fifo_v1 */ +static inline void +wp_fifo_v1_set_user_data(struct wp_fifo_v1 *wp_fifo_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fifo_v1, user_data); +} + +/** @ingroup iface_wp_fifo_v1 */ +static inline void * +wp_fifo_v1_get_user_data(struct wp_fifo_v1 *wp_fifo_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fifo_v1); +} + +static inline uint32_t +wp_fifo_v1_get_version(struct wp_fifo_v1 *wp_fifo_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fifo_v1); +} + +/** + * @ingroup iface_wp_fifo_v1 + * + * When the content update containing the "set_barrier" is applied, + * it sets a "fifo_barrier" condition on the surface associated with + * the fifo object. The condition is cleared immediately after the + * following latching deadline for non-tearing presentation. + * + * The compositor may clear the condition early if it must do so to + * ensure client forward progress assumptions. + * + * To wait for this condition to clear, use the "wait_barrier" request. + * + * "set_barrier" is double-buffered state, see wl_surface.commit. + * + * Requesting set_barrier after the fifo object's surface is + * destroyed will generate a "surface_destroyed" error. + */ +static inline void +wp_fifo_v1_set_barrier(struct wp_fifo_v1 *wp_fifo_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fifo_v1, + WP_FIFO_V1_SET_BARRIER, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fifo_v1), 0); +} + +/** + * @ingroup iface_wp_fifo_v1 + * + * Indicate that this content update is not ready while a + * "fifo_barrier" condition is present on the surface. + * + * This means that when the content update containing "set_barrier" + * was made active at a latching deadline, it will be active for + * at least one refresh cycle. A content update which is allowed to + * tear might become active after a latching deadline if no content + * update became active at the deadline. + * + * The constraint must be ignored if the surface is a subsurface in + * synchronized mode. If the surface is not being updated by the + * compositor (off-screen, occluded) the compositor may ignore the + * constraint. Clients must use an additional mechanism such as + * frame callbacks or timestamps to ensure throttling occurs under + * all conditions. + * + * "wait_barrier" is double-buffered state, see wl_surface.commit. + * + * Requesting "wait_barrier" after the fifo object's surface is + * destroyed will generate a "surface_destroyed" error. + */ +static inline void +wp_fifo_v1_wait_barrier(struct wp_fifo_v1 *wp_fifo_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fifo_v1, + WP_FIFO_V1_WAIT_BARRIER, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fifo_v1), 0); +} + +/** + * @ingroup iface_wp_fifo_v1 + * + * Informs the server that the client will no longer be using + * this protocol object. + * + * Surface state changes previously made by this protocol are + * unaffected by this object's destruction. + */ +static inline void +wp_fifo_v1_destroy(struct wp_fifo_v1 *wp_fifo_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fifo_v1, + WP_FIFO_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fifo_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/fifo-v1-protocol.c b/src/wayland/protocols/fifo-v1-protocol.c new file mode 100644 index 0000000..5c31da3 --- /dev/null +++ b/src/wayland/protocols/fifo-v1-protocol.c @@ -0,0 +1,71 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2023 Valve Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_fifo_v1_interface; + +static const struct wl_interface *fifo_v1_types[] = { + &wp_fifo_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_fifo_manager_v1_requests[] = { + { "destroy", "", fifo_v1_types + 0 }, + { "get_fifo", "no", fifo_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_fifo_manager_v1_interface = { + "wp_fifo_manager_v1", 1, + 2, wp_fifo_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_fifo_v1_requests[] = { + { "set_barrier", "", fifo_v1_types + 0 }, + { "wait_barrier", "", fifo_v1_types + 0 }, + { "destroy", "", fifo_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_fifo_v1_interface = { + "wp_fifo_v1", 1, + 3, wp_fifo_v1_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/fractional-scale-v1-client-protocol.h b/src/wayland/protocols/fractional-scale-v1-client-protocol.h new file mode 100644 index 0000000..65adbd0 --- /dev/null +++ b/src/wayland/protocols/fractional-scale-v1-client-protocol.h @@ -0,0 +1,264 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H +#define FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_fractional_scale_v1 The fractional_scale_v1 protocol + * Protocol for requesting fractional surface scales + * + * @section page_desc_fractional_scale_v1 Description + * + * This protocol allows a compositor to suggest for surfaces to render at + * fractional scales. + * + * A client can submit scaled content by utilizing wp_viewport. This is done by + * creating a wp_viewport object for the surface and setting the destination + * rectangle to the surface size before the scale factor is applied. + * + * The buffer size is calculated by multiplying the surface size by the + * intended scale. + * + * The wl_surface buffer scale should remain set to 1. + * + * If a surface has a surface-local size of 100 px by 50 px and wishes to + * submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + * be used and the wp_viewport destination rectangle should be 100 px by 50 px. + * + * For toplevel surfaces, the size is rounded halfway away from zero. The + * rounding algorithm for subsurface position and size is not defined. + * + * @section page_ifaces_fractional_scale_v1 Interfaces + * - @subpage page_iface_wp_fractional_scale_manager_v1 - fractional surface scale information + * - @subpage page_iface_wp_fractional_scale_v1 - fractional scale interface to a wl_surface + * @section page_copyright_fractional_scale_v1 Copyright + *
+ *
+ * Copyright © 2022 Kenny Levinsen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_fractional_scale_manager_v1; +struct wp_fractional_scale_v1; + +#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE +#define WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_fractional_scale_manager_v1 wp_fractional_scale_manager_v1 + * @section page_iface_wp_fractional_scale_manager_v1_desc Description + * + * A global interface for requesting surfaces to use fractional scales. + * @section page_iface_wp_fractional_scale_manager_v1_api API + * See @ref iface_wp_fractional_scale_manager_v1. + */ +/** + * @defgroup iface_wp_fractional_scale_manager_v1 The wp_fractional_scale_manager_v1 interface + * + * A global interface for requesting surfaces to use fractional scales. + */ +extern const struct wl_interface wp_fractional_scale_manager_v1_interface; +#endif +#ifndef WP_FRACTIONAL_SCALE_V1_INTERFACE +#define WP_FRACTIONAL_SCALE_V1_INTERFACE +/** + * @page page_iface_wp_fractional_scale_v1 wp_fractional_scale_v1 + * @section page_iface_wp_fractional_scale_v1_desc Description + * + * An additional interface to a wl_surface object which allows the compositor + * to inform the client of the preferred scale. + * @section page_iface_wp_fractional_scale_v1_api API + * See @ref iface_wp_fractional_scale_v1. + */ +/** + * @defgroup iface_wp_fractional_scale_v1 The wp_fractional_scale_v1 interface + * + * An additional interface to a wl_surface object which allows the compositor + * to inform the client of the preferred scale. + */ +extern const struct wl_interface wp_fractional_scale_v1_interface; +#endif + +#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM +#define WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM +enum wp_fractional_scale_manager_v1_error { + /** + * the surface already has a fractional_scale object associated + */ + WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS = 0, +}; +#endif /* WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM */ + +#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY 0 +#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE 1 + + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + */ +#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + */ +#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE_SINCE_VERSION 1 + +/** @ingroup iface_wp_fractional_scale_manager_v1 */ +static inline void +wp_fractional_scale_manager_v1_set_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1, user_data); +} + +/** @ingroup iface_wp_fractional_scale_manager_v1 */ +static inline void * +wp_fractional_scale_manager_v1_get_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1); +} + +static inline uint32_t +wp_fractional_scale_manager_v1_get_version(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1); +} + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + * + * Informs the server that the client will not be using this protocol + * object anymore. This does not affect any other objects, + * wp_fractional_scale_v1 objects included. + */ +static inline void +wp_fractional_scale_manager_v1_destroy(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, + WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + * + * Create an add-on object for the the wl_surface to let the compositor + * request fractional scales. If the given wl_surface already has a + * wp_fractional_scale_v1 object associated, the fractional_scale_exists + * protocol error is raised. + */ +static inline struct wp_fractional_scale_v1 * +wp_fractional_scale_manager_v1_get_fractional_scale(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, + WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE, &wp_fractional_scale_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), 0, NULL, surface); + + return (struct wp_fractional_scale_v1 *) id; +} + +/** + * @ingroup iface_wp_fractional_scale_v1 + * @struct wp_fractional_scale_v1_listener + */ +struct wp_fractional_scale_v1_listener { + /** + * notify of new preferred scale + * + * Notification of a new preferred scale for this surface that + * the compositor suggests that the client should use. + * + * The sent scale is the numerator of a fraction with a denominator + * of 120. + * @param scale the new preferred scale + */ + void (*preferred_scale)(void *data, + struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + uint32_t scale); +}; + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +static inline int +wp_fractional_scale_v1_add_listener(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + const struct wp_fractional_scale_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_fractional_scale_v1, + (void (**)(void)) listener, data); +} + +#define WP_FRACTIONAL_SCALE_V1_DESTROY 0 + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +#define WP_FRACTIONAL_SCALE_V1_PREFERRED_SCALE_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +#define WP_FRACTIONAL_SCALE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_fractional_scale_v1 */ +static inline void +wp_fractional_scale_v1_set_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_v1, user_data); +} + +/** @ingroup iface_wp_fractional_scale_v1 */ +static inline void * +wp_fractional_scale_v1_get_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_v1); +} + +static inline uint32_t +wp_fractional_scale_v1_get_version(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1); +} + +/** + * @ingroup iface_wp_fractional_scale_v1 + * + * Destroy the fractional scale object. When this object is destroyed, + * preferred_scale events will no longer be sent. + */ +static inline void +wp_fractional_scale_v1_destroy(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_v1, + WP_FRACTIONAL_SCALE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/fractional-scale-v1-protocol.c b/src/wayland/protocols/fractional-scale-v1-protocol.c new file mode 100644 index 0000000..b8c1a63 --- /dev/null +++ b/src/wayland/protocols/fractional-scale-v1-protocol.c @@ -0,0 +1,74 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2022 Kenny Levinsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_fractional_scale_v1_interface; + +static const struct wl_interface *fractional_scale_v1_types[] = { + NULL, + &wp_fractional_scale_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_fractional_scale_manager_v1_requests[] = { + { "destroy", "", fractional_scale_v1_types + 0 }, + { "get_fractional_scale", "no", fractional_scale_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface wp_fractional_scale_manager_v1_interface = { + "wp_fractional_scale_manager_v1", 1, + 2, wp_fractional_scale_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_fractional_scale_v1_requests[] = { + { "destroy", "", fractional_scale_v1_types + 0 }, +}; + +static const struct wl_message wp_fractional_scale_v1_events[] = { + { "preferred_scale", "u", fractional_scale_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_fractional_scale_v1_interface = { + "wp_fractional_scale_v1", 1, + 1, wp_fractional_scale_v1_requests, + 1, wp_fractional_scale_v1_events, +}; + diff --git a/src/wayland/protocols/meson.build b/src/wayland/protocols/meson.build new file mode 100644 index 0000000..6e20a6c --- /dev/null +++ b/src/wayland/protocols/meson.build @@ -0,0 +1,15 @@ +wl_protocol_src = files( + 'xdg-shell-protocol.c', + 'xdg-decoration-protocol.c', + 'cursor-shape-v1-protocol.c', + 'fractional-scale-v1-protocol.c', + 'viewporter-protocol.c', + 'tablet-v2-protocol.c', + 'text-input-unstable-v3-protocol.c', + 'tearing-control-v1-protocol.c', + 'presentation-time-protocol.c', + 'xdg-toplevel-drag-v1-protocol.c', + 'fifo-v1-protocol.c', + 'commit-timing-v1-protocol.c', + 'primary-selection-unstable-v1-protocol.c', +) diff --git a/src/wayland/protocols/presentation-time-client-protocol.h b/src/wayland/protocols/presentation-time-client-protocol.h new file mode 100644 index 0000000..720027d --- /dev/null +++ b/src/wayland/protocols/presentation-time-client-protocol.h @@ -0,0 +1,498 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef PRESENTATION_TIME_CLIENT_PROTOCOL_H +#define PRESENTATION_TIME_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_presentation_time The presentation_time protocol + * @section page_ifaces_presentation_time Interfaces + * - @subpage page_iface_wp_presentation - timed presentation related wl_surface requests + * - @subpage page_iface_wp_presentation_feedback - presentation time feedback event + * @section page_copyright_presentation_time Copyright + *
+ *
+ * Copyright © 2013-2014 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_surface; +struct wp_presentation; +struct wp_presentation_feedback; + +#ifndef WP_PRESENTATION_INTERFACE +#define WP_PRESENTATION_INTERFACE +/** + * @page page_iface_wp_presentation wp_presentation + * @section page_iface_wp_presentation_desc Description + * + * + * + * + * The main feature of this interface is accurate presentation + * timing feedback to ensure smooth video playback while maintaining + * audio/video synchronization. Some features use the concept of a + * presentation clock, which is defined in the + * presentation.clock_id event. + * + * A content update for a wl_surface is submitted by a + * wl_surface.commit request. Request 'feedback' associates with + * the wl_surface.commit and provides feedback on the content + * update, particularly the final realized presentation time. + * + * + * + * When the final realized presentation time is available, e.g. + * after a framebuffer flip completes, the requested + * presentation_feedback.presented events are sent. The final + * presentation time can differ from the compositor's predicted + * display update time and the update's target time, especially + * when the compositor misses its target vertical blanking period. + * @section page_iface_wp_presentation_api API + * See @ref iface_wp_presentation. + */ +/** + * @defgroup iface_wp_presentation The wp_presentation interface + * + * + * + * + * The main feature of this interface is accurate presentation + * timing feedback to ensure smooth video playback while maintaining + * audio/video synchronization. Some features use the concept of a + * presentation clock, which is defined in the + * presentation.clock_id event. + * + * A content update for a wl_surface is submitted by a + * wl_surface.commit request. Request 'feedback' associates with + * the wl_surface.commit and provides feedback on the content + * update, particularly the final realized presentation time. + * + * + * + * When the final realized presentation time is available, e.g. + * after a framebuffer flip completes, the requested + * presentation_feedback.presented events are sent. The final + * presentation time can differ from the compositor's predicted + * display update time and the update's target time, especially + * when the compositor misses its target vertical blanking period. + */ +extern const struct wl_interface wp_presentation_interface; +#endif +#ifndef WP_PRESENTATION_FEEDBACK_INTERFACE +#define WP_PRESENTATION_FEEDBACK_INTERFACE +/** + * @page page_iface_wp_presentation_feedback wp_presentation_feedback + * @section page_iface_wp_presentation_feedback_desc Description + * + * A presentation_feedback object returns an indication that a + * wl_surface content update has become visible to the user. + * One object corresponds to one content update submission + * (wl_surface.commit). There are two possible outcomes: the + * content update is presented to the user, and a presentation + * timestamp delivered; or, the user did not see the content + * update because it was superseded or its surface destroyed, + * and the content update is discarded. + * + * Once a presentation_feedback object has delivered a 'presented' + * or 'discarded' event it is automatically destroyed. + * @section page_iface_wp_presentation_feedback_api API + * See @ref iface_wp_presentation_feedback. + */ +/** + * @defgroup iface_wp_presentation_feedback The wp_presentation_feedback interface + * + * A presentation_feedback object returns an indication that a + * wl_surface content update has become visible to the user. + * One object corresponds to one content update submission + * (wl_surface.commit). There are two possible outcomes: the + * content update is presented to the user, and a presentation + * timestamp delivered; or, the user did not see the content + * update because it was superseded or its surface destroyed, + * and the content update is discarded. + * + * Once a presentation_feedback object has delivered a 'presented' + * or 'discarded' event it is automatically destroyed. + */ +extern const struct wl_interface wp_presentation_feedback_interface; +#endif + +#ifndef WP_PRESENTATION_ERROR_ENUM +#define WP_PRESENTATION_ERROR_ENUM +/** + * @ingroup iface_wp_presentation + * fatal presentation errors + * + * These fatal protocol errors may be emitted in response to + * illegal presentation requests. + */ +enum wp_presentation_error { + /** + * invalid value in tv_nsec + */ + WP_PRESENTATION_ERROR_INVALID_TIMESTAMP = 0, + /** + * invalid flag + */ + WP_PRESENTATION_ERROR_INVALID_FLAG = 1, +}; +#endif /* WP_PRESENTATION_ERROR_ENUM */ + +/** + * @ingroup iface_wp_presentation + * @struct wp_presentation_listener + */ +struct wp_presentation_listener { + /** + * clock ID for timestamps + * + * This event tells the client in which clock domain the + * compositor interprets the timestamps used by the presentation + * extension. This clock is called the presentation clock. + * + * The compositor sends this event when the client binds to the + * presentation interface. The presentation clock does not change + * during the lifetime of the client connection. + * + * The clock identifier is platform dependent. On POSIX platforms, + * the identifier value is one of the clockid_t values accepted by + * clock_gettime(). clock_gettime() is defined by POSIX.1-2001. + * + * Timestamps in this clock domain are expressed as tv_sec_hi, + * tv_sec_lo, tv_nsec triples, each component being an unsigned + * 32-bit value. Whole seconds are in tv_sec which is a 64-bit + * value combined from tv_sec_hi and tv_sec_lo, and the additional + * fractional part in tv_nsec as nanoseconds. Hence, for valid + * timestamps tv_nsec must be in [0, 999999999]. + * + * Note that clock_id applies only to the presentation clock, and + * implies nothing about e.g. the timestamps used in the Wayland + * core protocol input events. + * + * Compositors should prefer a clock which does not jump and is not + * slewed e.g. by NTP. The absolute value of the clock is + * irrelevant. Precision of one millisecond or better is + * recommended. Clients must be able to query the current clock + * value directly, not by asking the compositor. + * @param clk_id platform clock identifier + */ + void (*clock_id)(void *data, + struct wp_presentation *wp_presentation, + uint32_t clk_id); +}; + +/** + * @ingroup iface_wp_presentation + */ +static inline int +wp_presentation_add_listener(struct wp_presentation *wp_presentation, + const struct wp_presentation_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_presentation, + (void (**)(void)) listener, data); +} + +#define WP_PRESENTATION_DESTROY 0 +#define WP_PRESENTATION_FEEDBACK 1 + +/** + * @ingroup iface_wp_presentation + */ +#define WP_PRESENTATION_CLOCK_ID_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_presentation + */ +#define WP_PRESENTATION_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_presentation + */ +#define WP_PRESENTATION_FEEDBACK_SINCE_VERSION 1 + +/** @ingroup iface_wp_presentation */ +static inline void +wp_presentation_set_user_data(struct wp_presentation *wp_presentation, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_presentation, user_data); +} + +/** @ingroup iface_wp_presentation */ +static inline void * +wp_presentation_get_user_data(struct wp_presentation *wp_presentation) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_presentation); +} + +static inline uint32_t +wp_presentation_get_version(struct wp_presentation *wp_presentation) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_presentation); +} + +/** + * @ingroup iface_wp_presentation + * + * Informs the server that the client will no longer be using + * this protocol object. Existing objects created by this object + * are not affected. + */ +static inline void +wp_presentation_destroy(struct wp_presentation *wp_presentation) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_presentation, + WP_PRESENTATION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_presentation), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_presentation + * + * Request presentation feedback for the current content submission + * on the given surface. This creates a new presentation_feedback + * object, which will deliver the feedback information once. If + * multiple presentation_feedback objects are created for the same + * submission, they will all deliver the same information. + * + * For details on what information is returned, see the + * presentation_feedback interface. + */ +static inline struct wp_presentation_feedback * +wp_presentation_feedback(struct wp_presentation *wp_presentation, struct wl_surface *surface) +{ + struct wl_proxy *callback; + + callback = wl_proxy_marshal_flags((struct wl_proxy *) wp_presentation, + WP_PRESENTATION_FEEDBACK, &wp_presentation_feedback_interface, wl_proxy_get_version((struct wl_proxy *) wp_presentation), 0, surface, NULL); + + return (struct wp_presentation_feedback *) callback; +} + +#ifndef WP_PRESENTATION_FEEDBACK_KIND_ENUM +#define WP_PRESENTATION_FEEDBACK_KIND_ENUM +/** + * @ingroup iface_wp_presentation_feedback + * bitmask of flags in presented event + * + * These flags provide information about how the presentation of + * the related content update was done. The intent is to help + * clients assess the reliability of the feedback and the visual + * quality with respect to possible tearing and timings. + */ +enum wp_presentation_feedback_kind { + /** + * presentation was vsync'd + * + * The presentation was synchronized to the "vertical retrace" by + * the display hardware such that tearing does not happen. Relying + * on software scheduling is not acceptable for this flag. If + * presentation is done by a copy to the active frontbuffer, then + * it must guarantee that tearing cannot happen. + */ + WP_PRESENTATION_FEEDBACK_KIND_VSYNC = 0x1, + /** + * hardware provided the presentation timestamp + * + * The display hardware provided measurements that the hardware + * driver converted into a presentation timestamp. Sampling a clock + * in software is not acceptable for this flag. + */ + WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK = 0x2, + /** + * hardware signalled the start of the presentation + * + * The display hardware signalled that it started using the new + * image content. The opposite of this is e.g. a timer being used + * to guess when the display hardware has switched to the new image + * content. + */ + WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION = 0x4, + /** + * presentation was done zero-copy + * + * The presentation of this update was done zero-copy. This means + * the buffer from the client was given to display hardware as is, + * without copying it. Compositing with OpenGL counts as copying, + * even if textured directly from the client buffer. Possible + * zero-copy cases include direct scanout of a fullscreen surface + * and a surface on a hardware overlay. + */ + WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY = 0x8, +}; +#endif /* WP_PRESENTATION_FEEDBACK_KIND_ENUM */ + +/** + * @ingroup iface_wp_presentation_feedback + * @struct wp_presentation_feedback_listener + */ +struct wp_presentation_feedback_listener { + /** + * presentation synchronized to this output + * + * As presentation can be synchronized to only one output at a + * time, this event tells which output it was. This event is only + * sent prior to the presented event. + * + * As clients may bind to the same global wl_output multiple times, + * this event is sent for each bound instance that matches the + * synchronized output. If a client has not bound to the right + * wl_output global at all, this event is not sent. + * @param output presentation output + */ + void (*sync_output)(void *data, + struct wp_presentation_feedback *wp_presentation_feedback, + struct wl_output *output); + /** + * the content update was displayed + * + * The associated content update was displayed to the user at the + * indicated time (tv_sec_hi/lo, tv_nsec). For the interpretation + * of the timestamp, see presentation.clock_id event. + * + * The timestamp corresponds to the time when the content update + * turned into light the first time on the surface's main output. + * Compositors may approximate this from the framebuffer flip + * completion events from the system, and the latency of the + * physical display path if known. + * + * This event is preceded by all related sync_output events telling + * which output's refresh cycle the feedback corresponds to, i.e. + * the main output for the surface. Compositors are recommended to + * choose the output containing the largest part of the wl_surface, + * or keeping the output they previously chose. Having a stable + * presentation output association helps clients predict future + * output refreshes (vblank). + * + * The 'refresh' argument gives the compositor's prediction of how + * many nanoseconds after tv_sec, tv_nsec the very next output + * refresh may occur. This is to further aid clients in predicting + * future refreshes, i.e., estimating the timestamps targeting the + * next few vblanks. If such prediction cannot usefully be done, + * the argument is zero. + * + * For version 2 and later, if the output does not have a constant + * refresh rate, explicit video mode switches excluded, then the + * refresh argument must be either an appropriate rate picked by + * the compositor (e.g. fastest rate), or 0 if no such rate exists. + * For version 1, if the output does not have a constant refresh + * rate, the refresh argument must be zero. + * + * The 64-bit value combined from seq_hi and seq_lo is the value of + * the output's vertical retrace counter when the content update + * was first scanned out to the display. This value must be + * compatible with the definition of MSC in GLX_OML_sync_control + * specification. Note, that if the display path has a non-zero + * latency, the time instant specified by this counter may differ + * from the timestamp's. + * + * If the output does not have a concept of vertical retrace or a + * refresh cycle, or the output device is self-refreshing without a + * way to query the refresh count, then the arguments seq_hi and + * seq_lo must be zero. + * @param tv_sec_hi high 32 bits of the seconds part of the presentation timestamp + * @param tv_sec_lo low 32 bits of the seconds part of the presentation timestamp + * @param tv_nsec nanoseconds part of the presentation timestamp + * @param refresh nanoseconds till next refresh + * @param seq_hi high 32 bits of refresh counter + * @param seq_lo low 32 bits of refresh counter + * @param flags combination of 'kind' values + */ + void (*presented)(void *data, + struct wp_presentation_feedback *wp_presentation_feedback, + uint32_t tv_sec_hi, + uint32_t tv_sec_lo, + uint32_t tv_nsec, + uint32_t refresh, + uint32_t seq_hi, + uint32_t seq_lo, + uint32_t flags); + /** + * the content update was not displayed + * + * The content update was never displayed to the user. + */ + void (*discarded)(void *data, + struct wp_presentation_feedback *wp_presentation_feedback); +}; + +/** + * @ingroup iface_wp_presentation_feedback + */ +static inline int +wp_presentation_feedback_add_listener(struct wp_presentation_feedback *wp_presentation_feedback, + const struct wp_presentation_feedback_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_presentation_feedback, + (void (**)(void)) listener, data); +} + +/** + * @ingroup iface_wp_presentation_feedback + */ +#define WP_PRESENTATION_FEEDBACK_SYNC_OUTPUT_SINCE_VERSION 1 +/** + * @ingroup iface_wp_presentation_feedback + */ +#define WP_PRESENTATION_FEEDBACK_PRESENTED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_presentation_feedback + */ +#define WP_PRESENTATION_FEEDBACK_DISCARDED_SINCE_VERSION 1 + + +/** @ingroup iface_wp_presentation_feedback */ +static inline void +wp_presentation_feedback_set_user_data(struct wp_presentation_feedback *wp_presentation_feedback, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_presentation_feedback, user_data); +} + +/** @ingroup iface_wp_presentation_feedback */ +static inline void * +wp_presentation_feedback_get_user_data(struct wp_presentation_feedback *wp_presentation_feedback) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_presentation_feedback); +} + +static inline uint32_t +wp_presentation_feedback_get_version(struct wp_presentation_feedback *wp_presentation_feedback) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_presentation_feedback); +} + +/** @ingroup iface_wp_presentation_feedback */ +static inline void +wp_presentation_feedback_destroy(struct wp_presentation_feedback *wp_presentation_feedback) +{ + wl_proxy_destroy((struct wl_proxy *) wp_presentation_feedback); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/presentation-time-protocol.c b/src/wayland/protocols/presentation-time-protocol.c new file mode 100644 index 0000000..b7eef14 --- /dev/null +++ b/src/wayland/protocols/presentation-time-protocol.c @@ -0,0 +1,84 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2013-2014 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_presentation_feedback_interface; + +static const struct wl_interface *presentation_time_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_surface_interface, + &wp_presentation_feedback_interface, + &wl_output_interface, +}; + +static const struct wl_message wp_presentation_requests[] = { + { "destroy", "", presentation_time_types + 0 }, + { "feedback", "on", presentation_time_types + 7 }, +}; + +static const struct wl_message wp_presentation_events[] = { + { "clock_id", "u", presentation_time_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_presentation_interface = { + "wp_presentation", 2, + 2, wp_presentation_requests, + 1, wp_presentation_events, +}; + +static const struct wl_message wp_presentation_feedback_events[] = { + { "sync_output", "o", presentation_time_types + 9 }, + { "presented", "uuuuuuu", presentation_time_types + 0 }, + { "discarded", "", presentation_time_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_presentation_feedback_interface = { + "wp_presentation_feedback", 2, + 0, NULL, + 3, wp_presentation_feedback_events, +}; + diff --git a/src/wayland/protocols/primary-selection-unstable-v1-client-protocol.h b/src/wayland/protocols/primary-selection-unstable-v1-client-protocol.h new file mode 100644 index 0000000..01dd0e3 --- /dev/null +++ b/src/wayland/protocols/primary-selection-unstable-v1-client-protocol.h @@ -0,0 +1,582 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef WP_PRIMARY_SELECTION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define WP_PRIMARY_SELECTION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wp_primary_selection_unstable_v1 The wp_primary_selection_unstable_v1 protocol + * Primary selection protocol + * + * @section page_desc_wp_primary_selection_unstable_v1 Description + * + * This protocol provides the ability to have a primary selection device to + * match that of the X server. This primary selection is a shortcut to the + * common clipboard selection, where text just needs to be selected in order + * to allow copying it elsewhere. The de facto way to perform this action + * is the middle mouse button, although it is not limited to this one. + * + * Clients wishing to honor primary selection should create a primary + * selection source and set it as the selection through + * wp_primary_selection_device.set_selection whenever the text selection + * changes. In order to minimize calls in pointer-driven text selection, + * it should happen only once after the operation finished. Similarly, + * a NULL source should be set when text is unselected. + * + * wp_primary_selection_offer objects are first announced through the + * wp_primary_selection_device.data_offer event. Immediately after this event, + * the primary data offer will emit wp_primary_selection_offer.offer events + * to let know of the mime types being offered. + * + * When the primary selection changes, the client with the keyboard focus + * will receive wp_primary_selection_device.selection events. Only the client + * with the keyboard focus will receive such events with a non-NULL + * wp_primary_selection_offer. Across keyboard focus changes, previously + * focused clients will receive wp_primary_selection_device.events with a + * NULL wp_primary_selection_offer. + * + * In order to request the primary selection data, the client must pass + * a recent serial pertaining to the press event that is triggering the + * operation, if the compositor deems the serial valid and recent, the + * wp_primary_selection_source.send event will happen in the other end + * to let the transfer begin. The client owning the primary selection + * should write the requested data, and close the file descriptor + * immediately. + * + * If the primary selection owner client disappeared during the transfer, + * the client reading the data will receive a + * wp_primary_selection_device.selection event with a NULL + * wp_primary_selection_offer, the client should take this as a hint + * to finish the reads related to the no longer existing offer. + * + * The primary selection owner should be checking for errors during + * writes, merely cancelling the ongoing transfer if any happened. + * + * @section page_ifaces_wp_primary_selection_unstable_v1 Interfaces + * - @subpage page_iface_zwp_primary_selection_device_manager_v1 - X primary selection emulation + * - @subpage page_iface_zwp_primary_selection_device_v1 - + * - @subpage page_iface_zwp_primary_selection_offer_v1 - offer to transfer primary selection contents + * - @subpage page_iface_zwp_primary_selection_source_v1 - offer to replace the contents of the primary selection + * @section page_copyright_wp_primary_selection_unstable_v1 Copyright + *
+ *
+ * Copyright © 2015, 2016 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_seat; +struct zwp_primary_selection_device_manager_v1; +struct zwp_primary_selection_device_v1; +struct zwp_primary_selection_offer_v1; +struct zwp_primary_selection_source_v1; + +#ifndef ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_INTERFACE +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_INTERFACE +/** + * @page page_iface_zwp_primary_selection_device_manager_v1 zwp_primary_selection_device_manager_v1 + * @section page_iface_zwp_primary_selection_device_manager_v1_desc Description + * + * The primary selection device manager is a singleton global object that + * provides access to the primary selection. It allows to create + * wp_primary_selection_source objects, as well as retrieving the per-seat + * wp_primary_selection_device objects. + * @section page_iface_zwp_primary_selection_device_manager_v1_api API + * See @ref iface_zwp_primary_selection_device_manager_v1. + */ +/** + * @defgroup iface_zwp_primary_selection_device_manager_v1 The zwp_primary_selection_device_manager_v1 interface + * + * The primary selection device manager is a singleton global object that + * provides access to the primary selection. It allows to create + * wp_primary_selection_source objects, as well as retrieving the per-seat + * wp_primary_selection_device objects. + */ +extern const struct wl_interface zwp_primary_selection_device_manager_v1_interface; +#endif +#ifndef ZWP_PRIMARY_SELECTION_DEVICE_V1_INTERFACE +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_INTERFACE +/** + * @page page_iface_zwp_primary_selection_device_v1 zwp_primary_selection_device_v1 + * @section page_iface_zwp_primary_selection_device_v1_api API + * See @ref iface_zwp_primary_selection_device_v1. + */ +/** + * @defgroup iface_zwp_primary_selection_device_v1 The zwp_primary_selection_device_v1 interface + */ +extern const struct wl_interface zwp_primary_selection_device_v1_interface; +#endif +#ifndef ZWP_PRIMARY_SELECTION_OFFER_V1_INTERFACE +#define ZWP_PRIMARY_SELECTION_OFFER_V1_INTERFACE +/** + * @page page_iface_zwp_primary_selection_offer_v1 zwp_primary_selection_offer_v1 + * @section page_iface_zwp_primary_selection_offer_v1_desc Description + * + * A wp_primary_selection_offer represents an offer to transfer the contents + * of the primary selection clipboard to the client. Similar to + * wl_data_offer, the offer also describes the mime types that the data can + * be converted to and provides the mechanisms for transferring the data + * directly to the client. + * @section page_iface_zwp_primary_selection_offer_v1_api API + * See @ref iface_zwp_primary_selection_offer_v1. + */ +/** + * @defgroup iface_zwp_primary_selection_offer_v1 The zwp_primary_selection_offer_v1 interface + * + * A wp_primary_selection_offer represents an offer to transfer the contents + * of the primary selection clipboard to the client. Similar to + * wl_data_offer, the offer also describes the mime types that the data can + * be converted to and provides the mechanisms for transferring the data + * directly to the client. + */ +extern const struct wl_interface zwp_primary_selection_offer_v1_interface; +#endif +#ifndef ZWP_PRIMARY_SELECTION_SOURCE_V1_INTERFACE +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_INTERFACE +/** + * @page page_iface_zwp_primary_selection_source_v1 zwp_primary_selection_source_v1 + * @section page_iface_zwp_primary_selection_source_v1_desc Description + * + * The source side of a wp_primary_selection_offer, it provides a way to + * describe the offered data and respond to requests to transfer the + * requested contents of the primary selection clipboard. + * @section page_iface_zwp_primary_selection_source_v1_api API + * See @ref iface_zwp_primary_selection_source_v1. + */ +/** + * @defgroup iface_zwp_primary_selection_source_v1 The zwp_primary_selection_source_v1 interface + * + * The source side of a wp_primary_selection_offer, it provides a way to + * describe the offered data and respond to requests to transfer the + * requested contents of the primary selection clipboard. + */ +extern const struct wl_interface zwp_primary_selection_source_v1_interface; +#endif + +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_CREATE_SOURCE 0 +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_GET_DEVICE 1 +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_DESTROY 2 + + +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_CREATE_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_GET_DEVICE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_primary_selection_device_manager_v1 */ +static inline void +zwp_primary_selection_device_manager_v1_set_user_data(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_primary_selection_device_manager_v1, user_data); +} + +/** @ingroup iface_zwp_primary_selection_device_manager_v1 */ +static inline void * +zwp_primary_selection_device_manager_v1_get_user_data(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_primary_selection_device_manager_v1); +} + +static inline uint32_t +zwp_primary_selection_device_manager_v1_get_version(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_manager_v1); +} + +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + * + * Create a new primary selection source. + */ +static inline struct zwp_primary_selection_source_v1 * +zwp_primary_selection_device_manager_v1_create_source(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_device_manager_v1, + ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_CREATE_SOURCE, &zwp_primary_selection_source_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_manager_v1), 0, NULL); + + return (struct zwp_primary_selection_source_v1 *) id; +} + +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + * + * Create a new data device for a given seat. + */ +static inline struct zwp_primary_selection_device_v1 * +zwp_primary_selection_device_manager_v1_get_device(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_device_manager_v1, + ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_GET_DEVICE, &zwp_primary_selection_device_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_manager_v1), 0, NULL, seat); + + return (struct zwp_primary_selection_device_v1 *) id; +} + +/** + * @ingroup iface_zwp_primary_selection_device_manager_v1 + * + * Destroy the primary selection device manager. + */ +static inline void +zwp_primary_selection_device_manager_v1_destroy(struct zwp_primary_selection_device_manager_v1 *zwp_primary_selection_device_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_device_manager_v1, + ZWP_PRIMARY_SELECTION_DEVICE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + * @struct zwp_primary_selection_device_v1_listener + */ +struct zwp_primary_selection_device_v1_listener { + /** + * introduce a new wp_primary_selection_offer + * + * Introduces a new wp_primary_selection_offer object that may be + * used to receive the current primary selection. Immediately + * following this event, the new wp_primary_selection_offer object + * will send wp_primary_selection_offer.offer events to describe + * the offered mime types. + */ + void (*data_offer)(void *data, + struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1 *offer); + /** + * advertise a new primary selection + * + * The wp_primary_selection_device.selection event is sent to + * notify the client of a new primary selection. This event is sent + * after the wp_primary_selection.data_offer event introducing this + * object, and after the offer has announced its mimetypes through + * wp_primary_selection_offer.offer. + * + * The data_offer is valid until a new offer or NULL is received or + * until the client loses keyboard focus. The client must destroy + * the previous selection data_offer, if any, upon receiving this + * event. + */ + void (*selection)(void *data, + struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1 *id); +}; + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + */ +static inline int +zwp_primary_selection_device_v1_add_listener(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, + const struct zwp_primary_selection_device_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_primary_selection_device_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_SET_SELECTION 0 +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_DESTROY 1 + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_DATA_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_device_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_SELECTION_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_SET_SELECTION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_device_v1 + */ +#define ZWP_PRIMARY_SELECTION_DEVICE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_primary_selection_device_v1 */ +static inline void +zwp_primary_selection_device_v1_set_user_data(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_primary_selection_device_v1, user_data); +} + +/** @ingroup iface_zwp_primary_selection_device_v1 */ +static inline void * +zwp_primary_selection_device_v1_get_user_data(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_primary_selection_device_v1); +} + +static inline uint32_t +zwp_primary_selection_device_v1_get_version(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_v1); +} + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + * + * Replaces the current selection. The previous owner of the primary + * selection will receive a wp_primary_selection_source.cancelled event. + * + * To unset the selection, set the source to NULL. + */ +static inline void +zwp_primary_selection_device_v1_set_selection(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, struct zwp_primary_selection_source_v1 *source, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_device_v1, + ZWP_PRIMARY_SELECTION_DEVICE_V1_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_v1), 0, source, serial); +} + +/** + * @ingroup iface_zwp_primary_selection_device_v1 + * + * Destroy the primary selection device. + */ +static inline void +zwp_primary_selection_device_v1_destroy(struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_device_v1, + ZWP_PRIMARY_SELECTION_DEVICE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_device_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + * @struct zwp_primary_selection_offer_v1_listener + */ +struct zwp_primary_selection_offer_v1_listener { + /** + * advertise offered mime type + * + * Sent immediately after creating announcing the + * wp_primary_selection_offer through + * wp_primary_selection_device.data_offer. One event is sent per + * offered mime type. + */ + void (*offer)(void *data, + struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, + const char *mime_type); +}; + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + */ +static inline int +zwp_primary_selection_offer_v1_add_listener(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, + const struct zwp_primary_selection_offer_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_primary_selection_offer_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_PRIMARY_SELECTION_OFFER_V1_RECEIVE 0 +#define ZWP_PRIMARY_SELECTION_OFFER_V1_DESTROY 1 + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + */ +#define ZWP_PRIMARY_SELECTION_OFFER_V1_OFFER_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + */ +#define ZWP_PRIMARY_SELECTION_OFFER_V1_RECEIVE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + */ +#define ZWP_PRIMARY_SELECTION_OFFER_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_primary_selection_offer_v1 */ +static inline void +zwp_primary_selection_offer_v1_set_user_data(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_primary_selection_offer_v1, user_data); +} + +/** @ingroup iface_zwp_primary_selection_offer_v1 */ +static inline void * +zwp_primary_selection_offer_v1_get_user_data(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_primary_selection_offer_v1); +} + +static inline uint32_t +zwp_primary_selection_offer_v1_get_version(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_offer_v1); +} + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + * + * To transfer the contents of the primary selection clipboard, the client + * issues this request and indicates the mime type that it wants to + * receive. The transfer happens through the passed file descriptor + * (typically created with the pipe system call). The source client writes + * the data in the mime type representation requested and then closes the + * file descriptor. + * + * The receiving client reads from the read end of the pipe until EOF and + * closes its end, at which point the transfer is complete. + */ +static inline void +zwp_primary_selection_offer_v1_receive(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type, int32_t fd) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_offer_v1, + ZWP_PRIMARY_SELECTION_OFFER_V1_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_offer_v1), 0, mime_type, fd); +} + +/** + * @ingroup iface_zwp_primary_selection_offer_v1 + * + * Destroy the primary selection offer. + */ +static inline void +zwp_primary_selection_offer_v1_destroy(struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_offer_v1, + ZWP_PRIMARY_SELECTION_OFFER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_offer_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + * @struct zwp_primary_selection_source_v1_listener + */ +struct zwp_primary_selection_source_v1_listener { + /** + * send the primary selection contents + * + * Request for the current primary selection contents from the + * client. Send the specified mime type over the passed file + * descriptor, then close it. + */ + void (*send)(void *data, + struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1, + const char *mime_type, + int32_t fd); + /** + * request for primary selection contents was canceled + * + * This primary selection source is no longer valid. The client + * should clean up and destroy this primary selection source. + */ + void (*cancelled)(void *data, + struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1); +}; + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + */ +static inline int +zwp_primary_selection_source_v1_add_listener(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1, + const struct zwp_primary_selection_source_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_primary_selection_source_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_OFFER 0 +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_DESTROY 1 + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + */ +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_SEND_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_source_v1 + */ +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_CANCELLED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + */ +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_primary_selection_source_v1 + */ +#define ZWP_PRIMARY_SELECTION_SOURCE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_primary_selection_source_v1 */ +static inline void +zwp_primary_selection_source_v1_set_user_data(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_primary_selection_source_v1, user_data); +} + +/** @ingroup iface_zwp_primary_selection_source_v1 */ +static inline void * +zwp_primary_selection_source_v1_get_user_data(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_primary_selection_source_v1); +} + +static inline uint32_t +zwp_primary_selection_source_v1_get_version(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_source_v1); +} + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + * + * This request adds a mime type to the set of mime types advertised to + * targets. Can be called several times to offer multiple types. + */ +static inline void +zwp_primary_selection_source_v1_offer(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1, const char *mime_type) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_source_v1, + ZWP_PRIMARY_SELECTION_SOURCE_V1_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_source_v1), 0, mime_type); +} + +/** + * @ingroup iface_zwp_primary_selection_source_v1 + * + * Destroy the primary selection source. + */ +static inline void +zwp_primary_selection_source_v1_destroy(struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_primary_selection_source_v1, + ZWP_PRIMARY_SELECTION_SOURCE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_primary_selection_source_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/primary-selection-unstable-v1-protocol.c b/src/wayland/protocols/primary-selection-unstable-v1-protocol.c new file mode 100644 index 0000000..8c99e28 --- /dev/null +++ b/src/wayland/protocols/primary-selection-unstable-v1-protocol.c @@ -0,0 +1,116 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2015, 2016 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface zwp_primary_selection_device_v1_interface; +extern const struct wl_interface zwp_primary_selection_offer_v1_interface; +extern const struct wl_interface zwp_primary_selection_source_v1_interface; + +static const struct wl_interface *wp_primary_selection_unstable_v1_types[] = { + NULL, + NULL, + &zwp_primary_selection_source_v1_interface, + &zwp_primary_selection_device_v1_interface, + &wl_seat_interface, + &zwp_primary_selection_source_v1_interface, + NULL, + &zwp_primary_selection_offer_v1_interface, + &zwp_primary_selection_offer_v1_interface, +}; + +static const struct wl_message zwp_primary_selection_device_manager_v1_requests[] = { + { "create_source", "n", wp_primary_selection_unstable_v1_types + 2 }, + { "get_device", "no", wp_primary_selection_unstable_v1_types + 3 }, + { "destroy", "", wp_primary_selection_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_primary_selection_device_manager_v1_interface = { + "zwp_primary_selection_device_manager_v1", 1, + 3, zwp_primary_selection_device_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwp_primary_selection_device_v1_requests[] = { + { "set_selection", "?ou", wp_primary_selection_unstable_v1_types + 5 }, + { "destroy", "", wp_primary_selection_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwp_primary_selection_device_v1_events[] = { + { "data_offer", "n", wp_primary_selection_unstable_v1_types + 7 }, + { "selection", "?o", wp_primary_selection_unstable_v1_types + 8 }, +}; + +WL_PRIVATE const struct wl_interface zwp_primary_selection_device_v1_interface = { + "zwp_primary_selection_device_v1", 1, + 2, zwp_primary_selection_device_v1_requests, + 2, zwp_primary_selection_device_v1_events, +}; + +static const struct wl_message zwp_primary_selection_offer_v1_requests[] = { + { "receive", "sh", wp_primary_selection_unstable_v1_types + 0 }, + { "destroy", "", wp_primary_selection_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwp_primary_selection_offer_v1_events[] = { + { "offer", "s", wp_primary_selection_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_primary_selection_offer_v1_interface = { + "zwp_primary_selection_offer_v1", 1, + 2, zwp_primary_selection_offer_v1_requests, + 1, zwp_primary_selection_offer_v1_events, +}; + +static const struct wl_message zwp_primary_selection_source_v1_requests[] = { + { "offer", "s", wp_primary_selection_unstable_v1_types + 0 }, + { "destroy", "", wp_primary_selection_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwp_primary_selection_source_v1_events[] = { + { "send", "sh", wp_primary_selection_unstable_v1_types + 0 }, + { "cancelled", "", wp_primary_selection_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_primary_selection_source_v1_interface = { + "zwp_primary_selection_source_v1", 1, + 2, zwp_primary_selection_source_v1_requests, + 2, zwp_primary_selection_source_v1_events, +}; + diff --git a/src/wayland/protocols/tablet-v2-client-protocol.h b/src/wayland/protocols/tablet-v2-client-protocol.h new file mode 100644 index 0000000..d3aa023 --- /dev/null +++ b/src/wayland/protocols/tablet-v2-client-protocol.h @@ -0,0 +1,2495 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef TABLET_V2_CLIENT_PROTOCOL_H +#define TABLET_V2_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_tablet_v2 The tablet_v2 protocol + * Wayland protocol for graphics tablets + * + * @section page_desc_tablet_v2 Description + * + * This description provides a high-level overview of the interplay between + * the interfaces defined this protocol. For details, see the protocol + * specification. + * + * More than one tablet may exist, and device-specifics matter. Tablets are + * not represented by a single virtual device like wl_pointer. A client + * binds to the tablet manager object which is just a proxy object. From + * that, the client requests zwp_tablet_manager_v2.get_tablet_seat(wl_seat) + * and that returns the actual interface that has all the tablets. With + * this indirection, we can avoid merging zwp_tablet_v2 into the actual Wayland + * protocol, a long-term benefit. + * + * The zwp_tablet_seat_v2 sends a "tablet added" event for each tablet + * connected. That event is followed by descriptive events about the + * hardware; currently that includes events for name, vid/pid and + * a zwp_tablet_v2.path event that describes a local path. This path can be + * used to uniquely identify a tablet or get more information through + * libwacom. Emulated or nested tablets can skip any of those, e.g. a + * virtual tablet may not have a vid/pid. The sequence of descriptive + * events is terminated by a zwp_tablet_v2.done event to signal that a client + * may now finalize any initialization for that tablet. + * + * Events from tablets require a tool in proximity. Tools are also managed + * by the tablet seat; a "tool added" event is sent whenever a tool is new + * to the compositor. That event is followed by a number of descriptive + * events about the hardware; currently that includes capabilities, + * hardware id and serial number, and tool type. Similar to the tablet + * interface, a zwp_tablet_tool_v2.done event is sent to terminate that initial + * sequence. + * + * Any event from a tool happens on the zwp_tablet_tool_v2 interface. When the + * tool gets into proximity of the tablet, a proximity_in event is sent on + * the zwp_tablet_tool_v2 interface, listing the tablet and the surface. That + * event is followed by a motion event with the coordinates. After that, + * it's the usual motion, axis, button, etc. events. The protocol's + * serialisation means events are grouped by zwp_tablet_tool_v2.frame events. + * + * Two special events (that don't exist in X) are down and up. They signal + * "tip touching the surface". For tablets without real proximity + * detection, the sequence is: proximity_in, motion, down, frame. + * + * When the tool leaves proximity, a proximity_out event is sent. If any + * button is still down, a button release event is sent before this + * proximity event. These button events are sent in the same frame as the + * proximity event to signal to the client that the buttons were held when + * the tool left proximity. + * + * If the tool moves out of the surface but stays in proximity (i.e. + * between windows), compositor-specific grab policies apply. This usually + * means that the proximity-out is delayed until all buttons are released. + * + * Moving a tool physically from one tablet to the other has no real effect + * on the protocol, since we already have the tool object from the "tool + * added" event. All the information is already there and the proximity + * events on both tablets are all a client needs to reconstruct what + * happened. + * + * Some extra axes are normalized, i.e. the client knows the range as + * specified in the protocol (e.g. [0, 65535]), the granularity however is + * unknown. The current normalized axes are pressure, distance, and slider. + * + * Other extra axes are in physical units as specified in the protocol. + * The current extra axes with physical units are tilt, rotation and + * wheel rotation. + * + * Since tablets work independently of the pointer controlled by the mouse, + * the focus handling is independent too and controlled by proximity. + * The zwp_tablet_tool_v2.set_cursor request sets a tool-specific cursor. + * This cursor surface may be the same as the mouse cursor, and it may be + * the same across tools but it is possible to be more fine-grained. For + * example, a client may set different cursors for the pen and eraser. + * + * Tools are generally independent of tablets and it is + * compositor-specific policy when a tool can be removed. Common approaches + * will likely include some form of removing a tool when all tablets the + * tool was used on are removed. + * + * @section page_ifaces_tablet_v2 Interfaces + * - @subpage page_iface_zwp_tablet_manager_v2 - controller object for graphic tablet devices + * - @subpage page_iface_zwp_tablet_seat_v2 - controller object for graphic tablet devices of a seat + * - @subpage page_iface_zwp_tablet_tool_v2 - a physical tablet tool + * - @subpage page_iface_zwp_tablet_v2 - graphics tablet device + * - @subpage page_iface_zwp_tablet_pad_ring_v2 - pad ring + * - @subpage page_iface_zwp_tablet_pad_strip_v2 - pad strip + * - @subpage page_iface_zwp_tablet_pad_group_v2 - a set of buttons, rings and strips + * - @subpage page_iface_zwp_tablet_pad_v2 - a set of buttons, rings, strips and dials + * - @subpage page_iface_zwp_tablet_pad_dial_v2 - pad dial + * @section page_copyright_tablet_v2 Copyright + *
+ *
+ * Copyright 2014 © Stephen "Lyude" Chandler Paul
+ * Copyright 2015-2024 © Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct wl_seat; +struct wl_surface; +struct zwp_tablet_manager_v2; +struct zwp_tablet_pad_dial_v2; +struct zwp_tablet_pad_group_v2; +struct zwp_tablet_pad_ring_v2; +struct zwp_tablet_pad_strip_v2; +struct zwp_tablet_pad_v2; +struct zwp_tablet_seat_v2; +struct zwp_tablet_tool_v2; +struct zwp_tablet_v2; + +#ifndef ZWP_TABLET_MANAGER_V2_INTERFACE +#define ZWP_TABLET_MANAGER_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_manager_v2 zwp_tablet_manager_v2 + * @section page_iface_zwp_tablet_manager_v2_desc Description + * + * An object that provides access to the graphics tablets available on this + * system. All tablets are associated with a seat, to get access to the + * actual tablets, use zwp_tablet_manager_v2.get_tablet_seat. + * @section page_iface_zwp_tablet_manager_v2_api API + * See @ref iface_zwp_tablet_manager_v2. + */ +/** + * @defgroup iface_zwp_tablet_manager_v2 The zwp_tablet_manager_v2 interface + * + * An object that provides access to the graphics tablets available on this + * system. All tablets are associated with a seat, to get access to the + * actual tablets, use zwp_tablet_manager_v2.get_tablet_seat. + */ +extern const struct wl_interface zwp_tablet_manager_v2_interface; +#endif +#ifndef ZWP_TABLET_SEAT_V2_INTERFACE +#define ZWP_TABLET_SEAT_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_seat_v2 zwp_tablet_seat_v2 + * @section page_iface_zwp_tablet_seat_v2_desc Description + * + * An object that provides access to the graphics tablets available on this + * seat. After binding to this interface, the compositor sends a set of + * zwp_tablet_seat_v2.tablet_added and zwp_tablet_seat_v2.tool_added events. + * @section page_iface_zwp_tablet_seat_v2_api API + * See @ref iface_zwp_tablet_seat_v2. + */ +/** + * @defgroup iface_zwp_tablet_seat_v2 The zwp_tablet_seat_v2 interface + * + * An object that provides access to the graphics tablets available on this + * seat. After binding to this interface, the compositor sends a set of + * zwp_tablet_seat_v2.tablet_added and zwp_tablet_seat_v2.tool_added events. + */ +extern const struct wl_interface zwp_tablet_seat_v2_interface; +#endif +#ifndef ZWP_TABLET_TOOL_V2_INTERFACE +#define ZWP_TABLET_TOOL_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_tool_v2 zwp_tablet_tool_v2 + * @section page_iface_zwp_tablet_tool_v2_desc Description + * + * An object that represents a physical tool that has been, or is + * currently in use with a tablet in this seat. Each zwp_tablet_tool_v2 + * object stays valid until the client destroys it; the compositor + * reuses the zwp_tablet_tool_v2 object to indicate that the object's + * respective physical tool has come into proximity of a tablet again. + * + * A zwp_tablet_tool_v2 object's relation to a physical tool depends on the + * tablet's ability to report serial numbers. If the tablet supports + * this capability, then the object represents a specific physical tool + * and can be identified even when used on multiple tablets. + * + * A tablet tool has a number of static characteristics, e.g. tool type, + * hardware_serial and capabilities. These capabilities are sent in an + * event sequence after the zwp_tablet_seat_v2.tool_added event before any + * actual events from this tool. This initial event sequence is + * terminated by a zwp_tablet_tool_v2.done event. + * + * Tablet tool events are grouped by zwp_tablet_tool_v2.frame events. + * Any events received before a zwp_tablet_tool_v2.frame event should be + * considered part of the same hardware state change. + * @section page_iface_zwp_tablet_tool_v2_api API + * See @ref iface_zwp_tablet_tool_v2. + */ +/** + * @defgroup iface_zwp_tablet_tool_v2 The zwp_tablet_tool_v2 interface + * + * An object that represents a physical tool that has been, or is + * currently in use with a tablet in this seat. Each zwp_tablet_tool_v2 + * object stays valid until the client destroys it; the compositor + * reuses the zwp_tablet_tool_v2 object to indicate that the object's + * respective physical tool has come into proximity of a tablet again. + * + * A zwp_tablet_tool_v2 object's relation to a physical tool depends on the + * tablet's ability to report serial numbers. If the tablet supports + * this capability, then the object represents a specific physical tool + * and can be identified even when used on multiple tablets. + * + * A tablet tool has a number of static characteristics, e.g. tool type, + * hardware_serial and capabilities. These capabilities are sent in an + * event sequence after the zwp_tablet_seat_v2.tool_added event before any + * actual events from this tool. This initial event sequence is + * terminated by a zwp_tablet_tool_v2.done event. + * + * Tablet tool events are grouped by zwp_tablet_tool_v2.frame events. + * Any events received before a zwp_tablet_tool_v2.frame event should be + * considered part of the same hardware state change. + */ +extern const struct wl_interface zwp_tablet_tool_v2_interface; +#endif +#ifndef ZWP_TABLET_V2_INTERFACE +#define ZWP_TABLET_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_v2 zwp_tablet_v2 + * @section page_iface_zwp_tablet_v2_desc Description + * + * The zwp_tablet_v2 interface represents one graphics tablet device. The + * tablet interface itself does not generate events; all events are + * generated by zwp_tablet_tool_v2 objects when in proximity above a tablet. + * + * A tablet has a number of static characteristics, e.g. device name and + * pid/vid. These capabilities are sent in an event sequence after the + * zwp_tablet_seat_v2.tablet_added event. This initial event sequence is + * terminated by a zwp_tablet_v2.done event. + * @section page_iface_zwp_tablet_v2_api API + * See @ref iface_zwp_tablet_v2. + */ +/** + * @defgroup iface_zwp_tablet_v2 The zwp_tablet_v2 interface + * + * The zwp_tablet_v2 interface represents one graphics tablet device. The + * tablet interface itself does not generate events; all events are + * generated by zwp_tablet_tool_v2 objects when in proximity above a tablet. + * + * A tablet has a number of static characteristics, e.g. device name and + * pid/vid. These capabilities are sent in an event sequence after the + * zwp_tablet_seat_v2.tablet_added event. This initial event sequence is + * terminated by a zwp_tablet_v2.done event. + */ +extern const struct wl_interface zwp_tablet_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_RING_V2_INTERFACE +#define ZWP_TABLET_PAD_RING_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_ring_v2 zwp_tablet_pad_ring_v2 + * @section page_iface_zwp_tablet_pad_ring_v2_desc Description + * + * A circular interaction area, such as the touch ring on the Wacom Intuos + * Pro series tablets. + * + * Events on a ring are logically grouped by the zwp_tablet_pad_ring_v2.frame + * event. + * @section page_iface_zwp_tablet_pad_ring_v2_api API + * See @ref iface_zwp_tablet_pad_ring_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_ring_v2 The zwp_tablet_pad_ring_v2 interface + * + * A circular interaction area, such as the touch ring on the Wacom Intuos + * Pro series tablets. + * + * Events on a ring are logically grouped by the zwp_tablet_pad_ring_v2.frame + * event. + */ +extern const struct wl_interface zwp_tablet_pad_ring_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_STRIP_V2_INTERFACE +#define ZWP_TABLET_PAD_STRIP_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_strip_v2 zwp_tablet_pad_strip_v2 + * @section page_iface_zwp_tablet_pad_strip_v2_desc Description + * + * A linear interaction area, such as the strips found in Wacom Cintiq + * models. + * + * Events on a strip are logically grouped by the zwp_tablet_pad_strip_v2.frame + * event. + * @section page_iface_zwp_tablet_pad_strip_v2_api API + * See @ref iface_zwp_tablet_pad_strip_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_strip_v2 The zwp_tablet_pad_strip_v2 interface + * + * A linear interaction area, such as the strips found in Wacom Cintiq + * models. + * + * Events on a strip are logically grouped by the zwp_tablet_pad_strip_v2.frame + * event. + */ +extern const struct wl_interface zwp_tablet_pad_strip_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_GROUP_V2_INTERFACE +#define ZWP_TABLET_PAD_GROUP_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_group_v2 zwp_tablet_pad_group_v2 + * @section page_iface_zwp_tablet_pad_group_v2_desc Description + * + * A pad group describes a distinct (sub)set of buttons, rings and strips + * present in the tablet. The criteria of this grouping is usually positional, + * eg. if a tablet has buttons on the left and right side, 2 groups will be + * presented. The physical arrangement of groups is undisclosed and may + * change on the fly. + * + * Pad groups will announce their features during pad initialization. Between + * the corresponding zwp_tablet_pad_v2.group event and zwp_tablet_pad_group_v2.done, the + * pad group will announce the buttons, rings and strips contained in it, + * plus the number of supported modes. + * + * Modes are a mechanism to allow multiple groups of actions for every element + * in the pad group. The number of groups and available modes in each is + * persistent across device plugs. The current mode is user-switchable, it + * will be announced through the zwp_tablet_pad_group_v2.mode_switch event both + * whenever it is switched, and after zwp_tablet_pad_v2.enter. + * + * The current mode logically applies to all elements in the pad group, + * although it is at clients' discretion whether to actually perform different + * actions, and/or issue the respective .set_feedback requests to notify the + * compositor. See the zwp_tablet_pad_group_v2.mode_switch event for more details. + * @section page_iface_zwp_tablet_pad_group_v2_api API + * See @ref iface_zwp_tablet_pad_group_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_group_v2 The zwp_tablet_pad_group_v2 interface + * + * A pad group describes a distinct (sub)set of buttons, rings and strips + * present in the tablet. The criteria of this grouping is usually positional, + * eg. if a tablet has buttons on the left and right side, 2 groups will be + * presented. The physical arrangement of groups is undisclosed and may + * change on the fly. + * + * Pad groups will announce their features during pad initialization. Between + * the corresponding zwp_tablet_pad_v2.group event and zwp_tablet_pad_group_v2.done, the + * pad group will announce the buttons, rings and strips contained in it, + * plus the number of supported modes. + * + * Modes are a mechanism to allow multiple groups of actions for every element + * in the pad group. The number of groups and available modes in each is + * persistent across device plugs. The current mode is user-switchable, it + * will be announced through the zwp_tablet_pad_group_v2.mode_switch event both + * whenever it is switched, and after zwp_tablet_pad_v2.enter. + * + * The current mode logically applies to all elements in the pad group, + * although it is at clients' discretion whether to actually perform different + * actions, and/or issue the respective .set_feedback requests to notify the + * compositor. See the zwp_tablet_pad_group_v2.mode_switch event for more details. + */ +extern const struct wl_interface zwp_tablet_pad_group_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_V2_INTERFACE +#define ZWP_TABLET_PAD_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_v2 zwp_tablet_pad_v2 + * @section page_iface_zwp_tablet_pad_v2_desc Description + * + * A pad device is a set of buttons, rings, strips and dials + * usually physically present on the tablet device itself. Some + * exceptions exist where the pad device is physically detached, e.g. the + * Wacom ExpressKey Remote. + * + * Pad devices have no axes that control the cursor and are generally + * auxiliary devices to the tool devices used on the tablet surface. + * + * A pad device has a number of static characteristics, e.g. the number + * of rings. These capabilities are sent in an event sequence after the + * zwp_tablet_seat_v2.pad_added event before any actual events from this pad. + * This initial event sequence is terminated by a zwp_tablet_pad_v2.done + * event. + * + * All pad features (buttons, rings, strips and dials) are logically divided into + * groups and all pads have at least one group. The available groups are + * notified through the zwp_tablet_pad_v2.group event; the compositor will + * emit one event per group before emitting zwp_tablet_pad_v2.done. + * + * Groups may have multiple modes. Modes allow clients to map multiple + * actions to a single pad feature. Only one mode can be active per group, + * although different groups may have different active modes. + * @section page_iface_zwp_tablet_pad_v2_api API + * See @ref iface_zwp_tablet_pad_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_v2 The zwp_tablet_pad_v2 interface + * + * A pad device is a set of buttons, rings, strips and dials + * usually physically present on the tablet device itself. Some + * exceptions exist where the pad device is physically detached, e.g. the + * Wacom ExpressKey Remote. + * + * Pad devices have no axes that control the cursor and are generally + * auxiliary devices to the tool devices used on the tablet surface. + * + * A pad device has a number of static characteristics, e.g. the number + * of rings. These capabilities are sent in an event sequence after the + * zwp_tablet_seat_v2.pad_added event before any actual events from this pad. + * This initial event sequence is terminated by a zwp_tablet_pad_v2.done + * event. + * + * All pad features (buttons, rings, strips and dials) are logically divided into + * groups and all pads have at least one group. The available groups are + * notified through the zwp_tablet_pad_v2.group event; the compositor will + * emit one event per group before emitting zwp_tablet_pad_v2.done. + * + * Groups may have multiple modes. Modes allow clients to map multiple + * actions to a single pad feature. Only one mode can be active per group, + * although different groups may have different active modes. + */ +extern const struct wl_interface zwp_tablet_pad_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_DIAL_V2_INTERFACE +#define ZWP_TABLET_PAD_DIAL_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_dial_v2 zwp_tablet_pad_dial_v2 + * @section page_iface_zwp_tablet_pad_dial_v2_desc Description + * + * A rotary control, e.g. a dial or a wheel. + * + * Events on a dial are logically grouped by the zwp_tablet_pad_dial_v2.frame + * event. + * @section page_iface_zwp_tablet_pad_dial_v2_api API + * See @ref iface_zwp_tablet_pad_dial_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_dial_v2 The zwp_tablet_pad_dial_v2 interface + * + * A rotary control, e.g. a dial or a wheel. + * + * Events on a dial are logically grouped by the zwp_tablet_pad_dial_v2.frame + * event. + */ +extern const struct wl_interface zwp_tablet_pad_dial_v2_interface; +#endif + +#define ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT 0 +#define ZWP_TABLET_MANAGER_V2_DESTROY 1 + + +/** + * @ingroup iface_zwp_tablet_manager_v2 + */ +#define ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_manager_v2 + */ +#define ZWP_TABLET_MANAGER_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_manager_v2 */ +static inline void +zwp_tablet_manager_v2_set_user_data(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_manager_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_manager_v2 */ +static inline void * +zwp_tablet_manager_v2_get_user_data(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_manager_v2); +} + +static inline uint32_t +zwp_tablet_manager_v2_get_version(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2); +} + +/** + * @ingroup iface_zwp_tablet_manager_v2 + * + * Get the zwp_tablet_seat_v2 object for the given seat. This object + * provides access to all graphics tablets in this seat. + */ +static inline struct zwp_tablet_seat_v2 * +zwp_tablet_manager_v2_get_tablet_seat(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2, struct wl_seat *seat) +{ + struct wl_proxy *tablet_seat; + + tablet_seat = wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_manager_v2, + ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT, &zwp_tablet_seat_v2_interface, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2), 0, NULL, seat); + + return (struct zwp_tablet_seat_v2 *) tablet_seat; +} + +/** + * @ingroup iface_zwp_tablet_manager_v2 + * + * Destroy the zwp_tablet_manager_v2 object. Objects created from this + * object are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_manager_v2_destroy(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_manager_v2, + ZWP_TABLET_MANAGER_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_seat_v2 + * @struct zwp_tablet_seat_v2_listener + */ +struct zwp_tablet_seat_v2_listener { + /** + * new device notification + * + * This event is sent whenever a new tablet becomes available on + * this seat. This event only provides the object id of the tablet, + * any static information about the tablet (device name, vid/pid, + * etc.) is sent through the zwp_tablet_v2 interface. + * @param id the newly added graphics tablet + */ + void (*tablet_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_v2 *id); + /** + * a new tool has been used with a tablet + * + * This event is sent whenever a tool that has not previously + * been used with a tablet comes into use. This event only provides + * the object id of the tool; any static information about the tool + * (capabilities, type, etc.) is sent through the + * zwp_tablet_tool_v2 interface. + * @param id the newly added tablet tool + */ + void (*tool_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_tool_v2 *id); + /** + * new pad notification + * + * This event is sent whenever a new pad is known to the system. + * Typically, pads are physically attached to tablets and a + * pad_added event is sent immediately after the + * zwp_tablet_seat_v2.tablet_added. However, some standalone pad + * devices logically attach to tablets at runtime, and the client + * must wait for zwp_tablet_pad_v2.enter to know the tablet a pad + * is attached to. + * + * This event only provides the object id of the pad. All further + * features (buttons, strips, rings) are sent through the + * zwp_tablet_pad_v2 interface. + * @param id the newly added pad + */ + void (*pad_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_pad_v2 *id); +}; + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +static inline int +zwp_tablet_seat_v2_add_listener(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + const struct zwp_tablet_seat_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_seat_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_SEAT_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_TABLET_ADDED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_TOOL_ADDED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_PAD_ADDED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_seat_v2 */ +static inline void +zwp_tablet_seat_v2_set_user_data(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_seat_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_seat_v2 */ +static inline void * +zwp_tablet_seat_v2_get_user_data(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_seat_v2); +} + +static inline uint32_t +zwp_tablet_seat_v2_get_version(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_seat_v2); +} + +/** + * @ingroup iface_zwp_tablet_seat_v2 + * + * Destroy the zwp_tablet_seat_v2 object. Objects created from this + * object are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_seat_v2_destroy(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_seat_v2, + ZWP_TABLET_SEAT_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_seat_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_TOOL_V2_TYPE_ENUM +#define ZWP_TABLET_TOOL_V2_TYPE_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * a physical tool type + * + * Describes the physical type of a tool. The physical type of a tool + * generally defines its base usage. + * + * The mouse tool represents a mouse-shaped tool that is not a relative + * device but bound to the tablet's surface, providing absolute + * coordinates. + * + * The lens tool is a mouse-shaped tool with an attached lens to + * provide precision focus. + */ +enum zwp_tablet_tool_v2_type { + /** + * Pen + */ + ZWP_TABLET_TOOL_V2_TYPE_PEN = 0x140, + /** + * Eraser + */ + ZWP_TABLET_TOOL_V2_TYPE_ERASER = 0x141, + /** + * Brush + */ + ZWP_TABLET_TOOL_V2_TYPE_BRUSH = 0x142, + /** + * Pencil + */ + ZWP_TABLET_TOOL_V2_TYPE_PENCIL = 0x143, + /** + * Airbrush + */ + ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH = 0x144, + /** + * Finger + */ + ZWP_TABLET_TOOL_V2_TYPE_FINGER = 0x145, + /** + * Mouse + */ + ZWP_TABLET_TOOL_V2_TYPE_MOUSE = 0x146, + /** + * Lens + */ + ZWP_TABLET_TOOL_V2_TYPE_LENS = 0x147, +}; +#endif /* ZWP_TABLET_TOOL_V2_TYPE_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM +#define ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * capability flags for a tool + * + * Describes extra capabilities on a tablet. + * + * Any tool must provide x and y values, extra axes are + * device-specific. + */ +enum zwp_tablet_tool_v2_capability { + /** + * Tilt axes + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_TILT = 1, + /** + * Pressure axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE = 2, + /** + * Distance axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE = 3, + /** + * Z-rotation axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION = 4, + /** + * Slider axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER = 5, + /** + * Wheel axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL = 6, +}; +#endif /* ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM +#define ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * physical button state + * + * Describes the physical state of a button that produced the button event. + */ +enum zwp_tablet_tool_v2_button_state { + /** + * button is not pressed + */ + ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED = 0, + /** + * button is pressed + */ + ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED = 1, +}; +#endif /* ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_ERROR_ENUM +#define ZWP_TABLET_TOOL_V2_ERROR_ENUM +enum zwp_tablet_tool_v2_error { + /** + * given wl_surface has another role + */ + ZWP_TABLET_TOOL_V2_ERROR_ROLE = 0, +}; +#endif /* ZWP_TABLET_TOOL_V2_ERROR_ENUM */ + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * @struct zwp_tablet_tool_v2_listener + */ +struct zwp_tablet_tool_v2_listener { + /** + * tool type + * + * The tool type is the high-level type of the tool and usually + * decides the interaction expected from this tool. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_tool_v2.done event. + * @param tool_type the physical tool type + */ + void (*type)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t tool_type); + /** + * unique hardware serial number of the tool + * + * If the physical tool can be identified by a unique 64-bit + * serial number, this event notifies the client of this serial + * number. + * + * If multiple tablets are available in the same seat and the tool + * is uniquely identifiable by the serial number, that tool may + * move between tablets. + * + * Otherwise, if the tool has no serial number and this event is + * missing, the tool is tied to the tablet it first comes into + * proximity with. Even if the physical tool is used on multiple + * tablets, separate zwp_tablet_tool_v2 objects will be created, + * one per tablet. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_tool_v2.done event. + * @param hardware_serial_hi the unique serial number of the tool, most significant bits + * @param hardware_serial_lo the unique serial number of the tool, least significant bits + */ + void (*hardware_serial)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t hardware_serial_hi, + uint32_t hardware_serial_lo); + /** + * hardware id notification in Wacom's format + * + * This event notifies the client of a hardware id available on + * this tool. + * + * The hardware id is a device-specific 64-bit id that provides + * extra information about the tool in use, beyond the wl_tool.type + * enumeration. The format of the id is specific to tablets made by + * Wacom Inc. For example, the hardware id of a Wacom Grip Pen (a + * stylus) is 0x802. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_tool_v2.done event. + * @param hardware_id_hi the hardware id, most significant bits + * @param hardware_id_lo the hardware id, least significant bits + */ + void (*hardware_id_wacom)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t hardware_id_hi, + uint32_t hardware_id_lo); + /** + * tool capability notification + * + * This event notifies the client of any capabilities of this + * tool, beyond the main set of x/y axes and tip up/down detection. + * + * One event is sent for each extra capability available on this + * tool. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_tool_v2.done event. + * @param capability the capability + */ + void (*capability)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t capability); + /** + * tool description events sequence complete + * + * This event signals the end of the initial burst of descriptive + * events. A client may consider the static description of the tool + * to be complete and finalize initialization of the tool. + */ + void (*done)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * tool removed + * + * This event is sent when the tool is removed from the system + * and will send no further events. Should the physical tool come + * back into proximity later, a new zwp_tablet_tool_v2 object will + * be created. + * + * It is compositor-dependent when a tool is removed. A compositor + * may remove a tool on proximity out, tablet removal or any other + * reason. A compositor may also keep a tool alive until shutdown. + * + * If the tool is currently in proximity, a proximity_out event + * will be sent before the removed event. See + * zwp_tablet_tool_v2.proximity_out for the handling of any buttons + * logically down. + * + * When this event is received, the client must + * zwp_tablet_tool_v2.destroy the object. + */ + void (*removed)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * proximity in event + * + * Notification that this tool is focused on a certain surface. + * + * This event can be received when the tool has moved from one + * surface to another, or when the tool has come back into + * proximity above the surface. + * + * If any button is logically down when the tool comes into + * proximity, the respective button event is sent after the + * proximity_in event but within the same frame as the proximity_in + * event. + * @param tablet The tablet the tool is in proximity of + * @param surface The current surface the tablet tool is over + */ + void (*proximity_in)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial, + struct zwp_tablet_v2 *tablet, + struct wl_surface *surface); + /** + * proximity out event + * + * Notification that this tool has either left proximity, or is + * no longer focused on a certain surface. + * + * When the tablet tool leaves proximity of the tablet, button + * release events are sent for each button that was held down at + * the time of leaving proximity. These events are sent before the + * proximity_out event but within the same zwp_tablet_v2.frame. + * + * If the tool stays within proximity of the tablet, but the focus + * changes from one surface to another, a button release event may + * not be sent until the button is actually released or the tool + * leaves the proximity of the tablet. + */ + void (*proximity_out)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * tablet tool is making contact + * + * Sent whenever the tablet tool comes in contact with the + * surface of the tablet. + * + * If the tool is already in contact with the tablet when entering + * the input region, the client owning said region will receive a + * zwp_tablet_v2.proximity_in event, followed by a + * zwp_tablet_v2.down event and a zwp_tablet_v2.frame event. + * + * Note that this event describes logical contact, not physical + * contact. On some devices, a compositor may not consider a tool + * in logical contact until a minimum physical pressure threshold + * is exceeded. + */ + void (*down)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial); + /** + * tablet tool is no longer making contact + * + * Sent whenever the tablet tool stops making contact with the + * surface of the tablet, or when the tablet tool moves out of the + * input region and the compositor grab (if any) is dismissed. + * + * If the tablet tool moves out of the input region while in + * contact with the surface of the tablet and the compositor does + * not have an ongoing grab on the surface, the client owning said + * region will receive a zwp_tablet_v2.up event, followed by a + * zwp_tablet_v2.proximity_out event and a zwp_tablet_v2.frame + * event. If the compositor has an ongoing grab on this device, + * this event sequence is sent whenever the grab is dismissed in + * the future. + * + * Note that this event describes logical contact, not physical + * contact. On some devices, a compositor may not consider a tool + * out of logical contact until physical pressure falls below a + * specific threshold. + */ + void (*up)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * motion event + * + * Sent whenever a tablet tool moves. + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t x, + wl_fixed_t y); + /** + * pressure change event + * + * Sent whenever the pressure axis on a tool changes. The value + * of this event is normalized to a value between 0 and 65535. + * + * Note that pressure may be nonzero even when a tool is not in + * logical contact. See the down and up events for more details. + * @param pressure The current pressure value + */ + void (*pressure)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t pressure); + /** + * distance change event + * + * Sent whenever the distance axis on a tool changes. The value + * of this event is normalized to a value between 0 and 65535. + * + * Note that distance may be nonzero even when a tool is not in + * logical contact. See the down and up events for more details. + * @param distance The current distance value + */ + void (*distance)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t distance); + /** + * tilt change event + * + * Sent whenever one or both of the tilt axes on a tool change. + * Each tilt value is in degrees, relative to the z-axis of the + * tablet. The angle is positive when the top of a tool tilts along + * the positive x or y axis. + * @param tilt_x The current value of the X tilt axis + * @param tilt_y The current value of the Y tilt axis + */ + void (*tilt)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t tilt_x, + wl_fixed_t tilt_y); + /** + * z-rotation change event + * + * Sent whenever the z-rotation axis on the tool changes. The + * rotation value is in degrees clockwise from the tool's logical + * neutral position. + * @param degrees The current rotation of the Z axis + */ + void (*rotation)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t degrees); + /** + * Slider position change event + * + * Sent whenever the slider position on the tool changes. The + * value is normalized between -65535 and 65535, with 0 as the + * logical neutral position of the slider. + * + * The slider is available on e.g. the Wacom Airbrush tool. + * @param position The current position of slider + */ + void (*slider)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + int32_t position); + /** + * Wheel delta event + * + * Sent whenever the wheel on the tool emits an event. This event + * contains two values for the same axis change. The degrees value + * is in the same orientation as the wl_pointer.vertical_scroll + * axis. The clicks value is in discrete logical clicks of the + * mouse wheel. This value may be zero if the movement of the wheel + * was less than one logical click. + * + * Clients should choose either value and avoid mixing degrees and + * clicks. The compositor may accumulate values smaller than a + * logical click and emulate click events when a certain threshold + * is met. Thus, zwp_tablet_tool_v2.wheel events with non-zero + * clicks values may have different degrees values. + * @param degrees The wheel delta in degrees + * @param clicks The wheel delta in discrete clicks + */ + void (*wheel)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t degrees, + int32_t clicks); + /** + * button event + * + * Sent whenever a button on the tool is pressed or released. + * + * If a button is held down when the tool moves in or out of + * proximity, button events are generated by the compositor. See + * zwp_tablet_tool_v2.proximity_in and + * zwp_tablet_tool_v2.proximity_out for details. + * @param button The button whose state has changed + * @param state Whether the button was pressed or released + */ + void (*button)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial, + uint32_t button, + uint32_t state); + /** + * frame event + * + * Marks the end of a series of axis and/or button updates from + * the tablet. The Wayland protocol requires axis updates to be + * sent sequentially, however all events within a frame should be + * considered one hardware event. + * @param time The time of the event with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +static inline int +zwp_tablet_tool_v2_add_listener(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + const struct zwp_tablet_tool_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_tool_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_TOOL_V2_SET_CURSOR 0 +#define ZWP_TABLET_TOOL_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_TYPE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_HARDWARE_SERIAL_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_HARDWARE_ID_WACOM_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_CAPABILITY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_REMOVED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PROXIMITY_IN_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PROXIMITY_OUT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DOWN_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_UP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PRESSURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DISTANCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_TILT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_ROTATION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_SLIDER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_WHEEL_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_SET_CURSOR_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_tool_v2 */ +static inline void +zwp_tablet_tool_v2_set_user_data(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_tool_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_tool_v2 */ +static inline void * +zwp_tablet_tool_v2_get_user_data(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_tool_v2); +} + +static inline uint32_t +zwp_tablet_tool_v2_get_version(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2); +} + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * + * Sets the surface of the cursor used for this tool on the given + * tablet. This request only takes effect if the tool is in proximity + * of one of the requesting client's surfaces or the surface parameter + * is the current pointer surface. If there was a previous surface set + * with this request it is replaced. If surface is NULL, the cursor + * image is hidden. + * + * The parameters hotspot_x and hotspot_y define the position of the + * pointer surface relative to the pointer location. Its top-left corner + * is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the + * coordinates of the pointer location, in surface-local coordinates. + * + * On surface.attach requests to the pointer surface, hotspot_x and + * hotspot_y are decremented by the x and y parameters passed to the + * request. Attach must be confirmed by wl_surface.commit as usual. + * + * The hotspot can also be updated by passing the currently set pointer + * surface to this request with new values for hotspot_x and hotspot_y. + * + * The current and pending input regions of the wl_surface are cleared, + * and wl_surface.set_input_region is ignored until the wl_surface is no + * longer used as the cursor. When the use as a cursor ends, the current + * and pending input regions become undefined, and the wl_surface is + * unmapped. + * + * This request gives the surface the role of a zwp_tablet_tool_v2 cursor. A + * surface may only ever be used as the cursor surface for one + * zwp_tablet_tool_v2. If the surface already has another role or has + * previously been used as cursor surface for a different tool, a + * protocol error is raised. + */ +static inline void +zwp_tablet_tool_v2_set_cursor(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_tool_v2, + ZWP_TABLET_TOOL_V2_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2), 0, serial, surface, hotspot_x, hotspot_y); +} + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * + * This destroys the client's resource for this tool object. + */ +static inline void +zwp_tablet_tool_v2_destroy(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_tool_v2, + ZWP_TABLET_TOOL_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_V2_BUSTYPE_ENUM +#define ZWP_TABLET_V2_BUSTYPE_ENUM +/** + * @ingroup iface_zwp_tablet_v2 + * bus type + * + * Describes the bus types this tablet is connected to. + */ +enum zwp_tablet_v2_bustype { + /** + * USB + */ + ZWP_TABLET_V2_BUSTYPE_USB = 3, + /** + * Bluetooth + */ + ZWP_TABLET_V2_BUSTYPE_BLUETOOTH = 5, + /** + * Virtual + */ + ZWP_TABLET_V2_BUSTYPE_VIRTUAL = 6, + /** + * Serial + */ + ZWP_TABLET_V2_BUSTYPE_SERIAL = 17, + /** + * I2C + */ + ZWP_TABLET_V2_BUSTYPE_I2C = 24, +}; +#endif /* ZWP_TABLET_V2_BUSTYPE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_v2 + * @struct zwp_tablet_v2_listener + */ +struct zwp_tablet_v2_listener { + /** + * tablet device name + * + * A descriptive name for the tablet device. + * + * If the device has no descriptive name, this event is not sent. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_v2.done event. + * @param name the device name + */ + void (*name)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + const char *name); + /** + * tablet device vendor/product id + * + * The vendor and product IDs for the tablet device. + * + * The interpretation of the id depends on the + * zwp_tablet_v2.bustype. Prior to version v2 of this protocol, the + * id was implied to be a USB vendor and product ID. If no + * zwp_tablet_v2.bustype is sent, the ID is to be interpreted as + * USB vendor and product ID. + * + * If the device has no vendor/product ID, this event is not sent. + * This can happen for virtual devices or non-USB devices, for + * instance. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_v2.done event. + * @param vid vendor id + * @param pid product id + */ + void (*id)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + uint32_t vid, + uint32_t pid); + /** + * path to the device + * + * A system-specific device path that indicates which device is + * behind this zwp_tablet_v2. This information may be used to + * gather additional information about the device, e.g. through + * libwacom. + * + * A device may have more than one device path. If so, multiple + * zwp_tablet_v2.path events are sent. A device may be emulated and + * not have a device path, and in that case this event will not be + * sent. + * + * The format of the path is unspecified, it may be a device node, + * a sysfs path, or some other identifier. It is up to the client + * to identify the string provided. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_v2.done event. + * @param path path to local device + */ + void (*path)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + const char *path); + /** + * tablet description events sequence complete + * + * This event is sent immediately to signal the end of the + * initial burst of descriptive events. A client may consider the + * static description of the tablet to be complete and finalize + * initialization of the tablet. + */ + void (*done)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2); + /** + * tablet removed event + * + * Sent when the tablet has been removed from the system. When a + * tablet is removed, some tools may be removed. + * + * When this event is received, the client must + * zwp_tablet_v2.destroy the object. + */ + void (*removed)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2); + /** + * tablet device bus type + * + * The bustype argument is one of the BUS_ defines in the Linux + * kernel's linux/input.h + * + * If the device has no known bustype or the bustype cannot be + * queried, this event is not sent. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_v2.done event. + * @param bustype bus type + * @since 2 + */ + void (*bustype)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + uint32_t bustype); +}; + +/** + * @ingroup iface_zwp_tablet_v2 + */ +static inline int +zwp_tablet_v2_add_listener(struct zwp_tablet_v2 *zwp_tablet_v2, + const struct zwp_tablet_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_NAME_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_ID_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_PATH_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_REMOVED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_BUSTYPE_SINCE_VERSION 2 + +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_v2 */ +static inline void +zwp_tablet_v2_set_user_data(struct zwp_tablet_v2 *zwp_tablet_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_v2 */ +static inline void * +zwp_tablet_v2_get_user_data(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_v2); +} + +static inline uint32_t +zwp_tablet_v2_get_version(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_v2); +} + +/** + * @ingroup iface_zwp_tablet_v2 + * + * This destroys the client's resource for this tablet object. + */ +static inline void +zwp_tablet_v2_destroy(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_v2, + ZWP_TABLET_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM +#define ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * ring axis source + * + * Describes the source types for ring events. This indicates to the + * client how a ring event was physically generated; a client may + * adjust the user interface accordingly. For example, events + * from a "finger" source may trigger kinetic scrolling. + */ +enum zwp_tablet_pad_ring_v2_source { + /** + * finger + */ + ZWP_TABLET_PAD_RING_V2_SOURCE_FINGER = 1, +}; +#endif /* ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * @struct zwp_tablet_pad_ring_v2_listener + */ +struct zwp_tablet_pad_ring_v2_listener { + /** + * ring event source + * + * Source information for ring events. + * + * This event does not occur on its own. It is sent before a + * zwp_tablet_pad_ring_v2.frame event and carries the source + * information for all events within that frame. + * + * The source specifies how this event was generated. If the source + * is zwp_tablet_pad_ring_v2.source.finger, a + * zwp_tablet_pad_ring_v2.stop event will be sent when the user + * lifts the finger off the device. + * + * This event is optional. If the source is unknown for an + * interaction, no event is sent. + * @param source the event source + */ + void (*source)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t source); + /** + * angle changed + * + * Sent whenever the angle on a ring changes. + * + * The angle is provided in degrees clockwise from the logical + * north of the ring in the pad's current rotation. + * @param degrees the current angle in degrees + */ + void (*angle)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + wl_fixed_t degrees); + /** + * interaction stopped + * + * Stop notification for ring events. + * + * For some zwp_tablet_pad_ring_v2.source types, a + * zwp_tablet_pad_ring_v2.stop event is sent to notify a client + * that the interaction with the ring has terminated. This enables + * the client to implement kinetic scrolling. See the + * zwp_tablet_pad_ring_v2.source documentation for information on + * when this event may be generated. + * + * Any zwp_tablet_pad_ring_v2.angle events with the same source + * after this event should be considered as the start of a new + * interaction. + */ + void (*stop)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2); + /** + * end of a ring event sequence + * + * Indicates the end of a set of ring events that logically + * belong together. A client is expected to accumulate the data in + * all events within the frame before proceeding. + * + * All zwp_tablet_pad_ring_v2 events before a + * zwp_tablet_pad_ring_v2.frame event belong logically together. + * For example, on termination of a finger interaction on a ring + * the compositor will send a zwp_tablet_pad_ring_v2.source event, + * a zwp_tablet_pad_ring_v2.stop event and a + * zwp_tablet_pad_ring_v2.frame event. + * + * A zwp_tablet_pad_ring_v2.frame event is sent for every logical + * event group, even if the group only contains a single + * zwp_tablet_pad_ring_v2 event. Specifically, a client may get a + * sequence: angle, frame, angle, frame, etc. + * @param time timestamp with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +static inline int +zwp_tablet_pad_ring_v2_add_listener(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + const struct zwp_tablet_pad_ring_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_ring_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_RING_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_ANGLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_STOP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_ring_v2 */ +static inline void +zwp_tablet_pad_ring_v2_set_user_data(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_ring_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_ring_v2 */ +static inline void * +zwp_tablet_pad_ring_v2_get_user_data(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_ring_v2); +} + +static inline uint32_t +zwp_tablet_pad_ring_v2_get_version(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * + * Request that the compositor use the provided feedback string + * associated with this ring. This request should be issued immediately + * after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding + * group is received, or whenever the ring is mapped to a different + * action. See zwp_tablet_pad_group_v2.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with the ring; compositors may use this + * information to offer visual feedback about the button layout + * (eg. on-screen displays). + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * zwp_tablet_pad_group_v2.mode_switch event received for the group of this + * ring. Requests providing other serials than the most recent one will be + * ignored. + */ +static inline void +zwp_tablet_pad_ring_v2_set_feedback(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_ring_v2, + ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2), 0, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * + * This destroys the client's resource for this ring object. + */ +static inline void +zwp_tablet_pad_ring_v2_destroy(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_ring_v2, + ZWP_TABLET_PAD_RING_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM +#define ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * strip axis source + * + * Describes the source types for strip events. This indicates to the + * client how a strip event was physically generated; a client may + * adjust the user interface accordingly. For example, events + * from a "finger" source may trigger kinetic scrolling. + */ +enum zwp_tablet_pad_strip_v2_source { + /** + * finger + */ + ZWP_TABLET_PAD_STRIP_V2_SOURCE_FINGER = 1, +}; +#endif /* ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * @struct zwp_tablet_pad_strip_v2_listener + */ +struct zwp_tablet_pad_strip_v2_listener { + /** + * strip event source + * + * Source information for strip events. + * + * This event does not occur on its own. It is sent before a + * zwp_tablet_pad_strip_v2.frame event and carries the source + * information for all events within that frame. + * + * The source specifies how this event was generated. If the source + * is zwp_tablet_pad_strip_v2.source.finger, a + * zwp_tablet_pad_strip_v2.stop event will be sent when the user + * lifts their finger off the device. + * + * This event is optional. If the source is unknown for an + * interaction, no event is sent. + * @param source the event source + */ + void (*source)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t source); + /** + * position changed + * + * Sent whenever the position on a strip changes. + * + * The position is normalized to a range of [0, 65535], the 0-value + * represents the top-most and/or left-most position of the strip + * in the pad's current rotation. + * @param position the current position + */ + void (*position)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t position); + /** + * interaction stopped + * + * Stop notification for strip events. + * + * For some zwp_tablet_pad_strip_v2.source types, a + * zwp_tablet_pad_strip_v2.stop event is sent to notify a client + * that the interaction with the strip has terminated. This enables + * the client to implement kinetic scrolling. See the + * zwp_tablet_pad_strip_v2.source documentation for information on + * when this event may be generated. + * + * Any zwp_tablet_pad_strip_v2.position events with the same source + * after this event should be considered as the start of a new + * interaction. + */ + void (*stop)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2); + /** + * end of a strip event sequence + * + * Indicates the end of a set of events that represent one + * logical hardware strip event. A client is expected to accumulate + * the data in all events within the frame before proceeding. + * + * All zwp_tablet_pad_strip_v2 events before a + * zwp_tablet_pad_strip_v2.frame event belong logically together. + * For example, on termination of a finger interaction on a strip + * the compositor will send a zwp_tablet_pad_strip_v2.source event, + * a zwp_tablet_pad_strip_v2.stop event and a + * zwp_tablet_pad_strip_v2.frame event. + * + * A zwp_tablet_pad_strip_v2.frame event is sent for every logical + * event group, even if the group only contains a single + * zwp_tablet_pad_strip_v2 event. Specifically, a client may get a + * sequence: position, frame, position, frame, etc. + * @param time timestamp with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +static inline int +zwp_tablet_pad_strip_v2_add_listener(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + const struct zwp_tablet_pad_strip_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_strip_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_STRIP_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_STOP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_strip_v2 */ +static inline void +zwp_tablet_pad_strip_v2_set_user_data(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_strip_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_strip_v2 */ +static inline void * +zwp_tablet_pad_strip_v2_get_user_data(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_strip_v2); +} + +static inline uint32_t +zwp_tablet_pad_strip_v2_get_version(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * + * Requests the compositor to use the provided feedback string + * associated with this strip. This request should be issued immediately + * after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding + * group is received, or whenever the strip is mapped to a different + * action. See zwp_tablet_pad_group_v2.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with the strip, and compositors may use this + * information to offer visual feedback about the button layout + * (eg. on-screen displays). + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * zwp_tablet_pad_group_v2.mode_switch event received for the group of this + * strip. Requests providing other serials than the most recent one will be + * ignored. + */ +static inline void +zwp_tablet_pad_strip_v2_set_feedback(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_strip_v2, + ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2), 0, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * + * This destroys the client's resource for this strip object. + */ +static inline void +zwp_tablet_pad_strip_v2_destroy(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_strip_v2, + ZWP_TABLET_PAD_STRIP_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + * @struct zwp_tablet_pad_group_v2_listener + */ +struct zwp_tablet_pad_group_v2_listener { + /** + * buttons announced + * + * Sent on zwp_tablet_pad_group_v2 initialization to announce the + * available buttons in the group. Button indices start at 0, a + * button may only be in one group at a time. + * + * This event is first sent in the initial burst of events before + * the zwp_tablet_pad_group_v2.done event. + * + * Some buttons are reserved by the compositor. These buttons may + * not be assigned to any zwp_tablet_pad_group_v2. Compositors may + * broadcast this event in the case of changes to the mapping of + * these reserved buttons. If the compositor happens to reserve all + * buttons in a group, this event will be sent with an empty array. + * @param buttons buttons in this group + */ + void (*buttons)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct wl_array *buttons); + /** + * ring announced + * + * Sent on zwp_tablet_pad_group_v2 initialization to announce + * available rings. One event is sent for each ring available on + * this pad group. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_group_v2.done event. + */ + void (*ring)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_ring_v2 *ring); + /** + * strip announced + * + * Sent on zwp_tablet_pad_v2 initialization to announce available + * strips. One event is sent for each strip available on this pad + * group. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_group_v2.done event. + */ + void (*strip)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_strip_v2 *strip); + /** + * mode-switch ability announced + * + * Sent on zwp_tablet_pad_group_v2 initialization to announce + * that the pad group may switch between modes. A client may use a + * mode to store a specific configuration for buttons, rings and + * strips and use the zwp_tablet_pad_group_v2.mode_switch event to + * toggle between these configurations. Mode indices start at 0. + * + * Switching modes is compositor-dependent. See the + * zwp_tablet_pad_group_v2.mode_switch event for more details. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_group_v2.done event. This event is only sent when + * more than one mode is available. + * @param modes the number of modes + */ + void (*modes)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t modes); + /** + * tablet group description events sequence complete + * + * This event is sent immediately to signal the end of the + * initial burst of descriptive events. A client may consider the + * static description of the tablet to be complete and finalize + * initialization of the tablet group. + */ + void (*done)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2); + /** + * mode switch event + * + * Notification that the mode was switched. + * + * A mode applies to all buttons, rings, strips and dials in a + * group simultaneously, but a client is not required to assign + * different actions for each mode. For example, a client may have + * mode-specific button mappings but map the ring to vertical + * scrolling in all modes. Mode indices start at 0. + * + * Switching modes is compositor-dependent. The compositor may + * provide visual cues to the user about the mode, e.g. by toggling + * LEDs on the tablet device. Mode-switching may be + * software-controlled or controlled by one or more physical + * buttons. For example, on a Wacom Intuos Pro, the button inside + * the ring may be assigned to switch between modes. + * + * The compositor will also send this event after + * zwp_tablet_pad_v2.enter on each group in order to notify of the + * current mode. Groups that only feature one mode will use mode=0 + * when emitting this event. + * + * If a button action in the new mode differs from the action in + * the previous mode, the client should immediately issue a + * zwp_tablet_pad_v2.set_feedback request for each changed button. + * + * If a ring, strip or dial action in the new mode differs from the + * action in the previous mode, the client should immediately issue + * a zwp_tablet_ring_v2.set_feedback, + * zwp_tablet_strip_v2.set_feedback or + * zwp_tablet_dial_v2.set_feedback request for each changed ring, + * strip or dial. + * @param time the time of the event with millisecond granularity + * @param mode the new mode of the pad + */ + void (*mode_switch)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t time, + uint32_t serial, + uint32_t mode); + /** + * dial announced + * + * Sent on zwp_tablet_pad_v2 initialization to announce available + * dials. One event is sent for each dial available on this pad + * group. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_group_v2.done event. + * @since 2 + */ + void (*dial)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_dial_v2 *dial); +}; + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +static inline int +zwp_tablet_pad_group_v2_add_listener(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + const struct zwp_tablet_pad_group_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_group_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_GROUP_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_BUTTONS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_RING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_STRIP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_MODES_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_MODE_SWITCH_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_DIAL_SINCE_VERSION 2 + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_group_v2 */ +static inline void +zwp_tablet_pad_group_v2_set_user_data(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_group_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_group_v2 */ +static inline void * +zwp_tablet_pad_group_v2_get_user_data(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_group_v2); +} + +static inline uint32_t +zwp_tablet_pad_group_v2_get_version(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_group_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + * + * Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object + * are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_pad_group_v2_destroy(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_group_v2, + ZWP_TABLET_PAD_GROUP_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_group_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM +#define ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_v2 + * physical button state + * + * Describes the physical state of a button that caused the button + * event. + */ +enum zwp_tablet_pad_v2_button_state { + /** + * the button is not pressed + */ + ZWP_TABLET_PAD_V2_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED = 1, +}; +#endif /* ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * @struct zwp_tablet_pad_v2_listener + */ +struct zwp_tablet_pad_v2_listener { + /** + * group announced + * + * Sent on zwp_tablet_pad_v2 initialization to announce available + * groups. One event is sent for each pad group available. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_v2.done event. At least one group will be + * announced. + */ + void (*group)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + struct zwp_tablet_pad_group_v2 *pad_group); + /** + * path to the device + * + * A system-specific device path that indicates which device is + * behind this zwp_tablet_pad_v2. This information may be used to + * gather additional information about the device, e.g. through + * libwacom. + * + * The format of the path is unspecified, it may be a device node, + * a sysfs path, or some other identifier. It is up to the client + * to identify the string provided. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_v2.done event. + * @param path path to local device + */ + void (*path)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + const char *path); + /** + * buttons announced + * + * Sent on zwp_tablet_pad_v2 initialization to announce the + * available buttons. + * + * This event is sent in the initial burst of events before the + * zwp_tablet_pad_v2.done event. This event is only sent when at + * least one button is available. + * @param buttons the number of buttons + */ + void (*buttons)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t buttons); + /** + * pad description event sequence complete + * + * This event signals the end of the initial burst of descriptive + * events. A client may consider the static description of the pad + * to be complete and finalize initialization of the pad. + */ + void (*done)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2); + /** + * physical button state + * + * Sent whenever the physical state of a button changes. + * @param time the time of the event with millisecond granularity + * @param button the index of the button that changed state + */ + void (*button)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t time, + uint32_t button, + uint32_t state); + /** + * enter event + * + * Notification that this pad is focused on the specified + * surface. + * @param serial serial number of the enter event + * @param tablet the tablet the pad is attached to + * @param surface surface the pad is focused on + */ + void (*enter)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct zwp_tablet_v2 *tablet, + struct wl_surface *surface); + /** + * leave event + * + * Notification that this pad is no longer focused on the + * specified surface. + * @param serial serial number of the leave event + * @param surface surface the pad is no longer focused on + */ + void (*leave)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct wl_surface *surface); + /** + * pad removed event + * + * Sent when the pad has been removed from the system. When a + * tablet is removed its pad(s) will be removed too. + * + * When this event is received, the client must destroy all rings, + * strips and groups that were offered by this pad, and issue + * zwp_tablet_pad_v2.destroy the pad itself. + */ + void (*removed)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2); +}; + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +static inline int +zwp_tablet_pad_v2_add_listener(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + const struct zwp_tablet_pad_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_GROUP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_PATH_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_BUTTONS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_REMOVED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_v2 */ +static inline void +zwp_tablet_pad_v2_set_user_data(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_v2 */ +static inline void * +zwp_tablet_pad_v2_get_user_data(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_v2); +} + +static inline uint32_t +zwp_tablet_pad_v2_get_version(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * + * Requests the compositor to use the provided feedback string + * associated with this button. This request should be issued immediately + * after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding + * group is received, or whenever a button is mapped to a different + * action. See zwp_tablet_pad_group_v2.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with each button, and compositors may use + * this information to offer visual feedback on the button layout + * (e.g. on-screen displays). + * + * Button indices start at 0. Setting the feedback string on a button + * that is reserved by the compositor (i.e. not belonging to any + * zwp_tablet_pad_group_v2) does not generate an error but the compositor + * is free to ignore the request. + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * zwp_tablet_pad_group_v2.mode_switch event received for the group of this + * button. Requests providing other serials than the most recent one will + * be ignored. + */ +static inline void +zwp_tablet_pad_v2_set_feedback(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t button, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_v2, + ZWP_TABLET_PAD_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2), 0, button, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * + * Destroy the zwp_tablet_pad_v2 object. Objects created from this object + * are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_pad_v2_destroy(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_v2, + ZWP_TABLET_PAD_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + * @struct zwp_tablet_pad_dial_v2_listener + */ +struct zwp_tablet_pad_dial_v2_listener { + /** + * delta movement + * + * Sent whenever the position on a dial changes. + * + * This event carries the wheel delta as multiples or fractions of + * 120 with each multiple of 120 representing one logical wheel + * detent. For example, an axis_value120 of 30 is one quarter of a + * logical wheel step in the positive direction, a value120 of -240 + * are two logical wheel steps in the negative direction within the + * same hardware event. See the wl_pointer.axis_value120 for more + * details. + * + * The value120 must not be zero. + * @param value120 rotation distance as fraction of 120 + */ + void (*delta)(void *data, + struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2, + int32_t value120); + /** + * end of a dial event sequence + * + * Indicates the end of a set of events that represent one + * logical hardware dial event. A client is expected to accumulate + * the data in all events within the frame before proceeding. + * + * All zwp_tablet_pad_dial_v2 events before a + * zwp_tablet_pad_dial_v2.frame event belong logically together. + * + * A zwp_tablet_pad_dial_v2.frame event is sent for every logical + * event group, even if the group only contains a single + * zwp_tablet_pad_dial_v2 event. Specifically, a client may get a + * sequence: delta, frame, delta, frame, etc. + * @param time timestamp with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + */ +static inline int +zwp_tablet_pad_dial_v2_add_listener(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2, + const struct zwp_tablet_pad_dial_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_dial_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_DIAL_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_DIAL_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + */ +#define ZWP_TABLET_PAD_DIAL_V2_DELTA_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + */ +#define ZWP_TABLET_PAD_DIAL_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + */ +#define ZWP_TABLET_PAD_DIAL_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + */ +#define ZWP_TABLET_PAD_DIAL_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_dial_v2 */ +static inline void +zwp_tablet_pad_dial_v2_set_user_data(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_dial_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_dial_v2 */ +static inline void * +zwp_tablet_pad_dial_v2_get_user_data(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_dial_v2); +} + +static inline uint32_t +zwp_tablet_pad_dial_v2_get_version(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_dial_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + * + * Requests the compositor to use the provided feedback string + * associated with this dial. This request should be issued immediately + * after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding + * group is received, or whenever the dial is mapped to a different + * action. See zwp_tablet_pad_group_v2.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with the dial, and compositors may use this + * information to offer visual feedback about the button layout + * (eg. on-screen displays). + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * zwp_tablet_pad_group_v2.mode_switch event received for the group of this + * dial. Requests providing other serials than the most recent one will be + * ignored. + */ +static inline void +zwp_tablet_pad_dial_v2_set_feedback(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_dial_v2, + ZWP_TABLET_PAD_DIAL_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_dial_v2), 0, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_dial_v2 + * + * This destroys the client's resource for this dial object. + */ +static inline void +zwp_tablet_pad_dial_v2_destroy(struct zwp_tablet_pad_dial_v2 *zwp_tablet_pad_dial_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_dial_v2, + ZWP_TABLET_PAD_DIAL_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_dial_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/tablet-v2-protocol.c b/src/wayland/protocols/tablet-v2-protocol.c new file mode 100644 index 0000000..4a1f57b --- /dev/null +++ b/src/wayland/protocols/tablet-v2-protocol.c @@ -0,0 +1,254 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright 2014 © Stephen "Lyude" Chandler Paul + * Copyright 2015-2024 © Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zwp_tablet_pad_dial_v2_interface; +extern const struct wl_interface zwp_tablet_pad_group_v2_interface; +extern const struct wl_interface zwp_tablet_pad_ring_v2_interface; +extern const struct wl_interface zwp_tablet_pad_strip_v2_interface; +extern const struct wl_interface zwp_tablet_pad_v2_interface; +extern const struct wl_interface zwp_tablet_seat_v2_interface; +extern const struct wl_interface zwp_tablet_tool_v2_interface; +extern const struct wl_interface zwp_tablet_v2_interface; + +static const struct wl_interface *tablet_v2_types[] = { + NULL, + NULL, + NULL, + &zwp_tablet_seat_v2_interface, + &wl_seat_interface, + &zwp_tablet_v2_interface, + &zwp_tablet_tool_v2_interface, + &zwp_tablet_pad_v2_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &zwp_tablet_v2_interface, + &wl_surface_interface, + &zwp_tablet_pad_ring_v2_interface, + &zwp_tablet_pad_strip_v2_interface, + &zwp_tablet_pad_dial_v2_interface, + &zwp_tablet_pad_group_v2_interface, + NULL, + &zwp_tablet_v2_interface, + &wl_surface_interface, + NULL, + &wl_surface_interface, +}; + +static const struct wl_message zwp_tablet_manager_v2_requests[] = { + { "get_tablet_seat", "no", tablet_v2_types + 3 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_manager_v2_interface = { + "zwp_tablet_manager_v2", 2, + 2, zwp_tablet_manager_v2_requests, + 0, NULL, +}; + +static const struct wl_message zwp_tablet_seat_v2_requests[] = { + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_seat_v2_events[] = { + { "tablet_added", "n", tablet_v2_types + 5 }, + { "tool_added", "n", tablet_v2_types + 6 }, + { "pad_added", "n", tablet_v2_types + 7 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_seat_v2_interface = { + "zwp_tablet_seat_v2", 2, + 1, zwp_tablet_seat_v2_requests, + 3, zwp_tablet_seat_v2_events, +}; + +static const struct wl_message zwp_tablet_tool_v2_requests[] = { + { "set_cursor", "u?oii", tablet_v2_types + 8 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_tool_v2_events[] = { + { "type", "u", tablet_v2_types + 0 }, + { "hardware_serial", "uu", tablet_v2_types + 0 }, + { "hardware_id_wacom", "uu", tablet_v2_types + 0 }, + { "capability", "u", tablet_v2_types + 0 }, + { "done", "", tablet_v2_types + 0 }, + { "removed", "", tablet_v2_types + 0 }, + { "proximity_in", "uoo", tablet_v2_types + 12 }, + { "proximity_out", "", tablet_v2_types + 0 }, + { "down", "u", tablet_v2_types + 0 }, + { "up", "", tablet_v2_types + 0 }, + { "motion", "ff", tablet_v2_types + 0 }, + { "pressure", "u", tablet_v2_types + 0 }, + { "distance", "u", tablet_v2_types + 0 }, + { "tilt", "ff", tablet_v2_types + 0 }, + { "rotation", "f", tablet_v2_types + 0 }, + { "slider", "i", tablet_v2_types + 0 }, + { "wheel", "fi", tablet_v2_types + 0 }, + { "button", "uuu", tablet_v2_types + 0 }, + { "frame", "u", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_tool_v2_interface = { + "zwp_tablet_tool_v2", 2, + 2, zwp_tablet_tool_v2_requests, + 19, zwp_tablet_tool_v2_events, +}; + +static const struct wl_message zwp_tablet_v2_requests[] = { + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_v2_events[] = { + { "name", "s", tablet_v2_types + 0 }, + { "id", "uu", tablet_v2_types + 0 }, + { "path", "s", tablet_v2_types + 0 }, + { "done", "", tablet_v2_types + 0 }, + { "removed", "", tablet_v2_types + 0 }, + { "bustype", "2u", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_v2_interface = { + "zwp_tablet_v2", 2, + 1, zwp_tablet_v2_requests, + 6, zwp_tablet_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_ring_v2_requests[] = { + { "set_feedback", "su", tablet_v2_types + 0 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_ring_v2_events[] = { + { "source", "u", tablet_v2_types + 0 }, + { "angle", "f", tablet_v2_types + 0 }, + { "stop", "", tablet_v2_types + 0 }, + { "frame", "u", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_ring_v2_interface = { + "zwp_tablet_pad_ring_v2", 2, + 2, zwp_tablet_pad_ring_v2_requests, + 4, zwp_tablet_pad_ring_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_strip_v2_requests[] = { + { "set_feedback", "su", tablet_v2_types + 0 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_strip_v2_events[] = { + { "source", "u", tablet_v2_types + 0 }, + { "position", "u", tablet_v2_types + 0 }, + { "stop", "", tablet_v2_types + 0 }, + { "frame", "u", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_strip_v2_interface = { + "zwp_tablet_pad_strip_v2", 2, + 2, zwp_tablet_pad_strip_v2_requests, + 4, zwp_tablet_pad_strip_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_group_v2_requests[] = { + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_group_v2_events[] = { + { "buttons", "a", tablet_v2_types + 0 }, + { "ring", "n", tablet_v2_types + 15 }, + { "strip", "n", tablet_v2_types + 16 }, + { "modes", "u", tablet_v2_types + 0 }, + { "done", "", tablet_v2_types + 0 }, + { "mode_switch", "uuu", tablet_v2_types + 0 }, + { "dial", "2n", tablet_v2_types + 17 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_group_v2_interface = { + "zwp_tablet_pad_group_v2", 2, + 1, zwp_tablet_pad_group_v2_requests, + 7, zwp_tablet_pad_group_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_v2_requests[] = { + { "set_feedback", "usu", tablet_v2_types + 0 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_v2_events[] = { + { "group", "n", tablet_v2_types + 18 }, + { "path", "s", tablet_v2_types + 0 }, + { "buttons", "u", tablet_v2_types + 0 }, + { "done", "", tablet_v2_types + 0 }, + { "button", "uuu", tablet_v2_types + 0 }, + { "enter", "uoo", tablet_v2_types + 19 }, + { "leave", "uo", tablet_v2_types + 22 }, + { "removed", "", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_v2_interface = { + "zwp_tablet_pad_v2", 2, + 2, zwp_tablet_pad_v2_requests, + 8, zwp_tablet_pad_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_dial_v2_requests[] = { + { "set_feedback", "su", tablet_v2_types + 0 }, + { "destroy", "", tablet_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_dial_v2_events[] = { + { "delta", "i", tablet_v2_types + 0 }, + { "frame", "u", tablet_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_dial_v2_interface = { + "zwp_tablet_pad_dial_v2", 2, + 2, zwp_tablet_pad_dial_v2_requests, + 2, zwp_tablet_pad_dial_v2_events, +}; + diff --git a/src/wayland/protocols/tearing-control-v1-client-protocol.h b/src/wayland/protocols/tearing-control-v1-client-protocol.h new file mode 100644 index 0000000..48f9861 --- /dev/null +++ b/src/wayland/protocols/tearing-control-v1-client-protocol.h @@ -0,0 +1,298 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef TEARING_CONTROL_V1_CLIENT_PROTOCOL_H +#define TEARING_CONTROL_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_tearing_control_v1 The tearing_control_v1 protocol + * @section page_ifaces_tearing_control_v1 Interfaces + * - @subpage page_iface_wp_tearing_control_manager_v1 - protocol for tearing control + * - @subpage page_iface_wp_tearing_control_v1 - per-surface tearing control interface + * @section page_copyright_tearing_control_v1 Copyright + *
+ *
+ * Copyright © 2021 Xaver Hugl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_tearing_control_manager_v1; +struct wp_tearing_control_v1; + +#ifndef WP_TEARING_CONTROL_MANAGER_V1_INTERFACE +#define WP_TEARING_CONTROL_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_tearing_control_manager_v1 wp_tearing_control_manager_v1 + * @section page_iface_wp_tearing_control_manager_v1_desc Description + * + * For some use cases like games or drawing tablets it can make sense to + * reduce latency by accepting tearing with the use of asynchronous page + * flips. This global is a factory interface, allowing clients to inform + * which type of presentation the content of their surfaces is suitable for. + * + * Graphics APIs like EGL or Vulkan, that manage the buffer queue and commits + * of a wl_surface themselves, are likely to be using this extension + * internally. If a client is using such an API for a wl_surface, it should + * not directly use this extension on that surface, to avoid raising a + * tearing_control_exists protocol error. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_wp_tearing_control_manager_v1_api API + * See @ref iface_wp_tearing_control_manager_v1. + */ +/** + * @defgroup iface_wp_tearing_control_manager_v1 The wp_tearing_control_manager_v1 interface + * + * For some use cases like games or drawing tablets it can make sense to + * reduce latency by accepting tearing with the use of asynchronous page + * flips. This global is a factory interface, allowing clients to inform + * which type of presentation the content of their surfaces is suitable for. + * + * Graphics APIs like EGL or Vulkan, that manage the buffer queue and commits + * of a wl_surface themselves, are likely to be using this extension + * internally. If a client is using such an API for a wl_surface, it should + * not directly use this extension on that surface, to avoid raising a + * tearing_control_exists protocol error. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface wp_tearing_control_manager_v1_interface; +#endif +#ifndef WP_TEARING_CONTROL_V1_INTERFACE +#define WP_TEARING_CONTROL_V1_INTERFACE +/** + * @page page_iface_wp_tearing_control_v1 wp_tearing_control_v1 + * @section page_iface_wp_tearing_control_v1_desc Description + * + * An additional interface to a wl_surface object, which allows the client + * to hint to the compositor if the content on the surface is suitable for + * presentation with tearing. + * The default presentation hint is vsync. See presentation_hint for more + * details. + * + * If the associated wl_surface is destroyed, this object becomes inert and + * should be destroyed. + * @section page_iface_wp_tearing_control_v1_api API + * See @ref iface_wp_tearing_control_v1. + */ +/** + * @defgroup iface_wp_tearing_control_v1 The wp_tearing_control_v1 interface + * + * An additional interface to a wl_surface object, which allows the client + * to hint to the compositor if the content on the surface is suitable for + * presentation with tearing. + * The default presentation hint is vsync. See presentation_hint for more + * details. + * + * If the associated wl_surface is destroyed, this object becomes inert and + * should be destroyed. + */ +extern const struct wl_interface wp_tearing_control_v1_interface; +#endif + +#ifndef WP_TEARING_CONTROL_MANAGER_V1_ERROR_ENUM +#define WP_TEARING_CONTROL_MANAGER_V1_ERROR_ENUM +enum wp_tearing_control_manager_v1_error { + /** + * the surface already has a tearing object associated + */ + WP_TEARING_CONTROL_MANAGER_V1_ERROR_TEARING_CONTROL_EXISTS = 0, +}; +#endif /* WP_TEARING_CONTROL_MANAGER_V1_ERROR_ENUM */ + +#define WP_TEARING_CONTROL_MANAGER_V1_DESTROY 0 +#define WP_TEARING_CONTROL_MANAGER_V1_GET_TEARING_CONTROL 1 + + +/** + * @ingroup iface_wp_tearing_control_manager_v1 + */ +#define WP_TEARING_CONTROL_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_tearing_control_manager_v1 + */ +#define WP_TEARING_CONTROL_MANAGER_V1_GET_TEARING_CONTROL_SINCE_VERSION 1 + +/** @ingroup iface_wp_tearing_control_manager_v1 */ +static inline void +wp_tearing_control_manager_v1_set_user_data(struct wp_tearing_control_manager_v1 *wp_tearing_control_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_tearing_control_manager_v1, user_data); +} + +/** @ingroup iface_wp_tearing_control_manager_v1 */ +static inline void * +wp_tearing_control_manager_v1_get_user_data(struct wp_tearing_control_manager_v1 *wp_tearing_control_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_tearing_control_manager_v1); +} + +static inline uint32_t +wp_tearing_control_manager_v1_get_version(struct wp_tearing_control_manager_v1 *wp_tearing_control_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_manager_v1); +} + +/** + * @ingroup iface_wp_tearing_control_manager_v1 + * + * Destroy this tearing control factory object. Other objects, including + * wp_tearing_control_v1 objects created by this factory, are not affected + * by this request. + */ +static inline void +wp_tearing_control_manager_v1_destroy(struct wp_tearing_control_manager_v1 *wp_tearing_control_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_tearing_control_manager_v1, + WP_TEARING_CONTROL_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_tearing_control_manager_v1 + * + * Instantiate an interface extension for the given wl_surface to request + * asynchronous page flips for presentation. + * + * If the given wl_surface already has a wp_tearing_control_v1 object + * associated, the tearing_control_exists protocol error is raised. + */ +static inline struct wp_tearing_control_v1 * +wp_tearing_control_manager_v1_get_tearing_control(struct wp_tearing_control_manager_v1 *wp_tearing_control_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_tearing_control_manager_v1, + WP_TEARING_CONTROL_MANAGER_V1_GET_TEARING_CONTROL, &wp_tearing_control_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_manager_v1), 0, NULL, surface); + + return (struct wp_tearing_control_v1 *) id; +} + +#ifndef WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ENUM +#define WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ENUM +/** + * @ingroup iface_wp_tearing_control_v1 + * presentation hint values + * + * This enum provides information for if submitted frames from the client + * may be presented with tearing. + */ +enum wp_tearing_control_v1_presentation_hint { + /** + * tearing-free presentation + * + * The content of this surface is meant to be synchronized to the + * vertical blanking period. This should not result in visible + * tearing and may result in a delay before a surface commit is + * presented. + */ + WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC = 0, + /** + * asynchronous presentation + * + * The content of this surface is meant to be presented with + * minimal latency and tearing is acceptable. + */ + WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC = 1, +}; +#endif /* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ENUM */ + +#define WP_TEARING_CONTROL_V1_SET_PRESENTATION_HINT 0 +#define WP_TEARING_CONTROL_V1_DESTROY 1 + + +/** + * @ingroup iface_wp_tearing_control_v1 + */ +#define WP_TEARING_CONTROL_V1_SET_PRESENTATION_HINT_SINCE_VERSION 1 +/** + * @ingroup iface_wp_tearing_control_v1 + */ +#define WP_TEARING_CONTROL_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_tearing_control_v1 */ +static inline void +wp_tearing_control_v1_set_user_data(struct wp_tearing_control_v1 *wp_tearing_control_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_tearing_control_v1, user_data); +} + +/** @ingroup iface_wp_tearing_control_v1 */ +static inline void * +wp_tearing_control_v1_get_user_data(struct wp_tearing_control_v1 *wp_tearing_control_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_tearing_control_v1); +} + +static inline uint32_t +wp_tearing_control_v1_get_version(struct wp_tearing_control_v1 *wp_tearing_control_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_v1); +} + +/** + * @ingroup iface_wp_tearing_control_v1 + * + * Set the presentation hint for the associated wl_surface. This state is + * double-buffered, see wl_surface.commit. + * + * The compositor is free to dynamically respect or ignore this hint based + * on various conditions like hardware capabilities, surface state and + * user preferences. + */ +static inline void +wp_tearing_control_v1_set_presentation_hint(struct wp_tearing_control_v1 *wp_tearing_control_v1, uint32_t hint) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_tearing_control_v1, + WP_TEARING_CONTROL_V1_SET_PRESENTATION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_v1), 0, hint); +} + +/** + * @ingroup iface_wp_tearing_control_v1 + * + * Destroy this surface tearing object and revert the presentation hint to + * vsync. The change will be applied on the next wl_surface.commit. + */ +static inline void +wp_tearing_control_v1_destroy(struct wp_tearing_control_v1 *wp_tearing_control_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_tearing_control_v1, + WP_TEARING_CONTROL_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_tearing_control_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/tearing-control-v1-protocol.c b/src/wayland/protocols/tearing-control-v1-protocol.c new file mode 100644 index 0000000..afedad8 --- /dev/null +++ b/src/wayland/protocols/tearing-control-v1-protocol.c @@ -0,0 +1,71 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2021 Xaver Hugl + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_tearing_control_v1_interface; + +static const struct wl_interface *tearing_control_v1_types[] = { + NULL, + &wp_tearing_control_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_tearing_control_manager_v1_requests[] = { + { "destroy", "", tearing_control_v1_types + 0 }, + { "get_tearing_control", "no", tearing_control_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface wp_tearing_control_manager_v1_interface = { + "wp_tearing_control_manager_v1", 1, + 2, wp_tearing_control_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_tearing_control_v1_requests[] = { + { "set_presentation_hint", "u", tearing_control_v1_types + 0 }, + { "destroy", "", tearing_control_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_tearing_control_v1_interface = { + "wp_tearing_control_v1", 1, + 2, wp_tearing_control_v1_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/text-input-unstable-v3-client-protocol.h b/src/wayland/protocols/text-input-unstable-v3-client-protocol.h new file mode 100644 index 0000000..2c4c23b --- /dev/null +++ b/src/wayland/protocols/text-input-unstable-v3-client-protocol.h @@ -0,0 +1,1103 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H +#define TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_text_input_unstable_v3 The text_input_unstable_v3 protocol + * Protocol for composing text + * + * @section page_desc_text_input_unstable_v3 Description + * + * This protocol allows compositors to act as input methods and to send text + * to applications. A text input object is used to manage state of what are + * typically text entry fields in the application. + * + * This document adheres to the RFC 2119 when using words like "must", + * "should", "may", etc. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * + * @section page_ifaces_text_input_unstable_v3 Interfaces + * - @subpage page_iface_zwp_text_input_v3 - text input + * - @subpage page_iface_zwp_text_input_manager_v3 - text input manager + * @section page_copyright_text_input_unstable_v3 Copyright + *
+ *
+ * Copyright © 2012, 2013 Intel Corporation
+ * Copyright © 2015, 2016 Jan Arne Petersen
+ * Copyright © 2017, 2018 Red Hat, Inc.
+ * Copyright © 2018       Purism SPC
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * 
+ */ +struct wl_seat; +struct wl_surface; +struct zwp_text_input_manager_v3; +struct zwp_text_input_v3; + +#ifndef ZWP_TEXT_INPUT_V3_INTERFACE +#define ZWP_TEXT_INPUT_V3_INTERFACE +/** + * @page page_iface_zwp_text_input_v3 zwp_text_input_v3 + * @section page_iface_zwp_text_input_v3_desc Description + * + * The zwp_text_input_v3 interface represents text input and input methods + * associated with a seat. It provides enter/leave events to follow the + * text input focus for a seat. + * + * Requests are used to enable/disable the text-input object and set + * state information like surrounding and selected text or the content type. + * The information about the entered text is sent to the text-input object + * via the preedit_string and commit_string events. + * + * Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + * must not point to middle bytes inside a code point: they must either + * point to the first byte of a code point or to the end of the buffer. + * Lengths must be measured between two valid indices. + * + * Focus moving throughout surfaces will result in the emission of + * zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused + * surface must commit zwp_text_input_v3.enable and + * zwp_text_input_v3.disable requests as the keyboard focus moves across + * editable and non-editable elements of the UI. Those two requests are not + * expected to be paired with each other, the compositor must be able to + * handle consecutive series of the same request. + * + * State is sent by the state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) and a commit request. After an + * enter event or disable request all state information is invalidated and + * needs to be resent by the client. + * @section page_iface_zwp_text_input_v3_api API + * See @ref iface_zwp_text_input_v3. + */ +/** + * @defgroup iface_zwp_text_input_v3 The zwp_text_input_v3 interface + * + * The zwp_text_input_v3 interface represents text input and input methods + * associated with a seat. It provides enter/leave events to follow the + * text input focus for a seat. + * + * Requests are used to enable/disable the text-input object and set + * state information like surrounding and selected text or the content type. + * The information about the entered text is sent to the text-input object + * via the preedit_string and commit_string events. + * + * Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + * must not point to middle bytes inside a code point: they must either + * point to the first byte of a code point or to the end of the buffer. + * Lengths must be measured between two valid indices. + * + * Focus moving throughout surfaces will result in the emission of + * zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused + * surface must commit zwp_text_input_v3.enable and + * zwp_text_input_v3.disable requests as the keyboard focus moves across + * editable and non-editable elements of the UI. Those two requests are not + * expected to be paired with each other, the compositor must be able to + * handle consecutive series of the same request. + * + * State is sent by the state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) and a commit request. After an + * enter event or disable request all state information is invalidated and + * needs to be resent by the client. + */ +extern const struct wl_interface zwp_text_input_v3_interface; +#endif +#ifndef ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE +#define ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE +/** + * @page page_iface_zwp_text_input_manager_v3 zwp_text_input_manager_v3 + * @section page_iface_zwp_text_input_manager_v3_desc Description + * + * A factory for text-input objects. This object is a global singleton. + * @section page_iface_zwp_text_input_manager_v3_api API + * See @ref iface_zwp_text_input_manager_v3. + */ +/** + * @defgroup iface_zwp_text_input_manager_v3 The zwp_text_input_manager_v3 interface + * + * A factory for text-input objects. This object is a global singleton. + */ +extern const struct wl_interface zwp_text_input_manager_v3_interface; +#endif + +#ifndef ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM +#define ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * text change reason + * + * Reason for the change of surrounding text or cursor posision. + */ +enum zwp_text_input_v3_change_cause { + /** + * input method caused the change + */ + ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD = 0, + /** + * something else than the input method caused the change + */ + ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER = 1, +}; +#endif /* ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * content hint + * + * Content hint is a bitmask to allow to modify the behavior of the text + * input. + */ +enum zwp_text_input_v3_content_hint { + /** + * no special behavior + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE = 0x0, + /** + * suggest word completions + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION = 0x1, + /** + * suggest word corrections + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK = 0x2, + /** + * switch to uppercase letters at the start of a sentence + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION = 0x4, + /** + * prefer lowercase letters + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE = 0x8, + /** + * prefer uppercase letters + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE = 0x10, + /** + * prefer casing for titles and headings (can be language dependent) + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE = 0x20, + /** + * characters should be hidden + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT = 0x40, + /** + * typed text should not be stored + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA = 0x80, + /** + * just Latin characters should be entered + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN = 0x100, + /** + * the text input is multiline + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE = 0x200, + /** + * an on-screen way to fill in the input is already provided by the client + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED = 0x400, + /** + * prefer not offering emoji support + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NO_EMOJI = 0x800, + /** + * the text input will display preedit text in place + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_PREEDIT_SHOWN = 0x1000, +}; +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_NO_EMOJI_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_PREEDIT_SHOWN_SINCE_VERSION 2 +#endif /* ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM +#define ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * content purpose + * + * The content purpose allows to specify the primary purpose of a text + * input. + * + * This allows an input method to show special purpose input panels with + * extra characters or to disallow some characters. + */ +enum zwp_text_input_v3_content_purpose { + /** + * default input, allowing all characters + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL = 0, + /** + * allow only alphabetic characters + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ALPHA = 1, + /** + * allow only digits + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS = 2, + /** + * input a number (including decimal separator and sign) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER = 3, + /** + * input a phone number + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE = 4, + /** + * input an URL + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL = 5, + /** + * input an email address + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL = 6, + /** + * input a name of a person + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME = 7, + /** + * input a password (combine with sensitive_data hint) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD = 8, + /** + * input is a numeric password (combine with sensitive_data hint) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN = 9, + /** + * input a date + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE = 10, + /** + * input a time + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME = 11, + /** + * input a date and time + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME = 12, + /** + * input for a terminal + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL = 13, +}; +#endif /* ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_ERROR_ENUM +#define ZWP_TEXT_INPUT_V3_ERROR_ENUM +enum zwp_text_input_v3_error { + /** + * an invalid or duplicate action was specified + */ + ZWP_TEXT_INPUT_V3_ERROR_INVALID_ACTION = 0, +}; +#endif /* ZWP_TEXT_INPUT_V3_ERROR_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_ACTION_ENUM +#define ZWP_TEXT_INPUT_V3_ACTION_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * action + * + * A possible action to perform on a text input. + * + * The submit action is intended for input entries that expect some sort of + * activation after user interaction, e.g. the URL entry in a browser. + */ +enum zwp_text_input_v3_action { + /** + * no action + */ + ZWP_TEXT_INPUT_V3_ACTION_NONE = 0, + /** + * the action is submitted + */ + ZWP_TEXT_INPUT_V3_ACTION_SUBMIT = 1, +}; +#endif /* ZWP_TEXT_INPUT_V3_ACTION_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM +#define ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * preedit style hint + * + * Style hints for the preedit string. + */ +enum zwp_text_input_v3_preedit_hint { + /** + * simple pre-edit text style, typically underlined + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_WHOLE = 1, + /** + * hint for a selected piece of text, e.g. per-character navigation and composition + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SELECTION = 2, + /** + * predicted text, not typed by the user + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_PREDICTION = 3, + /** + * prefixed text not being currently edited, e.g. prior to a 'selection' section + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_PREFIX = 4, + /** + * suffixed text not being currently edited, e.g. after a 'selection' section + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SUFFIX = 5, + /** + * spelling error + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SPELLING_ERROR = 6, + /** + * wrong composition, e.g. user input that can not be transliterated + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_COMPOSE_ERROR = 7, +}; +#endif /* ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM */ + +/** + * @ingroup iface_zwp_text_input_v3 + * @struct zwp_text_input_v3_listener + */ +struct zwp_text_input_v3_listener { + /** + * enter event + * + * Notification that this seat's text-input focus is on a certain + * surface. + * + * If client has created multiple text input objects, compositor + * must send this event to all of them. + * + * When the seat has the keyboard capability the text-input focus + * follows the keyboard focus. This event sets the current surface + * for the text-input object. + */ + void (*enter)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface); + /** + * leave event + * + * Notification that this seat's text-input focus is no longer on + * a certain surface. The client should reset any preedit string + * previously set. + * + * The leave notification clears the current surface. It is sent + * before the enter notification for the new focus. After leave + * event, compositor must ignore requests from any text input + * instances until next enter event. + * + * When the seat has the keyboard capability the text-input focus + * follows the keyboard focus. + */ + void (*leave)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface); + /** + * pre-edit + * + * Notify when a new composing text (pre-edit) should be set at + * the current cursor position. Any previously set composing text + * must be removed. Any previously existing selected text must be + * removed. + * + * The argument text contains the pre-edit string buffer. + * + * The parameters cursor_begin and cursor_end are counted in bytes + * relative to the beginning of the submitted text buffer. Cursor + * should be hidden when both are equal to -1. + * + * They could be represented by the client as a line if both values + * are the same, or as a text highlight otherwise. + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of text is an empty string, and cursor_begin, + * cursor_end and cursor_hidden are all 0. + */ + void (*preedit_string)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text, + int32_t cursor_begin, + int32_t cursor_end); + /** + * text commit + * + * Notify when text should be inserted into the editor widget. + * The text to commit could be either just a single character after + * a key press or the result of some composing (pre-edit). + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of text is an empty string. + */ + void (*commit_string)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text); + /** + * delete surrounding text + * + * Notify when the text around the current cursor position should + * be deleted. + * + * Before_length and after_length are the number of bytes before + * and after the current cursor index (excluding the selection) to + * delete. + * + * If a preedit text is present, in effect before_length is counted + * from the beginning of it, and after_length from its end (see + * done event sequence). + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial values of both before_length and after_length are 0. + * @param before_length length of text before current cursor position + * @param after_length length of text after current cursor position + */ + void (*delete_surrounding_text)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t before_length, + uint32_t after_length); + /** + * apply changes + * + * Instruct the application to apply changes to state requested + * by the preedit_string, commit_string delete_surrounding_text, + * and action events. + * + * The state relating to these events is double-buffered, and each + * one modifies the pending state. This event replaces the current + * state with the pending state. + * + * The application must proceed by evaluating the changes in the + * following order: + * + * 1. Replace existing preedit string with the cursor. 2. Delete + * requested surrounding text. 3. Insert commit string with the + * cursor at its end. 4. Calculate surrounding text to send. 5. + * Insert new preedit text in cursor position. 6. Place cursor + * inside preedit text. 7. Perform the requested action. + * + * The serial number reflects the last state of the + * zwp_text_input_v3 object known to the compositor. The value of + * the serial argument must be equal to the number of commit + * requests already issued on that object. + * + * When the client receives a done event with a serial different + * than the number of past commit requests, it must proceed with + * evaluating and applying the changes as normal, except it should + * not change the current state of the zwp_text_input_v3 object. + * All pending state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) on the + * zwp_text_input_v3 object should be sent and committed after + * receiving a zwp_text_input_v3.done event with a matching serial. + */ + void (*done)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t serial); + /** + * action performed + * + * An action was performed on this text input. + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of action is none. + * @param action action performed + * @param serial serial number of the action event + * @since 2 + */ + void (*action)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t action, + uint32_t serial); + /** + * notify of language selection + * + * Notify the application of language used by the input method. + * + * This event will be sent on creation if known and for all + * subsequent changes. + * + * The language should be specified as an IETF BCP 47 tag. Setting + * an empty string will reset any known language back to the + * default unknown state. + * @param language new language set by IME + * @since 2 + */ + void (*language)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *language); + /** + * pre-edit + * + * Notify of contextual hints for the pre-edit string. This event + * is always sent together with a zwp_text_input_v3.preedit_string + * event. + * + * The parameters start and end are counted in bytes relative to + * the beginning of the text buffer submitted through + * zwp_text_input_v3.preedit_string, and represent the substring in + * the pre-edit text affected by the hint. + * + * Multiple events may be submitted if the preedit string has + * different sections. The extent of hints may overlap. The parts + * of the preedit string that are not covered by any + * zwp_text_input_v3.preedit_hint event, the text will be + * considered unhinted. This is also the case if no preedit_hint + * event is sent. + * + * Clients should provide recognizable visuals to these hints. if + * they are unable to comply with this requisition, it may be + * preferable for them keep the preedit_shown content hint + * disabled. + * + * Values set with this event are double-buffered. They must be + * applied and reset on the next zwp_text_input_v3.done event. + * @param start starting point of the affected substring + * @param end end point of the affected substring + * @param hint hint to apply + * @since 2 + */ + void (*preedit_hint)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t start, + uint32_t end, + uint32_t hint); +}; + +/** + * @ingroup iface_zwp_text_input_v3 + */ +static inline int +zwp_text_input_v3_add_listener(struct zwp_text_input_v3 *zwp_text_input_v3, + const struct zwp_text_input_v3_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_text_input_v3, + (void (**)(void)) listener, data); +} + +#define ZWP_TEXT_INPUT_V3_DESTROY 0 +#define ZWP_TEXT_INPUT_V3_ENABLE 1 +#define ZWP_TEXT_INPUT_V3_DISABLE 2 +#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT 3 +#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE 4 +#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE 5 +#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE 6 +#define ZWP_TEXT_INPUT_V3_COMMIT 7 +#define ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS 8 +#define ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL 9 +#define ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL 10 + +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_PREEDIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_COMMIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DELETE_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ACTION_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_LANGUAGE_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SINCE_VERSION 2 + +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ENABLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DISABLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL_SINCE_VERSION 2 + +/** @ingroup iface_zwp_text_input_v3 */ +static inline void +zwp_text_input_v3_set_user_data(struct zwp_text_input_v3 *zwp_text_input_v3, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_v3, user_data); +} + +/** @ingroup iface_zwp_text_input_v3 */ +static inline void * +zwp_text_input_v3_get_user_data(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_v3); +} + +static inline uint32_t +zwp_text_input_v3_get_version(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Destroy the wp_text_input object. Also disables all surfaces enabled + * through this wp_text_input object. + */ +static inline void +zwp_text_input_v3_destroy(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests text input on the surface previously obtained from the enter + * event. + * + * This request must be issued every time the focused text input changes + * to a new one, including within the current surface. Use + * zwp_text_input_v3.disable when there is no longer any input focus on + * the current surface. + * + * Clients must not enable more than one text input on the single seat + * and should disable the current text input before enabling the new one. + * Requests to enable a text input when another text input is enabled + * on the same seat must be ignored by compositor. + * + * This request resets all state associated with previous enable, disable, + * set_surrounding_text, set_text_change_cause, set_content_type, and + * set_cursor_rectangle requests, as well as the state associated with + * preedit_string, commit_string, and delete_surrounding_text events. + * + * The set_surrounding_text, set_content_type and set_cursor_rectangle + * requests must follow if the text input supports the necessary + * functionality. + * + * State set with this request is double-buffered. It will get applied on + * the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The changes must be applied by the compositor after issuing a + * zwp_text_input_v3.commit request. + */ +static inline void +zwp_text_input_v3_enable(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_ENABLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Explicitly disable text input on the current surface (typically when + * there is no focus on any text entry inside the surface). + * + * State set with this request is double-buffered. It will get applied on + * the next zwp_text_input_v3.commit request. + */ +static inline void +zwp_text_input_v3_disable(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_DISABLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Sets the surrounding plain text around the input, excluding the preedit + * text. + * + * The client should notify the compositor of any changes in any of the + * values carried with this request, including changes caused by handling + * incoming text-input events as well as changes caused by other + * mechanisms like keyboard typing. + * + * If the client is unaware of the text around the cursor, it should not + * issue this request, to signify lack of support to the compositor. + * + * Text is UTF-8 encoded, and should include the cursor position, the + * complete selection and additional characters before and after them. + * There is a maximum length of wayland messages, so text can not be + * longer than 4000 bytes. + * + * Cursor is the byte offset of the cursor within text buffer. + * + * Anchor is the byte offset of the selection anchor within text buffer. + * If there is no selected text, anchor is the same as cursor. + * + * If any preedit text is present, it is replaced with a cursor for the + * purpose of this event. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The initial state for affected fields is empty, meaning that the text + * input does not support sending surrounding text. If the empty values + * get applied, subsequent attempts to change them may have no effect. + */ +static inline void +zwp_text_input_v3_set_surrounding_text(struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor, int32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, text, cursor, anchor); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Tells the compositor why the text surrounding the cursor changed. + * + * Whenever the client detects an external change in text, cursor, or + * anchor posision, it must issue this request to the compositor. This + * request is intended to give the input method a chance to update the + * preedit text in an appropriate way, e.g. by removing it when the user + * starts typing with a keyboard. + * + * cause describes the source of the change. + * + * The value set with this request is double-buffered. It must be applied + * and reset to initial at the next zwp_text_input_v3.commit request. + * + * The initial value of cause is input_method. + */ +static inline void +zwp_text_input_v3_set_text_change_cause(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t cause) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, cause); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Sets the content purpose and content hint. While the purpose is the + * basic purpose of an input field, the hint flags allow to modify some of + * the behavior. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request. + * Subsequent attempts to update them may have no effect. The values + * remain valid until the next committed enable or disable request. + * + * The initial value for hint is none, and the initial value for purpose + * is normal. + */ +static inline void +zwp_text_input_v3_set_content_type(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t hint, uint32_t purpose) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, hint, purpose); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Marks an area around the cursor as a x, y, width, height rectangle in + * surface local coordinates. + * + * Allows the compositor to put a window with word suggestions near the + * cursor, without obstructing the text being input. + * + * If the client is unaware of the position of edited text, it should not + * issue this request, to signify lack of support to the compositor. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The initial values describing a cursor rectangle are empty. That means + * the text input does not support describing the cursor area. If the + * empty values get applied, subsequent attempts to change them may have + * no effect. + * + * As of version 2, the zwp_text_input_v3.commit request does not apply + * values sent with this request. Instead, it stores them in a separate + * "committed" area. The committed values, if still valid, get applied on + * the next wl_surface.commit request on the surface with text-input focus. + * Both committed and applied values get invalidated on: + * + * - the next committed enable or disable request, or + * - a change of the focused surface of the text-input (leave or enter events). + * + * This double stage application allows the compositor to position + * the input method popup in the same frame as the contents + * of the text on the surface are updated. + */ +static inline void +zwp_text_input_v3_set_cursor_rectangle(struct zwp_text_input_v3 *zwp_text_input_v3, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, x, y, width, height); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Atomically applies state changes recently sent to the compositor. + * + * The commit request establishes and updates the state of the client, and + * must be issued after any changes to apply them. + * + * Text input state (enabled status, content purpose, content hint, + * surrounding text and change cause, cursor rectangle) is conceptually + * double-buffered within the context of a text input, i.e. between a + * committed enable request and the following committed enable or disable + * request. + * + * Protocol requests modify the pending state, as opposed to the current + * state in use by the input method. A commit request atomically applies + * all pending state, replacing the current state. After commit, the new + * pending state is as documented for each related request. + * + * Requests are applied in the order of arrival. + * + * Neither current nor pending state are modified unless noted otherwise. + * + * The compositor must count the number of commit requests coming from + * each zwp_text_input_v3 object and use the count as the serial in done + * events. + */ +static inline void +zwp_text_input_v3_commit(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Set the actions available for this text input. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request. + * + * If the available_actions array contains the none action, or contains the + * same action multiple times, the compositor must raise the invalid_action + * protocol error. + * + * Initially, no actions are available. + */ +static inline void +zwp_text_input_v3_set_available_actions(struct zwp_text_input_v3 *zwp_text_input_v3, struct wl_array *available_actions) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, available_actions); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests an input panel to be shown (e.g. a on-screen keyboard). + * + * This request only hints the desired interaction pattern from the + * client side, and its effect may be ignored by compositors given + * other environmental factors. Repeated calls will be ignored. + */ +static inline void +zwp_text_input_v3_show_input_panel(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests an input panel to be hidden. + * + * This request only hints the desired interaction pattern from the + * client side, and its effect may be ignored by compositors given + * other environmental factors. Repeated calls will be ignored. + */ +static inline void +zwp_text_input_v3_hide_input_panel(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY 0 +#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT 1 + + +/** + * @ingroup iface_zwp_text_input_manager_v3 + */ +#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_manager_v3 + */ +#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT_SINCE_VERSION 1 + +/** @ingroup iface_zwp_text_input_manager_v3 */ +static inline void +zwp_text_input_manager_v3_set_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_manager_v3, user_data); +} + +/** @ingroup iface_zwp_text_input_manager_v3 */ +static inline void * +zwp_text_input_manager_v3_get_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_manager_v3); +} + +static inline uint32_t +zwp_text_input_manager_v3_get_version(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3); +} + +/** + * @ingroup iface_zwp_text_input_manager_v3 + * + * Destroy the wp_text_input_manager object. + */ +static inline void +zwp_text_input_manager_v3_destroy(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_manager_v3, + ZWP_TEXT_INPUT_MANAGER_V3_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_text_input_manager_v3 + * + * Creates a new text-input object for a given seat. + */ +static inline struct zwp_text_input_v3 * +zwp_text_input_manager_v3_get_text_input(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_manager_v3, + ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT, &zwp_text_input_v3_interface, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3), 0, NULL, seat); + + return (struct zwp_text_input_v3 *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/text-input-unstable-v3-protocol.c b/src/wayland/protocols/text-input-unstable-v3-protocol.c new file mode 100644 index 0000000..7683650 --- /dev/null +++ b/src/wayland/protocols/text-input-unstable-v3-protocol.c @@ -0,0 +1,103 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2012, 2013 Intel Corporation + * Copyright © 2015, 2016 Jan Arne Petersen + * Copyright © 2017, 2018 Red Hat, Inc. + * Copyright © 2018 Purism SPC + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zwp_text_input_v3_interface; + +static const struct wl_interface *text_input_unstable_v3_types[] = { + NULL, + NULL, + NULL, + NULL, + &wl_surface_interface, + &wl_surface_interface, + &zwp_text_input_v3_interface, + &wl_seat_interface, +}; + +static const struct wl_message zwp_text_input_v3_requests[] = { + { "destroy", "", text_input_unstable_v3_types + 0 }, + { "enable", "", text_input_unstable_v3_types + 0 }, + { "disable", "", text_input_unstable_v3_types + 0 }, + { "set_surrounding_text", "sii", text_input_unstable_v3_types + 0 }, + { "set_text_change_cause", "u", text_input_unstable_v3_types + 0 }, + { "set_content_type", "uu", text_input_unstable_v3_types + 0 }, + { "set_cursor_rectangle", "iiii", text_input_unstable_v3_types + 0 }, + { "commit", "", text_input_unstable_v3_types + 0 }, + { "set_available_actions", "2a", text_input_unstable_v3_types + 0 }, + { "show_input_panel", "2", text_input_unstable_v3_types + 0 }, + { "hide_input_panel", "2", text_input_unstable_v3_types + 0 }, +}; + +static const struct wl_message zwp_text_input_v3_events[] = { + { "enter", "o", text_input_unstable_v3_types + 4 }, + { "leave", "o", text_input_unstable_v3_types + 5 }, + { "preedit_string", "?sii", text_input_unstable_v3_types + 0 }, + { "commit_string", "?s", text_input_unstable_v3_types + 0 }, + { "delete_surrounding_text", "uu", text_input_unstable_v3_types + 0 }, + { "done", "u", text_input_unstable_v3_types + 0 }, + { "action", "2uu", text_input_unstable_v3_types + 0 }, + { "language", "2s", text_input_unstable_v3_types + 0 }, + { "preedit_hint", "2uuu", text_input_unstable_v3_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_text_input_v3_interface = { + "zwp_text_input_v3", 2, + 11, zwp_text_input_v3_requests, + 9, zwp_text_input_v3_events, +}; + +static const struct wl_message zwp_text_input_manager_v3_requests[] = { + { "destroy", "", text_input_unstable_v3_types + 0 }, + { "get_text_input", "no", text_input_unstable_v3_types + 6 }, +}; + +WL_PRIVATE const struct wl_interface zwp_text_input_manager_v3_interface = { + "zwp_text_input_manager_v3", 2, + 2, zwp_text_input_manager_v3_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/viewporter-client-protocol.h b/src/wayland/protocols/viewporter-client-protocol.h new file mode 100644 index 0000000..a7818d3 --- /dev/null +++ b/src/wayland/protocols/viewporter-client-protocol.h @@ -0,0 +1,394 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef VIEWPORTER_CLIENT_PROTOCOL_H +#define VIEWPORTER_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_viewporter The viewporter protocol + * @section page_ifaces_viewporter Interfaces + * - @subpage page_iface_wp_viewporter - surface cropping and scaling + * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface + * @section page_copyright_viewporter Copyright + *
+ *
+ * Copyright © 2013-2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_viewport; +struct wp_viewporter; + +#ifndef WP_VIEWPORTER_INTERFACE +#define WP_VIEWPORTER_INTERFACE +/** + * @page page_iface_wp_viewporter wp_viewporter + * @section page_iface_wp_viewporter_desc Description + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + * @section page_iface_wp_viewporter_api API + * See @ref iface_wp_viewporter. + */ +/** + * @defgroup iface_wp_viewporter The wp_viewporter interface + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + */ +extern const struct wl_interface wp_viewporter_interface; +#endif +#ifndef WP_VIEWPORT_INTERFACE +#define WP_VIEWPORT_INTERFACE +/** + * @page page_iface_wp_viewport wp_viewport + * @section page_iface_wp_viewport_desc Description + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, see wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + * @section page_iface_wp_viewport_api API + * See @ref iface_wp_viewport. + */ +/** + * @defgroup iface_wp_viewport The wp_viewport interface + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, see wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + */ +extern const struct wl_interface wp_viewport_interface; +#endif + +#ifndef WP_VIEWPORTER_ERROR_ENUM +#define WP_VIEWPORTER_ERROR_ENUM +enum wp_viewporter_error { + /** + * the surface already has a viewport object associated + */ + WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0, +}; +#endif /* WP_VIEWPORTER_ERROR_ENUM */ + +#define WP_VIEWPORTER_DESTROY 0 +#define WP_VIEWPORTER_GET_VIEWPORT 1 + + +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewporter */ +static inline void +wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data); +} + +/** @ingroup iface_wp_viewporter */ +static inline void * +wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter); +} + +static inline uint32_t +wp_viewporter_get_version(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewporter); +} + +/** + * @ingroup iface_wp_viewporter + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other objects, + * wp_viewport objects included. + */ +static inline void +wp_viewporter_destroy(struct wp_viewporter *wp_viewporter) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_viewporter + * + * Instantiate an interface extension for the given wl_surface to + * crop and scale its content. If the given wl_surface already has + * a wp_viewport object associated, the viewport_exists + * protocol error is raised. + */ +static inline struct wp_viewport * +wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface); + + return (struct wp_viewport *) id; +} + +#ifndef WP_VIEWPORT_ERROR_ENUM +#define WP_VIEWPORT_ERROR_ENUM +enum wp_viewport_error { + /** + * negative or zero values in width or height + */ + WP_VIEWPORT_ERROR_BAD_VALUE = 0, + /** + * destination size is not integer + */ + WP_VIEWPORT_ERROR_BAD_SIZE = 1, + /** + * source rectangle extends outside of the content area + */ + WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2, + /** + * the wl_surface was destroyed + */ + WP_VIEWPORT_ERROR_NO_SURFACE = 3, +}; +#endif /* WP_VIEWPORT_ERROR_ENUM */ + +#define WP_VIEWPORT_DESTROY 0 +#define WP_VIEWPORT_SET_SOURCE 1 +#define WP_VIEWPORT_SET_DESTINATION 2 + + +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewport */ +static inline void +wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data); +} + +/** @ingroup iface_wp_viewport */ +static inline void * +wp_viewport_get_user_data(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport); +} + +static inline uint32_t +wp_viewport_get_version(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewport); +} + +/** + * @ingroup iface_wp_viewport + * + * The associated wl_surface's crop and scale state is removed. + * The change is applied on the next wl_surface.commit. + */ +static inline void +wp_viewport_destroy(struct wp_viewport *wp_viewport) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the source rectangle of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If all of x, y, width and height are -1.0, the source rectangle is + * unset instead. Any other set of values where width or height are zero + * or negative, or x or y are negative, raise the bad_value protocol + * error. + * + * The crop and scale state is double-buffered, see wl_surface.commit. + */ +static inline void +wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the destination size of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If width is -1 and height is -1, the destination size is unset + * instead. Any other pair of values for width and height that + * contains zero or negative values raises the bad_value protocol + * error. + * + * The crop and scale state is double-buffered, see wl_surface.commit. + */ +static inline void +wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/viewporter-protocol.c b/src/wayland/protocols/viewporter-protocol.c new file mode 100644 index 0000000..12c9527 --- /dev/null +++ b/src/wayland/protocols/viewporter-protocol.c @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2013-2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_viewport_interface; + +static const struct wl_interface *viewporter_types[] = { + NULL, + NULL, + NULL, + NULL, + &wp_viewport_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_viewporter_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "get_viewport", "no", viewporter_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewporter_interface = { + "wp_viewporter", 1, + 2, wp_viewporter_requests, + 0, NULL, +}; + +static const struct wl_message wp_viewport_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "set_source", "ffff", viewporter_types + 0 }, + { "set_destination", "ii", viewporter_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewport_interface = { + "wp_viewport", 1, + 3, wp_viewport_requests, + 0, NULL, +}; + diff --git a/src/wayland/protocols/xdg-decoration-client-protocol.h b/src/wayland/protocols/xdg-decoration-client-protocol.h new file mode 100644 index 0000000..4cbc976 --- /dev/null +++ b/src/wayland/protocols/xdg-decoration-client-protocol.h @@ -0,0 +1,400 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol + * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager + * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface + * @section page_copyright_xdg_decoration_unstable_v1 Copyright + *
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct xdg_toplevel; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE +#define ZXDG_DECORATION_MANAGER_V1_INTERFACE +/** + * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1 + * @section page_iface_zxdg_decoration_manager_v1_desc Description + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zxdg_decoration_manager_v1_api API + * See @ref iface_zxdg_decoration_manager_v1. + */ +/** + * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + */ +extern const struct wl_interface zxdg_decoration_manager_v1_interface; +#endif +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +/** + * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1 + * @section page_iface_zxdg_toplevel_decoration_v1_desc Description + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + * @section page_iface_zxdg_toplevel_decoration_v1_api API + * See @ref iface_zxdg_toplevel_decoration_v1. + */ +/** + * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + */ +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; +#endif + +#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0 +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1 + + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void +zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data); +} + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void * +zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +static inline uint32_t +zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Destroy the decoration manager. This doesn't destroy objects created + * with the manager. + */ +static inline void +zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Create a new decoration object associated with the given toplevel. + * + * For objects of version 1, creating an xdg_toplevel_decoration from an + * xdg_toplevel which has a buffer attached or committed is a client + * error, and any attempts by a client to attach or manipulate a buffer + * prior to the first xdg_toplevel_decoration.configure event must also be + * treated as errors. + * + * For objects of version 2 or newer, creating an xdg_toplevel_decoration + * from an xdg_toplevel which has a buffer attached or committed is + * allowed. The initial decoration mode of the surface if a buffer is + * already attached depends on whether a xdg_toplevel_decoration object + * has been associated with the surface or not prior to this request. + * + * If an xdg_toplevel_decoration was associated with the surface, then + * destroyed without a surface commit, the previous decoration mode is + * retained. + * + * If no xdg_toplevel_decoration was associated with the surface prior to + * this request, or if a surface commit has been performed after a previous + * xdg_toplevel_decoration object associated with the surface was + * destroyed, the decoration mode is assumed to be client-side. + */ +static inline struct zxdg_toplevel_decoration_v1 * +zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel); + + return (struct zxdg_toplevel_decoration_v1 *) id; +} + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +enum zxdg_toplevel_decoration_v1_error { + /** + * xdg_toplevel has a buffer attached before configure + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0, + /** + * xdg_toplevel already has a decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1, + /** + * xdg_toplevel destroyed before the decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2, + /** + * invalid mode + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_INVALID_MODE = 3, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */ + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * window decoration modes + * + * These values describe window decoration modes. + */ +enum zxdg_toplevel_decoration_v1_mode { + /** + * no server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + /** + * server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * @struct zxdg_toplevel_decoration_v1_listener + */ +struct zxdg_toplevel_decoration_v1_listener { + /** + * notify a decoration mode change + * + * The configure event configures the effective decoration mode. + * The configured state should not be applied immediately. Clients + * must send an ack_configure in response to this event. See + * xdg_surface.configure and xdg_surface.ack_configure for details. + * + * A configure event can be sent at any time. The specified mode + * must be obeyed by the client. + * @param mode the decoration mode + */ + void (*configure)(void *data, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode); +}; + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +static inline int +zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0 +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1 +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void +zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data); +} + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void * +zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +static inline uint32_t +zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Switch back to a mode without any server-side decorations at the next + * commit, unless a new xdg_toplevel_decoration is created for the surface + * first. + */ +static inline void +zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Set the toplevel surface decoration mode. This informs the compositor + * that the client prefers the provided decoration mode. + * + * After requesting a decoration mode, the compositor will respond by + * emitting an xdg_surface.configure event. The client should then update + * its content, drawing it without decorations if the received mode is + * server-side decorations. The client must also acknowledge the configure + * when committing the new content (see xdg_surface.ack_configure). + * + * The compositor can decide not to use the client's mode and enforce a + * different mode instead. + * + * Clients whose decoration mode depend on the xdg_toplevel state may send + * a set_mode request in response to an xdg_surface.configure event and wait + * for the next xdg_surface.configure event to prevent unwanted state. + * Such clients are responsible for preventing configure loops and must + * make sure not to send multiple successive set_mode requests with the + * same decoration mode. + * + * If an invalid mode is supplied by the client, the invalid_mode protocol + * error is raised by the compositor. + */ +static inline void +zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Unset the toplevel surface decoration mode. This informs the compositor + * that the client doesn't prefer a particular decoration mode. + * + * This request has the same semantics as set_mode. + */ +static inline void +zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/xdg-decoration-protocol.c b/src/wayland/protocols/xdg-decoration-protocol.c new file mode 100644 index 0000000..db0a29d --- /dev/null +++ b/src/wayland/protocols/xdg-decoration-protocol.c @@ -0,0 +1,76 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2018 Simon Ser + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface xdg_toplevel_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static const struct wl_interface *xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 2, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 }, + { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 }, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + { "configure", "u", xdg_decoration_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", 2, + 3, zxdg_toplevel_decoration_v1_requests, + 1, zxdg_toplevel_decoration_v1_events, +}; + diff --git a/src/wayland/protocols/xdg-shell-client-protocol.h b/src/wayland/protocols/xdg-shell-client-protocol.h new file mode 100644 index 0000000..1cb6016 --- /dev/null +++ b/src/wayland/protocols/xdg-shell-client-protocol.h @@ -0,0 +1,2392 @@ +/* Generated by wayland-scanner 1.25.0 */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * An xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * An xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. The + * “unresponsive” error is provided for compositors that wish + * to disconnect unresponsive clients. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_wm_base object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is illegal + * and will result in a defunct_surfaces error. + */ +static inline void +xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * While xdg_surface itself is not a role, the corresponding surface may + * only be assigned a role extending xdg_surface, such as xdg_toplevel or + * xdg_popup. It is illegal to create an xdg_surface for a wl_surface which + * already has anassigned role and this will result in a role error. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface); + + return (struct xdg_surface *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping + * and xdg_wm_base.error.unresponsive. + */ +static inline void +xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used to derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +static inline void +xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * specified (e.g. 'bottom_right' or 'top_left'), then the child surface + * will be placed towards the specified gravity; otherwise, the child + * surface will be centered over the anchor point on any axis that had no + * gravity specified. If the gravity is not in the ‘gravity’ enum, an + * invalid_input error is raised. + */ +static inline void +xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y); +} + +/** + * @ingroup iface_xdg_positioner + * + * When set reactive, the surface is reconstrained if the conditions used + * for constraining changed, e.g. the parent window moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, followed by an + * xdg_surface.configure event. + */ +static inline void +xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information to + * determine the future state the popup should be constrained using. If + * this doesn't match the dimension of the parent the popup is eventually + * positioned against, the behavior is undefined. + * + * The arguments are given in the surface-local coordinate space. + */ +static inline void +xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of an xdg_surface.configure event this positioner will be + * used in response to. The compositor may use this information together + * with set_parent_size to determine what future state the popup should be + * constrained using. + */ +static inline void +xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial); +} + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed, otherwise + * a defunct_role_object error is raised. + */ +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. Note that + * in some situations, compositors may clip rendering to the window + * geometry, so the client should avoid putting functional elements + * outside of it. + * + * The window geometry is double-buffered state, see wl_surface.commit. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend outside + * of the wl_surface itself to mark parts of the subsurface tree as part of + * the window geometry. + * + * When applied, the effective window geometry will be the set window + * geometry clamped to the bounding rectangle of the combined + * geometry of the surface of the xdg_surface and the associated + * subsurfaces. + * + * The effective geometry will not be recalculated unless a new call to + * set_window_geometry is done and the new pending surface state is + * subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an invalid_serial + * error. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + * + * Sending an ack_configure request consumes the serial number sent with + * the request, as well as serial numbers sent by all configure events + * sent on this xdg_surface prior to the configure event referenced by + * the committed serial. + * + * It is an error to issue multiple ack_configure requests referencing a + * serial from the same configure event, or to issue an ack_configure + * request referencing a serial from a configure event issued before the + * event identified by the last ack_configure request for the same + * xdg_surface. Doing so will raise an invalid_serial error. + */ +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered, see wl_surface.commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the left edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the right edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the top edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the bottom edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, + /** + * the surface’s left edge is constrained + * + * The left edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10, + /** + * the surface’s right edge is constrained + * + * The right edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11, + /** + * the surface’s top edge is constrained + * + * The top edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12, + /** + * the surface’s bottom edge is constrained + * + * The bottom edge of the window is currently constrained, + * meaning it shouldn't attempt to resize from that edge. It can + * for example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_listener + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * The states are sent as an array of 32-bit unsigned integers in + * native endianness. State values are defined in the state enum. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + * @param width suggested width of window + * @param height suggested height of window + * @param states suggested states of the window + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct xdg_toplevel *xdg_toplevel); + /** + * recommended window geometry bounds + * + * The configure_bounds event may be sent prior to a + * xdg_toplevel.configure event to communicate the bounds a window + * geometry size is recommended to constrain to. + * + * The passed width and height are in surface coordinate space. If + * width and height are 0, it means bounds is unknown and + * equivalent to as if no configure_bounds event was ever sent for + * this surface. + * + * The bounds can for example correspond to the size of a monitor + * excluding any panels or other shell components, so that a + * surface isn't created in a way that it cannot fit. + * + * The bounds may change at any point, and in such a case, a new + * xdg_toplevel.configure_bounds will be sent, followed by + * xdg_toplevel.configure and xdg_surface.configure. + * @param width suggested maximum width of surface + * @param height suggested maximum height of surface + * @since 4 + */ + void (*configure_bounds)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height); + /** + * compositor capabilities + * + * This event advertises the capabilities supported by the + * compositor. If a capability isn't supported, clients should hide + * or disable the UI elements that expose this functionality. For + * instance, if the compositor doesn't advertise support for + * minimized toplevels, a button triggering the set_minimized + * request should not be displayed. + * + * The compositor will ignore requests it doesn't support. For + * instance, a compositor which doesn't advertise support for + * minimized will ignore set_minimized requests. + * + * Compositors must send this event once before the first + * xdg_surface.configure event. When the capabilities change, + * compositors must send this event again and then send an + * xdg_surface.configure event. + * + * The configured state should not be applied immediately. See + * xdg_surface.configure for details. + * + * The capabilities are sent as an array of 32-bit unsigned + * integers in native endianness. Capability values are defined in + * the wm_capabilities enum. + * @param capabilities array of 32-bit capabilities + * @since 5 + */ + void (*wm_capabilities)(void *data, + struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +static inline void +xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set the "parent" of this surface. This surface should be stacked + * above the parent surface and all other ancestor surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + * + * Setting a null parent for a child surface unsets its parent. Setting + * a null parent for a surface which currently has no parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent which + * is not mapped is equivalent to setting a null parent. If a surface + * becomes unmapped, its children's parent is set to the parent of + * the now-unmapped surface. If the now-unmapped surface has no parent, + * its children's parent is unset. If the now-unmapped surface becomes + * mapped again, its parent-child relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child toplevel, + * otherwise the invalid_parent protocol error is raised. + */ +static inline void +xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains, or even if a window menu will be drawn + * at all. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, and + * is one of the values of the resize_edge enum. Values not matching + * a variant of the enum will cause the invalid_resize_edge protocol error. + * The compositor may use this information to update the surface position + * for example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an appropriate + * cursor image. + */ +static inline void +xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width or height will result in an + * invalid_size error. + */ +static inline void +xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in an + * invalid_size error. + */ +static inline void +xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +static inline void +xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +static inline void +xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_popup + * + * Reposition an already-mapped popup. The popup will be placed given the + * details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any parameters set + * by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not take + * effect until the corresponding configure event is acknowledged by the + * client. See xdg_popup.repositioned for details. The token itself is + * opaque, and has no other special meaning. + * + * If multiple reposition requests are sent, the compositor may skip all + * but the last one. + * + * If the popup is repositioned in response to a configure event for its + * parent, the client should send an xdg_positioner.set_parent_configure + * and possibly an xdg_positioner.set_parent_size request to allow the + * compositor to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is being + * resized, but not in response to a configure event, the client should + * send an xdg_positioner.set_parent_size request. + */ +static inline void +xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/xdg-shell-protocol.c b/src/wayland/protocols/xdg-shell-protocol.c new file mode 100644 index 0000000..9dc1f61 --- /dev/null +++ b/src/wayland/protocols/xdg-shell-protocol.c @@ -0,0 +1,184 @@ +/* Generated by wayland-scanner 1.25.0 */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; + +static const struct wl_interface *xdg_shell_types[] = { + NULL, + NULL, + NULL, + NULL, + &xdg_positioner_interface, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &xdg_positioner_interface, + NULL, +}; + +static const struct wl_message xdg_wm_base_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "create_positioner", "n", xdg_shell_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_types + 5 }, + { "pong", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_wm_base_events[] = { + { "ping", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 7, + 4, xdg_wm_base_requests, + 1, xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_size", "ii", xdg_shell_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, + { "set_anchor", "u", xdg_shell_types + 0 }, + { "set_gravity", "u", xdg_shell_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, + { "set_offset", "ii", xdg_shell_types + 0 }, + { "set_reactive", "3", xdg_shell_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 7, + 10, xdg_positioner_requests, + 0, NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "get_toplevel", "n", xdg_shell_types + 7 }, + { "get_popup", "n?oo", xdg_shell_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_types + 0 }, + { "ack_configure", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_surface_interface = { + "xdg_surface", 7, + 5, xdg_surface_requests, + 1, xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_parent", "?o", xdg_shell_types + 11 }, + { "set_title", "s", xdg_shell_types + 0 }, + { "set_app_id", "s", xdg_shell_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_types + 12 }, + { "move", "ou", xdg_shell_types + 16 }, + { "resize", "ouu", xdg_shell_types + 18 }, + { "set_max_size", "ii", xdg_shell_types + 0 }, + { "set_min_size", "ii", xdg_shell_types + 0 }, + { "set_maximized", "", xdg_shell_types + 0 }, + { "unset_maximized", "", xdg_shell_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_types + 21 }, + { "unset_fullscreen", "", xdg_shell_types + 0 }, + { "set_minimized", "", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_toplevel_events[] = { + { "configure", "iia", xdg_shell_types + 0 }, + { "close", "", xdg_shell_types + 0 }, + { "configure_bounds", "4ii", xdg_shell_types + 0 }, + { "wm_capabilities", "5a", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 7, + 14, xdg_toplevel_requests, + 4, xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "grab", "ou", xdg_shell_types + 22 }, + { "reposition", "3ou", xdg_shell_types + 24 }, +}; + +static const struct wl_message xdg_popup_events[] = { + { "configure", "iiii", xdg_shell_types + 0 }, + { "popup_done", "", xdg_shell_types + 0 }, + { "repositioned", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_popup_interface = { + "xdg_popup", 7, + 3, xdg_popup_requests, + 3, xdg_popup_events, +}; + diff --git a/src/wayland/protocols/xdg-toplevel-drag-v1-client-protocol.h b/src/wayland/protocols/xdg-toplevel-drag-v1-client-protocol.h new file mode 100644 index 0000000..e5d6860 --- /dev/null +++ b/src/wayland/protocols/xdg-toplevel-drag-v1-client-protocol.h @@ -0,0 +1,320 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef XDG_TOPLEVEL_DRAG_V1_CLIENT_PROTOCOL_H +#define XDG_TOPLEVEL_DRAG_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_toplevel_drag_v1 The xdg_toplevel_drag_v1 protocol + * @section page_ifaces_xdg_toplevel_drag_v1 Interfaces + * - @subpage page_iface_xdg_toplevel_drag_manager_v1 - Move a window during a drag + * - @subpage page_iface_xdg_toplevel_drag_v1 - Object representing a toplevel move during a drag + * @section page_copyright_xdg_toplevel_drag_v1 Copyright + *
+ *
+ * Copyright 2023 David Redondo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_data_source; +struct xdg_toplevel; +struct xdg_toplevel_drag_manager_v1; +struct xdg_toplevel_drag_v1; + +#ifndef XDG_TOPLEVEL_DRAG_MANAGER_V1_INTERFACE +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_INTERFACE +/** + * @page page_iface_xdg_toplevel_drag_manager_v1 xdg_toplevel_drag_manager_v1 + * @section page_iface_xdg_toplevel_drag_manager_v1_desc Description + * + * This protocol enhances normal drag and drop with the ability to move a + * window at the same time. This allows having detachable parts of a window + * that when dragged out of it become a new window and can be dragged over + * an existing window to be reattached. + * + * A typical workflow would be when the user starts dragging on top of a + * detachable part of a window, the client would create a wl_data_source and + * a xdg_toplevel_drag_v1 object and start the drag as normal via + * wl_data_device.start_drag. Once the client determines that the detachable + * window contents should be detached from the originating window, it creates + * a new xdg_toplevel with these contents and issues a + * xdg_toplevel_drag_v1.attach request before mapping it. From now on the new + * window is moved by the compositor during the drag as if the client called + * xdg_toplevel.move. + * + * Dragging an existing window is similar. The client creates a + * xdg_toplevel_drag_v1 object and attaches the existing toplevel before + * starting the drag. + * + * Clients use the existing drag and drop mechanism to detect when a window + * can be docked or undocked. If the client wants to snap a window into a + * parent window it should delete or unmap the dragged top-level. If the + * contents should be detached again it attaches a new toplevel as described + * above. If a drag operation is cancelled without being dropped, clients + * should revert to the previous state, deleting any newly created windows + * as appropriate. When a drag operation ends as indicated by + * wl_data_source.dnd_drop_performed the dragged toplevel window's final + * position is determined as if a xdg_toplevel_move operation ended. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_xdg_toplevel_drag_manager_v1_api API + * See @ref iface_xdg_toplevel_drag_manager_v1. + */ +/** + * @defgroup iface_xdg_toplevel_drag_manager_v1 The xdg_toplevel_drag_manager_v1 interface + * + * This protocol enhances normal drag and drop with the ability to move a + * window at the same time. This allows having detachable parts of a window + * that when dragged out of it become a new window and can be dragged over + * an existing window to be reattached. + * + * A typical workflow would be when the user starts dragging on top of a + * detachable part of a window, the client would create a wl_data_source and + * a xdg_toplevel_drag_v1 object and start the drag as normal via + * wl_data_device.start_drag. Once the client determines that the detachable + * window contents should be detached from the originating window, it creates + * a new xdg_toplevel with these contents and issues a + * xdg_toplevel_drag_v1.attach request before mapping it. From now on the new + * window is moved by the compositor during the drag as if the client called + * xdg_toplevel.move. + * + * Dragging an existing window is similar. The client creates a + * xdg_toplevel_drag_v1 object and attaches the existing toplevel before + * starting the drag. + * + * Clients use the existing drag and drop mechanism to detect when a window + * can be docked or undocked. If the client wants to snap a window into a + * parent window it should delete or unmap the dragged top-level. If the + * contents should be detached again it attaches a new toplevel as described + * above. If a drag operation is cancelled without being dropped, clients + * should revert to the previous state, deleting any newly created windows + * as appropriate. When a drag operation ends as indicated by + * wl_data_source.dnd_drop_performed the dragged toplevel window's final + * position is determined as if a xdg_toplevel_move operation ended. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface xdg_toplevel_drag_manager_v1_interface; +#endif +#ifndef XDG_TOPLEVEL_DRAG_V1_INTERFACE +#define XDG_TOPLEVEL_DRAG_V1_INTERFACE +/** + * @page page_iface_xdg_toplevel_drag_v1 xdg_toplevel_drag_v1 + * @section page_iface_xdg_toplevel_drag_v1_desc Description + * + * @section page_iface_xdg_toplevel_drag_v1_api API + * See @ref iface_xdg_toplevel_drag_v1. + */ +/** + * @defgroup iface_xdg_toplevel_drag_v1 The xdg_toplevel_drag_v1 interface + * + */ +extern const struct wl_interface xdg_toplevel_drag_v1_interface; +#endif + +#ifndef XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM +enum xdg_toplevel_drag_manager_v1_error { + /** + * data_source already used for toplevel drag + */ + XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_INVALID_SOURCE = 0, +}; +#endif /* XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM */ + +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY 0 +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG 1 + + +/** + * @ingroup iface_xdg_toplevel_drag_manager_v1 + */ +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel_drag_manager_v1 + */ +#define XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel_drag_manager_v1 */ +static inline void +xdg_toplevel_drag_manager_v1_set_user_data(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel_drag_manager_v1, user_data); +} + +/** @ingroup iface_xdg_toplevel_drag_manager_v1 */ +static inline void * +xdg_toplevel_drag_manager_v1_get_user_data(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel_drag_manager_v1); +} + +static inline uint32_t +xdg_toplevel_drag_manager_v1_get_version(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1); +} + +/** + * @ingroup iface_xdg_toplevel_drag_manager_v1 + * + * Destroy this xdg_toplevel_drag_manager_v1 object. Other objects, + * including xdg_toplevel_drag_v1 objects created by this factory, are not + * affected by this request. + */ +static inline void +xdg_toplevel_drag_manager_v1_destroy(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_manager_v1, + XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_toplevel_drag_manager_v1 + * + * Create an xdg_toplevel_drag for a drag and drop operation that is going + * to be started with data_source. + * + * This request can only be made on sources used in drag-and-drop, so it + * must be performed before wl_data_device.start_drag. Attempting to use + * the source other than for drag-and-drop such as in + * wl_data_device.set_selection will raise an invalid_source error. + * + * Destroying data_source while a toplevel is attached to the + * xdg_toplevel_drag is undefined. + */ +static inline struct xdg_toplevel_drag_v1 * +xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1, struct wl_data_source *data_source) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_manager_v1, + XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG, &xdg_toplevel_drag_v1_interface, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1), 0, NULL, data_source); + + return (struct xdg_toplevel_drag_v1 *) id; +} + +#ifndef XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM +#define XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM +enum xdg_toplevel_drag_v1_error { + /** + * valid toplevel already attached + */ + XDG_TOPLEVEL_DRAG_V1_ERROR_TOPLEVEL_ATTACHED = 0, + /** + * drag has not ended + */ + XDG_TOPLEVEL_DRAG_V1_ERROR_ONGOING_DRAG = 1, +}; +#endif /* XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM */ + +#define XDG_TOPLEVEL_DRAG_V1_DESTROY 0 +#define XDG_TOPLEVEL_DRAG_V1_ATTACH 1 + + +/** + * @ingroup iface_xdg_toplevel_drag_v1 + */ +#define XDG_TOPLEVEL_DRAG_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel_drag_v1 + */ +#define XDG_TOPLEVEL_DRAG_V1_ATTACH_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel_drag_v1 */ +static inline void +xdg_toplevel_drag_v1_set_user_data(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel_drag_v1, user_data); +} + +/** @ingroup iface_xdg_toplevel_drag_v1 */ +static inline void * +xdg_toplevel_drag_v1_get_user_data(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel_drag_v1); +} + +static inline uint32_t +xdg_toplevel_drag_v1_get_version(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1); +} + +/** + * @ingroup iface_xdg_toplevel_drag_v1 + * + * Destroy this xdg_toplevel_drag_v1 object. This request must only be + * called after the underlying wl_data_source drag has ended, as indicated + * by the dnd_drop_performed or cancelled events. In any other case an + * ongoing_drag error is raised. + */ +static inline void +xdg_toplevel_drag_v1_destroy(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_v1, + XDG_TOPLEVEL_DRAG_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_toplevel_drag_v1 + * + * Request that the window will be moved with the cursor during the drag + * operation. The offset is a hint to the compositor how the toplevel + * should be positioned relative to the cursor hotspot in surface local + * coordinates and relative to the geometry of the toplevel being attached. + * See xdg_surface.set_window_geometry. For example it might only + * be used when an unmapped window is attached. The attached window + * does not participate in the selection of the drag target. + * + * If the toplevel is unmapped while it is attached, it is automatically + * detached from the drag. In this case this request has to be called again + * if the window should be attached after it is remapped. + * + * This request can be called multiple times but issuing it while a + * toplevel with an active role is attached raises a toplevel_attached + * error. + */ +static inline void +xdg_toplevel_drag_v1_attach(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1, struct xdg_toplevel *toplevel, int32_t x_offset, int32_t y_offset) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_v1, + XDG_TOPLEVEL_DRAG_V1_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1), 0, toplevel, x_offset, y_offset); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/wayland/protocols/xdg-toplevel-drag-v1-protocol.c b/src/wayland/protocols/xdg-toplevel-drag-v1-protocol.c new file mode 100644 index 0000000..1411819 --- /dev/null +++ b/src/wayland/protocols/xdg-toplevel-drag-v1-protocol.c @@ -0,0 +1,74 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright 2023 David Redondo + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_data_source_interface; +extern const struct wl_interface xdg_toplevel_interface; +extern const struct wl_interface xdg_toplevel_drag_v1_interface; + +static const struct wl_interface *xdg_toplevel_drag_v1_types[] = { + &xdg_toplevel_drag_v1_interface, + &wl_data_source_interface, + &xdg_toplevel_interface, + NULL, + NULL, +}; + +static const struct wl_message xdg_toplevel_drag_manager_v1_requests[] = { + { "destroy", "", xdg_toplevel_drag_v1_types + 0 }, + { "get_xdg_toplevel_drag", "no", xdg_toplevel_drag_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_drag_manager_v1_interface = { + "xdg_toplevel_drag_manager_v1", 1, + 2, xdg_toplevel_drag_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message xdg_toplevel_drag_v1_requests[] = { + { "destroy", "", xdg_toplevel_drag_v1_types + 0 }, + { "attach", "oii", xdg_toplevel_drag_v1_types + 2 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_drag_v1_interface = { + "xdg_toplevel_drag_v1", 1, + 2, xdg_toplevel_drag_v1_requests, + 0, NULL, +}; + diff --git a/src/wayland/shell.c b/src/wayland/shell.c new file mode 100644 index 0000000..ef72512 --- /dev/null +++ b/src/wayland/shell.c @@ -0,0 +1,398 @@ +#include "internal.h" + +static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial); +static const struct xdg_wm_base_listener wm_base_listener; + +static void presentation_clock_id(void *data, struct wp_presentation *presentation, + uint32_t clk_id) +{ + (void)presentation; + struct yasl_display *c = data; + struct timespec ts; + c->pres_clock = (clockid_t)clk_id; + c->pres_clock_known = clock_gettime(c->pres_clock, &ts) == 0; +} + +static uint64_t clock_ns(clockid_t clock) +{ + struct timespec ts; + if (clock_gettime(clock, &ts) != 0) + return 0; + return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; +} + +uint64_t conn_pres_to_mono(const struct yasl_display *c, uint64_t ns) +{ + if (c->pres_clock == CLOCK_MONOTONIC) + return ns; + uint64_t mono = clock_ns(CLOCK_MONOTONIC); + uint64_t pres = clock_ns(c->pres_clock); + return ns + mono - pres; +} + +uint64_t conn_mono_to_pres(const struct yasl_display *c, uint64_t ns) +{ + if (c->pres_clock == CLOCK_MONOTONIC) + return ns; + uint64_t mono = clock_ns(CLOCK_MONOTONIC); + uint64_t pres = clock_ns(c->pres_clock); + return ns + pres - mono; +} + +static const struct wp_presentation_listener presentation_listener = { + .clock_id = presentation_clock_id, +}; + +static void output_geometry(void *data, struct wl_output *output, + int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, + int32_t subpixel, const char *make, const char *model, int32_t transform) +{ + (void)data; (void)output; (void)x; (void)y; (void)physical_width; + (void)physical_height; (void)subpixel; (void)make; (void)model; + (void)transform; +} + +static void output_mode(void *data, struct wl_output *output, uint32_t flags, + int32_t width, int32_t height, int32_t refresh) +{ + (void)output; (void)width; (void)height; + struct wl_conn_output *o = data; + if ((flags & WL_OUTPUT_MODE_CURRENT) && refresh > 0) + o->pending_refresh_ns = (uint32_t)(1000000000000ull / (uint32_t)refresh); +} + +static void conn_follow_outputs(struct yasl_display *c) +{ + for (struct yasl_surface *w = c->surfaces; w; w = w->conn_next) + surface_follow_outputs(w); +} + +static void output_done(void *data, struct wl_output *output) +{ + (void)output; + struct wl_conn_output *o = data; + if (o->pending_scale == o->scale && o->pending_refresh_ns == o->refresh_ns) + return; + o->scale = o->pending_scale; + o->refresh_ns = o->pending_refresh_ns; + conn_follow_outputs(o->conn); +} + +static void output_scale(void *data, struct wl_output *output, int32_t factor) +{ + (void)output; + struct wl_conn_output *o = data; + if (factor > 0) + o->pending_scale = factor; +} + +static void output_name(void *data, struct wl_output *output, const char *name) +{ (void)data; (void)output; (void)name; } + +static void output_description(void *data, struct wl_output *output, const char *description) +{ (void)data; (void)output; (void)description; } + +static const struct wl_output_listener output_listener = { + .name = output_name, + .description = output_description, + .geometry = output_geometry, + .mode = output_mode, + .done = output_done, + .scale = output_scale, +}; + +static void conn_bind_output(struct yasl_display *c, struct wl_registry *registry, + uint32_t name, uint32_t version) +{ + struct wl_conn_output *o = calloc(1, sizeof(*o)); + if (!o) return; + o->proxy = wl_registry_bind(registry, name, &wl_output_interface, + version < 3 ? version : 3); + if (!o->proxy) { + free(o); + return; + } + o->conn = c; + o->name = name; + o->scale = o->pending_scale = 1; + o->mask = ~c->output_masks & (c->output_masks + 1); + c->output_masks |= o->mask; + struct wl_conn_output **tail = &c->outputs; + while (*tail) + tail = &(*tail)->next; + *tail = o; + wl_output_add_listener(o->proxy, &output_listener, o); +} + +static void output_destroy(struct wl_conn_output *o) +{ + if (wl_output_get_version(o->proxy) >= WL_OUTPUT_RELEASE_SINCE_VERSION) + wl_output_release(o->proxy); + else + wl_output_destroy(o->proxy); + o->conn->output_masks &= ~o->mask; + free(o); +} + +static bool conn_remove_output(struct yasl_display *c, uint32_t name) +{ + struct wl_conn_output **link = &c->outputs; + while (*link && (*link)->name != name) + link = &(*link)->next; + struct wl_conn_output *o = *link; + if (!o) + return false; + *link = o->next; + for (struct yasl_surface *w = c->surfaces; w; w = w->conn_next) + w->outputs &= ~o->mask; + output_destroy(o); + conn_follow_outputs(c); + return true; +} + +void conn_destroy_outputs(struct yasl_display *c) +{ + while (c->outputs) { + struct wl_conn_output *o = c->outputs; + c->outputs = o->next; + output_destroy(o); + } +} + +uint64_t conn_output_mask(const struct yasl_display *c, const struct wl_output *proxy) +{ + for (const struct wl_conn_output *o = c->outputs; o; o = o->next) + if (o->proxy == proxy) + return o->mask; + return 0; +} + +uint32_t conn_output_scale_120(const struct yasl_display *c, uint64_t outputs) +{ + int32_t scale = 0; + for (const struct wl_conn_output *o = c->outputs; o; o = o->next) + if ((o->mask & outputs) && o->scale > scale) + scale = o->scale; + return (uint32_t)scale * YASL_SCALE_UNIT; +} + +static void registry_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + struct yasl_display *c = data; + if (strcmp(interface, wl_compositor_interface.name) == 0) { + c->compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, version < 6 ? version : 6); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + c->shm = wl_registry_bind(registry, name, + &wl_shm_interface, version < 2 ? version : 2); + } else if (strcmp(interface, wl_output_interface.name) == 0) { + conn_bind_output(c, registry, name, version); + } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { + c->data_manager = wl_registry_bind(registry, name, &wl_data_device_manager_interface, + version < 3 ? version : 3); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + c->wm_base = wl_registry_bind(registry, name, + &xdg_wm_base_interface, version < 7 ? version : 7); + if (c->wm_base) + xdg_wm_base_add_listener(c->wm_base, &wm_base_listener, c); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + c->decor_mgr = wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, 1); + } else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) { + c->primary_selection_mgr = wl_registry_bind(registry, name, + &zwp_primary_selection_device_manager_v1_interface, 1); + for (struct seat *s = c->seats; s; s = s->next) + if (s->clipboard) + clipboard_set_primary_manager(s->clipboard, c->primary_selection_mgr); + } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { + c->cursor_shape_mgr = wl_registry_bind(registry, name, + &wp_cursor_shape_manager_v1_interface, 1); + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + c->scale_mgr = wl_registry_bind(registry, name, + &wp_fractional_scale_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + c->viewporter = wl_registry_bind(registry, name, &wp_viewporter_interface, 1); + } else if (strcmp(interface, zwp_tablet_manager_v2_interface.name) == 0) { + c->tablet_mgr = wl_registry_bind(registry, name, + &zwp_tablet_manager_v2_interface, 1); + } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { + c->text_input_mgr = wl_registry_bind(registry, name, + &zwp_text_input_manager_v3_interface, 1); + } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { + c->tearing_mgr = wl_registry_bind(registry, name, + &wp_tearing_control_manager_v1_interface, 1); + } else if (strcmp(interface, wp_presentation_interface.name) == 0) { + c->presentation = wl_registry_bind(registry, name, + &wp_presentation_interface, 1); + if (c->presentation) + wp_presentation_add_listener(c->presentation, &presentation_listener, c); + } else if (strcmp(interface, wp_fifo_manager_v1_interface.name) == 0) { + c->fifo_mgr = wl_registry_bind(registry, name, + &wp_fifo_manager_v1_interface, 1); + } else if (strcmp(interface, wp_commit_timing_manager_v1_interface.name) == 0) { + c->commit_timing_mgr = wl_registry_bind(registry, name, + &wp_commit_timing_manager_v1_interface, 1); + } else if (strcmp(interface, xdg_toplevel_drag_manager_v1_interface.name) == 0) { + c->toplevel_drag_mgr = wl_registry_bind(registry, name, + &xdg_toplevel_drag_manager_v1_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat_bind(c, registry, name, version); + } +} + +static void registry_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + (void)registry; + struct yasl_display *c = data; + if (c && !conn_remove_output(c, name)) + seat_remove(c, name); +} + +const struct wl_registry_listener registry_listener = { + .global = registry_global, + .global_remove = registry_global_remove, +}; + +static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) +{ + (void)data; + xdg_wm_base_pong(wm_base, serial); +} + +static const struct xdg_wm_base_listener wm_base_listener = { + .ping = wm_base_ping, +}; + +static void notify_state(struct yasl_surface *w) +{ + if (w->cbs && w->cbs->state) + w->cbs->state(w, yasl_surface_state(w), w->ud); +} + +static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, + int32_t width, int32_t height, struct wl_array *states) +{ + (void)toplevel; + struct yasl_surface *w = data; + + bool fs = false, max = false, act = false, susp = false, tiled = false; + uint32_t *s; + wl_array_for_each(s, states) { + switch (*s) { + case XDG_TOPLEVEL_STATE_FULLSCREEN: fs = true; break; + case XDG_TOPLEVEL_STATE_MAXIMIZED: max = true; break; + case XDG_TOPLEVEL_STATE_ACTIVATED: act = true; break; + case XDG_TOPLEVEL_STATE_SUSPENDED: susp = true; break; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + case XDG_TOPLEVEL_STATE_TILED_TOP: + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: tiled = true; break; + default: break; + } + } + + if (fs != w->fullscreen || max != w->maximized || + act != w->activated || susp != w->suspended) { + w->fullscreen = fs; + w->maximized = max; + w->activated = act; + w->suspended = susp; + notify_state(w); + } + + w->tiled = tiled; + w->req_width = width; + w->req_height = height; +} + +static void toplevel_close(void *data, struct xdg_toplevel *toplevel) +{ + (void)toplevel; + surface_fail(data); +} + +static void toplevel_configure_bounds(void *data, struct xdg_toplevel *toplevel, + int32_t width, int32_t height) +{ + (void)toplevel; + struct yasl_surface *w = data; + w->bound_width = width; + w->bound_height = height; + if ((width > 0 && w->logical_width > width) || + (height > 0 && w->logical_height > height)) { + w->size_pending = true; + yasl_surface_schedule_redraw(w); + } +} + +static void toplevel_wm_capabilities(void *data, struct xdg_toplevel *toplevel, + struct wl_array *capabilities) +{ + (void)data; (void)toplevel; (void)capabilities; +} + +static const struct xdg_toplevel_listener toplevel_listener = { + .configure = toplevel_configure, + .close = toplevel_close, + .configure_bounds = toplevel_configure_bounds, + .wm_capabilities = toplevel_wm_capabilities, +}; + +static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) +{ + struct yasl_surface *w = data; + (void)xdg_surface; + w->pending_serial = serial; + w->has_pending_serial = true; + w->size_pending = true; + w->configured = true; + yasl_surface_schedule_redraw(w); +} + +const struct xdg_surface_listener shell_surface_listener = { + .configure = xdg_surface_configure, +}; + +static void toplevel_decoration_configure(void *data, + struct zxdg_toplevel_decoration_v1 *toplevel_decor, uint32_t mode) +{ + (void)toplevel_decor; + struct yasl_surface *w = data; + bool was_server = w->server_decorated; + w->server_decorated = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + if (was_server != w->server_decorated) + notify_state(w); +} + +static const struct zxdg_toplevel_decoration_v1_listener toplevel_decoration_listener = { + .configure = toplevel_decoration_configure, +}; + +int surface_init_shell(struct yasl_surface *w, const char *title) +{ + w->xdg_surface = xdg_wm_base_get_xdg_surface(w->conn->wm_base, w->surface); + if (!w->xdg_surface) return -1; + xdg_surface_add_listener(w->xdg_surface, &shell_surface_listener, w); + w->toplevel = xdg_surface_get_toplevel(w->xdg_surface); + if (!w->toplevel) return -1; + xdg_toplevel_add_listener(w->toplevel, &toplevel_listener, w); + + yasl_surface_set_title(w, title ? title : "yasl_app"); + + const char *app_id = w->conn->app_id ? w->conn->app_id : "yasl_app"; + xdg_toplevel_set_app_id(w->toplevel, app_id); + xdg_toplevel_set_min_size(w->toplevel, YASL_MIN_LOGICAL_PX, YASL_MIN_LOGICAL_PX); + + if (w->conn->decor_mgr) { + w->toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration( + w->conn->decor_mgr, w->toplevel); + if (!w->toplevel_decor) return -1; + zxdg_toplevel_decoration_v1_add_listener(w->toplevel_decor, + &toplevel_decoration_listener, w); + zxdg_toplevel_decoration_v1_set_mode(w->toplevel_decor, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + return 0; +} diff --git a/src/wayland/surface.c b/src/wayland/surface.c new file mode 100644 index 0000000..da334e4 --- /dev/null +++ b/src/wayland/surface.c @@ -0,0 +1,430 @@ +#include "internal.h" +#include + +static void display_free(struct yasl_display *c); + +static void display_cancel_read(struct yasl_display *c) +{ + if (!c->reading) + return; + wl_display_cancel_read(c->wl); + c->reading = false; +} + +static void report_display_error(struct yasl_display *c) +{ + int err = wl_display_get_error(c->wl); + if (!err) + return; + uint32_t object_id = 0; + const struct wl_interface *iface = NULL; + uint32_t protocol_err = wl_display_get_protocol_error(c->wl, &iface, &object_id); + if (protocol_err) + fprintf(stderr, "[yasl] protocol error %u on %s (object %u)\n", + protocol_err, iface ? iface->name : "?", object_id); + else + fprintf(stderr, "[yasl] display error %d\n", err); +} + +void display_enter(struct yasl_display *c) +{ + c->depth++; +} + +void display_leave(struct yasl_display *c) +{ + if (--c->depth > 0) + return; + keyboard_settle_focus(c); + while (c->dead) { + struct yasl_surface *w = c->dead; + c->dead = w->dead_next; + free(w); + } +} + +static void display_lose(struct yasl_display *c) +{ + if (c->lost) + return; + c->lost = true; + report_display_error(c); + display_cancel_read(c); + display_enter(c); + for (struct yasl_surface *w = c->surfaces, *next; w; w = next) { + next = w->conn_next; + surface_fail(w); + } + display_leave(c); + if (c->cbs && c->cbs->lost) + c->cbs->lost(c->ud); +} + +void surface_fail(struct yasl_surface *w) +{ + if (w->closed) + return; + w->closed = true; + if (w->cbs->close) + w->cbs->close(w, w->ud); +} + +static int display_ready(int fd, short revents, void *ud) +{ + (void)fd; + struct yasl_display *c = ud; + if (c->lost) + return 0; + display_enter(c); + if (c->reading) { + c->reading = false; + if (!(revents & POLLIN)) + wl_display_cancel_read(c->wl); + else if (wl_display_read_events(c->wl) < 0) + revents |= POLLERR; + } + if (wl_display_dispatch_pending(c->wl) < 0 || + (revents & (POLLERR | POLLHUP | POLLNVAL))) + display_lose(c); + display_leave(c); + return 0; +} + +void yasl_display_dispatch(struct yasl_display *c) +{ + if (!c || c->lost || c->reading) + return; + display_enter(c); + if (wl_display_dispatch_pending(c->wl) < 0) + display_lose(c); + display_leave(c); +} + +static void display_arm(struct yasl_display *c) +{ + while (!c->reading && wl_display_prepare_read(c->wl) != 0) { + if (wl_display_dispatch_pending(c->wl) < 0) { + display_lose(c); + return; + } + } + c->reading = true; + short events = POLLIN; + if (wl_display_flush(c->wl) < 0) { + if (errno != EAGAIN) { + display_lose(c); + return; + } + events |= POLLOUT; + } + if (c->loop) + yasl_loop_set_fd_events(c->loop, c->watch, events); +} + +void yasl_display_flush(struct yasl_display *c) +{ + if (!c || c->lost) + return; + display_enter(c); + for (struct yasl_surface *w = c->surfaces, *next; w; w = next) { + next = w->conn_next; + surface_draw_frame(w); + } + if (!c->lost) + display_arm(c); + display_leave(c); +} + +static void display_free(struct yasl_display *c) +{ + conn_drag_end(c); + if (c->loop && c->watch > 0) yasl_loop_del_fd(c->loop, c->watch); + if (c->wl) display_cancel_read(c); + while (c->seats) + seat_destroy(c->seats); + if (c->toplevel_drag_mgr) xdg_toplevel_drag_manager_v1_destroy(c->toplevel_drag_mgr); + if (c->primary_selection_mgr) zwp_primary_selection_device_manager_v1_destroy(c->primary_selection_mgr); + if (c->data_manager) wl_data_device_manager_destroy(c->data_manager); + if (c->cursor_shape_mgr) wp_cursor_shape_manager_v1_destroy(c->cursor_shape_mgr); + if (c->cursor_theme) wl_cursor_theme_destroy(c->cursor_theme); + if (c->tablet_mgr) zwp_tablet_manager_v2_destroy(c->tablet_mgr); + if (c->text_input_mgr) zwp_text_input_manager_v3_destroy(c->text_input_mgr); + if (c->tearing_mgr) wp_tearing_control_manager_v1_destroy(c->tearing_mgr); + if (c->fifo_mgr) wp_fifo_manager_v1_destroy(c->fifo_mgr); + if (c->commit_timing_mgr) wp_commit_timing_manager_v1_destroy(c->commit_timing_mgr); + if (c->presentation) wp_presentation_destroy(c->presentation); + if (c->xkb_ctx) xkb_context_unref(c->xkb_ctx); + if (c->scale_mgr) wp_fractional_scale_manager_v1_destroy(c->scale_mgr); + if (c->viewporter) wp_viewporter_destroy(c->viewporter); + if (c->decor_mgr) zxdg_decoration_manager_v1_destroy(c->decor_mgr); + conn_destroy_outputs(c); + if (c->wm_base) xdg_wm_base_destroy(c->wm_base); + if (c->shm) wl_shm_destroy(c->shm); + if (c->compositor) wl_compositor_destroy(c->compositor); + if (c->registry) wl_registry_destroy(c->registry); + if (c->wl) wl_display_disconnect(c->wl); + free(c->app_id); + free(c); +} + +struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec) +{ + struct yasl_display *c = calloc(1, sizeof(*c)); + if (!c) return NULL; + c->loop = loop; + if (spec) { + c->cbs = spec->cbs; + c->ud = spec->ud; + if (spec->app_id) c->app_id = strdup(spec->app_id); + } + c->xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + c->wl = c->xkb_ctx ? wl_display_connect(NULL) : NULL; + if (!c->wl) goto err; + + c->registry = wl_display_get_registry(c->wl); + if (!c->registry) goto err; + wl_registry_add_listener(c->registry, ®istry_listener, c); + if (wl_display_roundtrip(c->wl) < 0 || !c->compositor || !c->shm || !c->wm_base) + goto err; + + surface_init_cursor(c); + if (c->loop) { + c->watch = yasl_loop_add_fd(loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c); + if (c->watch <= 0) { c->watch = 0; goto err; } + } + if (display_input_init(c) < 0) + goto err; + return c; + +err: + display_free(c); + return NULL; +} + +void yasl_display_close(struct yasl_display *c) +{ + if (!c) return; + assert(!c->surfaces && "destroy every surface before its display"); + display_free(c); +} + +uint32_t yasl_display_caps(const struct yasl_display *c) +{ + if (!c) return 0; + uint32_t caps = YASL_CAP_POPUPS | YASL_CAP_CSD; + struct seat *s = conn_active_seat(c); + const struct wl_data_device *device = s ? clipboard_data_device(s->clipboard) : NULL; + if (device && wl_data_device_get_version((struct wl_data_device *)device) >= 3) + caps |= YASL_CAP_DRAG; + if (c->toplevel_drag_mgr) + caps |= YASL_CAP_DRAG_CARRY; + if (c->primary_selection_mgr) + caps |= YASL_CAP_PRIMARY_SELECTION; + return caps; +} + +static void conn_link(struct yasl_display *c, struct yasl_surface *w) +{ + w->conn = c; + w->conn_next = c->surfaces; + c->surfaces = w; +} + +static void conn_unlink(struct yasl_surface *w) +{ + struct yasl_display *c = w->conn; + if (!c) return; + for (struct yasl_surface **p = &c->surfaces; *p; p = &(*p)->conn_next) { + if (*p == w) { + *p = w->conn_next; + break; + } + } + if (c->paste_target == w) + c->paste_target = NULL; + for (struct seat *s = c->seats; s; s = s->next) + seat_forget_surface(s, w); + w->conn = NULL; +} + +struct yasl_surface *conn_surface_for(struct yasl_display *c, struct wl_surface *s) +{ + for (struct yasl_surface *w = c->surfaces; w && s; w = w->conn_next) + if (w->surface == s) + return w; + return NULL; +} + +static bool spec_valid(const struct yasl_surface_spec *spec) +{ + size_t bytes; + return spec && spec->size.x > 0 && spec->size.y > 0 && + buffer_size(spec->size.x, spec->size.y, &bytes); +} + +struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *c, + const struct yasl_surface_spec *spec) +{ + if (!c || c->lost || !spec_valid(spec)) + return NULL; + int width = spec->size.x, height = spec->size.y; + display_cancel_read(c); + struct yasl_surface *w = calloc(1, sizeof(*w)); + if (!w) return NULL; + display_enter(c); + conn_link(c, w); + yasl_surface_set_callbacks(w, NULL, NULL); + w->req_width = width; + w->req_height = height; + w->logical_width = width; + w->logical_height = height; + w->scale_120 = YASL_SCALE_UNIT; + w->pending_scale_120 = YASL_SCALE_UNIT; + w->scale_factor = 1.0; + w->size_pending = true; + w->clock.refresh_ns = c->outputs && c->outputs->refresh_ns + ? c->outputs->refresh_ns : YASL_REFRESH_DEFAULT_NS; + + w->surface = wl_compositor_create_surface(c->compositor); + if (!w->surface) goto err; + if (surface_init_scaling(w) < 0) goto err; + if (surface_init_shell(w, spec->title) < 0) goto err; + w->opaque = spec->fullscreen; + if (spec->fullscreen) + xdg_toplevel_set_fullscreen(w->toplevel, NULL); + if (spec->tearing && c->tearing_mgr) { + w->tearing_control = wp_tearing_control_manager_v1_get_tearing_control( + c->tearing_mgr, w->surface); + if (w->tearing_control) + wp_tearing_control_v1_set_presentation_hint(w->tearing_control, + WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC); + } + + wl_surface_commit(w->surface); + if (wl_display_roundtrip(c->wl) < 0) { + display_lose(c); + goto err; + } + if (apply_pending_geometry(w) < 0) goto err; + if (w->closed) goto err; + display_leave(c); + return w; + +err: + yasl_surface_destroy(w); + display_leave(c); + return NULL; +} + +void yasl_surface_set_callbacks(struct yasl_surface *w, const struct yasl_surface_cbs *cbs, void *ud) +{ + if (w && !w->closed) { + static const struct yasl_surface_cbs no_callbacks = {0}; + w->cbs = cbs ? cbs : &no_callbacks; + w->ud = ud; + } +} + +void yasl_surface_destroy(struct yasl_surface *w) +{ + if (!w || w->destroyed) return; + for (struct yasl_surface *o = w->conn ? w->conn->surfaces : NULL; o; o = o->conn_next) + assert(o->parent != w && "destroy a popup before its parent"); + input_queue_clear(&w->input); + free(w->ime_preedit); + free(w->ime_commit); + free(w->ime_shown); + if (w->tearing_control) wp_tearing_control_v1_destroy(w->tearing_control); + if (w->fifo) wp_fifo_v1_destroy(w->fifo); + if (w->commit_timer) wp_commit_timer_v1_destroy(w->commit_timer); + surface_feedback_destroy(w); + if (w->frame_cb) wl_callback_destroy(w->frame_cb); + for (int i = 0; i < NBUF; i++) buffer_destroy(&w->buffers[i]); + if (w->frac_scale) wp_fractional_scale_v1_destroy(w->frac_scale); + if (w->viewport) wp_viewport_destroy(w->viewport); + if (w->toplevel_decor) zxdg_toplevel_decoration_v1_destroy(w->toplevel_decor); + if (w->toplevel) xdg_toplevel_destroy(w->toplevel); + if (w->popup) xdg_popup_destroy(w->popup); + if (w->xdg_surface) xdg_surface_destroy(w->xdg_surface); + if (w->surface) wl_surface_destroy(w->surface); + struct yasl_display *c = w->conn; + conn_unlink(w); + static const struct yasl_surface_cbs no_callbacks = {0}; + *w = (struct yasl_surface){ + .conn_next = w->conn_next, + .cbs = &no_callbacks, + .closed = true, + .destroyed = true, + }; + if (c && c->depth > 0) { + w->dead_next = c->dead; + c->dead = w; + } else { + free(w); + } +} + +struct yasl_display *yasl_surface_display(const struct yasl_surface *w) +{ + return w ? w->conn : NULL; +} + +void yasl_surface_schedule_redraw(struct yasl_surface *w) +{ + if (w) w->want_draw = true; +} + +struct yasl_vector2i yasl_surface_size(const struct yasl_surface *w) +{ + return w ? (struct yasl_vector2i){ .x = w->width, .y = w->height } : (struct yasl_vector2i){0}; +} + +uint32_t yasl_surface_scale_120(const struct yasl_surface *w) +{ + return w ? w->scale_120 : YASL_SCALE_UNIT; +} + +void yasl_surface_set_background_color(struct yasl_surface *w, uint32_t bg) +{ + (void)w; (void)bg; +} + +bool yasl_surface_start_interactive_move(struct yasl_surface *s) +{ + if (!s || !s->toplevel || !s->conn) return false; + struct seat *seat = conn_active_seat(s->conn); + if (!seat || !seat->proxy || !seat->press_serial) return false; + xdg_toplevel_move(s->toplevel, seat->proxy, seat->press_serial); + return true; +} + +bool yasl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge) +{ + if (!s || !s->toplevel || !s->conn || edge == YASL_EDGE_NONE) return false; + struct seat *seat = conn_active_seat(s->conn); + if (!seat || !seat->proxy || !seat->press_serial) return false; + xdg_toplevel_resize(s->toplevel, seat->proxy, seat->press_serial, (uint32_t)edge); + return true; +} + +bool yasl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos) +{ + if (!s || !s->toplevel || !s->conn) return false; + struct seat *seat = conn_active_seat(s->conn); + if (!seat || !seat->proxy || !seat->press_serial) return false; + uint32_t scale = s->scale_120 ? s->scale_120 : YASL_SCALE_UNIT; + xdg_toplevel_show_window_menu(s->toplevel, seat->proxy, seat->press_serial, + yasl_scale_to_logical(pos.x, scale), + yasl_scale_to_logical(pos.y, scale)); + return true; +} + +void *yasl_display_get_native_handle(struct yasl_display *d) +{ + return d ? d->wl : NULL; +} + +void *yasl_surface_get_native_handle(struct yasl_surface *s) +{ + return s ? s->surface : NULL; +} -- cgit v1.2.3