commit 1c606d027489d803338d0dbb683391410ec89ba0 Author: Richard Acayan Date: Mon Apr 15 22:11:00 2024 -0400 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bb32e7 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +The unfettered keyboard is an on-screen keyboard designed for Linux mobile. It +uses the concept of Julow's [Unexpected Keyboard](https://github.com/Julow/Unexpected-Keyboard), +where swiping on a displayed key cap produces a different key press. For +example, swiping up and right on the "q" key generates a "1" keypress. This +makes it possible for many keys to be available on the same keyboard layout. + +# Dependencies + +The dependencies are: + +- [expat](https://github.com/libexpat/libexpat) - 🌿 Fast streaming XML parser written in C99 with >90% test coverage +- [fcft](https://codeberg.org/dnkl/fcft) - A simple library for font loading and glyph rasterization using FontConfig, FreeType and pixman. +- [meson](https://github.com/mesonbuild/meson) - The Meson Build System +- [pixman](https://gitlab.freedesktop.org/pixman/pixman) - Image processing and manipulation library +- [wayland](https//gitlab.freedesktop.org/wayland/wayland) - Core Wayland window system code and protocol +- [xkbcommon](https://github.com/xkbcommon/libxkbcommon) - keymap handling library for toolkits and window systems + +Additionally, fonts are needed to render the following Unicode, non-ASCII symbols: + +- ← (U+2190) +- ↑ (U+2191) +- → (U+2192) +- ↓ (U+2193) +- ⇧ (U+21E7) +- ⌦ (U+2326) +- ⌫ (U+232B) +- ⏎ (U+23CE) +- ⭾ (U+2B7E) + +# Usage + +This keyboard is designed to work, but it is not designed to be used. Using it +is awkward: + + $ meson setup build + $ ninja -C build + $ curl -L -o /tmp/bottom_row.xml https://github.com/Julow/Unexpected-Keyboard/raw/master/res/xml/bottom_row.xml + $ curl -L -o /tmp/latn_qwerty_us.xml https://github.com/Julow/Unexpected-Keyboard/raw/master/srcs/layouts/latn_qwerty_us.xml + $ sudo mkdir /usr/share/unfettered-keyboard/layouts + $ sudo cp /tmp/bottom_row.xml /tmp/latn_qwerty_us.xml /usr/share/unfettered-keyboard/layouts + $ build/ufkbd diff --git a/graphics.c b/graphics.c new file mode 100644 index 0000000..a285541 --- /dev/null +++ b/graphics.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "graphics.h" +#include "layout.h" +#include "modifier.h" +#include "ufkbd.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +enum label_align { + LABEL_ALIGNL = 0x1, + LABEL_ALIGNR = 0x2, + LABEL_ALIGNU = 0x4, + LABEL_ALIGND = 0x8, +}; + +struct draw_data { + struct ufkbd_ctx *ufkbd; + pixman_image_t *img; +}; + +static const char *fonts[] = { + "Sans" +}; + +struct key_label { + xkb_keysym_t sym; + const char *label; +}; + +// List of custom key labels, sorted by XKB keysym. +static const struct key_label keylabels[] = { + { .sym = XKB_KEY_BackSpace, .label = "\u232B", }, + { .sym = XKB_KEY_Tab, .label = "\u2B7E", }, + { .sym = XKB_KEY_Return, .label = "\u23CE", }, + { .sym = XKB_KEY_Escape, .label = "Esc", }, + { .sym = XKB_KEY_Left, .label = "\u2190", }, + { .sym = XKB_KEY_Up, .label = "\u2191", }, + { .sym = XKB_KEY_Right, .label = "\u2192", }, + { .sym = XKB_KEY_Down, .label = "\u2193", }, + { .sym = XKB_KEY_Shift_L, .label = "\u21E7", }, + { .sym = XKB_KEY_Control_L, .label = "Ctrl", }, + { .sym = XKB_KEY_Alt_L, .label = "Alt", }, + { .sym = XKB_KEY_Delete, .label = "\u2326", }, + { .sym = XKB_KEY_XF86Fn, .label = "Fn", }, +}; + +static int compare_key_label(const void *va, const void *vb) +{ + const struct key_label *a = va; + const struct key_label *b = vb; + + return a->sym - b->sym; +} + +static void draw_part(struct ufkbd_graphics_ctx *graphics, + struct fcft_font *font, + xkb_keysym_t keysym, + bool pressed, + int x1, int y1, int x2, int y2, + enum label_align align, + pixman_image_t *img) +{ + pixman_image_t *color; + struct key_label pattern; + struct fcft_text_run *text; + const struct key_label *label; + ssize_t len; + size_t i; + + int pos = 0; + int min = 0, max = 0; + int level; + + if (pressed) + color = graphics->key_pressed; + else + color = graphics->key_default; + + pattern.sym = keysym; + label = bsearch(&pattern, keylabels, + ARRAY_SIZE(keylabels), + sizeof(*keylabels), + compare_key_label); + if (label != NULL) { + len = utf8proc_decompose((const utf8proc_uint8_t *) label->label, 0, + graphics->buf, + graphics->size / sizeof(utf8proc_int32_t), + UTF8PROC_NULLTERM); + if (len <= 0) + return; + } else { + ((utf8proc_int32_t *) graphics->buf)[0] = keysym; + len = 1; + } + + text = fcft_rasterize_text_run_utf32(font, len, graphics->buf, + FCFT_SUBPIXEL_DEFAULT); + if (text == NULL) + return; + + for (i = 0; i < text->count; i++) { + if (max < pos + text->glyphs[i]->width) + max = pos + text->glyphs[i]->width; + + pos += text->glyphs[i]->advance.x; + + if (min > pos) + min = pos; + } + + if (align & LABEL_ALIGNL) + pos = x1; + else if (align & LABEL_ALIGNR) + pos = x2 - max; + else + pos = (x1 + x2 + min - max) / 2; + + if (align & LABEL_ALIGNU) + level = y1 + font->ascent; + else if (align & LABEL_ALIGND) + level = y2 - font->descent; + else + level = (y1 + y2 + font->ascent) / 2; + + for (i = 0; i < text->count; i++) { + pixman_image_composite32(PIXMAN_OP_OVER, color, text->glyphs[i]->pix, img, + 0, 0, 0, 0, + pos, level - text->glyphs[i]->y, + text->glyphs[i]->width, text->glyphs[i]->height); + + pos += text->glyphs[i]->advance.x; + } + + fcft_text_run_destroy(text); +} + +static inline bool is_key_pressed(const struct ufkbd_ctx *ctx, + const struct ufkbd_key *key, + int part) +{ + if (key->presses[part]) + return true; + + return false; +} + +static int draw_single(struct ufkbd_ctx *ctx, struct ufkbd_key *key, + int x1, int y1, int x2, int y2, + pixman_image_t *img) +{ + bool keycap = true; + int width = x2 - x1 + 1, height = y2 - y1 + 1; + size_t i; + + for (i = 0; i < UFKBD_PART_MAX; i++) { + if (is_key_pressed(ctx, key, i)) { + keycap = false; + break; + } + } + + pixman_image_composite32(PIXMAN_OP_SRC, ctx->graphics->fill_bg, NULL, img, + 0, 0, 0, 0, x1, y1, width, height); + + if (keycap) + pixman_image_composite32(PIXMAN_OP_SRC, ctx->graphics->fill_keycap, NULL, img, + 0, 0, 0, 0, x1 + 2, y1 + 2, width - 4, height - 4); + + if (key->keyids[UFKBD_PART_CENTER] != -1) { + draw_part(ctx->graphics, ctx->graphics->font, + key->keysyms[UFKBD_PART_CENTER], + is_key_pressed(ctx, key, UFKBD_PART_CENTER), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, 0, img); + } + + if (key->keyids[UFKBD_PART_TL] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_TL], + is_key_pressed(ctx, key, UFKBD_PART_TL), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNL | LABEL_ALIGNU, img); + } + + if (key->keyids[UFKBD_PART_TR] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_TR], + is_key_pressed(ctx, key, UFKBD_PART_TR), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNR | LABEL_ALIGNU, img); + } + + if (key->keyids[UFKBD_PART_BL] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_BL], + is_key_pressed(ctx, key, UFKBD_PART_BL), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNL | LABEL_ALIGND, img); + } + + if (key->keyids[UFKBD_PART_BR] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_BR], + is_key_pressed(ctx, key, UFKBD_PART_BR), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNR | LABEL_ALIGND, img); + } + + if (key->keyids[UFKBD_PART_LEFT] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_LEFT], + is_key_pressed(ctx, key, UFKBD_PART_LEFT), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNL, img); + } + + if (key->keyids[UFKBD_PART_RIGHT] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_RIGHT], + is_key_pressed(ctx, key, UFKBD_PART_RIGHT), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNR, img); + } + + if (key->keyids[UFKBD_PART_TOP] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_TOP], + is_key_pressed(ctx, key, UFKBD_PART_TOP), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGNU, img); + } + + if (key->keyids[UFKBD_PART_BOTTOM] != -1) { + draw_part(ctx->graphics, ctx->graphics->font_sec, + key->keysyms[UFKBD_PART_BOTTOM], + is_key_pressed(ctx, key, UFKBD_PART_BOTTOM), + x1 + 2, y1 + 2, x2 - 2, y2 - 2, LABEL_ALIGND, img); + } + + return 0; +} + +void ufkbd_graphics_draw_key(struct ufkbd_ctx *ctx, struct ufkbd_key *key, + int x1, int y1, int x2, int y2) +{ + pixman_image_t *img; + void *ptr; + unsigned int scale = ctx->graphics->scale; + size_t stride; + int ret; + + ret = ctx->drv->draw_begin(ctx->drv_data, &stride, &ptr); + if (ret) + return; + + // We don't need the full image, just the part that we're touching. + img = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, + x2 * scale + 1, y2 * scale + 1, + ptr, stride); + if (img == NULL) + return; + + ret = draw_single(ctx, key, x1 * scale, y1 * scale, x2 * scale, y2 * scale, img); + if (!ret) + ctx->drv->draw_touch(ctx->drv_data, x1 * scale, y1 * scale, (x2 * scale) - (x1 * scale) + 1, (y2 * scale) - (y1 * scale) + 1); + + pixman_image_unref(img); + + ctx->drv->draw_end(ctx->drv_data); +} + +static void draw_from_layout(struct ufkbd_key *key, + int x1, int y1, int x2, int y2, + void *data) +{ + struct draw_data *ctx = data; + unsigned int scale = ctx->ufkbd->graphics->scale; + + draw_single(ctx->ufkbd, key, x1 * scale, y1 * scale, + x2 * scale, y2 * scale, ctx->img); +} + +void ufkbd_graphics_draw_layout(struct ufkbd_ctx *ctx, struct ufkbd_layout *layout, + size_t width, size_t height) +{ + struct draw_data data; + pixman_image_t *img; + void *ptr; + size_t stride; + int ret; + + ret = ctx->drv->draw_begin(ctx->drv_data, &stride, &ptr); + if (ret) + return; + + img = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, + width * ctx->graphics->scale, + height * ctx->graphics->scale, + ptr, stride); + if (img == NULL) + return; + + pixman_image_composite32(PIXMAN_OP_SRC, ctx->graphics->fill_bg, NULL, img, + 0, 0, 0, 0, 0, 0, width * ctx->graphics->scale, height * ctx->graphics->scale); + + ctx->drv->draw_touch(ctx->drv_data, 0, 0, + width * ctx->graphics->scale - 1, + height * ctx->graphics->scale - 1); + + data.ufkbd = ctx; + data.img = img; + + ufkbd_layout_foreach(ctx->layout, draw_from_layout, &data); + + pixman_image_unref(img); + + ctx->drv->draw_end(ctx->drv_data); +} + +int ufkbd_graphics_set_scale(struct ufkbd_graphics_ctx *graphics, unsigned int scale) +{ + struct fcft_font *font, *font_sec; + + graphics->scale = scale; + + snprintf(graphics->buf, graphics->size, "size=%u", 10 * scale); + font = fcft_from_name(ARRAY_SIZE(fonts), fonts, graphics->buf); + if (font == NULL) { + fprintf(stderr, "Failed to resize key label font when setting scale\n"); + return -1; + } + + snprintf(graphics->buf, graphics->size, "size=%u", 8 * scale); + font_sec = fcft_from_name(ARRAY_SIZE(fonts), fonts, graphics->buf); + if (font_sec == NULL) { + fprintf(stderr, "Failed to resize secondary key label font when setting scale\n"); + goto err_free_font; + } + + fcft_destroy(graphics->font); + fcft_destroy(graphics->font_sec); + + graphics->font = font; + graphics->font_sec = font_sec; + + return 0; + +err_free_font: + fcft_destroy(font); + return -1; +} + +struct ufkbd_graphics_ctx *ufkbd_graphics_init(void) +{ + struct ufkbd_graphics_ctx *graphics; + pixman_color_t color; + + graphics = malloc(sizeof(*graphics)); + if (graphics == NULL) + return NULL; + + graphics->scale = 1; + + fcft_init(FCFT_LOG_COLORIZE_AUTO, false, FCFT_LOG_CLASS_DEBUG); + + graphics->font = fcft_from_name(ARRAY_SIZE(fonts), fonts, "size=10"); + if (graphics->font == NULL) + goto err_free_ctx; + + graphics->font_sec = fcft_from_name(ARRAY_SIZE(fonts), fonts, "size=8"); + if (graphics->font_sec == NULL) + goto err_free_font; + + graphics->size = 256; + graphics->buf = malloc(graphics->size); + if (graphics->buf == NULL) + goto err_free_font_sec; + + color.red = 0; + color.green = 0; + color.blue = 0; + color.alpha = 65535; + graphics->fill_bg = pixman_image_create_solid_fill(&color); + if (graphics->fill_bg == NULL) + goto err_free_buf; + + color.red = 16383; + color.green = 16383; + color.blue = 16383; + color.alpha = 65535; + graphics->fill_keycap = pixman_image_create_solid_fill(&color); + if (graphics->fill_keycap == NULL) + goto err_unref_bg; + + color.red = 65535; + color.green = 65535; + color.blue = 65535; + color.alpha = 65535; + graphics->key_default = pixman_image_create_solid_fill(&color); + if (graphics->key_default == NULL) + goto err_unref_keycap; + + color.red = 0; + color.green = 40959; + color.blue = 65535; + color.alpha = 65535; + graphics->key_pressed = pixman_image_create_solid_fill(&color); + if (graphics->key_pressed == NULL) + goto err_unref_key_def; + + return graphics; + +err_unref_key_def: + pixman_image_unref(graphics->key_default); +err_unref_keycap: + pixman_image_unref(graphics->fill_keycap); +err_unref_bg: + pixman_image_unref(graphics->fill_bg); +err_free_buf: + free(graphics->buf); +err_free_font_sec: + fcft_destroy(graphics->font_sec); +err_free_font: + fcft_destroy(graphics->font); +err_free_ctx: + free(graphics); + return NULL; +} + +void ufkbd_graphics_uninit(struct ufkbd_graphics_ctx *graphics) +{ + pixman_image_unref(graphics->key_pressed); + pixman_image_unref(graphics->key_default); + pixman_image_unref(graphics->fill_keycap); + pixman_image_unref(graphics->fill_bg); + + fcft_destroy(graphics->font_sec); + fcft_destroy(graphics->font); + + fcft_fini(); + + free(graphics->buf); + + free(graphics); +} diff --git a/include/graphics.h b/include/graphics.h new file mode 100644 index 0000000..60523d7 --- /dev/null +++ b/include/graphics.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Interface for drawing keys to a buffer. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_GRAPHICS_H +#define UFKBD_GRAPHICS_H + +#include +#include + +struct fcft_font; + +struct ufkbd_ctx; +struct ufkbd_key; +struct ufkbd_layout; + +struct ufkbd_graphics_ctx { + struct fcft_font *font; + struct fcft_font *font_sec; + + pixman_image_t *fill_bg; + pixman_image_t *fill_keycap; + pixman_image_t *key_default; + pixman_image_t *key_pressed; + + pixman_image_t *target; + + unsigned int scale; + + size_t size; + void *buf; +}; + +struct ufkbd_graphics_ctx *ufkbd_graphics_init(void); +void ufkbd_graphics_uninit(struct ufkbd_graphics_ctx *graphics); + +int ufkbd_graphics_set_scale(struct ufkbd_graphics_ctx *graphics, unsigned int scale); + +void ufkbd_graphics_draw_key(struct ufkbd_ctx *ctx, struct ufkbd_key *key, + int x1, int y1, int x2, int y2); +void ufkbd_graphics_draw_layout(struct ufkbd_ctx *ctx, struct ufkbd_layout *layout, + size_t width, size_t height); + +#endif /* UFKBD_GRAPHICS_H */ diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..adfb438 --- /dev/null +++ b/include/input.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Input driver interface. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_INPUT_H +#define UFKBD_INPUT_H + +#include + +struct ufkbd_ctx; +struct ufkbd_key; + +int ufkbd_input_press(struct ufkbd_ctx *ctx, int id); +int ufkbd_input_position(struct ufkbd_ctx *ctx, int id, int x, int y); +int ufkbd_input_release(struct ufkbd_ctx *ctx, int id); +int ufkbd_input_repeat(struct ufkbd_ctx *ctx, int id); + +int ufkbd_input_repeat_held(struct ufkbd_ctx *ctx); + +#endif /* UFKBD_INPUT_H */ diff --git a/include/keymap.h b/include/keymap.h new file mode 100644 index 0000000..8dac1fa --- /dev/null +++ b/include/keymap.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Keymap generation interface. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_KEYMAP_H +#define UFKBD_KEYMAP_H + +#include + +struct ufkbd_keymap { + int count; + + size_t size; + int fd; + + char path[256]; +}; + +int ufkbd_keymap_add_key(struct ufkbd_keymap *keymap, xkb_keysym_t keysym); +void ufkbd_keymap_end(struct ufkbd_keymap *keymap); + +struct ufkbd_keymap *ufkbd_keymap_init(void); +void ufkbd_keymap_uninit(struct ufkbd_keymap *keymap); + +#endif /* UFKBD_KEYMAP_H */ diff --git a/include/layout.h b/include/layout.h new file mode 100644 index 0000000..4b765ad --- /dev/null +++ b/include/layout.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Keyboard layout management. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_LAYOUT_H +#define UFKBD_LAYOUT_H + +#include + +struct ufkbd_key; + +struct ufkbd_layout_column { + double x1_unscaled, x2_unscaled; + int x1, x2; + + struct ufkbd_key *key; +}; + +struct ufkbd_layout_row { + double y1_unscaled, y2_unscaled; + int y1, y2; + + size_t n_cols; + struct ufkbd_layout_column *cols; +}; + +struct ufkbd_layout { + size_t max_cols; + + size_t n_rows; + struct ufkbd_layout_row *rows; +}; + +struct ufkbd_layout *ufkbd_layout_init(void); +void ufkbd_layout_uninit(struct ufkbd_layout *layout); + +struct ufkbd_key *ufkbd_layout_search(struct ufkbd_layout *layout, int x, int y, + int *x1, int *y1, int *x2, int *y2); +void ufkbd_layout_foreach(struct ufkbd_layout *layout, + void (*func)(struct ufkbd_key *key, + int x1, int y1, int x2, int y2, + void *data), + void *data); +void ufkbd_layout_resize(struct ufkbd_layout *layout, int width, int height); + +#endif diff --git a/include/modifier.h b/include/modifier.h new file mode 100644 index 0000000..89f060b --- /dev/null +++ b/include/modifier.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Modifier key callbacks. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_MODIFIER_H +#define UFKBD_MODIFIER_H + +#include "ufkbd.h" + +struct ufkbd_ctx; +struct ufkbd_press; + +bool ufkbd_is_modifier(struct ufkbd_press *press); + +enum ufkbd_mod_state ufkbd_modifier_get_state(const struct ufkbd_ctx *ctx, + const struct ufkbd_key *key, + int part); + +void ufkbd_modifier_press(struct ufkbd_ctx *ctx, struct ufkbd_press *press); +void ufkbd_modifier_cancel(struct ufkbd_ctx *ctx, struct ufkbd_press *press); +void ufkbd_modifier_release(struct ufkbd_ctx *ctx, struct ufkbd_press *press); +void ufkbd_modifier_unlatch_all(struct ufkbd_ctx *ctx); + +#endif /* UFKBD_MODIFIER_H */ diff --git a/include/parser.h b/include/parser.h new file mode 100644 index 0000000..0e6584b --- /dev/null +++ b/include/parser.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Parser for Unfettered Keyboard keyboard layouts in XML. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_PARSER_H +#define UFKBD_PARSER_H + +struct ufkbd_keymap; +struct ufkbd_layout; + +int ufkbd_parser_parse(int dir, const char *fname, + struct ufkbd_keymap *keymap, + struct ufkbd_layout *layout); + +#endif /* UFKBD_PARSER_H */ diff --git a/include/ufkbd.h b/include/ufkbd.h new file mode 100644 index 0000000..e5f9845 --- /dev/null +++ b/include/ufkbd.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_H +#define UFKBD_H + +#include +#include +#include + +#define UFKBD_PRESS_MAX 64 +#define UFKBD_MOD_MAX 4 + +struct ufkbd_ctx; +struct ufkbd_graphics_ctx; +struct ufkbd_graphics_driver; +struct ufkbd_input_driver; + +// These correspond to the key0..key8 properties in the layout definitions +enum ufkbd_part { + UFKBD_PART_CENTER, + UFKBD_PART_TL, + UFKBD_PART_TR, + UFKBD_PART_BL, + UFKBD_PART_BR, + UFKBD_PART_LEFT, + UFKBD_PART_RIGHT, + UFKBD_PART_TOP, + UFKBD_PART_BOTTOM, + UFKBD_PART_MAX +}; + +enum ufkbd_mod_state { + UFKBD_MOD_RELEASED, + UFKBD_MOD_PRESSED, + UFKBD_MOD_LATCHED, + UFKBD_MOD_LOCKED, +}; + +enum ufkbd_modifier { + UFKBD_MOD_SHIFT, + UFKBD_MOD_CTRL, + UFKBD_MOD_ALT, +}; + +struct ufkbd_key { + // Graphical parameters + size_t presses[UFKBD_PART_MAX]; + void *labels_mask[UFKBD_PART_MAX * 2]; + void *labels_color[UFKBD_PART_MAX * 2]; + + int keyids[UFKBD_PART_MAX]; + xkb_keysym_t keysyms[UFKBD_PART_MAX]; + enum ufkbd_part lut[16]; + int latch_state; +}; + +struct ufkbd_driver { + void *(*init)(struct ufkbd_ctx *ufkbd); + void (*uninit)(void *data); + + // Deprecated + void (*listen_one)(void *data, bool block); + + void (*listen_step)(void *data, int timeout); + int (*send_key)(void *data, int code, bool repeat); + int (*send_mod)(void *data, enum ufkbd_modifier mod, bool pressed); + + int (*draw_begin)(void *data, size_t *stride, void **ptr); + void (*draw_touch)(void *data, int x, int y, int width, int height); + void (*draw_end)(void *data); +}; + +struct ufkbd_press { + struct ufkbd_key *key; + int xl, xr, yt, yb; + + struct timespec repeat; + + // Coordinates of starting and ending position of keypress + int x1, y1, x2, y2; + + // Cached section of the key that is pressed + enum ufkbd_part part; +}; + +struct ufkbd_ctx { + struct ufkbd_keymap *keymap; + struct ufkbd_layout *layout; + + struct ufkbd_driver *drv; + void *drv_data; + + struct ufkbd_graphics_ctx *graphics; + + // Settings + int repeat_delay_ns; + int repeat_interval_ns; + int dist_squared; + + uint32_t mods[(UFKBD_MOD_MAX + 15) / 16]; + + size_t n_presses; + struct ufkbd_press presses[UFKBD_PRESS_MAX]; + + bool terminate; +}; + +void ufkbd_terminate(struct ufkbd_ctx *ctx); + +#endif /* UFKBD_H */ diff --git a/include/wayland/fractional-scale-v1.h b/include/wayland/fractional-scale-v1.h new file mode 100644 index 0000000..7f0dec4 --- /dev/null +++ b/include/wayland/fractional-scale-v1.h @@ -0,0 +1,264 @@ +/* Generated by wayland-scanner 1.22.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/include/wayland/input-method-unstable-v2.h b/include/wayland/input-method-unstable-v2.h new file mode 100644 index 0000000..f9a1489 --- /dev/null +++ b/include/wayland/input-method-unstable-v2.h @@ -0,0 +1,945 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef INPUT_METHOD_UNSTABLE_V2_CLIENT_PROTOCOL_H +#define INPUT_METHOD_UNSTABLE_V2_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_input_method_unstable_v2 The input_method_unstable_v2 protocol + * Protocol for creating input methods + * + * @section page_desc_input_method_unstable_v2 Description + * + * This protocol allows applications to act as input methods for compositors. + * + * An input method context is used to manage the state of the input method. + * + * Text strings are UTF-8 encoded, their indices and lengths are in bytes. + * + * 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_input_method_unstable_v2 Interfaces + * - @subpage page_iface_zwp_input_method_v2 - input method + * - @subpage page_iface_zwp_input_popup_surface_v2 - popup surface + * - @subpage page_iface_zwp_input_method_keyboard_grab_v2 - keyboard grab + * - @subpage page_iface_zwp_input_method_manager_v2 - input method manager + * @section page_copyright_input_method_unstable_v2 Copyright + *
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * Copyright © 2012, 2013 Intel Corporation
+ * Copyright © 2015, 2016 Jan Arne Petersen
+ * Copyright © 2017, 2018 Red Hat, Inc.
+ * Copyright © 2018       Purism SPC
+ *
+ * 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_input_method_keyboard_grab_v2; +struct zwp_input_method_manager_v2; +struct zwp_input_method_v2; +struct zwp_input_popup_surface_v2; + +#ifndef ZWP_INPUT_METHOD_V2_INTERFACE +#define ZWP_INPUT_METHOD_V2_INTERFACE +/** + * @page page_iface_zwp_input_method_v2 zwp_input_method_v2 + * @section page_iface_zwp_input_method_v2_desc Description + * + * An input method object allows for clients to compose text. + * + * The objects connects the client to a text input in an application, and + * lets the client to serve as an input method for a seat. + * + * The zwp_input_method_v2 object can occupy two distinct states: active and + * inactive. In the active state, the object is associated to and + * communicates with a text input. In the inactive state, there is no + * associated text input, and the only communication is with the compositor. + * Initially, the input method is in the inactive state. + * + * Requests issued in the inactive state must be accepted by the compositor. + * Because of the serial mechanism, and the state reset on activate event, + * they will not have any effect on the state of the next text input. + * + * There must be no more than one input method object per seat. + * @section page_iface_zwp_input_method_v2_api API + * See @ref iface_zwp_input_method_v2. + */ +/** + * @defgroup iface_zwp_input_method_v2 The zwp_input_method_v2 interface + * + * An input method object allows for clients to compose text. + * + * The objects connects the client to a text input in an application, and + * lets the client to serve as an input method for a seat. + * + * The zwp_input_method_v2 object can occupy two distinct states: active and + * inactive. In the active state, the object is associated to and + * communicates with a text input. In the inactive state, there is no + * associated text input, and the only communication is with the compositor. + * Initially, the input method is in the inactive state. + * + * Requests issued in the inactive state must be accepted by the compositor. + * Because of the serial mechanism, and the state reset on activate event, + * they will not have any effect on the state of the next text input. + * + * There must be no more than one input method object per seat. + */ +extern const struct wl_interface zwp_input_method_v2_interface; +#endif +#ifndef ZWP_INPUT_POPUP_SURFACE_V2_INTERFACE +#define ZWP_INPUT_POPUP_SURFACE_V2_INTERFACE +/** + * @page page_iface_zwp_input_popup_surface_v2 zwp_input_popup_surface_v2 + * @section page_iface_zwp_input_popup_surface_v2_desc Description + * + * This interface marks a surface as a popup for interacting with an input + * method. + * + * The compositor should place it near the active text input area. It must + * be visible if and only if the input method is in the active state. + * + * The client must not destroy the underlying wl_surface while the + * zwp_input_popup_surface_v2 object exists. + * @section page_iface_zwp_input_popup_surface_v2_api API + * See @ref iface_zwp_input_popup_surface_v2. + */ +/** + * @defgroup iface_zwp_input_popup_surface_v2 The zwp_input_popup_surface_v2 interface + * + * This interface marks a surface as a popup for interacting with an input + * method. + * + * The compositor should place it near the active text input area. It must + * be visible if and only if the input method is in the active state. + * + * The client must not destroy the underlying wl_surface while the + * zwp_input_popup_surface_v2 object exists. + */ +extern const struct wl_interface zwp_input_popup_surface_v2_interface; +#endif +#ifndef ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_INTERFACE +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_INTERFACE +/** + * @page page_iface_zwp_input_method_keyboard_grab_v2 zwp_input_method_keyboard_grab_v2 + * @section page_iface_zwp_input_method_keyboard_grab_v2_desc Description + * + * The zwp_input_method_keyboard_grab_v2 interface represents an exclusive + * grab of the wl_keyboard interface associated with the seat. + * @section page_iface_zwp_input_method_keyboard_grab_v2_api API + * See @ref iface_zwp_input_method_keyboard_grab_v2. + */ +/** + * @defgroup iface_zwp_input_method_keyboard_grab_v2 The zwp_input_method_keyboard_grab_v2 interface + * + * The zwp_input_method_keyboard_grab_v2 interface represents an exclusive + * grab of the wl_keyboard interface associated with the seat. + */ +extern const struct wl_interface zwp_input_method_keyboard_grab_v2_interface; +#endif +#ifndef ZWP_INPUT_METHOD_MANAGER_V2_INTERFACE +#define ZWP_INPUT_METHOD_MANAGER_V2_INTERFACE +/** + * @page page_iface_zwp_input_method_manager_v2 zwp_input_method_manager_v2 + * @section page_iface_zwp_input_method_manager_v2_desc Description + * + * The input method manager allows the client to become the input method on + * a chosen seat. + * + * No more than one input method must be associated with any seat at any + * given time. + * @section page_iface_zwp_input_method_manager_v2_api API + * See @ref iface_zwp_input_method_manager_v2. + */ +/** + * @defgroup iface_zwp_input_method_manager_v2 The zwp_input_method_manager_v2 interface + * + * The input method manager allows the client to become the input method on + * a chosen seat. + * + * No more than one input method must be associated with any seat at any + * given time. + */ +extern const struct wl_interface zwp_input_method_manager_v2_interface; +#endif + +/** + * @ingroup iface_zwp_input_method_v2 + * @struct zwp_input_method_v2_listener + */ +struct zwp_input_method_v2_listener { + /** + * input method has been requested + * + * Notification that a text input focused on this seat requested + * the input method to be activated. + * + * This event serves the purpose of providing the compositor with + * an active input method. + * + * This event resets all state associated with previous enable, + * disable, surrounding_text, text_change_cause, and content_type + * events, as well as the state associated with set_preedit_string, + * commit_string, and delete_surrounding_text requests. In + * addition, it marks the zwp_input_method_v2 object as active, and + * makes any existing zwp_input_popup_surface_v2 objects visible. + * + * The surrounding_text, and content_type events must follow before + * the next done event if the text input supports the respective + * functionality. + * + * State set with this event is double-buffered. It will get + * applied on the next zwp_input_method_v2.done event, and stay + * valid until changed. + */ + void (*activate)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2); + /** + * deactivate event + * + * Notification that no focused text input currently needs an + * active input method on this seat. + * + * This event marks the zwp_input_method_v2 object as inactive. The + * compositor must make all existing zwp_input_popup_surface_v2 + * objects invisible until the next activate event. + * + * State set with this event is double-buffered. It will get + * applied on the next zwp_input_method_v2.done event, and stay + * valid until changed. + */ + void (*deactivate)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2); + /** + * surrounding text event + * + * Updates the surrounding plain text around the cursor, + * excluding the preedit text. + * + * If any preedit text is present, it is replaced with the cursor + * for the purpose of this event. + * + * The argument text is a buffer containing the preedit string, and + * must include the cursor position, and the complete selection. It + * should contain additional characters before and after these. + * 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 the text buffer. + * + * anchor is the byte offset of the selection anchor within the + * text buffer. If there is no selected text, anchor must be the + * same as cursor. + * + * If this event does not arrive before the first done event, the + * input method may assume that the text input does not support + * this functionality and ignore following surrounding_text events. + * + * Values set with this event are double-buffered. They will get + * applied and set to initial values on the next + * zwp_input_method_v2.done event. + * + * 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. + */ + void (*surrounding_text)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + const char *text, + uint32_t cursor, + uint32_t anchor); + /** + * indicates the cause of surrounding text change + * + * Tells the input method why the text surrounding the cursor + * changed. + * + * Whenever the client detects an external change in text, cursor, + * or anchor position, 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 event is double-buffered. It will get + * applied and set to its initial value on the next + * zwp_input_method_v2.done event. + * + * The initial value of cause is input_method. + */ + void (*text_change_cause)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t cause); + /** + * content purpose and hint + * + * Indicates the content type and hint for the current + * zwp_input_method_v2 instance. + * + * Values set with this event are double-buffered. They will get + * applied on the next zwp_input_method_v2.done event. + * + * The initial value for hint is none, and the initial value for + * purpose is normal. + */ + void (*content_type)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t hint, + uint32_t purpose); + /** + * apply state + * + * Atomically applies state changes recently sent to the client. + * + * The done event establishes and updates the state of the client, + * and must be issued after any changes to apply them. + * + * Text input state (content purpose, content hint, surrounding + * text, and change cause) is conceptually double-buffered within + * an input method context. + * + * Events modify the pending state, as opposed to the current state + * in use by the input method. A done event atomically applies all + * pending state, replacing the current state. After done, the new + * pending state is as documented for each related request. + * + * Events must be applied in the order of arrival. + * + * Neither current nor pending state are modified unless noted + * otherwise. + */ + void (*done)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2); + /** + * input method unavailable + * + * The input method ceased to be available. + * + * The compositor must issue this event as the only event on the + * object if there was another input_method object associated with + * the same seat at the time of its creation. + * + * The compositor must issue this request when the object is no + * longer useable, e.g. due to seat removal. + * + * The input method context becomes inert and should be destroyed + * after deactivation is handled. Any further requests and events + * except for the destroy request must be ignored. + */ + void (*unavailable)(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2); +}; + +/** + * @ingroup iface_zwp_input_method_v2 + */ +static inline int +zwp_input_method_v2_add_listener(struct zwp_input_method_v2 *zwp_input_method_v2, + const struct zwp_input_method_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_input_method_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_INPUT_METHOD_V2_COMMIT_STRING 0 +#define ZWP_INPUT_METHOD_V2_SET_PREEDIT_STRING 1 +#define ZWP_INPUT_METHOD_V2_DELETE_SURROUNDING_TEXT 2 +#define ZWP_INPUT_METHOD_V2_COMMIT 3 +#define ZWP_INPUT_METHOD_V2_GET_INPUT_POPUP_SURFACE 4 +#define ZWP_INPUT_METHOD_V2_GRAB_KEYBOARD 5 +#define ZWP_INPUT_METHOD_V2_DESTROY 6 + +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_ACTIVATE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_DEACTIVATE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_TEXT_CHANGE_CAUSE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_CONTENT_TYPE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_UNAVAILABLE_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_COMMIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_SET_PREEDIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_DELETE_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_GET_INPUT_POPUP_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_GRAB_KEYBOARD_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_v2 + */ +#define ZWP_INPUT_METHOD_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_input_method_v2 */ +static inline void +zwp_input_method_v2_set_user_data(struct zwp_input_method_v2 *zwp_input_method_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_input_method_v2, user_data); +} + +/** @ingroup iface_zwp_input_method_v2 */ +static inline void * +zwp_input_method_v2_get_user_data(struct zwp_input_method_v2 *zwp_input_method_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_method_v2); +} + +static inline uint32_t +zwp_input_method_v2_get_version(struct zwp_input_method_v2 *zwp_input_method_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2); +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Send the commit string text for insertion to the application. + * + * Inserts a string at current cursor position (see commit event + * sequence). The string to commit could be either just a single character + * after a key press or the result of some composing. + * + * The argument text is a buffer containing the string to insert. There is + * a maximum length of wayland messages, so text can not be longer than + * 4000 bytes. + * + * Values set with this event are double-buffered. They must be applied + * and reset to initial on the next zwp_text_input_v3.commit request. + * + * The initial value of text is an empty string. + */ +static inline void +zwp_input_method_v2_commit_string(struct zwp_input_method_v2 *zwp_input_method_v2, const char *text) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_COMMIT_STRING, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, text); +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Send the pre-edit string text to the application text input. + * + * Place a new composing text (pre-edit) at the current cursor position. + * Any previously set composing text must be removed. Any previously + * existing selected text must be removed. The cursor is moved to a new + * position within the preedit string. + * + * The argument text is a buffer containing the preedit string. There is + * a maximum length of wayland messages, so text can not be longer than + * 4000 bytes. + * + * The arguments cursor_begin and cursor_end are counted in bytes relative + * to the beginning of the submitted string buffer. Cursor should be + * hidden by the text input when both are equal to -1. + * + * cursor_begin indicates the beginning of the cursor. cursor_end + * indicates the end of the cursor. It may be equal or different than + * cursor_begin. + * + * Values set with this event are double-buffered. They must be applied on + * the next zwp_input_method_v2.commit event. + * + * The initial value of text is an empty string. The initial value of + * cursor_begin, and cursor_end are both 0. + */ +static inline void +zwp_input_method_v2_set_preedit_string(struct zwp_input_method_v2 *zwp_input_method_v2, const char *text, int32_t cursor_begin, int32_t cursor_end) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_SET_PREEDIT_STRING, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, text, cursor_begin, cursor_end); +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Remove the surrounding text. + * + * before_length and after_length are the number of bytes before and after + * the current cursor index (excluding the preedit text) to delete. + * + * If any preedit text is present, it is replaced with the cursor for the + * purpose of this event. In effect before_length is counted from the + * beginning of preedit text, and after_length from its end (see commit + * event sequence). + * + * Values set with this event are double-buffered. They must be applied + * and reset to initial on the next zwp_input_method_v2.commit request. + * + * The initial values of both before_length and after_length are 0. + */ +static inline void +zwp_input_method_v2_delete_surrounding_text(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t before_length, uint32_t after_length) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_DELETE_SURROUNDING_TEXT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, before_length, after_length); +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Apply state changes from commit_string, set_preedit_string and + * delete_surrounding_text requests. + * + * The state relating to these events is double-buffered, and each one + * modifies the pending state. This request replaces the current state + * with the pending state. + * + * The connected text input is expected to 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. + * + * The serial number reflects the last state of the zwp_input_method_v2 + * object known to the client. The value of the serial argument must be + * equal to the number of done events already issued by that object. When + * the compositor receives a commit request with a serial different than + * the number of past done events, it must proceed as normal, except it + * should not change the current state of the zwp_input_method_v2 object. + */ +static inline void +zwp_input_method_v2_commit(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, serial); +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Creates a new zwp_input_popup_surface_v2 object wrapping a given + * surface. + * + * The surface gets assigned the "input_popup" role. If the surface + * already has an assigned role, the compositor must issue a protocol + * error. + */ +static inline struct zwp_input_popup_surface_v2 * +zwp_input_method_v2_get_input_popup_surface(struct zwp_input_method_v2 *zwp_input_method_v2, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_GET_INPUT_POPUP_SURFACE, &zwp_input_popup_surface_v2_interface, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, NULL, surface); + + return (struct zwp_input_popup_surface_v2 *) id; +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Allow an input method to receive hardware keyboard input and process + * key events to generate text events (with pre-edit) over the wire. This + * allows input methods which compose multiple key events for inputting + * text like it is done for CJK languages. + * + * The compositor should send all keyboard events on the seat to the grab + * holder via the returned wl_keyboard object. Nevertheless, the + * compositor may decide not to forward any particular event. The + * compositor must not further process any event after it has been + * forwarded to the grab holder. + * + * Releasing the resulting wl_keyboard object releases the grab. + */ +static inline struct zwp_input_method_keyboard_grab_v2 * +zwp_input_method_v2_grab_keyboard(struct zwp_input_method_v2 *zwp_input_method_v2) +{ + struct wl_proxy *keyboard; + + keyboard = wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_GRAB_KEYBOARD, &zwp_input_method_keyboard_grab_v2_interface, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), 0, NULL); + + return (struct zwp_input_method_keyboard_grab_v2 *) keyboard; +} + +/** + * @ingroup iface_zwp_input_method_v2 + * + * Destroys the zwp_text_input_v2 object and any associated child + * objects, i.e. zwp_input_popup_surface_v2 and + * zwp_input_method_keyboard_grab_v2. + */ +static inline void +zwp_input_method_v2_destroy(struct zwp_input_method_v2 *zwp_input_method_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_v2, + ZWP_INPUT_METHOD_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_input_popup_surface_v2 + * @struct zwp_input_popup_surface_v2_listener + */ +struct zwp_input_popup_surface_v2_listener { + /** + * set text input area position + * + * Notify about the position of the area of the text input + * expressed as a rectangle in surface local coordinates. + * + * This is a hint to the input method telling it the relative + * position of the text being entered. + */ + void (*text_input_rectangle)(void *data, + struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2, + int32_t x, + int32_t y, + int32_t width, + int32_t height); +}; + +/** + * @ingroup iface_zwp_input_popup_surface_v2 + */ +static inline int +zwp_input_popup_surface_v2_add_listener(struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2, + const struct zwp_input_popup_surface_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_input_popup_surface_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_INPUT_POPUP_SURFACE_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_input_popup_surface_v2 + */ +#define ZWP_INPUT_POPUP_SURFACE_V2_TEXT_INPUT_RECTANGLE_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_input_popup_surface_v2 + */ +#define ZWP_INPUT_POPUP_SURFACE_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_input_popup_surface_v2 */ +static inline void +zwp_input_popup_surface_v2_set_user_data(struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_input_popup_surface_v2, user_data); +} + +/** @ingroup iface_zwp_input_popup_surface_v2 */ +static inline void * +zwp_input_popup_surface_v2_get_user_data(struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_popup_surface_v2); +} + +static inline uint32_t +zwp_input_popup_surface_v2_get_version(struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_input_popup_surface_v2); +} + +/** + * @ingroup iface_zwp_input_popup_surface_v2 + */ +static inline void +zwp_input_popup_surface_v2_destroy(struct zwp_input_popup_surface_v2 *zwp_input_popup_surface_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_popup_surface_v2, + ZWP_INPUT_POPUP_SURFACE_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_popup_surface_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + * @struct zwp_input_method_keyboard_grab_v2_listener + */ +struct zwp_input_method_keyboard_grab_v2_listener { + /** + * keyboard mapping + * + * This event provides a file descriptor to the client which can + * be memory-mapped to provide a keyboard mapping description. + * @param format keymap format + * @param fd keymap file descriptor + * @param size keymap size, in bytes + */ + void (*keymap)(void *data, + struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, + uint32_t format, + int32_t fd, + uint32_t size); + /** + * key event + * + * A key was pressed or released. The time argument is a + * timestamp with millisecond granularity, with an undefined base. + * @param serial serial number of the key event + * @param time timestamp with millisecond granularity + * @param key key that produced the event + * @param state physical state of the key + */ + void (*key)(void *data, + struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state); + /** + * modifier and group state + * + * Notifies clients that the modifier and/or group state has + * changed, and it should update its local state. + * @param serial serial number of the modifiers event + * @param mods_depressed depressed modifiers + * @param mods_latched latched modifiers + * @param mods_locked locked modifiers + * @param group keyboard layout + */ + void (*modifiers)(void *data, + struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group); + /** + * repeat rate and delay + * + * Informs the client about the keyboard's repeat rate and delay. + * + * This event is sent as soon as the + * zwp_input_method_keyboard_grab_v2 object has been created, and + * is guaranteed to be received by the client before any key press + * event. + * + * Negative values for either rate or delay are illegal. A rate of + * zero will disable any repeating (regardless of the value of + * delay). + * + * This event can be sent later on as well with a new value if + * necessary, so clients should continue listening for the event + * past the creation of zwp_input_method_keyboard_grab_v2. + * @param rate the rate of repeating keys in characters per second + * @param delay delay in milliseconds since key down until repeating starts + */ + void (*repeat_info)(void *data, + struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, + int32_t rate, + int32_t delay); +}; + +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +static inline int +zwp_input_method_keyboard_grab_v2_add_listener(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, + const struct zwp_input_method_keyboard_grab_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_input_method_keyboard_grab_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_RELEASE 0 + +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_KEYMAP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_KEY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_MODIFIERS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_REPEAT_INFO_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +#define ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_RELEASE_SINCE_VERSION 1 + +/** @ingroup iface_zwp_input_method_keyboard_grab_v2 */ +static inline void +zwp_input_method_keyboard_grab_v2_set_user_data(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_input_method_keyboard_grab_v2, user_data); +} + +/** @ingroup iface_zwp_input_method_keyboard_grab_v2 */ +static inline void * +zwp_input_method_keyboard_grab_v2_get_user_data(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_method_keyboard_grab_v2); +} + +static inline uint32_t +zwp_input_method_keyboard_grab_v2_get_version(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_input_method_keyboard_grab_v2); +} + +/** @ingroup iface_zwp_input_method_keyboard_grab_v2 */ +static inline void +zwp_input_method_keyboard_grab_v2_destroy(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2) +{ + wl_proxy_destroy((struct wl_proxy *) zwp_input_method_keyboard_grab_v2); +} + +/** + * @ingroup iface_zwp_input_method_keyboard_grab_v2 + */ +static inline void +zwp_input_method_keyboard_grab_v2_release(struct zwp_input_method_keyboard_grab_v2 *zwp_input_method_keyboard_grab_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_keyboard_grab_v2, + ZWP_INPUT_METHOD_KEYBOARD_GRAB_V2_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_keyboard_grab_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#define ZWP_INPUT_METHOD_MANAGER_V2_GET_INPUT_METHOD 0 +#define ZWP_INPUT_METHOD_MANAGER_V2_DESTROY 1 + + +/** + * @ingroup iface_zwp_input_method_manager_v2 + */ +#define ZWP_INPUT_METHOD_MANAGER_V2_GET_INPUT_METHOD_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_input_method_manager_v2 + */ +#define ZWP_INPUT_METHOD_MANAGER_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_input_method_manager_v2 */ +static inline void +zwp_input_method_manager_v2_set_user_data(struct zwp_input_method_manager_v2 *zwp_input_method_manager_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_input_method_manager_v2, user_data); +} + +/** @ingroup iface_zwp_input_method_manager_v2 */ +static inline void * +zwp_input_method_manager_v2_get_user_data(struct zwp_input_method_manager_v2 *zwp_input_method_manager_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_method_manager_v2); +} + +static inline uint32_t +zwp_input_method_manager_v2_get_version(struct zwp_input_method_manager_v2 *zwp_input_method_manager_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_input_method_manager_v2); +} + +/** + * @ingroup iface_zwp_input_method_manager_v2 + * + * Request a new input zwp_input_method_v2 object associated with a given + * seat. + */ +static inline struct zwp_input_method_v2 * +zwp_input_method_manager_v2_get_input_method(struct zwp_input_method_manager_v2 *zwp_input_method_manager_v2, struct wl_seat *seat) +{ + struct wl_proxy *input_method; + + input_method = wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_manager_v2, + ZWP_INPUT_METHOD_MANAGER_V2_GET_INPUT_METHOD, &zwp_input_method_v2_interface, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_manager_v2), 0, seat, NULL); + + return (struct zwp_input_method_v2 *) input_method; +} + +/** + * @ingroup iface_zwp_input_method_manager_v2 + * + * Destroys the zwp_input_method_manager_v2 object. + * + * The zwp_input_method_v2 objects originating from it remain valid. + */ +static inline void +zwp_input_method_manager_v2_destroy(struct zwp_input_method_manager_v2 *zwp_input_method_manager_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_input_method_manager_v2, + ZWP_INPUT_METHOD_MANAGER_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_input_method_manager_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wayland/viewporter.h b/include/wayland/viewporter.h new file mode 100644 index 0000000..e1295d4 --- /dev/null +++ b/include/wayland/viewporter.h @@ -0,0 +1,398 @@ +/* Generated by wayland-scanner 1.22.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, and is applied on the next + * 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, and is applied on the next + * 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 state, and will be + * applied on the next 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 state, and will be + * applied on the next 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/include/wayland/virtual-keyboard-unstable-v1.h b/include/wayland/virtual-keyboard-unstable-v1.h new file mode 100644 index 0000000..29c2807 --- /dev/null +++ b/include/wayland/virtual-keyboard-unstable-v1.h @@ -0,0 +1,280 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef VIRTUAL_KEYBOARD_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define VIRTUAL_KEYBOARD_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_virtual_keyboard_unstable_v1 The virtual_keyboard_unstable_v1 protocol + * @section page_ifaces_virtual_keyboard_unstable_v1 Interfaces + * - @subpage page_iface_zwp_virtual_keyboard_v1 - virtual keyboard + * - @subpage page_iface_zwp_virtual_keyboard_manager_v1 - virtual keyboard manager + * @section page_copyright_virtual_keyboard_unstable_v1 Copyright + *
+ *
+ * Copyright © 2008-2011  Kristian Høgsberg
+ * Copyright © 2010-2013  Intel Corporation
+ * Copyright © 2012-2013  Collabora, Ltd.
+ * Copyright © 2018       Purism SPC
+ *
+ * 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_virtual_keyboard_manager_v1; +struct zwp_virtual_keyboard_v1; + +#ifndef ZWP_VIRTUAL_KEYBOARD_V1_INTERFACE +#define ZWP_VIRTUAL_KEYBOARD_V1_INTERFACE +/** + * @page page_iface_zwp_virtual_keyboard_v1 zwp_virtual_keyboard_v1 + * @section page_iface_zwp_virtual_keyboard_v1_desc Description + * + * The virtual keyboard provides an application with requests which emulate + * the behaviour of a physical keyboard. + * + * This interface can be used by clients on its own to provide raw input + * events, or it can accompany the input method protocol. + * @section page_iface_zwp_virtual_keyboard_v1_api API + * See @ref iface_zwp_virtual_keyboard_v1. + */ +/** + * @defgroup iface_zwp_virtual_keyboard_v1 The zwp_virtual_keyboard_v1 interface + * + * The virtual keyboard provides an application with requests which emulate + * the behaviour of a physical keyboard. + * + * This interface can be used by clients on its own to provide raw input + * events, or it can accompany the input method protocol. + */ +extern const struct wl_interface zwp_virtual_keyboard_v1_interface; +#endif +#ifndef ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_INTERFACE +#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_INTERFACE +/** + * @page page_iface_zwp_virtual_keyboard_manager_v1 zwp_virtual_keyboard_manager_v1 + * @section page_iface_zwp_virtual_keyboard_manager_v1_desc Description + * + * A virtual keyboard manager allows an application to provide keyboard + * input events as if they came from a physical keyboard. + * @section page_iface_zwp_virtual_keyboard_manager_v1_api API + * See @ref iface_zwp_virtual_keyboard_manager_v1. + */ +/** + * @defgroup iface_zwp_virtual_keyboard_manager_v1 The zwp_virtual_keyboard_manager_v1 interface + * + * A virtual keyboard manager allows an application to provide keyboard + * input events as if they came from a physical keyboard. + */ +extern const struct wl_interface zwp_virtual_keyboard_manager_v1_interface; +#endif + +#ifndef ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM +#define ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM +enum zwp_virtual_keyboard_v1_error { + /** + * No keymap was set + */ + ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP = 0, +}; +#endif /* ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM */ + +#define ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP 0 +#define ZWP_VIRTUAL_KEYBOARD_V1_KEY 1 +#define ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS 2 +#define ZWP_VIRTUAL_KEYBOARD_V1_DESTROY 3 + + +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + */ +#define ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + */ +#define ZWP_VIRTUAL_KEYBOARD_V1_KEY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + */ +#define ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + */ +#define ZWP_VIRTUAL_KEYBOARD_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_virtual_keyboard_v1 */ +static inline void +zwp_virtual_keyboard_v1_set_user_data(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_virtual_keyboard_v1, user_data); +} + +/** @ingroup iface_zwp_virtual_keyboard_v1 */ +static inline void * +zwp_virtual_keyboard_v1_get_user_data(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_virtual_keyboard_v1); +} + +static inline uint32_t +zwp_virtual_keyboard_v1_get_version(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1); +} + +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + * + * Provide a file descriptor to the compositor which can be + * memory-mapped to provide a keyboard mapping description. + * + * Format carries a value from the keymap_format enumeration. + */ +static inline void +zwp_virtual_keyboard_v1_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t format, int32_t fd, uint32_t size) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1, + ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, format, fd, size); +} + +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + * + * A key was pressed or released. + * The time argument is a timestamp with millisecond granularity, with an + * undefined base. All requests regarding a single object must share the + * same clock. + * + * Keymap must be set before issuing this request. + * + * State carries a value from the key_state enumeration. + */ +static inline void +zwp_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t time, uint32_t key, uint32_t state) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1, + ZWP_VIRTUAL_KEYBOARD_V1_KEY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, time, key, state); +} + +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + * + * Notifies the compositor that the modifier and/or group state has + * changed, and it should update state. + * + * The client should use wl_keyboard.modifiers event to synchronize its + * internal state with seat state. + * + * Keymap must be set before issuing this request. + */ +static inline void +zwp_virtual_keyboard_v1_modifiers(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1, + ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, mods_depressed, mods_latched, mods_locked, group); +} + +/** + * @ingroup iface_zwp_virtual_keyboard_v1 + */ +static inline void +zwp_virtual_keyboard_v1_destroy(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1, + ZWP_VIRTUAL_KEYBOARD_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM +#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM +enum zwp_virtual_keyboard_manager_v1_error { + /** + * client not authorized to use the interface + */ + ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_UNAUTHORIZED = 0, +}; +#endif /* ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM */ + +#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD 0 + + +/** + * @ingroup iface_zwp_virtual_keyboard_manager_v1 + */ +#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD_SINCE_VERSION 1 + +/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */ +static inline void +zwp_virtual_keyboard_manager_v1_set_user_data(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_virtual_keyboard_manager_v1, user_data); +} + +/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */ +static inline void * +zwp_virtual_keyboard_manager_v1_get_user_data(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_virtual_keyboard_manager_v1); +} + +static inline uint32_t +zwp_virtual_keyboard_manager_v1_get_version(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_manager_v1); +} + +/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */ +static inline void +zwp_virtual_keyboard_manager_v1_destroy(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1) +{ + wl_proxy_destroy((struct wl_proxy *) zwp_virtual_keyboard_manager_v1); +} + +/** + * @ingroup iface_zwp_virtual_keyboard_manager_v1 + * + * Creates a new virtual keyboard associated to a seat. + * + * If the compositor enables a keyboard to perform arbitrary actions, it + * should present an error when an untrusted client requests a new + * keyboard. + */ +static inline struct zwp_virtual_keyboard_v1 * +zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_manager_v1, + ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD, &zwp_virtual_keyboard_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_manager_v1), 0, seat, NULL); + + return (struct zwp_virtual_keyboard_v1 *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wayland/wlr-layer-shell-unstable-v1.h b/include/wayland/wlr-layer-shell-unstable-v1.h new file mode 100644 index 0000000..880e59e --- /dev/null +++ b/include/wayland/wlr-layer-shell-unstable-v1.h @@ -0,0 +1,706 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol + * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces + * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop + * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface + * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright + *
+ *
+ * Copyright © 2017 Drew DeVault
+ *
+ * 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_output; +struct wl_surface; +struct xdg_popup; +struct zwlr_layer_shell_v1; +struct zwlr_layer_surface_v1; + +#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE +#define ZWLR_LAYER_SHELL_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1 + * @section page_iface_zwlr_layer_shell_v1_desc Description + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + * @section page_iface_zwlr_layer_shell_v1_api API + * See @ref iface_zwlr_layer_shell_v1. + */ +/** + * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + */ +extern const struct wl_interface zwlr_layer_shell_v1_interface; +#endif +#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE +#define ZWLR_LAYER_SURFACE_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1 + * @section page_iface_zwlr_layer_surface_v1_desc Description + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + * @section page_iface_zwlr_layer_surface_v1_api API + * See @ref iface_zwlr_layer_surface_v1. + */ +/** + * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + */ +extern const struct wl_interface zwlr_layer_surface_v1_interface; +#endif + +#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM +#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM +enum zwlr_layer_shell_v1_error { + /** + * wl_surface has another role + */ + ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0, + /** + * layer value is invalid + */ + ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1, + /** + * wl_surface has a buffer attached or committed + */ + ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2, +}; +#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM +#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM +/** + * @ingroup iface_zwlr_layer_shell_v1 + * available layers for surfaces + * + * These values indicate which layers a surface can be rendered in. They + * are ordered by z depth, bottom-most first. Traditional shell surfaces + * will typically be rendered between the bottom and top layers. + * Fullscreen shell surfaces are typically rendered at the top layer. + * Multiple surfaces can share a single layer, and ordering within a + * single layer is undefined. + */ +enum zwlr_layer_shell_v1_layer { + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, + ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, +}; +#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ + +#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0 +#define ZWLR_LAYER_SHELL_V1_DESTROY 1 + + +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3 + +/** @ingroup iface_zwlr_layer_shell_v1 */ +static inline void +zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data); +} + +/** @ingroup iface_zwlr_layer_shell_v1 */ +static inline void * +zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1); +} + +static inline uint32_t +zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1); +} + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * + * Create a layer surface for an existing surface. This assigns the role of + * layer_surface, or raises a protocol error if another role is already + * assigned. + * + * Creating a layer 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 layer_surface.configure call + * must also be treated as errors. + * + * After creating a layer_surface object and setting it up, the client + * must perform an initial commit without any buffer attached. + * The compositor will reply with a layer_surface.configure event. + * The client must acknowledge it and is then allowed to attach a buffer + * to map the surface. + * + * You may pass NULL for output to allow the compositor to decide which + * output to use. Generally this will be the one that the user most + * recently interacted with. + * + * Clients can specify a namespace that defines the purpose of the layer + * surface. + */ +static inline struct zwlr_layer_surface_v1 * +zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_shell_v1, + ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1), 0, NULL, surface, output, layer, namespace); + + return (struct zwlr_layer_surface_v1 *) id; +} + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * + * This request indicates that the client will not use the layer_shell + * object any more. Objects that have been created through this instance + * are not affected. + */ +static inline void +zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_shell_v1, + ZWLR_LAYER_SHELL_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +/** + * @ingroup iface_zwlr_layer_surface_v1 + * types of keyboard interaction possible for a layer shell surface + * + * Types of keyboard interaction possible for layer shell surfaces. The + * rationale for this is twofold: (1) some applications are not interested + * in keyboard events and not allowing them to be focused can improve the + * desktop experience; (2) some applications will want to take exclusive + * keyboard focus. + */ +enum zwlr_layer_surface_v1_keyboard_interactivity { + /** + * no keyboard focus is possible + * + * This value indicates that this surface is not interested in + * keyboard events and the compositor should never assign it the + * keyboard focus. + * + * This is the default value, set for newly created layer shell + * surfaces. + * + * This is useful for e.g. desktop widgets that display information + * or only have interaction with non-keyboard input devices. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0, + /** + * request exclusive keyboard focus + * + * Request exclusive keyboard focus if this surface is above the + * shell surface layer. + * + * For the top and overlay layers, the seat will always give + * exclusive keyboard focus to the top-most layer which has + * keyboard interactivity set to exclusive. If this layer contains + * multiple surfaces with keyboard interactivity set to exclusive, + * the compositor determines the one receiving keyboard events in + * an implementation- defined manner. In this case, no guarantee is + * made when this surface will receive keyboard focus (if ever). + * + * For the bottom and background layers, the compositor is allowed + * to use normal focus semantics. + * + * This setting is mainly intended for applications that need to + * ensure they receive all keyboard events, such as a lock screen + * or a password prompt. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1, + /** + * request regular keyboard focus semantics + * + * This requests the compositor to allow this surface to be + * focused and unfocused by the user in an implementation-defined + * manner. The user should be able to unfocus this surface even + * regardless of the layer it is on. + * + * Typically, the compositor will want to use its normal mechanism + * to manage keyboard focus between layer shell surfaces with this + * setting and regular toplevels on the desktop layer (e.g. click + * to focus). Nevertheless, it is possible for a compositor to + * require a special interaction to focus or unfocus layer shell + * surfaces (e.g. requiring a click even if focus follows the mouse + * normally, or providing a keybinding to switch focus between + * layers). + * + * This setting is mainly intended for desktop shell components + * (e.g. panels) that allow keyboard interaction. Using this option + * can allow implementing a desktop shell that can be fully usable + * without the mouse. + * @since 4 + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4 +#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +enum zwlr_layer_surface_v1_error { + /** + * provided surface state is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0, + /** + * size is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1, + /** + * anchor bitfield is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2, + /** + * keyboard interactivity is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3, +}; +#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +enum zwlr_layer_surface_v1_anchor { + /** + * the top edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, + /** + * the bottom edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, + /** + * the left edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, + /** + * the right edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, +}; +#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * @struct zwlr_layer_surface_v1_listener + */ +struct zwlr_layer_surface_v1_listener { + /** + * suggest a surface change + * + * The configure event asks the client to resize its surface. + * + * 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. + * + * The client is free to dismiss all but the last configure event + * it received. + * + * The width and height arguments specify the size of the window in + * surface-local coordinates. + * + * The size is a hint, in the sense that the client is free to + * ignore it if it doesn't resize, pick a smaller size (to satisfy + * aspect ratio or resize in steps of NxM pixels). If the client + * picks a smaller size and is anchored to two opposite anchors + * (e.g. 'top' and 'bottom'), the surface will be centered on this + * axis. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. + */ + void (*configure)(void *data, + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, + uint32_t serial, + uint32_t width, + uint32_t height); + /** + * surface should be closed + * + * The closed event is sent by the compositor when the surface + * will no longer be shown. The output may have been destroyed or + * the user may have asked for it to be removed. Further changes to + * the surface will be ignored. The client should destroy the + * resource after receiving this event, and create a new surface if + * they so choose. + */ + void (*closed)(void *data, + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1); +}; + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +static inline int +zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, + const struct zwlr_layer_surface_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1, + (void (**)(void)) listener, data); +} + +#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0 +#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1 +#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2 +#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3 +#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4 +#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5 +#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6 +#define ZWLR_LAYER_SURFACE_V1_DESTROY 7 +#define ZWLR_LAYER_SURFACE_V1_SET_LAYER 8 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2 + +/** @ingroup iface_zwlr_layer_surface_v1 */ +static inline void +zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data); +} + +/** @ingroup iface_zwlr_layer_surface_v1 */ +static inline void * +zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1); +} + +static inline uint32_t +zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Sets the size of the surface in surface-local coordinates. The + * compositor will display the surface centered with respect to its + * anchors. + * + * If you pass 0 for either value, the compositor will assign it and + * inform you of the assignment in the configure event. You must set your + * anchor to opposite edges in the dimensions you omit; not doing so is a + * protocol error. Both values are 0 by default. + * + * Size is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, width, height); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Requests that the compositor anchor the surface to the specified edges + * and corners. If two orthogonal edges are specified (e.g. 'top' and + * 'left'), then the anchor point will be the intersection of the edges + * (e.g. the top left corner of the output); otherwise the anchor point + * will be centered on that edge, or in the center if none is specified. + * + * Anchor is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, anchor); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Requests that the compositor avoids occluding an area with other + * surfaces. The compositor's use of this information is + * implementation-dependent - do not assume that this region will not + * actually be occluded. + * + * A positive value is only meaningful if the surface is anchored to one + * edge or an edge and both perpendicular edges. If the surface is not + * anchored, anchored to only two perpendicular edges (a corner), anchored + * to only two parallel edges or anchored to all edges, a positive value + * will be treated the same as zero. + * + * A positive zone is the distance from the edge in surface-local + * coordinates to consider exclusive. + * + * Surfaces that do not wish to have an exclusive zone may instead specify + * how they should interact with surfaces that do. If set to zero, the + * surface indicates that it would like to be moved to avoid occluding + * surfaces with a positive exclusive zone. If set to -1, the surface + * indicates that it would not like to be moved to accommodate for other + * surfaces, and the compositor should extend it all the way to the edges + * it is anchored to. + * + * For example, a panel might set its exclusive zone to 10, so that + * maximized shell surfaces are not shown on top of it. A notification + * might set its exclusive zone to 0, so that it is moved to avoid + * occluding the panel, but shell surfaces are shown underneath it. A + * wallpaper or lock screen might set their exclusive zone to -1, so that + * they stretch below or over the panel. + * + * The default value is 0. + * + * Exclusive zone is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, zone); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Requests that the surface be placed some distance away from the anchor + * point on the output, in surface-local coordinates. Setting this value + * for edges you are not anchored to has no effect. + * + * The exclusive zone includes the margin. + * + * Margin is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_MARGIN, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, top, right, bottom, left); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Set how keyboard events are delivered to this surface. By default, + * layer shell surfaces do not receive keyboard events; this request can + * be used to change this. + * + * This setting is inherited by child surfaces set by the get_popup + * request. + * + * Layer surfaces receive pointer, touch, and tablet events normally. If + * you do not want to receive them, set the input region on your surface + * to an empty region. + * + * Keyboard interactivity is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, keyboard_interactivity); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * This assigns an xdg_popup's parent to this layer_surface. This popup + * should have been created via xdg_surface::get_popup with the parent set + * to NULL, and this request must be invoked before committing the popup's + * initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline void +zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_GET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, popup); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, serial); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * This request destroys the layer surface. + */ +static inline void +zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Change the layer that the surface is rendered on. + * + * Layer is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_layer(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t layer) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_LAYER, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, layer); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wayland/xdg-shell.h b/include/wayland/xdg-shell.h new file mode 100644 index 0000000..8b24f09 --- /dev/null +++ b/include/wayland/xdg-shell.h @@ -0,0 +1,2315 @@ +/* Generated by wayland-scanner 1.22.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, 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, 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. + * + * A 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 perfoming 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. + * + * A 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 perfoming 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. 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 an + * assigned role and this will result in a role error. + * + * 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. + * + * 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 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. + * + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * 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. They will get applied on + * the next 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. + * @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. + * @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. + * @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. + * @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, +}; +/** + * @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 +#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. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + 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. + * @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. + * @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. They will get applied + * on the next 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 a + * 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. They will get applied + * on the next 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 a + * 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 + * 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/input.c b/input.c new file mode 100644 index 0000000..c22dd03 --- /dev/null +++ b/input.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "graphics.h" +#include "input.h" +#include "layout.h" +#include "modifier.h" +#include "ufkbd.h" + +// Simple function to add nanoseconds to a time struct. +static inline void time_add(struct timespec *time, long ns) +{ + time->tv_nsec += ns; + + if (time->tv_nsec >= 1000000000) { + time->tv_sec += time->tv_nsec / 1000000000; + time->tv_nsec = time->tv_nsec % 1000000000; + } +} + +static enum ufkbd_part part_calc(struct ufkbd_ctx *ctx, + struct ufkbd_key *key, + int x1, int y1, int x2, int y2) +{ + double angle; + int dx, dy; + int r_square; + int idx; + + dx = x2 - x1; + dy = y2 - y1; + + r_square = dx * dx + dy * dy; + + if (r_square < ctx->dist_squared) + return UFKBD_PART_CENTER; + + angle = atan2(dy, dx); + if (angle < 0) + angle += M_PI * 2; + + idx = floor(angle * 8 / M_PI); + + return key->lut[idx]; +} + +int ufkbd_input_press(struct ufkbd_ctx *ctx, int id) +{ + struct ufkbd_press *press; + int x1, y1, x2, y2; + int ret; + + if (id >= UFKBD_PRESS_MAX) + return -EINVAL; + + press = &ctx->presses[id]; + + // Only reset the press if it is new. + if (press->key == NULL) { + press->x1 = press->x2; + press->y1 = press->y2; + } + + // Failure to find a key results in ignoring the press. + press->key = ufkbd_layout_search(ctx->layout, press->x1, press->y1, + &x1, &y1, &x2, &y2); + + press->part = UFKBD_PART_CENTER; + + if (press->key != NULL) { + ufkbd_modifier_press(ctx, press); + + press->key->presses[press->part]++; + ctx->n_presses++; + + press->xl = x1; + press->yt = y1; + press->xr = x2; + press->yb = y2; + + ufkbd_graphics_draw_key(ctx, press->key, x1, y1, x2, y2); + } + + // The keypress may function partially if this fails. + ret = clock_gettime(CLOCK_REALTIME, &press->repeat); + if (ret == -1) + return 0; + time_add(&press->repeat, ctx->repeat_delay_ns); + + return 0; +} + +int ufkbd_input_position(struct ufkbd_ctx *ctx, int id, int x, int y) +{ + struct ufkbd_press *press; + enum ufkbd_part part; + + if (id >= UFKBD_PRESS_MAX) + return -EINVAL; + + press = &ctx->presses[id]; + + press->x2 = x; + press->y2 = y; + + // We only want to do this if a valid key is being pressed. + if (press->key != NULL) { + part = part_calc(ctx, press->key, + press->x1, press->y1, + press->x2, press->y2); + + if (press->part != part) { + press->key->presses[press->part]--; + press->key->presses[part]++; + + ufkbd_graphics_draw_key(ctx, press->key, + press->xl, press->yt, + press->xr, press->yb); + + ufkbd_modifier_cancel(ctx, press); + press->part = part; + ufkbd_modifier_press(ctx, press); + } + } + + return 0; +} + +int ufkbd_input_release(struct ufkbd_ctx *ctx, int id) +{ + struct ufkbd_press *press; + int part, code; + int ret = 0; + + if (ctx->drv->send_key == NULL) + return -ENOTSUP; + + if (ctx->presses[id].part >= UFKBD_PART_MAX) + return -EINVAL; + + press = &ctx->presses[id]; + + if (press->key == NULL) + return 0; + + part = press->part; + code = press->key->keyids[part]; + + /* + * If the key is a modifier, a state change is needed, and the key + * should only be sent to the driver when the modifier is released. + * Otherwise, the key should be sent to the driver and any latched + * modifiers should be released. + */ + if (ufkbd_is_modifier(press)) { + ufkbd_modifier_release(ctx, press); + } else if (code != -1) { + ret = ctx->drv->send_key(ctx->drv_data, code, false); + ufkbd_modifier_unlatch_all(ctx); + } + + press->key->presses[part]--; + ctx->n_presses--; + + ufkbd_graphics_draw_key(ctx, press->key, + press->xl, press->yt, + press->xr, press->yb); + + press->key = NULL; + + return ret; +} + +int ufkbd_input_repeat(struct ufkbd_ctx *ctx, int id) +{ + struct ufkbd_press *press; + enum ufkbd_part part; + int code; + + press = &ctx->presses[id]; + + // Modifier keys are not repeated. + if (ufkbd_is_modifier(press)) + return 0; + + time_add(&press->repeat, ctx->repeat_interval_ns); + + part = press->part; + code = press->key->keyids[part]; + + return ctx->drv->send_key(ctx->drv_data, code, true); +} + +int ufkbd_input_repeat_held(struct ufkbd_ctx *ctx) +{ + struct ufkbd_press *press; + struct timespec time; + size_t i; + int ret; + + ret = clock_gettime(CLOCK_REALTIME, &time); + if (ret == -1) + return 0; + + for (i = 0; i < UFKBD_PRESS_MAX; i++) { + press = &ctx->presses[i]; + if (press->key == NULL) + continue; + + if (time.tv_sec > press->repeat.tv_sec + || (time.tv_sec == press->repeat.tv_sec + && time.tv_nsec > press->repeat.tv_nsec)) { + ufkbd_input_repeat(ctx, i); + } + } + + return 0; +} diff --git a/keymap.c b/keymap.c new file mode 100644 index 0000000..b26cc3c --- /dev/null +++ b/keymap.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * XKB keymap manager. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "keymap.h" +#include "layout.h" +#include "ufkbd.h" + +static int write_keysym(int fd, xkb_keysym_t sym) +{ + char *name; + int len, ret; + + len = xkb_keysym_get_name(sym, NULL, 0); + if (len == -1) + return len; + + name = malloc((size_t) len + 1); + if (name == NULL) + return -1; + + xkb_keysym_get_name(sym, name, (size_t) len + 1); + + ret = dprintf(fd, "%s", name); + + free(name); + return ret; +} + +static int maybe_write_modmap(int fd, int keyid, xkb_keysym_t sym) +{ + if (sym == XKB_KEY_Shift_L || sym == XKB_KEY_Shift_R) + return dprintf(fd, " modifier_map Shift { };\n", + keyid); + else if (sym == XKB_KEY_Control_L || sym == XKB_KEY_Control_R) + return dprintf(fd, " modifier_map Control { };\n", + keyid); + else if (sym == XKB_KEY_Alt_L || sym == XKB_KEY_Alt_R) + return dprintf(fd, " modifier_map Mod1 { };\n", + keyid); + + return 0; +} + +int ufkbd_keymap_add_key(struct ufkbd_keymap *keymap, xkb_keysym_t keysym) +{ + xkb_keysym_t upper; + int len; + int keyid; + + keyid = keymap->count; + if (keyid >= 256) + return -1; + + upper = xkb_keysym_to_upper(keysym); + + len = dprintf(keymap->fd, " key { [ ", keyid); + if (len == -1) + return len; + keymap->size += len; + + len = write_keysym(keymap->fd, keysym); + if (len == -1) + return len; + keymap->size += len; + + len = dprintf(keymap->fd, ", "); + if (len == -1) + return len; + keymap->size += len; + + len = write_keysym(keymap->fd, upper); + if (len == -1) + return len; + keymap->size += len; + + len = dprintf(keymap->fd, " ] };\n"); + if (len == -1) + return len; + keymap->size += len; + + len = maybe_write_modmap(keymap->fd, keyid, keysym); + if (len == -1) + return len; + keymap->size += len; + + keymap->count++; + + return keyid; +} + +void ufkbd_keymap_end(struct ufkbd_keymap *keymap) +{ + int i; + int fd = keymap->fd; + size_t written; + + written = dprintf(fd, " };\n" + "\n" + " xkb_keycodes \"ufkbd\" {\n" + " minimum = 8;\n" + " maximum = 255;\n"); + + for (i = 8; i < keymap->count; i++) + written += dprintf(fd, " = %d;\n", i, i); + + written += dprintf(fd, " indicator 1 = \"Caps Lock\";\n" + " };\n" + "\n" + " xkb_types \"ufkbd\" {\n" + " type \"TWO_LEVEL\" {\n" + " modifiers = Shift;\n" + " map[Shift] = Level2;\n" + " level_name[Level1] = \"Base\";\n" + " level_name[Level2] = \"Shift\";\n" + " };\n" + " };\n" + "\n" + " xkb_compatibility \"ufkbd\" {\n" + " };\n" + "};\n"); + + keymap->size += written; +} + +struct ufkbd_keymap *ufkbd_keymap_init(void) +{ + struct ufkbd_keymap *keymap; + intmax_t pid; + + keymap = malloc(sizeof(*keymap)); + if (keymap == NULL) + return NULL; + + pid = getpid(); + snprintf(keymap->path, 256, "/tmp/ufkbd-keymap-pid%ju", pid); + + keymap->fd = open(keymap->path, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (keymap->fd == -1) + goto err; + + keymap->count = 8; + keymap->size = dprintf(keymap->fd, "xkb_keymap {\n" + " xkb_symbols \"ufkbd\" {\n"); + + return keymap; + +err: + free(keymap); + return NULL; +} + +void ufkbd_keymap_uninit(struct ufkbd_keymap *keymap) +{ + close(keymap->fd); + unlink(keymap->path); + free(keymap); +} diff --git a/layout.c b/layout.c new file mode 100644 index 0000000..1c702eb --- /dev/null +++ b/layout.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include + +#include "graphics.h" +#include "layout.h" +#include "parser.h" +#include "ufkbd.h" + +static struct ufkbd_layout_row *search_row(struct ufkbd_layout *layout, int y) +{ + struct ufkbd_layout_row *row; + size_t row1 = 0, row2; + size_t idx; + + if (layout->rows == NULL) + return NULL; + + row2 = layout->n_rows - 1; + + do { + idx = (row1 + row2) / 2; + row = &layout->rows[idx]; + + if (row->y1 <= y) + row1 = idx; + + if (row->y2 >= y) + row2 = idx; + } while (row2 - row1 > 1); + + if (layout->rows[row1].y1 <= y && layout->rows[row1].y2 >= y) + return &layout->rows[row1]; + else if (layout->rows[row2].y1 <= y && layout->rows[row2].y2 >= y) + return &layout->rows[row2]; + + return NULL; +} + +static struct ufkbd_layout_column *search_col(struct ufkbd_layout_row *row, int x) +{ + struct ufkbd_layout_column *col; + size_t col1 = 0, col2; + size_t idx; + + col2 = row->n_cols - 1; + + do { + idx = (col1 + col2) / 2; + col = &row->cols[idx]; + + if (col->x1 <= x) + col1 = idx; + + if (col->x2 >= x) + col2 = idx; + } while (col2 - col1 > 1); + + if (row->cols[col1].x1 <= x && row->cols[col1].x2 >= x) + return &row->cols[col1]; + else if (row->cols[col2].x1 <= x && row->cols[col2].x2 >= x) + return &row->cols[col2]; + + return NULL; +} + +struct ufkbd_key *ufkbd_layout_search(struct ufkbd_layout *layout, int x, int y, + int *x1, int *y1, int *x2, int *y2) +{ + struct ufkbd_layout_row *row; + struct ufkbd_layout_column *col; + + if (layout == NULL) + return NULL; + + row = search_row(layout, y); + if (row == NULL) + return NULL; + + col = search_col(row, x); + if (col == NULL) + return NULL; + + if (x1 != NULL) + *x1 = col->x1; + + if (y1 != NULL) + *y1 = row->y1; + + if (x2 != NULL) + *x2 = col->x2; + + if (y2 != NULL) + *y2 = row->y2; + + return col->key; +} + +void ufkbd_layout_foreach(struct ufkbd_layout *layout, + void (*func)(struct ufkbd_key *key, + int x1, int y1, int x2, int y2, + void *data), + void *data) +{ + struct ufkbd_layout_row *row; + struct ufkbd_layout_column *col; + size_t y, x; + + for (y = 0; y < layout->n_rows; y++) { + row = &layout->rows[y]; + + for (x = 0; x < row->n_cols; x++) { + col = &row->cols[x]; + func(col->key, + col->x1, row->y1, col->x2, row->y2, + data); + } + } +} + +void ufkbd_layout_resize(struct ufkbd_layout *layout, int width, int height) +{ + struct ufkbd_layout_row *row; + struct ufkbd_layout_column *col; + size_t y, x; + + for (y = 0; y < layout->n_rows; y++) { + row = &layout->rows[y]; + + row->y1 = row->y1_unscaled * height / layout->n_rows; + row->y2 = row->y2_unscaled * height / layout->n_rows - 1; + + if (row->y2 < row->y1) + row->y2 = row->y1; + + for (x = 0; x < row->n_cols; x++) { + col = &row->cols[x]; + col->x1 = col->x1_unscaled * width / layout->max_cols; + col->x2 = col->x2_unscaled * width / layout->max_cols - 1; + + if (col->x2 < col->x1) + col->x2 = col->x1; + } + } +} + +struct ufkbd_layout *ufkbd_layout_init(void) +{ + struct ufkbd_layout *layout; + + layout = malloc(sizeof(*layout)); + if (layout == NULL) + return NULL; + + layout->max_cols = 0; + layout->n_rows = 0; + layout->rows = NULL; + + return layout; +} + +void ufkbd_layout_uninit(struct ufkbd_layout *layout) +{ + struct ufkbd_layout_row *row; + size_t x, y; + + for (y = 0; y < layout->n_rows; y++) { + row = &layout->rows[y]; + + for (x = 0; x < row->n_cols; x++) + free(row->cols[x].key); + + free(row->cols); + } + + free(layout->rows); + free(layout); +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..b4b4ec7 --- /dev/null +++ b/main.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "graphics.h" +#include "input.h" +#include "layout.h" +#include "keymap.h" +#include "parser.h" +#include "ufkbd.h" + +extern struct ufkbd_input_driver ufkbd_input_wayland; +extern struct ufkbd_driver ufkbd_wayland; + +static struct ufkbd_ctx *ufkbd = NULL; + +void ufkbd_terminate(struct ufkbd_ctx *ctx) +{ + if (ctx != NULL) + ctx->terminate = true; +} + +static void sighandler(int sig) +{ + ufkbd_terminate(ufkbd); +} + +static int parse_layout(struct ufkbd_keymap *keymap, struct ufkbd_layout *layout) +{ + int ret, fd; + + fd = open("/usr/share/unfettered-keyboard/layouts", O_DIRECTORY | O_RDONLY); + if (fd == -1) { + perror("layout: failed to open /usr/share/unfettered-keyboard/layouts"); + return 1; + } + + ret = ufkbd_parser_parse(fd, "latn_qwerty_us.xml", keymap, layout); + if (ret) { + fprintf(stderr, "layout: failed to parse layout: %s\n", + strerror(-ret)); + return 1; + } + + close(fd); + + return 0; +} + +int main(void) +{ + struct ufkbd_ctx *ctx; + size_t i; + int ret; + + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return 1; + + ufkbd = ctx; + + ctx->keymap = ufkbd_keymap_init(); + if (ctx->keymap == NULL) + return 1; + + ctx->layout = ufkbd_layout_init(); + if (ctx->layout == NULL) + return 1; + + ret = parse_layout(ctx->keymap, ctx->layout); + if (ret) + return ret; + + ufkbd_keymap_end(ctx->keymap); + + ctx->graphics = ufkbd_graphics_init(); + if (ctx->graphics == NULL) + return 1; + + ctx->drv = &ufkbd_wayland; + ctx->drv_data = ctx->drv->init(ctx); + if (ctx->drv_data == NULL) + return 1; + + ctx->repeat_delay_ns = 600000000; + ctx->repeat_interval_ns = 25000000; + ctx->dist_squared = 1000; + + for (i = 0; i < UFKBD_PRESS_MAX; i++) + ctx->presses[i].key = NULL; + + while (!ctx->terminate) { + if (ctx->n_presses) { + ctx->drv->listen_step(ctx->drv_data, 25); + ufkbd_input_repeat_held(ctx); + } else { + ctx->drv->listen_step(ctx->drv_data, -1); + } + } + + ctx->drv->uninit(ctx->drv_data); + + ufkbd_graphics_uninit(ctx->graphics); + ufkbd_layout_uninit(ctx->layout); + ufkbd_keymap_uninit(ctx->keymap); + + free(ctx); +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..8cc5179 --- /dev/null +++ b/meson.build @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-3.0-only + +project('ufkbd', 'c') + +compiler = meson.get_compiler('c') + +expat = dependency('expat') +fcft = dependency('fcft') +pixman = dependency('pixman-1') +utf8proc = dependency('libutf8proc') +wayland = dependency('wayland-client') +xkbcommon = dependency('xkbcommon') + +libm = compiler.find_library('m') + +executable('ufkbd', + [ + 'graphics.c', + 'input.c', + 'keymap.c', + 'layout.c', + 'main.c', + 'modifier.c', + 'parser.c', + 'wayland/protocols/input-method-unstable-v2.c', + 'wayland/protocols/viewporter.c', + 'wayland/protocols/virtual-keyboard-unstable-v1.c', + 'wayland/protocols/wlr-layer-shell-unstable-v1.c', + 'wayland/protocols/xdg-shell.c', + 'wayland/buffer.c', + 'wayland/driver.c', + 'wayland/input.c', + 'wayland/surface.c', + ], + dependencies : [expat, fcft, libm, pixman, utf8proc, wayland, xkbcommon], + include_directories : 'include', + c_args : ['-Wall', '-Wextra', '-Wpedantic', '-Wno-unused-parameter'], +) diff --git a/modifier.c b/modifier.c new file mode 100644 index 0000000..be78867 --- /dev/null +++ b/modifier.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Management of keys that can be latched or locked. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include + +#include "ufkbd.h" + +static int mod_key_id(xkb_keysym_t sym) +{ + if (sym == XKB_KEY_Shift_L || sym == XKB_KEY_Shift_R) + return UFKBD_MOD_SHIFT; + else if (sym == XKB_KEY_Control_L || sym == XKB_KEY_Control_R) + return UFKBD_MOD_CTRL; + else if (sym == XKB_KEY_Alt_L || sym == XKB_KEY_Alt_R) + return UFKBD_MOD_ALT; + + return -1; +} + +static inline enum ufkbd_mod_state get_mod_state(const struct ufkbd_ctx *ctx, int id) +{ + int shift = id % 16 * 2; + + return (ctx->mods[id / 16] >> shift) & 0x3; +} + +static inline void set_mod_state(struct ufkbd_ctx *ctx, int id, enum ufkbd_mod_state state) +{ + int shift = id % 16 * 2; + + ctx->mods[id / 16] = (ctx->mods[id / 16] & ~(0x3 << shift)) + | state << shift; +} + +bool ufkbd_is_modifier(struct ufkbd_press *press) +{ + xkb_keysym_t sym; + int part, mod; + + part = press->part; + sym = press->key->keysyms[part]; + + mod = mod_key_id(sym); + + return mod != -1; +} + +enum ufkbd_mod_state ufkbd_modifier_get_state(const struct ufkbd_ctx *ctx, + const struct ufkbd_key *key, + int part) +{ + xkb_keysym_t sym; + int mod; + + sym = key->keysyms[part]; + + mod = mod_key_id(sym); + if (mod == -1) + return UFKBD_MOD_RELEASED; + + return get_mod_state(ctx, mod); +} + +void ufkbd_modifier_press(struct ufkbd_ctx *ctx, struct ufkbd_press *press) +{ + xkb_keysym_t sym; + enum ufkbd_mod_state curr; + int part, mod; + + part = press->part; + sym = press->key->keysyms[part]; + + // If this fails, the key is not a modifier key. + mod = mod_key_id(sym); + if (mod == -1) + return; + + curr = get_mod_state(ctx, mod); + if (curr == UFKBD_MOD_RELEASED) { + set_mod_state(ctx, mod, UFKBD_MOD_PRESSED); + ctx->drv->send_mod(ctx->drv_data, mod, true); + } +} + +void ufkbd_modifier_cancel(struct ufkbd_ctx *ctx, struct ufkbd_press *press) +{ + xkb_keysym_t sym; + enum ufkbd_mod_state curr; + int part, mod; + + part = press->part; + sym = press->key->keysyms[part]; + + mod = mod_key_id(sym); + if (mod == -1) + return; + + curr = get_mod_state(ctx, mod); + if (curr == UFKBD_MOD_PRESSED) { + set_mod_state(ctx, mod, UFKBD_MOD_RELEASED); + ctx->drv->send_mod(ctx->drv_data, mod, false); + } +} + +void ufkbd_modifier_release(struct ufkbd_ctx *ctx, struct ufkbd_press *press) +{ + struct timespec now = { + .tv_sec = 0, + .tv_nsec = 0, + }; + enum ufkbd_mod_state curr; + xkb_keysym_t sym; + int part, mod; + + part = press->part; + sym = press->key->keysyms[part]; + + mod = mod_key_id(sym); + if (mod == -1) + return; + + curr = get_mod_state(ctx, mod); + + if (curr == UFKBD_MOD_PRESSED) { + clock_gettime(CLOCK_REALTIME, &now); + + if (now.tv_sec > press->repeat.tv_sec + || (now.tv_sec == press->repeat.tv_sec + && now.tv_nsec > press->repeat.tv_nsec)) + set_mod_state(ctx, mod, UFKBD_MOD_LOCKED); + else + set_mod_state(ctx, mod, UFKBD_MOD_LATCHED); + } else if (curr == UFKBD_MOD_LATCHED || curr == UFKBD_MOD_LOCKED) { + set_mod_state(ctx, mod, UFKBD_MOD_RELEASED); + ctx->drv->send_mod(ctx->drv_data, mod, false); + } +} + +void ufkbd_modifier_unlatch_all(struct ufkbd_ctx *ctx) +{ + enum ufkbd_mod_state curr; + int i; + + for (i = 0; i < UFKBD_MOD_MAX; i++) { + curr = get_mod_state(ctx, i); + if (curr == UFKBD_MOD_LATCHED) { + set_mod_state(ctx, i, UFKBD_MOD_RELEASED); + ctx->drv->send_mod(ctx->drv_data, i, false); + } else if (curr == UFKBD_MOD_PRESSED) { + // This modifier key should go up on first release. + set_mod_state(ctx, i, UFKBD_MOD_LOCKED); + } + } +} diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..9f6ed02 --- /dev/null +++ b/parser.c @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Parser for keyboard layout files in the Unfettered Keyboard format. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "keymap.h" +#include "layout.h" +#include "ufkbd.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) +#define BOTTOM_ROW_FILE "bottom_row.xml" + +struct ufkbd_parser_ctx { + struct ufkbd_keymap *keymap; + struct ufkbd_layout *layout; + struct ufkbd_layout_row *row; + int err; +}; + +struct keyid_long { + const char *name; + int keyid; +}; + +/* + * This lookup table is sorted by codepoint so binary searches can be performed + * on it. Hash tables are too difficult to define statically. + */ +static const struct keyid_long keyids_long[] = { + { .name = "\\#", .keyid = XKB_KEY_numbersign, }, + { .name = "\\?", .keyid = XKB_KEY_question, }, + { .name = "\\@", .keyid = XKB_KEY_at, }, + { .name = "\\\\", .keyid = XKB_KEY_backslash, }, + { .name = "backspace", .keyid = XKB_KEY_BackSpace, }, + { .name = "ctrl", .keyid = XKB_KEY_Control_L, }, + { .name = "delete", .keyid = XKB_KEY_Delete, }, + { .name = "down", .keyid = XKB_KEY_Down, }, + { .name = "enter", .keyid = XKB_KEY_Return, }, + { .name = "esc", .keyid = XKB_KEY_Escape, }, + { .name = "fn", .keyid = XKB_KEY_XF86Fn, }, + { .name = "left", .keyid = XKB_KEY_Left, }, + { .name = "loc alt", .keyid = XKB_KEY_Alt_L, }, + { .name = "right", .keyid = XKB_KEY_Right, }, + { .name = "shift", .keyid = XKB_KEY_Shift_L, }, + { .name = "space", .keyid = XKB_KEY_space, }, + { .name = "tab", .keyid = XKB_KEY_Tab, }, + { .name = "up", .keyid = XKB_KEY_Up, }, +}; + +static void fill_lut_part(struct ufkbd_key *key, + enum ufkbd_part part, + enum ufkbd_part prev, + enum ufkbd_part next, + enum ufkbd_part prev_far, + enum ufkbd_part next_far, + size_t idx_p, size_t idx_n) +{ + if (key->keyids[part] == -1) + return; + + key->lut[idx_p] = part; + key->lut[idx_n] = part; + + if (key->keyids[prev] == -1) + key->lut[(idx_p - 1) % 16] = part; + + if (key->keyids[next] == -1) + key->lut[(idx_n + 1) % 16] = part; + + if (key->keyids[prev_far] == -1) { + key->lut[(idx_p - 2) % 16] = part; + key->lut[(idx_p - 3) % 16] = part; + } + + if (key->keyids[next_far] == -1) { + key->lut[(idx_n + 2) % 16] = part; + key->lut[(idx_n + 3) % 16] = part; + } +} + +static void construct_key_lut(struct ufkbd_key *key) +{ + size_t i; + + for (i = 0; i < UFKBD_PART_MAX; i++) + key->lut[i] = 0; + + fill_lut_part(key, UFKBD_PART_RIGHT, + UFKBD_PART_TR, UFKBD_PART_BR, + UFKBD_PART_TOP, UFKBD_PART_BOTTOM, + 15, 0); + fill_lut_part(key, UFKBD_PART_BR, + UFKBD_PART_RIGHT, UFKBD_PART_BOTTOM, + UFKBD_PART_TR, UFKBD_PART_BL, + 1, 2); + fill_lut_part(key, UFKBD_PART_BOTTOM, + UFKBD_PART_BR, UFKBD_PART_BL, + UFKBD_PART_RIGHT, UFKBD_PART_LEFT, + 3, 4); + fill_lut_part(key, UFKBD_PART_BL, + UFKBD_PART_BOTTOM, UFKBD_PART_LEFT, + UFKBD_PART_BR, UFKBD_PART_TL, + 5, 6); + fill_lut_part(key, UFKBD_PART_LEFT, + UFKBD_PART_BL, UFKBD_PART_TL, + UFKBD_PART_BOTTOM, UFKBD_PART_TOP, + 7, 8); + fill_lut_part(key, UFKBD_PART_TL, + UFKBD_PART_LEFT, UFKBD_PART_TOP, + UFKBD_PART_BL, UFKBD_PART_TR, + 9, 10); + fill_lut_part(key, UFKBD_PART_TOP, + UFKBD_PART_TL, UFKBD_PART_TR, + UFKBD_PART_LEFT, UFKBD_PART_RIGHT, + 11, 12); + fill_lut_part(key, UFKBD_PART_TR, + UFKBD_PART_TOP, UFKBD_PART_RIGHT, + UFKBD_PART_TL, UFKBD_PART_BR, + 13, 14); +} + +static int compare_keyid_long(const void *va, const void *vb) +{ + const struct keyid_long *a = va; + const struct keyid_long *b = vb; + + return strcmp(a->name, b->name); +} + +static void parse_keyid_attr(struct ufkbd_keymap *keymap, + int *keyid, xkb_keysym_t *keysym, + const XML_Char *val) +{ + struct keyid_long *id_long; + struct keyid_long pattern; + + pattern.name = val; + + id_long = bsearch(&pattern, keyids_long, + ARRAY_SIZE(keyids_long), + sizeof(*keyids_long), + compare_keyid_long); + if (id_long != NULL) { + *keysym = id_long->keyid; + } else if (val[1] == '\0') { + *keysym = val[0]; + } else { + *keyid = -1; + return; + } + + *keyid = ufkbd_keymap_add_key(keymap, *keysym); +} + +static void parse_key_attrs(struct ufkbd_keymap *keymap, + struct ufkbd_layout_column *col, + double start, + const XML_Char **attrs) +{ + struct ufkbd_key *key = col->key; + double width = 1; + size_t i; + + for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) { + if (!strcmp(attrs[i], "key0")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_CENTER], + &key->keysyms[UFKBD_PART_CENTER], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key1")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_TL], + &key->keysyms[UFKBD_PART_TL], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key2")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_TR], + &key->keysyms[UFKBD_PART_TR], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key3")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_BL], + &key->keysyms[UFKBD_PART_BL], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key4")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_BR], + &key->keysyms[UFKBD_PART_BR], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key5")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_LEFT], + &key->keysyms[UFKBD_PART_LEFT], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key6")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_RIGHT], + &key->keysyms[UFKBD_PART_RIGHT], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key7")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_TOP], + &key->keysyms[UFKBD_PART_TOP], + attrs[i + 1]); + else if (!strcmp(attrs[i], "key8")) + parse_keyid_attr(keymap, + &key->keyids[UFKBD_PART_BOTTOM], + &key->keysyms[UFKBD_PART_BOTTOM], + attrs[i + 1]); + else if (!strcmp(attrs[i], "shift")) + start += strtod(attrs[i + 1], NULL); + else if (!strcmp(attrs[i], "width")) + width = strtod(attrs[i + 1], NULL); + else + fprintf(stderr, "parser: skipping unknown key attribute %s\n", + attrs[i]); + } + + col->x1_unscaled = start; + col->x2_unscaled = start + width; +} + +static void parse_row_attrs(struct ufkbd_layout_row *row, + double start, + const XML_Char **attrs) +{ + double height = 1; + size_t i; + + for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) { + if (!strcmp(attrs[i], "height")) + height = strtod(attrs[i + 1], NULL); + } + + row->y1_unscaled = start; + row->y2_unscaled = start + height; +} + +static int start_key(struct ufkbd_parser_ctx *ctx, const XML_Char **attrs) +{ + struct ufkbd_layout_column *col, *prev; + struct ufkbd_layout_column *cols; + struct ufkbd_layout_row *row; + struct ufkbd_key *key; + double start = 0; + size_t i; + + if (ctx->row == NULL) + return -EINVAL; + + row = ctx->row; + + key = malloc(sizeof(*key)); + if (key == NULL) + return -errno; + + cols = realloc(row->cols, (row->n_cols + 1) * sizeof(*cols)); + if (cols == NULL) + return -errno; + + for (i = 0; i < UFKBD_PART_MAX; i++) { + key->labels_mask[i] = NULL; + key->labels_color[i] = NULL; + key->presses[i] = 0; + key->keyids[i] = -1; + } + + col = &cols[row->n_cols]; + prev = &cols[row->n_cols - 1]; + + col->key = key; + + if (row->n_cols > 0) + start = prev->x2_unscaled; + + parse_key_attrs(ctx->keymap, col, start, attrs); + construct_key_lut(key); + + row->cols = cols; + row->n_cols++; + + return 0; +} + +static int start_row(struct ufkbd_parser_ctx *ctx, const XML_Char **attrs) +{ + struct ufkbd_layout *layout = ctx->layout; + struct ufkbd_layout_row *rows; + struct ufkbd_layout_row *row, *prev; + double start = 0; + + rows = realloc(layout->rows, (layout->n_rows + 1) * sizeof(*rows)); + if (rows == NULL) + return -errno; + + row = &rows[layout->n_rows]; + prev = &rows[layout->n_rows - 1]; + + if (layout->n_rows > 0) + start = prev->y2_unscaled; + + parse_row_attrs(row, start, attrs); + + row->cols = NULL; + row->n_cols = 0; + + layout->rows = rows; + layout->n_rows++; + + ctx->row = row; + + return 0; +} + +static void start_elem(void *data, const XML_Char *name, const XML_Char **attrs) +{ + struct ufkbd_parser_ctx *ctx = data; + int ret = 0; + + if (!strcmp(name, "key")) + ret = start_key(ctx, attrs); + else if (!strcmp(name, "row")) + ret = start_row(ctx, attrs); + + if (ret) + fprintf(stderr, "parser: skipping %s: %s\n", + name, strerror(-ret)); +} + +static void end_elem(void *data, const XML_Char *name) +{ + struct ufkbd_parser_ctx *ctx = data; + + if (!strcmp(name, "row")) { + if (ctx->row == NULL) + return; + + if (ctx->layout->max_cols < ctx->row->n_cols) + ctx->layout->max_cols = ctx->row->n_cols; + + ctx->row = NULL; + } +} + +static int parse_until_eof(XML_Parser parser, int fd) +{ + char *buf; + ssize_t len; + size_t size = 4096; + enum XML_Status status; + enum XML_Error err; + int ret = 0; + + buf = malloc(size); + if (buf == NULL) + return -errno; + + do { + len = read(fd, buf, size); + if (len == -1) { + ret = -errno; + goto err; + } + + status = XML_Parse(parser, (const char *) buf, len, len == 0); + if (status != XML_STATUS_OK) { + err = XML_GetErrorCode(parser); + fprintf(stderr, "parser: xml parsing failed: " +#ifdef XML_UNICODE_WCHAR_T + "%ls\n", +#else + "%s\n", +#endif + XML_ErrorString(err)); + + ret = -EINVAL; + goto err; + } + } while (len != 0); + +err: + free(buf); + return ret; +} + +static int parse_file(int dir, const char *file, XML_Parser parser) +{ + int fd, ret; + + fd = openat(dir, file, O_RDONLY); + if (fd == -1) + return -errno; + + ret = parse_until_eof(parser, fd); + if (ret) + goto err_close; + +err_close: + close(fd); + return ret; +} + +int ufkbd_parser_parse(int dir, const char *fname, + struct ufkbd_keymap *keymap, + struct ufkbd_layout *layout) +{ + struct ufkbd_parser_ctx *ctx; + XML_Parser parser; + int ret; + + if (layout == NULL) + return -EINVAL; + + ctx = malloc(sizeof(*ctx)); + if (layout == NULL) + return -errno; + + ctx->keymap = keymap; + ctx->layout = layout; + ctx->row = NULL; + ctx->err = 0; + + parser = XML_ParserCreate(NULL); + if (parser == NULL) { + ret = -ENOMEM; + goto err_free_ctx; + } + + XML_SetElementHandler(parser, start_elem, end_elem); + XML_SetUserData(parser, ctx); + + ret = parse_file(dir, fname, parser); + if (ret) + goto err_free_parser; + + XML_ParserReset(parser, NULL); + XML_SetElementHandler(parser, start_elem, end_elem); + XML_SetUserData(parser, ctx); + + ret = parse_file(dir, BOTTOM_ROW_FILE, parser); + +err_free_parser: + XML_ParserFree(parser); +err_free_ctx: + free(ctx); + return ret; +} diff --git a/wayland/buffer.c b/wayland/buffer.c new file mode 100644 index 0000000..343be30 --- /dev/null +++ b/wayland/buffer.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Wayland buffer management. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "wayland.h" + +static int commit_buffer_resize(struct ufkbd_wl_buffer *ctx); + +static void on_buffer_release(void *data, struct wl_buffer *buf) +{ + struct ufkbd_wl_buffer *ctx = data; + + if (ctx->resize) + commit_buffer_resize(ctx); + + ctx->avail = true; +} + +static const struct wl_buffer_listener buf_listener = { + .release = on_buffer_release, +}; + +static int commit_buffer_resize(struct ufkbd_wl_buffer *ctx) +{ + int ret; + + wl_buffer_destroy(ctx->buf); + + ret = ftruncate(ctx->fd, ctx->size); + if (ret == -1) { + perror("wl: failed to resize shared memory"); + return -errno; + } + + ctx->ptr = mmap(NULL, ctx->size, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->fd, 0); + if (ctx->ptr == MAP_FAILED) { + perror("wl: failed to map buffer"); + return -errno; + } + + wl_shm_pool_resize(ctx->pool, ctx->size); + + ctx->buf = wl_shm_pool_create_buffer(ctx->pool, 0, + ctx->width, ctx->height, + ctx->width * 4, + WL_SHM_FORMAT_XRGB8888); + if (ctx->buf == NULL) { + fprintf(stderr, "wl: lost a buffer to failed resize\n"); + ctx->avail = false; + } + + wl_buffer_add_listener(ctx->buf, &buf_listener, ctx); + + ctx->resize = false; + + return 0; +} + +static void on_wl_shm(void *data, + struct wl_registry *reg, + uint32_t name, uint32_t ver) +{ + struct ufkbd_wl_buffer *ctx = data; + + ctx->wl = wl_registry_bind(reg, name, &wl_shm_interface, ver); + if (ctx->wl == NULL) { + fprintf(stderr, "wl: failed to bind to shared memory\n"); + return; + } + + ctx->pool = wl_shm_create_pool(ctx->wl, ctx->fd, 4); + if (ctx->pool == NULL) { + fprintf(stderr, "wl: failed to create memory pool\n"); + return; + } + + ctx->buf = wl_shm_pool_create_buffer(ctx->pool, 0, + 1, 1, 4, + WL_SHM_FORMAT_XRGB8888); + if (ctx->buf == NULL) { + fprintf(stderr, "wl: failed to create buffer\n"); + return; + } + + wl_buffer_add_listener(ctx->buf, &buf_listener, ctx); +} + +int ufkbd_wl_buffer_consume(struct ufkbd_wl_buffer *ctx, + struct wl_buffer **buf, void **ptr) +{ + if (buf == NULL || ptr == NULL) + return -EINVAL; + + if (!ctx->avail) + return -EBUSY; + + ctx->avail = false; + + *buf = ctx->buf; + *ptr = ctx->ptr; + + return 0; +} + +int ufkbd_wl_buffer_resize(struct ufkbd_wl_buffer *ctx, + uint32_t width, uint32_t height) +{ + int ret; + + if (width == 0 && height == 0) + return -EINVAL; + + ctx->width = width; + ctx->height = height; + + if (ctx->size < ctx->width * ctx->height * 4) { + munmap(ctx->ptr, ctx->size); + + ctx->size = ctx->width * ctx->height * 4; + } + + if (ctx->avail) { + ret = commit_buffer_resize(ctx); + if (ret) + return ret; + } else { + ctx->resize = true; + } + + return 0; +} + +int ufkbd_wl_buffer_init(struct ufkbd_wl_buffer *ctx, + struct ufkbd_input_wayland *ufkbd_wl, + unsigned int id) +{ + intmax_t pid; + int ret; + + ctx->ufkbd = ufkbd_wl->ufkbd; + ctx->id = id; + + ctx->avail = true; + ctx->dirty = false; + ctx->resize = false; + + ctx->listener.iface = &wl_shm_interface; + ctx->listener.cb = on_wl_shm; + ctx->listener.data = ctx; + + pid = getpid(); + + snprintf(ctx->path, SHM_PATH_SIZE, "/wl_shm_ufkbd_pid%jd_%u", pid, id); + ctx->path[SHM_PATH_SIZE - 1] = '\0'; + + ctx->fd = shm_open(ctx->path, O_RDWR | O_CREAT | O_EXCL, 0600); + if (ctx->fd == -1) { + perror("wl: failed to create shared memory"); + return -errno; + } + + ret = ftruncate(ctx->fd, 4); + if (ret) { + perror("wl: failed to allocate 4 bytes on shm"); + ret = -errno; + goto err; + } + + ctx->ptr = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->fd, 0); + if (ctx->ptr == MAP_FAILED) { + perror("wl: failed to map buffer"); + ret = -errno; + goto err; + } + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener); + if (ret) + goto err; + + ctx->width = 1; + ctx->height = 1; + ctx->size = 4; + + return 0; + +err: + close(ctx->fd); + shm_unlink(ctx->path); + return ret; +} + +void ufkbd_wl_buffer_uninit(struct ufkbd_wl_buffer *ctx) +{ + if (ctx->buf != NULL) + wl_buffer_destroy(ctx->buf); + + if (ctx->pool != NULL) + wl_shm_pool_destroy(ctx->pool); + + if (ctx->wl != NULL) + wl_shm_destroy(ctx->wl); + + close(ctx->fd); + shm_unlink(ctx->path); +} diff --git a/wayland/driver.c b/wayland/driver.c new file mode 100644 index 0000000..9c3a4cb --- /dev/null +++ b/wayland/driver.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Wayland driver. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "input.h" +#include "ufkbd.h" +#include "wayland.h" + +static void on_global_object(void *data, + struct wl_registry *reg, + uint32_t name, + const char *iface, + uint32_t version); + +static const struct wl_registry_listener reg_listener = { + .global = on_global_object, + .global_remove = NULL, +}; + +static void on_global_object(void *data, + struct wl_registry *reg, + uint32_t name, + const char *iface, + uint32_t version) +{ + struct ufkbd_input_wayland *ctx = data; + struct ufkbd_wl_global_listener *listener; + size_t i; + + // This is assumed to be a small list. + for (i = 0; i < ctx->n_global_listeners; i++) { + listener = ctx->global_listeners[i]; + + if (!strcmp(iface, listener->iface->name)) + listener->cb(listener->data, reg, name, version); + } +} + +int ufkbd_wl_global_listener_add(struct ufkbd_input_wayland *ctx, + struct ufkbd_wl_global_listener *listener) +{ + size_t idx = ctx->n_global_listeners; + + if (idx >= MAX_GLOBAL_LISTENERS) { + fprintf(stderr, "wl: no space for internal callback\n"); + return -ENOSPC; + } + + ctx->global_listeners[idx] = listener; + ctx->n_global_listeners++; + + return 0; +} + +static void ufkbd_wayland_listen_one(void *data, bool block) +{ + struct ufkbd_input_wayland *ctx = data; + struct pollfd pollfd; + int timeout = 0; + int ret; + + if (block) + timeout = -1; + + // Some listen events may be queued, so send them. + ret = wl_display_flush(ctx->display); + if (ret < 0) + fprintf(stderr, "warn: failed to flush outgoing events: %d\n", -errno); + + pollfd.fd = ctx->fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + ret = poll(&pollfd, 1, timeout); + if (ret == -1) + return; + + if (pollfd.revents) { + ret = wl_display_dispatch(ctx->display); + if (ret == -1) + return; + } +} + +static void ufkbd_wayland_listen_step(void *data, int timeout) +{ + struct ufkbd_input_wayland *ctx = data; + struct pollfd pollfd; + int ret; + + // Some listen events may be queued, so send them. + ret = wl_display_flush(ctx->display); + if (ret < 0) + fprintf(stderr, "warn: failed to flush outgoing events: %d\n", -errno); + + pollfd.fd = ctx->fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + ret = poll(&pollfd, 1, timeout); + if (ret == -1) + return; + + if (pollfd.revents) { + ret = wl_display_dispatch(ctx->display); + if (ret == -1) + return; + } +} + +static int ufkbd_wayland_send_key(void *data, int code, bool repeat) +{ + struct ufkbd_input_wayland *ctx = data; + + ufkbd_wl_input_send_key(ctx->input, code - 8, repeat); + + return 0; +} + +static int ufkbd_wayland_send_mod(void *data, enum ufkbd_modifier mod, bool pressed) +{ + struct ufkbd_input_wayland *ctx = data; + + ufkbd_wl_input_send_mod(ctx->input, mod, pressed); + + return 0; +} + +static int ufkbd_wayland_draw_begin(void *data, size_t *stride, void **ptr) +{ + struct ufkbd_input_wayland *ctx = data; + struct wl_buffer *buf; + int ret; + + ret = ufkbd_wl_surface_consume_buffer(ctx->surface, &buf, ptr); + if (ret) { + fprintf(stderr, "wl: warn: could not consume buffer: %s\n", + strerror(-ret)); + return ret; + } + + wl_surface_attach(ctx->surface->wl, buf, 0, 0); + + // NOPUSH + *stride = (size_t) ctx->surface->bufs[0].width * 4; + + return 0; +} + +static void ufkbd_wayland_draw_touch(void *data, int x, int y, int width, int height) +{ + struct ufkbd_input_wayland *ctx = data; + + wl_surface_damage_buffer(ctx->surface->wl, x, y, width, height); +} + +static void ufkbd_wayland_draw_end(void *data) +{ + struct ufkbd_input_wayland *ctx = data; + + wl_surface_commit(ctx->surface->wl); +} + +static void *ufkbd_wayland_init(struct ufkbd_ctx *ufkbd) +{ + struct ufkbd_input_wayland *ctx; + int ret; + + if (ufkbd == NULL) + return NULL; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->ufkbd = ufkbd; + + ctx->display = wl_display_connect(NULL); + if (ctx->display == NULL) + goto err_free_ctx; + + ctx->registry = wl_display_get_registry(ctx->display); + if (ctx->registry == NULL) + goto err_disconnect; + + ret = wl_registry_add_listener(ctx->registry, ®_listener, ctx); + if (ret) + goto err_destroy_reg; + + ret = ufkbd_wl_surface_init(ctx, &ctx->surface); + if (ret) + goto err_destroy_reg; + + ret = ufkbd_wl_input_init(ctx, &ctx->input); + if (ret) + goto err_uninit_surface; + + ctx->fd = wl_display_get_fd(ctx->display); + + return ctx; + +err_uninit_surface: + ufkbd_wl_surface_uninit(ctx->surface); +err_destroy_reg: + wl_registry_destroy(ctx->registry); +err_disconnect: + wl_display_disconnect(ctx->display); +err_free_ctx: + free(ctx); + return NULL; +} + +static void ufkbd_wayland_uninit(void *data) +{ + struct ufkbd_input_wayland *ctx = data; + + ufkbd_wl_input_uninit(ctx->input); + ufkbd_wl_surface_uninit(ctx->surface); + + wl_registry_destroy(ctx->registry); + wl_display_disconnect(ctx->display); + + free(ctx); +} + +struct ufkbd_driver ufkbd_wayland = { + .init = ufkbd_wayland_init, + .uninit = ufkbd_wayland_uninit, + .listen_one = ufkbd_wayland_listen_one, + .listen_step = ufkbd_wayland_listen_step, + .send_key = ufkbd_wayland_send_key, + .send_mod = ufkbd_wayland_send_mod, + .draw_begin = ufkbd_wayland_draw_begin, + .draw_touch = ufkbd_wayland_draw_touch, + .draw_end = ufkbd_wayland_draw_end, +}; diff --git a/wayland/input.c b/wayland/input.c new file mode 100644 index 0000000..0454e6e --- /dev/null +++ b/wayland/input.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Wayland input handling. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "input.h" +#include "keymap.h" +#include "ufkbd.h" +#include "wayland.h" +#include "wayland/input-method-unstable-v2.h" +#include "wayland/virtual-keyboard-unstable-v1.h" + +static void ignore() +{} + +static void on_pointer_move(void *data, + struct wl_pointer *pointer __attribute__((unused)), + uint32_t serial __attribute__((unused)), + wl_fixed_t x, + wl_fixed_t y) +{ + struct ufkbd_wl_input *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + ufkbd_input_position(ufkbd, UFKBD_PRESS_MAX - 1, x / 256, y / 256); +} + +static void on_pointer_button(void *data, + struct wl_pointer *pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + struct ufkbd_wl_input *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + if (state == WL_POINTER_BUTTON_STATE_PRESSED) + ufkbd_input_press(ufkbd, UFKBD_PRESS_MAX - 1); + else if (state == WL_POINTER_BUTTON_STATE_RELEASED) + ufkbd_input_release(ufkbd, UFKBD_PRESS_MAX - 1); +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = ignore, + .leave = ignore, + .motion = on_pointer_move, + .button = on_pointer_button, + .axis = ignore, + .frame = ignore, + .axis_source = ignore, + .axis_stop = ignore, + .axis_discrete = ignore, + .axis_value120 = ignore, + .axis_relative_direction = ignore, +}; + +void on_touch_down(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + struct ufkbd_wl_input *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + ufkbd_input_position(ufkbd, id, x / 256, y / 256); + ufkbd_input_press(ufkbd, id); +} + +void on_touch_up(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + int32_t id) +{ + struct ufkbd_wl_input *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + ufkbd_input_release(ufkbd, id); +} + +void on_touch_motion(void *data, + struct wl_touch *wl_touch, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + struct ufkbd_wl_input *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + ufkbd_input_position(ufkbd, id, x / 256, y / 256); +} + +static const struct wl_touch_listener touch_listener = { + .down = on_touch_down, + .up = on_touch_up, + .motion = on_touch_motion, + .frame = ignore, + .cancel = ignore, + .shape = ignore, + .orientation = ignore, +}; + +static void on_seat_caps(void *data, + struct wl_seat *seat, + uint32_t capabilities) +{ + struct ufkbd_wl_input *ctx = data; + + if (capabilities & WL_SEAT_CAPABILITY_TOUCH) { + ctx->touch = wl_seat_get_touch(seat); + if (ctx->touch == NULL) + return; + + wl_touch_add_listener(ctx->touch, &touch_listener, ctx); + } else { + if (ctx->touch != NULL) + wl_touch_destroy(ctx->touch); + + ctx->touch = NULL; + } + + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + ctx->pointer = wl_seat_get_pointer(seat); + if (ctx->pointer == NULL) + return; + + wl_pointer_add_listener(ctx->pointer, &pointer_listener, ctx); + } else { + if (ctx->pointer != NULL) + wl_pointer_destroy(ctx->pointer); + + ctx->pointer = NULL; + } +} + +static void on_seat_name(void *data, + struct wl_seat *seat, + const char *name) +{ + printf("wl: found seat %s\n", name); +} + +struct wl_seat_listener seat_listener = { + .name = on_seat_name, + .capabilities = on_seat_caps, +}; + +static int try_create_virtual_keyboard(struct ufkbd_wl_input *ctx) +{ + struct ufkbd_keymap *keymap = ctx->ufkbd_wl->ufkbd->keymap; + + if (ctx->manager == NULL) + return -EINVAL; + + if (ctx->seat == NULL) + return -EINVAL; + + if (ctx->kb != NULL) + return -EEXIST; + + ctx->kb = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(ctx->manager, + ctx->seat); + if (ctx->kb == NULL) + return -ENOMEM; + + zwp_virtual_keyboard_v1_keymap(ctx->kb, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keymap->fd, keymap->size); + + return 0; +} + +static void on_global_vkman(void *data, + struct wl_registry *reg, + uint32_t name, uint32_t version) +{ + struct ufkbd_wl_input *ctx = data; + + ctx->manager = wl_registry_bind(reg, name, + &zwp_virtual_keyboard_manager_v1_interface, + version); + if (ctx->manager == NULL) + return; + + try_create_virtual_keyboard(ctx); +} + +static void on_global_seat(void *data, + struct wl_registry *reg, + uint32_t name, uint32_t version) +{ + struct ufkbd_wl_input *ctx = data; + + ctx->seat = wl_registry_bind(reg, name, &wl_seat_interface, version); + if (ctx->seat == NULL) + return; + + wl_seat_add_listener(ctx->seat, &seat_listener, ctx); + + try_create_virtual_keyboard(ctx); +} + +int ufkbd_wl_input_send_key(struct ufkbd_wl_input *ctx, int key, bool repeat) +{ + if (ctx->kb == NULL) + return -ENODEV; + + zwp_virtual_keyboard_v1_key(ctx->kb, 0, key, WL_KEYBOARD_KEY_STATE_PRESSED); + + if (!repeat) + zwp_virtual_keyboard_v1_key(ctx->kb, 0, key, WL_KEYBOARD_KEY_STATE_RELEASED); + + return 0; +} + +int ufkbd_wl_input_send_mod(struct ufkbd_wl_input *ctx, enum ufkbd_modifier mod, bool pressed) +{ + int bit; + + if (ctx->kb == NULL) + return -ENODEV; + + if (mod == UFKBD_MOD_SHIFT) + bit = 0x1; + else if (mod == UFKBD_MOD_CTRL) + bit = 0x4; + else if (mod == UFKBD_MOD_ALT) + bit = 0x8; + else + bit = 0; + + if (pressed) + ctx->mod_state |= bit; + else + ctx->mod_state &= ~bit; + + zwp_virtual_keyboard_v1_modifiers(ctx->kb, ctx->mod_state, 0, 0, 0); + + return 0; +} + +int ufkbd_wl_input_init(struct ufkbd_input_wayland *ufkbd_wl, + struct ufkbd_wl_input **out) +{ + struct ufkbd_wl_input *ctx; + int ret; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return -errno; + + ctx->ufkbd_wl = ufkbd_wl; + + ctx->listener_seat.iface = &wl_seat_interface; + ctx->listener_seat.cb = on_global_seat; + ctx->listener_seat.data = ctx; + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener_seat); + if (ret) + goto err; + + ctx->listener_manager.iface = &zwp_virtual_keyboard_manager_v1_interface; + ctx->listener_manager.cb = on_global_vkman; + ctx->listener_manager.data = ctx; + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener_manager); + if (ret) + goto err; + + *out = ctx; + + return 0; + +err: + free(ctx); + return ret; +} + +void ufkbd_wl_input_uninit(struct ufkbd_wl_input *ctx) +{ + if (ctx->touch != NULL) + wl_touch_destroy(ctx->touch); + + if (ctx->pointer != NULL) + wl_pointer_destroy(ctx->pointer); + + if (ctx->seat != NULL) + wl_seat_destroy(ctx->seat); + + if (ctx->kb != NULL) + zwp_virtual_keyboard_v1_destroy(ctx->kb); + + if (ctx->manager != NULL) + zwp_virtual_keyboard_manager_v1_destroy(ctx->manager); + + free(ctx); +} diff --git a/wayland/protocols/fractional-scale-v1.c b/wayland/protocols/fractional-scale-v1.c new file mode 100644 index 0000000..090166b --- /dev/null +++ b/wayland/protocols/fractional-scale-v1.c @@ -0,0 +1,73 @@ +/* Generated by wayland-scanner 1.22.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 "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/wayland/protocols/input-method-unstable-v2.c b/wayland/protocols/input-method-unstable-v2.c new file mode 100644 index 0000000..41a7b45 --- /dev/null +++ b/wayland/protocols/input-method-unstable-v2.c @@ -0,0 +1,132 @@ +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2010-2011 Intel Corporation + * Copyright © 2012-2013 Collabora, Ltd. + * Copyright © 2012, 2013 Intel Corporation + * Copyright © 2015, 2016 Jan Arne Petersen + * Copyright © 2017, 2018 Red Hat, Inc. + * Copyright © 2018 Purism SPC + * + * 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 "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_input_method_keyboard_grab_v2_interface; +extern const struct wl_interface zwp_input_method_v2_interface; +extern const struct wl_interface zwp_input_popup_surface_v2_interface; + +static const struct wl_interface *input_method_unstable_v2_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &zwp_input_popup_surface_v2_interface, + &wl_surface_interface, + &zwp_input_method_keyboard_grab_v2_interface, + &wl_seat_interface, + &zwp_input_method_v2_interface, +}; + +static const struct wl_message zwp_input_method_v2_requests[] = { + { "commit_string", "s", input_method_unstable_v2_types + 0 }, + { "set_preedit_string", "sii", input_method_unstable_v2_types + 0 }, + { "delete_surrounding_text", "uu", input_method_unstable_v2_types + 0 }, + { "commit", "u", input_method_unstable_v2_types + 0 }, + { "get_input_popup_surface", "no", input_method_unstable_v2_types + 5 }, + { "grab_keyboard", "n", input_method_unstable_v2_types + 7 }, + { "destroy", "", input_method_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_input_method_v2_events[] = { + { "activate", "", input_method_unstable_v2_types + 0 }, + { "deactivate", "", input_method_unstable_v2_types + 0 }, + { "surrounding_text", "suu", input_method_unstable_v2_types + 0 }, + { "text_change_cause", "u", input_method_unstable_v2_types + 0 }, + { "content_type", "uu", input_method_unstable_v2_types + 0 }, + { "done", "", input_method_unstable_v2_types + 0 }, + { "unavailable", "", input_method_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_input_method_v2_interface = { + "zwp_input_method_v2", 1, + 7, zwp_input_method_v2_requests, + 7, zwp_input_method_v2_events, +}; + +static const struct wl_message zwp_input_popup_surface_v2_requests[] = { + { "destroy", "", input_method_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_input_popup_surface_v2_events[] = { + { "text_input_rectangle", "iiii", input_method_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_input_popup_surface_v2_interface = { + "zwp_input_popup_surface_v2", 1, + 1, zwp_input_popup_surface_v2_requests, + 1, zwp_input_popup_surface_v2_events, +}; + +static const struct wl_message zwp_input_method_keyboard_grab_v2_requests[] = { + { "release", "", input_method_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_input_method_keyboard_grab_v2_events[] = { + { "keymap", "uhu", input_method_unstable_v2_types + 0 }, + { "key", "uuuu", input_method_unstable_v2_types + 0 }, + { "modifiers", "uuuuu", input_method_unstable_v2_types + 0 }, + { "repeat_info", "ii", input_method_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_input_method_keyboard_grab_v2_interface = { + "zwp_input_method_keyboard_grab_v2", 1, + 1, zwp_input_method_keyboard_grab_v2_requests, + 4, zwp_input_method_keyboard_grab_v2_events, +}; + +static const struct wl_message zwp_input_method_manager_v2_requests[] = { + { "get_input_method", "on", input_method_unstable_v2_types + 8 }, + { "destroy", "", input_method_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_input_method_manager_v2_interface = { + "zwp_input_method_manager_v2", 1, + 2, zwp_input_method_manager_v2_requests, + 0, NULL, +}; + diff --git a/wayland/protocols/input-method-unstable-v2.xml b/wayland/protocols/input-method-unstable-v2.xml new file mode 100644 index 0000000..4a1c715 --- /dev/null +++ b/wayland/protocols/input-method-unstable-v2.xml @@ -0,0 +1,493 @@ + + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + Copyright © 2012, 2013 Intel Corporation + Copyright © 2015, 2016 Jan Arne Petersen + Copyright © 2017, 2018 Red Hat, Inc. + Copyright © 2018 Purism SPC + + 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. + + + + This protocol allows applications to act as input methods for compositors. + + An input method context is used to manage the state of the input method. + + Text strings are UTF-8 encoded, their indices and lengths are in bytes. + + 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. + + This protocol is copied from the Squeekboard and should be brought + up-to-date with it whenever upstream changes. + + + + + An input method object allows for clients to compose text. + + The objects connects the client to a text input in an application, and + lets the client to serve as an input method for a seat. + + The zwp_input_method_v2 object can occupy two distinct states: active and + inactive. In the active state, the object is associated to and + communicates with a text input. In the inactive state, there is no + associated text input, and the only communication is with the compositor. + Initially, the input method is in the inactive state. + + Requests issued in the inactive state must be accepted by the compositor. + Because of the serial mechanism, and the state reset on activate event, + they will not have any effect on the state of the next text input. + + There must be no more than one input method object per seat. + + + + + Notification that a text input focused on this seat requested the input + method to be activated. + + This event serves the purpose of providing the compositor with an + active input method. + + This event resets all state associated with previous enable, disable, + surrounding_text, text_change_cause, and content_type events, as well + as the state associated with set_preedit_string, commit_string, and + delete_surrounding_text requests. In addition, it marks the + zwp_input_method_v2 object as active, and makes any existing + zwp_input_popup_surface_v2 objects visible. + + The surrounding_text, and content_type events must follow before the + next done event if the text input supports the respective + functionality. + + State set with this event is double-buffered. It will get applied on + the next zwp_input_method_v2.done event, and stay valid until changed. + + + + + + Notification that no focused text input currently needs an active + input method on this seat. + + This event marks the zwp_input_method_v2 object as inactive. The + compositor must make all existing zwp_input_popup_surface_v2 objects + invisible until the next activate event. + + State set with this event is double-buffered. It will get applied on + the next zwp_input_method_v2.done event, and stay valid until changed. + + + + + + Updates the surrounding plain text around the cursor, excluding the + preedit text. + + If any preedit text is present, it is replaced with the cursor for the + purpose of this event. + + The argument text is a buffer containing the preedit string, and must + include the cursor position, and the complete selection. It should + contain additional characters before and after these. 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 the text buffer. + + anchor is the byte offset of the selection anchor within the text + buffer. If there is no selected text, anchor must be the same as + cursor. + + If this event does not arrive before the first done event, the input + method may assume that the text input does not support this + functionality and ignore following surrounding_text events. + + Values set with this event are double-buffered. They will get applied + and set to initial values on the next zwp_input_method_v2.done + event. + + 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. + + + + + + + + + Tells the input method why the text surrounding the cursor changed. + + Whenever the client detects an external change in text, cursor, or + anchor position, 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 event is double-buffered. It will get applied + and set to its initial value on the next zwp_input_method_v2.done + event. + + The initial value of cause is input_method. + + + + + + + Indicates the content type and hint for the current + zwp_input_method_v2 instance. + + Values set with this event are double-buffered. They will get applied + on the next zwp_input_method_v2.done event. + + The initial value for hint is none, and the initial value for purpose + is normal. + + + + + + + + Atomically applies state changes recently sent to the client. + + The done event establishes and updates the state of the client, and + must be issued after any changes to apply them. + + Text input state (content purpose, content hint, surrounding text, and + change cause) is conceptually double-buffered within an input method + context. + + Events modify the pending state, as opposed to the current state in use + by the input method. A done event atomically applies all pending state, + replacing the current state. After done, the new pending state is as + documented for each related request. + + Events must be applied in the order of arrival. + + Neither current nor pending state are modified unless noted otherwise. + + + + + + Send the commit string text for insertion to the application. + + Inserts a string at current cursor position (see commit event + sequence). The string to commit could be either just a single character + after a key press or the result of some composing. + + The argument text is a buffer containing the string to insert. There is + a maximum length of wayland messages, so text can not be longer than + 4000 bytes. + + Values set with this event are double-buffered. They must be applied + and reset to initial on the next zwp_text_input_v3.commit request. + + The initial value of text is an empty string. + + + + + + + Send the pre-edit string text to the application text input. + + Place a new composing text (pre-edit) at the current cursor position. + Any previously set composing text must be removed. Any previously + existing selected text must be removed. The cursor is moved to a new + position within the preedit string. + + The argument text is a buffer containing the preedit string. There is + a maximum length of wayland messages, so text can not be longer than + 4000 bytes. + + The arguments cursor_begin and cursor_end are counted in bytes relative + to the beginning of the submitted string buffer. Cursor should be + hidden by the text input when both are equal to -1. + + cursor_begin indicates the beginning of the cursor. cursor_end + indicates the end of the cursor. It may be equal or different than + cursor_begin. + + Values set with this event are double-buffered. They must be applied on + the next zwp_input_method_v2.commit event. + + The initial value of text is an empty string. The initial value of + cursor_begin, and cursor_end are both 0. + + + + + + + + + Remove the surrounding text. + + before_length and after_length are the number of bytes before and after + the current cursor index (excluding the preedit text) to delete. + + If any preedit text is present, it is replaced with the cursor for the + purpose of this event. In effect before_length is counted from the + beginning of preedit text, and after_length from its end (see commit + event sequence). + + Values set with this event are double-buffered. They must be applied + and reset to initial on the next zwp_input_method_v2.commit request. + + The initial values of both before_length and after_length are 0. + + + + + + + + Apply state changes from commit_string, set_preedit_string and + delete_surrounding_text requests. + + The state relating to these events is double-buffered, and each one + modifies the pending state. This request replaces the current state + with the pending state. + + The connected text input is expected to 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. + + The serial number reflects the last state of the zwp_input_method_v2 + object known to the client. The value of the serial argument must be + equal to the number of done events already issued by that object. When + the compositor receives a commit request with a serial different than + the number of past done events, it must proceed as normal, except it + should not change the current state of the zwp_input_method_v2 object. + + + + + + + Creates a new zwp_input_popup_surface_v2 object wrapping a given + surface. + + The surface gets assigned the "input_popup" role. If the surface + already has an assigned role, the compositor must issue a protocol + error. + + + + + + + + Allow an input method to receive hardware keyboard input and process + key events to generate text events (with pre-edit) over the wire. This + allows input methods which compose multiple key events for inputting + text like it is done for CJK languages. + + The compositor should send all keyboard events on the seat to the grab + holder via the returned wl_keyboard object. Nevertheless, the + compositor may decide not to forward any particular event. The + compositor must not further process any event after it has been + forwarded to the grab holder. + + Releasing the resulting wl_keyboard object releases the grab. + + + + + + + The input method ceased to be available. + + The compositor must issue this event as the only event on the object if + there was another input_method object associated with the same seat at + the time of its creation. + + The compositor must issue this request when the object is no longer + useable, e.g. due to seat removal. + + The input method context becomes inert and should be destroyed after + deactivation is handled. Any further requests and events except for the + destroy request must be ignored. + + + + + + Destroys the zwp_text_input_v2 object and any associated child + objects, i.e. zwp_input_popup_surface_v2 and + zwp_input_method_keyboard_grab_v2. + + + + + + + This interface marks a surface as a popup for interacting with an input + method. + + The compositor should place it near the active text input area. It must + be visible if and only if the input method is in the active state. + + The client must not destroy the underlying wl_surface while the + zwp_input_popup_surface_v2 object exists. + + + + + Notify about the position of the area of the text input expressed as a + rectangle in surface local coordinates. + + This is a hint to the input method telling it the relative position of + the text being entered. + + + + + + + + + + + + + + The zwp_input_method_keyboard_grab_v2 interface represents an exclusive + grab of the wl_keyboard interface associated with the seat. + + + + + This event provides a file descriptor to the client which can be + memory-mapped to provide a keyboard mapping description. + + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond granularity, with an + undefined base. + + + + + + + + + + Notifies clients that the modifier and/or group state has changed, and + it should update its local state. + + + + + + + + + + + + + + + Informs the client about the keyboard's repeat rate and delay. + + This event is sent as soon as the zwp_input_method_keyboard_grab_v2 + object has been created, and is guaranteed to be received by the + client before any key press event. + + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). + + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of zwp_input_method_keyboard_grab_v2. + + + + + + + + + The input method manager allows the client to become the input method on + a chosen seat. + + No more than one input method must be associated with any seat at any + given time. + + + + + Request a new input zwp_input_method_v2 object associated with a given + seat. + + + + + + + + Destroys the zwp_input_method_manager_v2 object. + + The zwp_input_method_v2 objects originating from it remain valid. + + + + diff --git a/wayland/protocols/viewporter.c b/wayland/protocols/viewporter.c new file mode 100644 index 0000000..fa70d5d --- /dev/null +++ b/wayland/protocols/viewporter.c @@ -0,0 +1,74 @@ +/* Generated by wayland-scanner 1.22.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 "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/wayland/protocols/virtual-keyboard-unstable-v1.c b/wayland/protocols/virtual-keyboard-unstable-v1.c new file mode 100644 index 0000000..60b847e --- /dev/null +++ b/wayland/protocols/virtual-keyboard-unstable-v1.c @@ -0,0 +1,77 @@ +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2012-2013 Collabora, Ltd. + * Copyright © 2018 Purism SPC + * + * 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 "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_virtual_keyboard_v1_interface; + +static const struct wl_interface *virtual_keyboard_unstable_v1_types[] = { + NULL, + NULL, + NULL, + NULL, + &wl_seat_interface, + &zwp_virtual_keyboard_v1_interface, +}; + +static const struct wl_message zwp_virtual_keyboard_v1_requests[] = { + { "keymap", "uhu", virtual_keyboard_unstable_v1_types + 0 }, + { "key", "uuu", virtual_keyboard_unstable_v1_types + 0 }, + { "modifiers", "uuuu", virtual_keyboard_unstable_v1_types + 0 }, + { "destroy", "", virtual_keyboard_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_virtual_keyboard_v1_interface = { + "zwp_virtual_keyboard_v1", 1, + 4, zwp_virtual_keyboard_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwp_virtual_keyboard_manager_v1_requests[] = { + { "create_virtual_keyboard", "on", virtual_keyboard_unstable_v1_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface zwp_virtual_keyboard_manager_v1_interface = { + "zwp_virtual_keyboard_manager_v1", 1, + 1, zwp_virtual_keyboard_manager_v1_requests, + 0, NULL, +}; + diff --git a/wayland/protocols/virtual-keyboard-unstable-v1.xml b/wayland/protocols/virtual-keyboard-unstable-v1.xml new file mode 100644 index 0000000..458900e --- /dev/null +++ b/wayland/protocols/virtual-keyboard-unstable-v1.xml @@ -0,0 +1,118 @@ + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2013 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + Copyright © 2018 Purism SPC + + 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. + + + + This protocol is copied from the Squeekboard and should be brought + up-to-date with it whenever upstream changes. + + + + + The virtual keyboard provides an application with requests which emulate + the behaviour of a physical keyboard. + + This interface can be used by clients on its own to provide raw input + events, or it can accompany the input method protocol. + + + + + Provide a file descriptor to the compositor which can be + memory-mapped to provide a keyboard mapping description. + + Format carries a value from the keymap_format enumeration. + + + + + + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond granularity, with an + undefined base. All requests regarding a single object must share the + same clock. + + Keymap must be set before issuing this request. + + State carries a value from the key_state enumeration. + + + + + + + + + Notifies the compositor that the modifier and/or group state has + changed, and it should update state. + + The client should use wl_keyboard.modifiers event to synchronize its + internal state with seat state. + + Keymap must be set before issuing this request. + + + + + + + + + + + + + + + A virtual keyboard manager allows an application to provide keyboard + input events as if they came from a physical keyboard. + + + + + + + + + Creates a new virtual keyboard associated to a seat. + + If the compositor enables a keyboard to perform arbitrary actions, it + should present an error when an untrusted client requests a new + keyboard. + + + + + + diff --git a/wayland/protocols/wlr-layer-shell-unstable-v1.c b/wayland/protocols/wlr-layer-shell-unstable-v1.c new file mode 100644 index 0000000..ecf00c5 --- /dev/null +++ b/wayland/protocols/wlr-layer-shell-unstable-v1.c @@ -0,0 +1,93 @@ +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2017 Drew DeVault + * + * 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 "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 xdg_popup_interface; +extern const struct wl_interface zwlr_layer_surface_v1_interface; + +static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = { + NULL, + NULL, + NULL, + NULL, + &zwlr_layer_surface_v1_interface, + &wl_surface_interface, + &wl_output_interface, + NULL, + NULL, + &xdg_popup_interface, +}; + +static const struct wl_message zwlr_layer_shell_v1_requests[] = { + { "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 }, + { "destroy", "3", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_layer_shell_v1_interface = { + "zwlr_layer_shell_v1", 4, + 2, zwlr_layer_shell_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwlr_layer_surface_v1_requests[] = { + { "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 }, + { "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "destroy", "", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_layer", "2u", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_layer_surface_v1_events[] = { + { "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 }, + { "closed", "", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_layer_surface_v1_interface = { + "zwlr_layer_surface_v1", 4, + 9, zwlr_layer_surface_v1_requests, + 2, zwlr_layer_surface_v1_events, +}; + diff --git a/wayland/protocols/wlr-layer-shell-unstable-v1.xml b/wayland/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..d62fd51 --- /dev/null +++ b/wayland/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,390 @@ + + + + Copyright © 2017 Drew DeVault + + 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. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer 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 layer_surface.configure call + must also be treated as errors. + + After creating a layer_surface object and setting it up, the client + must perform an initial commit without any buffer attached. + The compositor will reply with a layer_surface.configure event. + The client must acknowledge it and is then allowed to attach a buffer + to map the surface. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + + This request indicates that the client will not use the layer_shell + object any more. Objects that have been created through this instance + are not affected. + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + Attaching a null buffer to a layer surface unmaps it. + + Unmapping a layer_surface means that the surface cannot be shown by the + compositor until it is explicitly mapped again. The layer_surface + returns to the state it had right after layer_shell.get_layer_surface. + The client can re-map the surface by performing a commit without any + buffer attached, waiting for a configure event and handling it as usual. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Types of keyboard interaction possible for layer shell surfaces. The + rationale for this is twofold: (1) some applications are not interested + in keyboard events and not allowing them to be focused can improve the + desktop experience; (2) some applications will want to take exclusive + keyboard focus. + + + + + This value indicates that this surface is not interested in keyboard + events and the compositor should never assign it the keyboard focus. + + This is the default value, set for newly created layer shell surfaces. + + This is useful for e.g. desktop widgets that display information or + only have interaction with non-keyboard input devices. + + + + + Request exclusive keyboard focus if this surface is above the shell surface layer. + + For the top and overlay layers, the seat will always give + exclusive keyboard focus to the top-most layer which has keyboard + interactivity set to exclusive. If this layer contains multiple + surfaces with keyboard interactivity set to exclusive, the compositor + determines the one receiving keyboard events in an implementation- + defined manner. In this case, no guarantee is made when this surface + will receive keyboard focus (if ever). + + For the bottom and background layers, the compositor is allowed to use + normal focus semantics. + + This setting is mainly intended for applications that need to ensure + they receive all keyboard events, such as a lock screen or a password + prompt. + + + + + This requests the compositor to allow this surface to be focused and + unfocused by the user in an implementation-defined manner. The user + should be able to unfocus this surface even regardless of the layer + it is on. + + Typically, the compositor will want to use its normal mechanism to + manage keyboard focus between layer shell surfaces with this setting + and regular toplevels on the desktop layer (e.g. click to focus). + Nevertheless, it is possible for a compositor to require a special + interaction to focus or unfocus layer shell surfaces (e.g. requiring + a click even if focus follows the mouse normally, or providing a + keybinding to switch focus between layers). + + This setting is mainly intended for desktop shell components (e.g. + panels) that allow keyboard interaction. Using this option can allow + implementing a desktop shell that can be fully usable without the + mouse. + + + + + + + Set how keyboard events are delivered to this surface. By default, + layer shell surfaces do not receive keyboard events; this request can + be used to change this. + + This setting is inherited by child surfaces set by the get_popup + request. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Keyboard interactivity is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + 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. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + 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. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + 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. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/wayland/protocols/xdg-shell.c b/wayland/protocols/xdg-shell.c new file mode 100644 index 0000000..03826cd --- /dev/null +++ b/wayland/protocols/xdg-shell.c @@ -0,0 +1,183 @@ +/* Generated by wayland-scanner 1.22.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 "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", 6, + 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", 6, + 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", 6, + 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", 6, + 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", 6, + 3, xdg_popup_requests, + 3, xdg_popup_events, +}; + diff --git a/wayland/surface.c b/wayland/surface.c new file mode 100644 index 0000000..d705303 --- /dev/null +++ b/wayland/surface.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Wayland buffer manager and surface. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include + +#include "graphics.h" +#include "ufkbd.h" +#include "layout.h" +#include "wayland.h" +#include "wayland/viewporter.h" +#include "wayland/wlr-layer-shell-unstable-v1.h" + +extern struct ufkbd_driver ufkbd_wayland; + +static int ufkbd_wl_surface_resize_buffers(struct ufkbd_wl_surface *ctx, + uint32_t width, uint32_t height); + +static void on_surface_configure(void *data, + struct zwlr_layer_surface_v1 *surface, + uint32_t serial, + uint32_t width, + uint32_t height) +{ + struct ufkbd_wl_surface *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + zwlr_layer_surface_v1_ack_configure(surface, serial); + + wp_viewport_set_source(ctx->vp, 0, 0, width * 256 * ctx->scale, + height * 256 * ctx->scale); + wp_viewport_set_destination(ctx->vp, width, height); + + ufkbd_wl_surface_resize_buffers(ctx, width, height); + + ufkbd_layout_resize(ufkbd->layout, width, height); + ufkbd_graphics_draw_layout(ufkbd, ufkbd_wl->ufkbd->layout, + width, height); +} + +static void on_surface_closed(void *data, + struct zwlr_layer_surface_v1 *toplev) +{ + struct ufkbd_wl_surface *ctx = data; + struct ufkbd_input_wayland *ufkbd_wl = ctx->ufkbd_wl; + struct ufkbd_ctx *ufkbd = ufkbd_wl->ufkbd; + + ufkbd_terminate(ufkbd); +} + +static const struct zwlr_layer_surface_v1_listener surface_listener = { + .configure = on_surface_configure, + .closed = on_surface_closed, +}; + +static int try_create_layer_surface(struct ufkbd_wl_surface *ctx) +{ + if (ctx->wl == NULL) + return -EINVAL; + + if (ctx->shell == NULL) + return -EINVAL; + + if (ctx->vper == NULL) + return -EINVAL; + + ctx->vp = wp_viewporter_get_viewport(ctx->vper, ctx->wl); + if (ctx->vp == NULL) + return -ENOMEM; + + ctx->wlr = zwlr_layer_shell_v1_get_layer_surface(ctx->shell, ctx->wl, NULL, ZWLR_LAYER_SHELL_V1_LAYER_TOP, "ufkbd-osk"); + if (ctx->wlr == NULL) + return -ENOMEM; + + zwlr_layer_surface_v1_set_anchor(ctx->wlr, + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); + zwlr_layer_surface_v1_set_size(ctx->wlr, 0, 185); + zwlr_layer_surface_v1_set_exclusive_zone(ctx->wlr, 185); + + zwlr_layer_surface_v1_add_listener(ctx->wlr, &surface_listener, ctx); + + // Commit the role given to the surface + wl_surface_commit(ctx->wl); + + return 0; +} + +static void on_global_compositor(void *data, + struct wl_registry *reg, + uint32_t name, + uint32_t version) +{ + struct ufkbd_wl_surface *ctx = data; + + if (version < WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION) + return; + + ctx->compositor = wl_registry_bind(reg, + name, + &wl_compositor_interface, + version); + if (ctx->compositor == NULL) { + fprintf(stderr, "warn: could not bind to compositor\n"); + return; + } + + ctx->wl = wl_compositor_create_surface(ctx->compositor); + if (ctx->wl == NULL) { + fprintf(stderr, "warn: no valid surface\n"); + return; + } + + try_create_layer_surface(ctx); +} + +static void on_global_shell(void *data, + struct wl_registry *reg, + uint32_t name, + uint32_t version) +{ + struct ufkbd_wl_surface *ctx = data; + + ctx->shell = wl_registry_bind(reg, + name, + &zwlr_layer_shell_v1_interface, + version); + if (ctx->shell == NULL) { + fprintf(stderr, "wl: warn: could not bind to window manager\n"); + return; + } + + try_create_layer_surface(ctx); +} + +static void on_global_viewporter(void *data, + struct wl_registry *reg, + uint32_t name, + uint32_t version) +{ + struct ufkbd_wl_surface *ctx = data; + + ctx->vper = wl_registry_bind(reg, + name, + &wp_viewporter_interface, + version); + if (ctx->vper == NULL) { + fprintf(stderr, "wl: warn: could not bind to viewporter\n"); + return; + } + + try_create_layer_surface(ctx); +} + +int ufkbd_wl_surface_consume_buffer(struct ufkbd_wl_surface *ctx, + struct wl_buffer **buf, void **ptr) +{ + int ret; + + if (buf == NULL || ptr == NULL) + return -EINVAL; + + ret = ufkbd_wl_buffer_consume(&ctx->bufs[0], buf, ptr); + if (ret != -EBUSY) + return ret; + + ret = ufkbd_wl_buffer_consume(&ctx->bufs[1], buf, ptr); + + return ret; +} + +static int ufkbd_wl_surface_resize_buffers(struct ufkbd_wl_surface *ctx, + uint32_t width, uint32_t height) +{ + int ret; + + ctx->stride = (size_t) width * 4; + + ret = ufkbd_wl_buffer_resize(&ctx->bufs[0], + width * ctx->scale, + height * ctx->scale); + if (ret) + return ret; + + return ufkbd_wl_buffer_resize(&ctx->bufs[1], + width * ctx->scale, + height * ctx->scale); +} + +int ufkbd_wl_surface_init(struct ufkbd_input_wayland *ufkbd_wl, + struct ufkbd_wl_surface **out) +{ + struct ufkbd_wl_surface *ctx; + int ret; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return -errno; + + ctx->ufkbd_wl = ufkbd_wl; + ctx->scale = 1; + + ret = ufkbd_wl_buffer_init(&ctx->bufs[0], ufkbd_wl, 0); + if (ret) + goto err_free_ctx; + + ret = ufkbd_wl_buffer_init(&ctx->bufs[1], ufkbd_wl, 1); + if (ret) + goto err_uninit_buf0; + + ctx->listener_comp.iface = &wl_compositor_interface; + ctx->listener_comp.cb = on_global_compositor; + ctx->listener_comp.data = ctx; + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener_comp); + if (ret) + goto err_uninit_buf1; + + ctx->listener_shell.iface = &zwlr_layer_shell_v1_interface; + ctx->listener_shell.cb = on_global_shell; + ctx->listener_shell.data = ctx; + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener_shell); + if (ret) + goto err_uninit_buf1; + + ctx->listener_viewporter.iface = &wp_viewporter_interface; + ctx->listener_viewporter.cb = on_global_viewporter; + ctx->listener_viewporter.data = ctx; + + ret = ufkbd_wl_global_listener_add(ufkbd_wl, &ctx->listener_viewporter); + if (ret) + goto err_uninit_buf1; + + ufkbd_graphics_set_scale(ctx->ufkbd_wl->ufkbd->graphics, ctx->scale); + + *out = ctx; + + return 0; + +err_uninit_buf1: + ufkbd_wl_buffer_uninit(&ctx->bufs[1]); +err_uninit_buf0: + ufkbd_wl_buffer_uninit(&ctx->bufs[0]); +err_free_ctx: + free(ctx); + return ret; +} + +void ufkbd_wl_surface_uninit(struct ufkbd_wl_surface *ctx) +{ + if (ctx->vper != NULL) + wp_viewporter_destroy(ctx->vper); + + if (ctx->vp != NULL) + wp_viewport_destroy(ctx->vp); + + if (ctx->wlr != NULL) + zwlr_layer_surface_v1_destroy(ctx->wlr); + + if (ctx->wl != NULL) + wl_surface_destroy(ctx->wl); + + if (ctx->shell != NULL) + zwlr_layer_shell_v1_destroy(ctx->shell); + + if (ctx->compositor != NULL) + wl_compositor_destroy(ctx->compositor); + + ufkbd_wl_buffer_uninit(&ctx->bufs[1]); + ufkbd_wl_buffer_uninit(&ctx->bufs[0]); + + free(ctx); +} diff --git a/wayland/wayland.h b/wayland/wayland.h new file mode 100644 index 0000000..c8250c7 --- /dev/null +++ b/wayland/wayland.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * Wayland objects. + * + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +#ifndef UFKBD_WAYLAND_H +#define UFKBD_WAYLAND_H + +#include +#include +#include +#include + +#include "ufkbd.h" + +#define MAX_GLOBAL_LISTENERS 16 + +#define SHM_PATH_SIZE 256 + +struct ufkbd_ctx; + +struct wl_display; +struct wl_registry; +struct wl_seat; +struct wl_pointer; +struct wl_compositor; +struct xdg_wm_base; + +struct wl_surface; +struct wp_viewport; +struct wp_viewporter; +struct xdg_surface; +struct xdg_toplevel; + +struct zwp_virtual_keyboard_manager_v1; +struct zwp_virtual_keyboard_v1; + +struct zwp_input_method_manager_v2; +struct zwp_input_method_v2; + +struct ufkbd_input_wayland; + +struct ufkbd_wl_global_listener { + const struct wl_interface *iface; + void (*cb)(void *data, struct wl_registry *reg, uint32_t name, uint32_t version); + void *data; +}; + +struct ufkbd_wl_input { + struct ufkbd_input_wayland *ufkbd_wl; + + struct ufkbd_wl_global_listener listener_seat; + struct ufkbd_wl_global_listener listener_manager; + struct ufkbd_wl_global_listener listener_methodman; + + struct wl_seat *seat; + struct wl_pointer *pointer; + struct wl_touch *touch; + + struct zwp_virtual_keyboard_manager_v1 *manager; + struct zwp_virtual_keyboard_v1 *kb; + + uint32_t mod_state; +}; + +struct ufkbd_wl_buffer { + struct ufkbd_ctx *ufkbd; + unsigned int id; + + struct ufkbd_wl_global_listener listener; + struct wl_shm *wl; + + struct wl_shm_pool *pool; + struct wl_buffer *buf; + + bool avail, dirty, resize; + + void *ptr; + int fd; + + uint32_t width, height; + size_t size; + + char path[SHM_PATH_SIZE]; +}; + +struct ufkbd_wl_surface { + struct ufkbd_input_wayland *ufkbd_wl; + + struct ufkbd_wl_global_listener listener_comp; + struct ufkbd_wl_global_listener listener_shell; + struct ufkbd_wl_global_listener listener_viewporter; + + struct wl_compositor *compositor; + struct zwlr_layer_shell_v1 *shell; + + struct wl_surface *wl; + struct zwlr_layer_surface_v1 *wlr; + + struct wp_viewporter *vper; + struct wp_viewport *vp; + + unsigned int scale; + size_t stride; + + struct ufkbd_wl_buffer bufs[2]; +}; + +struct ufkbd_input_wayland { + struct ufkbd_ctx *ufkbd; + + struct ufkbd_wl_surface *surface; + struct ufkbd_wl_input *input; + + struct wl_display *display; + struct wl_registry *registry; + int fd; + + size_t n_global_listeners; + struct ufkbd_wl_global_listener *global_listeners[MAX_GLOBAL_LISTENERS]; +}; + +int ufkbd_wl_buffer_consume(struct ufkbd_wl_buffer *ctx, + struct wl_buffer **buf, void **ptr); +int ufkbd_wl_buffer_resize(struct ufkbd_wl_buffer *ctx, + uint32_t width, uint32_t height); +int ufkbd_wl_buffer_init(struct ufkbd_wl_buffer *ctx, + struct ufkbd_input_wayland *ufkbd_wl, + unsigned int id); +void ufkbd_wl_buffer_uninit(struct ufkbd_wl_buffer *ctx); + +int ufkbd_wl_surface_consume_buffer(struct ufkbd_wl_surface *ctx, + struct wl_buffer **buf, void **ptr); +int ufkbd_wl_surface_init(struct ufkbd_input_wayland *ufkbd_wl, + struct ufkbd_wl_surface **out); +void ufkbd_wl_surface_uninit(struct ufkbd_wl_surface *ctx); + +int ufkbd_wl_input_init(struct ufkbd_input_wayland *ufkbd_wl, + struct ufkbd_wl_input **out); +void ufkbd_wl_input_uninit(struct ufkbd_wl_input *ctx); +int ufkbd_wl_input_send_key(struct ufkbd_wl_input *ctx, int key, bool repeat); +int ufkbd_wl_input_send_mod(struct ufkbd_wl_input *ctx, enum ufkbd_modifier mod, bool pressed); + +int ufkbd_wl_global_listener_add(struct ufkbd_input_wayland *ctx, + struct ufkbd_wl_global_listener *listener); + +#endif /* UFKBD_WAYLAND_H */