diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5c2689e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rusted-fetter" +version = "0.1.0" + +[dependencies] +fontconfig = "0.9.0" +# Disable freetype-sys, as it vendors libfreetype2 while fontconfig dynamically +# links to it. Large dependencies should not be duplicated. +freetype = { version = "0.7.2", default-features = false } +imgref = "1.10.1" +libc = "0.2.155" +memmap2 = "0.9.4" +polling = "3.7.2" +rgb = "0.8.44" +wayland-backend = "0.3.5" +wayland-client = "0.31.4" +wayland-protocols = { version = "0.32.2", features = ["client", "staging", "unstable"] } +wayland-protocols-wlr = { version = "0.3.2", features = ["client"] } +wayland-scanner = "0.31.3" +xkeysym = "0.2.0" + +[build-dependencies] +bindgen = "0.69.4" diff --git a/README.md b/README.md deleted file mode 100644 index 3bb32e7..0000000 --- a/README.md +++ /dev/null @@ -1,41 +0,0 @@ -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/build.rs b/build.rs new file mode 100644 index 0000000..4536575 --- /dev/null +++ b/build.rs @@ -0,0 +1,20 @@ +use std::env; +use std::path::PathBuf; + +fn main() +{ + let builder = bindgen::builder(); + + let bindings = builder.header("/usr/include/expat.h") + .generate() + .expect("The libexpat headers must be installed"); + + let out_dir: PathBuf = env::var("OUT_DIR") + .expect("Environment variable $OUT_DIR must be defined") + .into(); + let out_file = out_dir.join("expat.rs"); + + println!("cargo::rustc-link-lib=expat"); + + bindings.write_to_file(out_file).expect("Writing failure"); +} diff --git a/graphics.c b/graphics.c deleted file mode 100644 index a285541..0000000 --- a/graphics.c +++ /dev/null @@ -1,452 +0,0 @@ -// 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 deleted file mode 100644 index 60523d7..0000000 --- a/include/graphics.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 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 deleted file mode 100644 index adfb438..0000000 --- a/include/input.h +++ /dev/null @@ -1,23 +0,0 @@ -/* 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 deleted file mode 100644 index 8dac1fa..0000000 --- a/include/keymap.h +++ /dev/null @@ -1,28 +0,0 @@ -/* 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 deleted file mode 100644 index 4b765ad..0000000 --- a/include/layout.h +++ /dev/null @@ -1,49 +0,0 @@ -/* 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 deleted file mode 100644 index 89f060b..0000000 --- a/include/modifier.h +++ /dev/null @@ -1,27 +0,0 @@ -/* 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 deleted file mode 100644 index 0e6584b..0000000 --- a/include/parser.h +++ /dev/null @@ -1,18 +0,0 @@ -/* 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 deleted file mode 100644 index e5f9845..0000000 --- a/include/ufkbd.h +++ /dev/null @@ -1,113 +0,0 @@ -/* 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 deleted file mode 100644 index 7f0dec4..0000000 --- a/include/wayland/fractional-scale-v1.h +++ /dev/null @@ -1,264 +0,0 @@ -/* 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 deleted file mode 100644 index f9a1489..0000000 --- a/include/wayland/input-method-unstable-v2.h +++ /dev/null @@ -1,945 +0,0 @@ -/* 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 deleted file mode 100644 index e1295d4..0000000 --- a/include/wayland/viewporter.h +++ /dev/null @@ -1,398 +0,0 @@ -/* 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 deleted file mode 100644 index 29c2807..0000000 --- a/include/wayland/virtual-keyboard-unstable-v1.h +++ /dev/null @@ -1,280 +0,0 @@ -/* 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 deleted file mode 100644 index 880e59e..0000000 --- a/include/wayland/wlr-layer-shell-unstable-v1.h +++ /dev/null @@ -1,706 +0,0 @@ -/* 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 deleted file mode 100644 index 8b24f09..0000000 --- a/include/wayland/xdg-shell.h +++ /dev/null @@ -1,2315 +0,0 @@ -/* 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 deleted file mode 100644 index c22dd03..0000000 --- a/input.c +++ /dev/null @@ -1,228 +0,0 @@ -// 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 deleted file mode 100644 index b26cc3c..0000000 --- a/keymap.c +++ /dev/null @@ -1,170 +0,0 @@ -// 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 deleted file mode 100644 index 1c702eb..0000000 --- a/layout.c +++ /dev/null @@ -1,184 +0,0 @@ -// 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 deleted file mode 100644 index b4b4ec7..0000000 --- a/main.c +++ /dev/null @@ -1,121 +0,0 @@ -// 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 deleted file mode 100644 index 8cc5179..0000000 --- a/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -# 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 deleted file mode 100644 index be78867..0000000 --- a/modifier.c +++ /dev/null @@ -1,159 +0,0 @@ -// 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 deleted file mode 100644 index 9f6ed02..0000000 --- a/parser.c +++ /dev/null @@ -1,460 +0,0 @@ -// 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/src/core/button.rs b/src/core/button.rs new file mode 100644 index 0000000..fdeb661 --- /dev/null +++ b/src/core/button.rs @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::Display; +use core::Graphics; +use core::Layout; +use core::layout::Key; +use core::layout::MODIFIERS_MAX; +use core::xkeysym::Keysym; +use std::collections::VecDeque; +use std::convert::TryInto; +use std::iter; +use std::ops::Add; +use std::sync::Arc; +use std::sync::Mutex; +use std::time::Duration; +use std::time::Instant; + +/* + * The available states for the modifier keys. + * + * The state goes Released -> Pressed when the modifier key is pressed. + * + * When pressed, the modifier can be released, going Pressed -> Latched so that + * the modifier will apply to the next key press. + * It could be held down for long enough that it goes Pressed -> Locked, and the + * modifier would apply to any other key press until it is released, pressed and + * released again. + * Finally, it could be held down while another key is being pressed, going + * Pressed -> Held (or Locked -> HeldLocked) to apply until it is released. + * + * When latched, it could go Latched -> Released when any key + * (including itself) is released. + * + * When held, it goes Held -> Released (or HeldLocked -> Released) when the + * modifier key is released. + * + * When locked, the modifier key goes Locked -> HeldLocked when it is pressed + * again. + */ +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ModState { + Released, + Pressed, + Latched, + Held, + Locked, + HeldLocked, +} + +#[derive(PartialEq)] +enum DrawOperation { + Key, + Modifiers([bool; MODIFIERS_MAX]), + Labels, +} + +impl DrawOperation { + fn from_modifier(modifier: usize) -> DrawOperation + { + let mut modifiers = [false; MODIFIERS_MAX]; + modifiers[modifier - 1] = true; + DrawOperation::Modifiers(modifiers) + } + + fn from_modifier_edge(modifier: usize) -> DrawOperation + { + if Layout::is_label_modifier(modifier) { + DrawOperation::Labels + } else { + DrawOperation::from_modifier(modifier) + } + } +} + +impl Add for DrawOperation { + type Output = Self; + + fn add(self, other: Self) -> Self + { + match (&self, &other) { + (&DrawOperation::Labels, _) => self, + (_, &DrawOperation::Labels) => other, + (&DrawOperation::Key, &DrawOperation::Modifiers(_)) => other, + (&DrawOperation::Modifiers(_), &DrawOperation::Key) => self, + (&DrawOperation::Modifiers(a), &DrawOperation::Modifiers(b)) => { + let mods = iter::zip(&a, &b).map(|(a, b)| *a || *b); + DrawOperation::Modifiers(mods.collect::>().try_into().unwrap()) + }, + (&DrawOperation::Key, &DrawOperation::Key) => self, + } + } +} + +struct Press { + x1: f64, + y1: f64, + part: usize, + timer: Instant, +} + +const PRESSES_MAX: usize = 64; + +pub trait Keyboard { + fn press(&mut self, sym: Keysym); + fn release(&mut self, sym: Keysym); + fn change_layout(&mut self, layout: &Layout); +} + +pub struct Button { + layout: Layout, + kbd: K, + gfx: Arc>>, + + presses: [Option; PRESSES_MAX], + timers: VecDeque, + modifiers: [ModState; MODIFIERS_MAX], + + longpress: Duration, + repeat: Duration, + r_square: f64, +} + +const PART_TL: usize = 1; +const PART_TR: usize = 2; +const PART_BL: usize = 3; +const PART_BR: usize = 4; +const PART_LEFT: usize = 5; +const PART_RIGHT: usize = 6; +const PART_TOP: usize = 7; +const PART_BOTTOM: usize = 8; + +const ANGLE_PARTS: [[usize; 4]; 16] = [ + [PART_LEFT, PART_TL, PART_BL, PART_TOP], + [PART_TL, PART_LEFT, PART_TOP, PART_BL], + [PART_TL, PART_TOP, PART_LEFT, PART_TR], + [PART_TOP, PART_TL, PART_TR, PART_LEFT], + [PART_TOP, PART_TR, PART_TL, PART_RIGHT], + [PART_TR, PART_TOP, PART_RIGHT, PART_TL], + [PART_TR, PART_RIGHT, PART_TOP, PART_BR], + [PART_RIGHT, PART_TR, PART_BR, PART_TOP], + [PART_RIGHT, PART_BR, PART_TR, PART_BOTTOM], + [PART_BR, PART_RIGHT, PART_BOTTOM, PART_TR], + [PART_BR, PART_BOTTOM, PART_RIGHT, PART_BL], + [PART_BOTTOM, PART_BR, PART_BL, PART_RIGHT], + [PART_BOTTOM, PART_BL, PART_BR, PART_LEFT], + [PART_BL, PART_BOTTOM, PART_LEFT, PART_BR], + [PART_BL, PART_LEFT, PART_BOTTOM, PART_TL], + [PART_LEFT, PART_BL, PART_TL, PART_BOTTOM], +]; + +// The None option cannot be copied, but it works if it is a constant. Rust is insane. +const NO_PRESS: Option = None; + +impl Button { + pub fn new(layout: Layout, mut kbd: K, + gfx: Arc>>) -> Button + { + kbd.change_layout(&layout); + + Button { + layout, + kbd, + gfx, + + presses: [NO_PRESS; PRESSES_MAX], + modifiers: [ModState::Released; MODIFIERS_MAX], + timers: VecDeque::with_capacity(PRESSES_MAX), + + longpress: Duration::from_millis(600), + repeat: Duration::from_millis(25), + r_square: 0.25, + } + } + + #[inline(always)] + pub fn layout(&self) -> &Layout + { + &self.layout + } + + pub fn mod_state(&self) -> &[ModState; MODIFIERS_MAX] + { + &self.modifiers + } + + pub fn next_time(&self) -> Option + { + let id = *self.timers.front()?; + if id == PRESSES_MAX { + return None; + } + + // The next timer must always be held by an active key press. + Some(self.presses[id].as_ref().unwrap().timer) + } + + fn update_modifier(&mut self, modifier: usize, old: ModState, new: ModState) -> bool + { + if self.modifiers[modifier - 1] == old { + self.modifiers[modifier - 1] = new; + + if new == ModState::Released { + self.kbd.release(Layout::modifier_keysym(modifier)); + } + + if old == ModState::Released || new == ModState::Released { + self.layout.update_modifiers(&self.modifiers); + if Layout::is_keysym_modifier(modifier) { + self.kbd.change_layout(&self.layout); + } + } + + if old == ModState::Released { + self.kbd.press(Layout::modifier_keysym(modifier)); + } + + true + } else { + false + } + } + + fn try_press_mod(&mut self, modifier: usize) -> DrawOperation + { + let mut draw = DrawOperation::Key; + + if modifier != 0 { + let changed = self.update_modifier(modifier, + ModState::Released, + ModState::Pressed); + if changed { + draw = draw + DrawOperation::from_modifier_edge(modifier); + } + + self.update_modifier(modifier, + ModState::Latched, + ModState::Held); + self.update_modifier(modifier, + ModState::Locked, + ModState::HeldLocked); + } else { + for modifier in 1..=MODIFIERS_MAX { + self.update_modifier(modifier, + ModState::Pressed, + ModState::Held); + self.update_modifier(modifier, + ModState::Locked, + ModState::HeldLocked); + } + } + + draw + } + + fn draw(op: DrawOperation, + gfx: &Arc>>, + layout: &Layout, + key: Option<&Key>, + mod_state: &[ModState]) + { + let mut gfx = gfx.lock().unwrap(); + + match op { + DrawOperation::Key => { + if let Some(key) = key { + gfx.draw_single(key, mod_state); + } + }, + DrawOperation::Modifiers(m) => { + gfx.draw_modifiers(layout, mod_state, &m); + + if let Some(key) = key { + gfx.draw_single(key, mod_state); + } + }, + DrawOperation::Labels => { + gfx.change_layout(layout, mod_state); + } + } + } + + pub fn press(&mut self, id: usize, x: f64, y: f64) + { + if self.presses[id].is_some() { + eprintln!("warn: pressed same ID twice before releasing"); + return; + } + + let key = match self.layout.locate_key_mut(x, y) { + Some(k) => k, + // Ignore the press if it is not for a key. + None => return, + }; + + key.parts[0].press(); + + let modifier = key.parts[0].modifier_id(); + let draw = self.try_press_mod(modifier); + + let timer = Instant::now() + self.longpress; + self.presses[id] = Some(Press { + x1: x, + y1: y, + part: 0, + timer, + }); + self.timers.push_back(id); + + let key = self.layout.locate_key(x, y).unwrap(); + Self::draw(draw, &self.gfx, &self.layout, Some(key), &self.modifiers); + } + + fn update_pressed_part(press: &mut Press, key: &Key, angle: usize) + { + if key.parts[ANGLE_PARTS[angle][0]].sym() != Keysym::NoSymbol { + press.part = ANGLE_PARTS[angle][0]; + } else if key.parts[ANGLE_PARTS[angle][1]].sym() != Keysym::NoSymbol { + press.part = ANGLE_PARTS[angle][1]; + } else if key.parts[ANGLE_PARTS[angle][2]].sym() != Keysym::NoSymbol { + press.part = ANGLE_PARTS[angle][2]; + } else if key.parts[ANGLE_PARTS[angle][3]].sym() != Keysym::NoSymbol { + press.part = ANGLE_PARTS[angle][3]; + } + } + + fn remove_timer(&mut self, id: usize) + { + for evt in self.timers.iter_mut() { + if *evt == id { + *evt = PRESSES_MAX; + break; + } + } + + while self.timers.front() == Some(&PRESSES_MAX) { + self.timers.pop_front(); + } + } + + fn try_cancel_mod(&mut self, modifier: usize) -> DrawOperation + { + let mut draw = DrawOperation::Key; + + if modifier != 0 { + let changed = self.update_modifier(modifier, + ModState::Pressed, + ModState::Released); + if changed && Layout::is_label_modifier(modifier) { + draw = draw + DrawOperation::Labels; + } + + let changed = self.update_modifier(modifier, + ModState::Locked, + ModState::Released); + if changed && Layout::is_label_modifier(modifier) { + draw = draw + DrawOperation::Labels; + } + + self.update_modifier(modifier, + ModState::Held, + ModState::Latched); + self.update_modifier(modifier, + ModState::HeldLocked, + ModState::Locked); + } + + draw + } + + pub fn pos(&mut self, id: usize, x: f64, y: f64) + { + let press = match &mut self.presses[id] { + Some(p) => p, + None => return, + }; + + let (dx, dy) = (x - press.x1, y - press.y1); + if dx * dx + dy * dy < self.r_square { + // We only need to make changes when the key is being dragged. + return; + } + + let angle = dy.atan2(dx) * 8.0 / std::f64::consts::PI + 8.0; + let angle = angle.clamp(0.0, 15.0) as usize; + + let key = self.layout.locate_key_mut(press.x1, press.y1).unwrap(); + + let old_part = press.part; + Self::update_pressed_part(press, key, angle); + let new_part = press.part; + + if new_part == old_part { + return; + } + + key.parts[old_part].release(); + key.parts[new_part].press(); + + let modifier1 = key.parts[old_part].modifier_id(); + let modifier2 = key.parts[new_part].modifier_id(); + + press.timer = Instant::now() + self.longpress; + self.remove_timer(id); + self.timers.push_back(id); + + let mut draw = self.try_cancel_mod(modifier1); + draw = draw + self.try_press_mod(modifier2); + + let press = self.presses[id].as_ref().unwrap(); + let key = self.layout.locate_key(press.x1, press.y1).unwrap(); + Self::draw(draw, &self.gfx, &self.layout, Some(key), &self.modifiers); + } + + /* + * Release the given modifier key. If the key being pressed is not a + * modifier key (i.e. modifier = 0), release all latched modifier keys. + */ + fn release_mod(&mut self, modifier: usize) -> DrawOperation + { + let mut draw = DrawOperation::Key; + + if modifier != 0 { + self.update_modifier(modifier, + ModState::Pressed, + ModState::Latched); + + let changed = self.update_modifier(modifier, + ModState::Held, + ModState::Released); + if changed && Layout::is_label_modifier(modifier) { + draw = draw + DrawOperation::Labels; + } + + let changed = self.update_modifier(modifier, + ModState::HeldLocked, + ModState::Released); + if changed && Layout::is_label_modifier(modifier) { + draw = draw + DrawOperation::Labels; + } + } else { + for modifier in 1..=MODIFIERS_MAX { + let changed = self.update_modifier(modifier, + ModState::Latched, + ModState::Released); + if changed { + draw = draw + DrawOperation::from_modifier_edge(modifier); + } + } + } + + draw + } + + pub fn release(&mut self, id: usize) + { + let press = match &mut self.presses[id] { + Some(p) => p, + None => return, + }; + + let key = self.layout.locate_key_mut(press.x1, press.y1).unwrap(); + + key.parts[press.part].release(); + + let modifier = key.parts[press.part].modifier_id(); + if modifier == 0 { + self.kbd.press(key.parts[press.part].sym()); + self.kbd.release(key.parts[press.part].sym()); + } + + let draw = self.release_mod(modifier); + + let press = self.presses[id].as_ref().unwrap(); + let key = self.layout.locate_key(press.x1, press.y1).unwrap(); + Self::draw(draw, &self.gfx, &self.layout, Some(key), &self.modifiers); + + self.remove_timer(id); + self.presses[id] = None; + } + + fn lock_mod(&mut self, modifier: usize) -> DrawOperation + { + let changed = self.update_modifier(modifier, ModState::Pressed, ModState::Locked); + if changed { + DrawOperation::from_modifier(modifier) + } else { + DrawOperation::Key + } + } + + pub fn dispatch_timers(&mut self) + { + let mut draw = DrawOperation::Key; + + while !self.timers.is_empty() { + let id = *self.timers.front().unwrap(); + if id == PRESSES_MAX { + self.timers.pop_front(); + continue; + } + + let press = self.presses[id].as_mut().unwrap(); + if Instant::now() < press.timer { + break; + } + + self.timers.pop_front(); + + let key = self.layout.locate_key(press.x1, press.y1).unwrap(); + + let modifier = key.parts[press.part].modifier_id(); + if modifier != 0 { + draw = draw + self.lock_mod(modifier); + } else { + self.kbd.press(key.parts[press.part].sym()); + self.kbd.release(key.parts[press.part].sym()); + + press.timer += self.repeat; + self.timers.push_back(id); + } + } + + Self::draw(draw, &self.gfx, &self.layout, None, &self.modifiers); + } +} diff --git a/src/core/expat.rs b/src/core/expat.rs new file mode 100644 index 0000000..08bf65f --- /dev/null +++ b/src/core/expat.rs @@ -0,0 +1,6 @@ +#![allow(dead_code, + improper_ctypes, + non_camel_case_types, + non_snake_case, + non_upper_case_globals)] +include!(concat!(env!("OUT_DIR"), "/expat.rs")); diff --git a/src/core/graphics.rs b/src/core/graphics.rs new file mode 100644 index 0000000..2fc1958 --- /dev/null +++ b/src/core/graphics.rs @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::button::ModState; +use core::fontconfig; +use core::freetype::freetype; +use core::imgref::ImgRefMut; +use core::imgref::ImgRef; +use core::imgref::ImgVec; +use core::Layout; +use core::layout::Key; +use core::layout::Part; +use core::rgb::alt::BGR; +use core::rgb::alt::BGRA; +use core::xkeysym::Keysym; +use std::collections::HashMap; +use std::convert::TryInto; +use std::fs::File; +use std::io::Read; +use std::iter; +use std::ptr; + +fn convert_gray_to_bgrx(mut dest: ImgRefMut>, src: ImgRef, fg_color: BGR) +{ + for (dest, src) in iter::zip(dest.rows_mut(), src.rows()) { + for (dest, src) in iter::zip(dest, src) { + dest.r = ((dest.r as f32 + *src as f32 * fg_color.r) as u16).try_into().unwrap_or(255); + dest.g = ((dest.g as f32 + *src as f32 * fg_color.g) as u16).try_into().unwrap_or(255); + dest.b = ((dest.b as f32 + *src as f32 * fg_color.b) as u16).try_into().unwrap_or(255); + } + } +} + +fn copy_image(mut dest: ImgRefMut, src: ImgRef) +{ + for (dest, src) in iter::zip(dest.pixels_mut(), src.pixels()) { + *dest = (src as u16 + *dest as u16).try_into().unwrap_or(255); + } +} + +fn fill_image(dest: &mut ImgRefMut>, src: BGRA) +{ + for dest in dest.pixels_mut() { + *dest = src; + } +} + +fn bitmap_to_imgref(bitmap: &freetype::FT_Bitmap) -> ImgRef +{ + unsafe { + let buf = &*ptr::slice_from_raw_parts(bitmap.buffer, + bitmap.pitch as usize + * bitmap.rows as usize); + ImgRef::new_stride(buf, + bitmap.width as usize, + bitmap.rows as usize, + bitmap.pitch as usize) + } +} + +#[derive(Clone, Copy)] +enum Anchor { + Min, + Center, + Max, +} + +pub trait Display { + fn size(&self) -> (u32, u32); + + fn begin(&mut self) -> ImgRefMut>; + fn resize(&mut self, width: u32, height: u32); + fn end(&mut self, x: u32, y: u32, width: u32, height: u32); +} + +pub struct Graphics { + disp: D, + fonts: Vec<(String, freetype::FT_Long)>, + fontbufs: Vec>, + labels: HashMap>, + sublabels: HashMap>, + ft: freetype::FT_Library, + + x_scale: f64, + y_scale: f64, +} + +struct Label<'a> { + sym: Keysym, + label: &'a str, + secondary: bool, + small: bool, +} + +const LABELS: [Label; 43] = [ + Label { sym: Keysym::Greek_MU, label: "\u{039C}", + secondary: false, small: false, }, + Label { sym: Keysym::emdash, label: "\u{2014}", + secondary: false, small: false, }, + Label { sym: Keysym::endash, label: "\u{2013}", + secondary: false, small: false, }, + Label { sym: Keysym::ellipsis, label: "\u{2026}", + secondary: false, small: false, }, + Label { sym: Keysym::leftsinglequotemark, label: "\u{2018}", + secondary: false, small: false, }, + Label { sym: Keysym::rightsinglequotemark, label: "\u{2019}", + secondary: false, small: false, }, + Label { sym: Keysym::leftdoublequotemark, label: "\u{201C}", + secondary: false, small: false, }, + Label { sym: Keysym::rightdoublequotemark, label: "\u{201D}", + secondary: false, small: false, }, + Label { sym: Keysym::permille, label: "\u{2030}", + secondary: false, small: false, }, + Label { sym: Keysym::singlelowquotemark, label: "\u{201A}", + secondary: false, small: false, }, + Label { sym: Keysym::doublelowquotemark, label: "\u{201E}", + secondary: false, small: false, }, + Label { sym: Keysym::OE, label: "\u{0152}", + secondary: false, small: false, }, + Label { sym: Keysym::oe, label: "\u{0153}", + secondary: false, small: false, }, + Label { sym: Keysym::BackSpace, label: "\u{232B}", + secondary: true, small: false, }, + Label { sym: Keysym::Tab, label: "\u{2B7E}", + secondary: true, small: true, }, + Label { sym: Keysym::Return, label: "\u{23CE}", + secondary: true, small: false, }, + Label { sym: Keysym::Escape, label: "Esc", + secondary: true, small: true, }, + Label { sym: Keysym::Home, label: "\u{21E4}", + secondary: true, small: false, }, + Label { sym: Keysym::Left, label: "\u{2190}", + secondary: true, small: false, }, + Label { sym: Keysym::Up, label: "\u{2191}", + secondary: true, small: false, }, + Label { sym: Keysym::Right, label: "\u{2192}", + secondary: true, small: false, }, + Label { sym: Keysym::Down, label: "\u{2193}", + secondary: true, small: false, }, + Label { sym: Keysym::Page_Up, label: "\u{21D1}", + secondary: true, small: false, }, + Label { sym: Keysym::Page_Down, label: "\u{21D3}", + secondary: true, small: false, }, + Label { sym: Keysym::End, label: "\u{21E5}", + secondary: true, small: false, }, + Label { sym: Keysym::Insert, label: "Ins", + secondary: true, small: true, }, + Label { sym: Keysym::F1, label: "F1", + secondary: false, small: false, }, + Label { sym: Keysym::F2, label: "F2", + secondary: false, small: false, }, + Label { sym: Keysym::F3, label: "F3", + secondary: false, small: false, }, + Label { sym: Keysym::F4, label: "F4", + secondary: false, small: false, }, + Label { sym: Keysym::F5, label: "F5", + secondary: false, small: false, }, + Label { sym: Keysym::F6, label: "F6", + secondary: false, small: false, }, + Label { sym: Keysym::F7, label: "F7", + secondary: false, small: false, }, + Label { sym: Keysym::F8, label: "F8", + secondary: false, small: false, }, + Label { sym: Keysym::F9, label: "F9", + secondary: false, small: false, }, + Label { sym: Keysym::F10, label: "F10", + secondary: false, small: false, }, + Label { sym: Keysym::F11, label: "F11", + secondary: false, small: true, }, + Label { sym: Keysym::F12, label: "F12", + secondary: false, small: true, }, + Label { sym: Keysym::Shift_L, label: "\u{21E7}", + secondary: true, small: false, }, + Label { sym: Keysym::Control_L, label: "Ctrl", + secondary: true, small: true, }, + Label { sym: Keysym::Alt_L, label: "Alt", + secondary: true, small: true, }, + Label { sym: Keysym::Delete, label: "\u{2326}", + secondary: true, small: false, }, + Label { sym: Keysym::XF86_Fn, label: "Fn", + secondary: true, small: true, }, + /* + Label { sym: Keysym::approxeq, label: "\u{2248}", + secondary: false, small: false, }, + */ +]; + +const ANCHORS: [(Anchor, Anchor); 8] = [ + (Anchor::Min, Anchor::Min), + (Anchor::Max, Anchor::Min), + (Anchor::Min, Anchor::Max), + (Anchor::Max, Anchor::Max), + (Anchor::Min, Anchor::Center), + (Anchor::Max, Anchor::Center), + (Anchor::Center, Anchor::Min), + (Anchor::Center, Anchor::Max), +]; + +impl Graphics { + pub fn new(disp: D) -> Graphics + { + let ft = unsafe { + let mut ft = std::ptr::null_mut(); + let err = freetype::FT_Init_FreeType(&mut ft); + if err != 0 { + panic!("FreeType error {}", err); + } + + ft + }; + + /* + * We want a pattern with default and config substitution, so use the + * side effect in font_match(). The first font might not provide all + * glyphs needed, so the returned font is unused. + */ + let fc = fontconfig::Fontconfig::new().unwrap(); + let mut pattern = fontconfig::Pattern::new(&fc); + pattern.font_match(); + + let fonts = fontconfig::sort_fonts(&pattern, true); + + let mut fontfiles = Vec::new(); + + for font in fonts.iter() { + let fname = match font.filename() { + Some(fname) => String::from(fname), + None => continue, + }; + + let idx = match font.face_index() { + Some(idx) => idx.into(), + None => 0, + }; + + fontfiles.push((fname, idx)); + } + + Graphics { + disp, + ft, + fonts: fontfiles, + fontbufs: Vec::new(), + labels: HashMap::new(), + sublabels: HashMap::new(), + + x_scale: 0.0, + y_scale: 0.0, + } + } + + fn keysym_to_label(sym: Keysym) -> String + { + let res = LABELS.binary_search_by_key(&sym, |&Label { sym, .. }| sym); + if let Ok(idx) = res { + return String::from(LABELS[idx].label); + } + + // The ! symbol is bitwise NOT. + match char::from_u32(sym.raw() & !0x01000000) { + Some(c) => { + let mut label = String::new(); + label.push(c); + label + }, + None => { + format!("U+{}", sym.raw()) + }, + } + } + + fn is_keysym_small(sym: Keysym) -> bool + { + match LABELS.binary_search_by_key(&sym, |&Label { sym, .. }| sym) { + Ok(idx) => LABELS[idx].small, + Err(_) => false, + } + } + + fn open_font(&mut self, idx: usize) -> Option + { + // Read the font if it is not already cached. + if self.fontbufs.len() <= idx { + let mut f = File::open(&self.fonts[idx].0).ok()?; + + let mut fontbuf = Vec::new(); + f.read_to_end(&mut fontbuf).ok()?; + + self.fontbufs.push(fontbuf); + } + + let fontbuf = &self.fontbufs[idx]; + + unsafe { + let mut ftface = std::ptr::null_mut(); + freetype::FT_New_Memory_Face(self.ft, + fontbuf.as_ptr(), + fontbuf.len() as freetype::FT_Long, + self.fonts[idx].1 as freetype::FT_Long, + &mut ftface); + if ptr::eq(ftface, ptr::null_mut()) { + None + } else { + Some(ftface) + } + } + } + + fn can_font_render_text(face: Option, text: &str) -> bool + { + let face = match face { + Some(face) => face, + None => return false, + }; + + for c in text.chars() { + unsafe { + if freetype::FT_Get_Char_Index(face, c.into()) == 0 { + return false; + } + } + } + + true + } + + fn open_font_for_text(&mut self, text: &str) -> Option + { + let mut ftface = self.open_font(0); + let mut i = 1; + + while !Self::can_font_render_text(ftface, text) { + if let Some(ftface) = ftface { + unsafe { + freetype::FT_Done_Face(ftface); + } + } + + ftface = self.open_font(i); + + i += 1; + if i >= self.fonts.len() { + // Fall back to the first font with placeholder glyphs + return self.open_font(0); + } + } + + ftface + } + + fn rasterize_text(&mut self, size: f64, text: &str) -> ImgVec + { + let ftface = self.open_font_for_text(text).unwrap(); + unsafe { + freetype::FT_Set_Char_Size(ftface, (size * 64.0) as i64, 0, 0, 0); + }; + + let (metrics, units_per_em, bbox) = unsafe { + ((*(*ftface).size).metrics, + (*ftface).units_per_EM, + (*ftface).bbox) + }; + + let mut width = 0; + let glyph_width = (bbox.xMax - bbox.xMin) as usize + * metrics.x_ppem as usize + / units_per_em as usize; + + let stride = metrics.max_advance as usize / 64 * (text.len() - 1) + glyph_width; + let height = (metrics.ascender - metrics.descender) as usize / 64; + + let vec: Vec = vec![0; stride * height]; + let mut img = ImgVec::new(vec, stride, height); + + let mut pen: i64 = 0; + + for c in text.chars() { + let glyph = unsafe { + freetype::FT_Load_Char(ftface, c.into(), 0); + freetype::FT_Render_Glyph((*ftface).glyph, freetype::FT_Render_Mode::FT_RENDER_MODE_NORMAL); + *(*ftface).glyph + }; + + if glyph.bitmap.rows != 0 && glyph.bitmap.width != 0 { + if pen < -glyph.bitmap_left as i64 { + pen -= glyph.bitmap_left as i64; + } + + let dest_x = pen + glyph.bitmap_left as i64; + let dest_y = metrics.ascender / 64 - glyph.bitmap_top as i64; + + let src = bitmap_to_imgref(&glyph.bitmap); + let dest = img.sub_image_mut(dest_x as usize, + dest_y as usize, + glyph.bitmap.width as usize, + glyph.bitmap.rows as usize); + copy_image(dest, src); + } + + let new_width = (pen + glyph.bitmap_left as i64 + + glyph.bitmap.width as i64) as usize; + if width < new_width { + width = new_width; + } + + pen += glyph.advance.x / 64; + } + + unsafe { + freetype::FT_Done_Face(ftface); + }; + + let vec = img.into_buf(); + ImgVec::new_stride(vec, width, height, stride) + } + + /* + * Rasterize a key symbol and store it in the labels hash table. + * + * We need two functions, one for labels and one for sublabels, in order to + * borrow the hash tables mutably. The text rasterizing operation borrows + * the self as mutable to store fonts for later use. Since the self and hash + * table cannot be mutable at the same time, this cannot be abstracted to a + * mutable self and mutable hash table. + */ + fn rasterize_label(&mut self, size: f64, sym: Keysym) + { + if !self.labels.contains_key(&sym) { + let label = Self::keysym_to_label(sym); + + let size = if Self::is_keysym_small(sym) { + size * 0.75 + } else { + size + }; + + let img = self.rasterize_text(size, &label); + self.labels.insert(sym, img); + } + } + + /* + * Rasterize a key symbol and store it in the sublabels hash table. + * + * We need two functions, one for labels and one for sublabels, in order to + * borrow the hash tables mutably. The text rasterizing operation borrows + * the self as mutable to store fonts for later use. Since the self and hash + * table cannot be mutable at the same time, this cannot be abstracted to a + * mutable self and mutable hash table. + */ + fn rasterize_sublabel(&mut self, size: f64, sym: Keysym) + { + if !self.sublabels.contains_key(&sym) { + let label = Self::keysym_to_label(sym); + + let size = if Self::is_keysym_small(sym) { + size * 0.75 + } else { + size + }; + + let img = self.rasterize_text(size, &label); + self.sublabels.insert(sym, img); + } + } + + fn rasterize_labels(&mut self, layout: &Layout, mod_state: &[ModState]) + { + self.labels = HashMap::new(); + self.sublabels = HashMap::new(); + + let label_size = self.y_scale * 0.33; + let sublabel_size = self.y_scale * 0.22; + + for row in layout.rows() { + self.labels.reserve(row.len()); + self.sublabels.reserve(row.len() * 8); + + for key in row { + let sym = key.parts[0].display_symbol(mod_state); + self.rasterize_label(label_size, sym); + + for part in &key.parts[1..] { + let sym = part.display_symbol(mod_state); + self.rasterize_sublabel(sublabel_size, sym); + } + } + } + } + + fn draw_label_part(labels: &HashMap>, + x_anchor: Anchor, y_anchor: Anchor, + img: &mut ImgRefMut>, + sym: Keysym, fg_color: BGR) + { + let src = labels.get(&sym) + .expect("Layout and size should be set before drawing"); + + let x = match x_anchor { + Anchor::Min => 0, + Anchor::Center => (img.width() - src.width()) / 2, + Anchor::Max => img.width() - src.width(), + }; + + let y = match y_anchor { + Anchor::Min => 0, + Anchor::Center => (img.height() - src.height()) / 2, + Anchor::Max => img.height() - src.height(), + }; + + let width = src.width(); + let height = src.height(); + + let src = src.sub_image(0, 0, width, height); + let dest = img.sub_image_mut(x, y, width, height); + + convert_gray_to_bgrx(dest, src, fg_color); + } + + fn keypart_to_color(part: &Part, sublabel: bool, + mod_state: &[ModState]) -> BGR + { + let color_locked = BGR { r: 0.0, g: 1.0, b: 0.1, }; + let color_pressed = BGR { r: 0.0, g: 0.6, b: 1.0, }; + let color_label = BGR { r: 1.0, g: 1.0, b: 1.0, }; + let color_sublabel = BGR { r: 0.7, g: 0.7, b: 0.7, }; + + let modifier = part.modifier_id(); + if modifier != 0 { + let modifier = modifier - 1; + if mod_state[modifier] == ModState::Locked + || mod_state[modifier] == ModState::HeldLocked { + return color_locked; + } else if mod_state[modifier] != ModState::Released { + return color_pressed; + } + } + + if part.presses() != 0 { + return color_pressed; + } + + if sublabel { + return color_sublabel; + } + + let res = LABELS.binary_search_by_key(&part.sym(), |&Label { sym, .. }| sym); + if let Ok(idx) = res { + if LABELS[idx].secondary { + return color_sublabel; + } + } + + color_label + } + + fn draw_key(labels: &HashMap>, + sublabels: &HashMap>, + x_scale: f64, y_scale: f64, + img: &mut ImgRefMut>, + key: &Key, mod_state: &[ModState]) + { + let x1 = (key.x1 * x_scale) as usize; + let y1 = (key.y1 * y_scale) as usize; + let x2 = (key.x2 * x_scale) as usize; + let y2 = (key.y2 * y_scale) as usize; + + let mut keyimg = img.sub_image_mut(x1, y1, x2 - x1, y2 - y1); + + let mut pressed = false; + for part in &key.parts { + let modifier = part.modifier_id(); + if modifier != 0 && mod_state[modifier - 1] != ModState::Released { + pressed = true; + break; + } + + if part.presses() != 0 { + pressed = true; + break; + } + } + + if pressed { + fill_image(&mut keyimg, BGRA { r: 51, g: 51, b: 51, a: 0, }); + } else { + fill_image(&mut keyimg, BGRA { r: 0, g: 0, b: 0, a: 0, }); + } + + let color = Self::keypart_to_color(&key.parts[0], false, mod_state); + let sym = key.parts[0].display_symbol(mod_state); + Self::draw_label_part(labels, Anchor::Center, Anchor::Center, + &mut keyimg, sym, color); + + for i in 0..8 { + let color = Self::keypart_to_color(&key.parts[i + 1], true, mod_state); + let sym = key.parts[i + 1].display_symbol(mod_state); + Self::draw_label_part(sublabels, ANCHORS[i].0, ANCHORS[i].1, + &mut keyimg, sym, color); + } + } + + pub fn draw_single(&mut self, key: &Key, mod_state: &[ModState]) + { + let mut img = self.disp.begin(); + + let x1 = (key.x1 * self.x_scale) as u32; + let y1 = (key.y1 * self.y_scale) as u32; + let x2 = (key.x2 * self.x_scale) as u32; + let y2 = (key.y2 * self.y_scale) as u32; + + Self::draw_key(&self.labels, &self.sublabels, + self.x_scale, self.y_scale, + &mut img, key, mod_state); + + self.disp.end(x1, y1, x2 - x1, y2 - y1); + } + + pub fn draw_modifiers(&mut self, + layout: &Layout, + mod_state: &[ModState], + modifiers: &[bool]) + { + for row in layout.rows() { + for key in row { + let draw = key.parts.iter().any(|p| p.modifier_id() != 0 + && modifiers[p.modifier_id() - 1]); + if draw { + self.draw_single(key, mod_state); + } + } + } + } + + pub fn draw(&mut self, layout: &Layout, mod_state: &[ModState]) + { + let mut img = self.disp.begin(); + + fill_image(&mut img, BGRA { r: 0, g: 0, b: 0, a: 0, }); + + for row in layout.rows() { + for key in row { + Self::draw_key(&self.labels, &self.sublabels, + self.x_scale, self.y_scale, + &mut img, key, mod_state); + } + } + + let (width, height) = (img.width() as u32, img.height() as u32); + self.disp.end(0, 0, width, height); + } + + pub fn change_layout(&mut self, layout: &Layout, mod_state: &[ModState]) + { + self.rasterize_labels(layout, mod_state); + self.draw(layout, mod_state); + } + + pub fn resize(&mut self, + layout: &Layout, mod_state: &[ModState], + width: u32, height: u32) + { + self.x_scale = width as f64 / layout.width(); + self.y_scale = height as f64 / layout.height(); + + self.rasterize_labels(layout, mod_state); + + self.disp.resize(width, height); + self.draw(layout, mod_state); + } + + #[inline(always)] + pub fn display(&self) -> &D + { + &self.disp + } + + #[inline(always)] + pub fn display_mut(&mut self) -> &mut D + { + &mut self.disp + } +} + +impl Drop for Graphics { + fn drop(&mut self) + { + unsafe { + freetype::FT_Done_FreeType(self.ft); + } + } +} diff --git a/src/core/layout.rs b/src/core/layout.rs new file mode 100644 index 0000000..9c5f2a1 --- /dev/null +++ b/src/core/layout.rs @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::button::ModState; +use core::expat; +use core::xkeysym::Keysym; +use std::cmp::Ordering; +use std::collections::HashMap; +use std::str::FromStr; +use std::ffi::CStr; +use std::fs::File; +use std::io::Error; +use std::io::ErrorKind; +use std::io::Read; +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::path::Path; +use std::ptr; + +unsafe extern "C" fn start_elem(data: *mut c_void, + c_name: *const expat::XML_Char, + c_attrs: *mut *const expat::XML_Char) +{ + let layout = &mut *(data as *mut Layout); + let name = CStr::from_ptr(c_name) + .to_str().expect("layout: XML element name must be UTF-8"); + + let mut attrs = HashMap::with_capacity(10); + + while !ptr::eq(*c_attrs.add(attrs.len() * 2), ptr::null()) { + let k = CStr::from_ptr(*c_attrs.add(attrs.len() * 2)) + .to_str().expect("layout: XML attribute name must be UTF-8"); + let v = CStr::from_ptr(*c_attrs.add(attrs.len() * 2 + 1)) + .to_str().expect("layout: XML attribute value must be UTF-8"); + + attrs.insert(k, v); + } + + layout.start_elem(name, &attrs); +} + +unsafe extern "C" fn end_elem(data: *mut c_void, c_name: *const expat::XML_Char) +{ + let layout = &mut *(data as *mut Layout); + let name = CStr::from_ptr(c_name) + .to_str().expect("layout: XML element name must be UTF-8"); + + layout.end_elem(name); +} + +pub const MOD_SHIFT: usize = 1; +pub const MOD_CTRL: usize = 2; +pub const MOD_ALT: usize = 3; +pub const MOD_FN: usize = 4; +pub const MODIFIERS_MAX: usize = 4; + +pub struct Part { + orig_sym: Keysym, + sym: Keysym, + + // TODO: use accessors here + presses: u32, +} + +impl Part { + pub fn modify_shift(orig_sym: Keysym) -> Keysym + { + match orig_sym { + Keysym::a => Keysym::A, + Keysym::b => Keysym::B, + Keysym::c => Keysym::C, + Keysym::d => Keysym::D, + Keysym::e => Keysym::E, + Keysym::f => Keysym::F, + Keysym::g => Keysym::G, + Keysym::h => Keysym::H, + Keysym::i => Keysym::I, + Keysym::j => Keysym::J, + Keysym::k => Keysym::K, + Keysym::l => Keysym::L, + Keysym::m => Keysym::M, + Keysym::n => Keysym::N, + Keysym::o => Keysym::O, + Keysym::p => Keysym::P, + Keysym::q => Keysym::Q, + Keysym::r => Keysym::R, + Keysym::s => Keysym::S, + Keysym::t => Keysym::T, + Keysym::u => Keysym::U, + Keysym::v => Keysym::V, + Keysym::w => Keysym::W, + Keysym::x => Keysym::X, + Keysym::y => Keysym::Y, + Keysym::z => Keysym::Z, + + Keysym::ae => Keysym::AE, + Keysym::oe => Keysym::OE, + Keysym::mu => Keysym::Greek_MU, + + _ => orig_sym, + } + } + + fn modify_fn(orig_sym: Keysym) -> Keysym + { + match orig_sym { + Keysym::Up => Keysym::Prior, // Page Up + Keysym::Down => Keysym::Next, // Page Down + Keysym::Left => Keysym::Home, + Keysym::Right => Keysym::End, + Keysym::Escape => Keysym::Insert, + + Keysym::_1 => Keysym::F1, + Keysym::_2 => Keysym::F2, + Keysym::_3 => Keysym::F3, + Keysym::_4 => Keysym::F4, + Keysym::_5 => Keysym::F5, + Keysym::_6 => Keysym::F6, + Keysym::_7 => Keysym::F7, + Keysym::_8 => Keysym::F8, + Keysym::_9 => Keysym::F9, + Keysym::_0 => Keysym::F10, + + Keysym::less => Keysym::guillemetleft, + Keysym::greater => Keysym::guillemetright, + // Keysym::braceleft => Keysym::from_char('\u{2039}'), + // Keysym::braceright => Keysym::from_char('\u{203A}'), + Keysym::bracketleft => Keysym::leftsinglequotemark, + Keysym::bracketright => Keysym::rightsinglequotemark, + Keysym::parenleft => Keysym::leftdoublequotemark, + Keysym::parenright => Keysym::rightdoublequotemark, + Keysym::apostrophe => Keysym::singlelowquotemark, + Keysym::quotedbl => Keysym::doublelowquotemark, + Keysym::minus => Keysym::endash, + Keysym::underscore => Keysym::emdash, + Keysym::asciicircum => Keysym::notsign, + Keysym::percent => Keysym::permille, + Keysym::equal => Keysym::approxeq, + Keysym::u => Keysym::mu, + Keysym::a => Keysym::ae, + Keysym::o => Keysym::oe, + Keysym::asterisk => Keysym::degree, + Keysym::period => Keysym::ellipsis, + Keysym::comma => Keysym::periodcentered, + Keysym::exclam => Keysym::exclamdown, + Keysym::question => Keysym::questiondown, + Keysym::bar => Keysym::brokenbar, + + Keysym::e => Keysym::EuroSign, + Keysym::l => Keysym::sterling, + // Keysym::r => Keysym::from_char('\u{20B9}'), + Keysym::y => Keysym::yen, + Keysym::c => Keysym::cent, + // Keysym::p => Keysym::from_char('\u{20BD}'), + // Keysym::b => Keysym::from_char('\u{20B1}'), + // Keysym::h => Keysym::from_char('\u{20B4}'), + // Keysym::z => Keysym::from_char('\u{20BF}'), + + _ => orig_sym, + } + } + + fn modify_no_fn(orig_sym: Keysym) -> Keysym + { + match orig_sym { + /* + Keysym::F11 => Keysym::NoSymbol, + Keysym::F12 => Keysym::NoSymbol, + */ + _ => orig_sym, + } + } + + fn new(orig_sym: Keysym) -> Part + { + Part { + orig_sym, + sym: Self::modify_no_fn(orig_sym), + presses: 0, + } + } + + #[inline(always)] + pub fn sym(&self) -> Keysym + { + self.sym + } + + #[inline(always)] + pub fn press(&mut self) + { + self.presses += 1; + } + + #[inline(always)] + pub fn release(&mut self) + { + self.presses -= 1; + } + + #[inline(always)] + pub fn presses(&self) -> u32 + { + self.presses + } + + pub fn modifier_id(&self) -> usize + { + match self.sym { + Keysym::Shift_L => MOD_SHIFT, + Keysym::Control_L => MOD_CTRL, + Keysym::Alt_L => MOD_ALT, + Keysym::XF86_Fn => MOD_FN, + _ => 0, + } + } + + pub fn update_modifiers(&mut self, mod_state: &[ModState]) + { + let mut sym = self.orig_sym; + + if mod_state[MOD_FN - 1] != ModState::Released { + sym = Self::modify_fn(sym); + } else { + sym = Self::modify_no_fn(sym); + } + + self.sym = sym; + } + + pub fn display_symbol(&self, mod_state: &[ModState]) -> Keysym + { + let mut sym = self.sym; + + if mod_state[MOD_SHIFT - 1] != ModState::Released { + sym = Self::modify_shift(sym); + } + + sym + } +} + +pub struct Key { + // NOPUSH + pub parts: [Part; 9], + pub x1: f64, + pub y1: f64, + pub x2: f64, + pub y2: f64, +} + +impl Key { + fn new(x1: f64, y1: f64, x2: f64, y2: f64, + center: Keysym, + top_left: Keysym, + top_right: Keysym, + bottom_left: Keysym, + bottom_right: Keysym, + left: Keysym, + right: Keysym, + top: Keysym, + bottom: Keysym) -> Key + { + Key { + x1, y1, x2, y2, + parts: [ + Part::new(center), + Part::new(top_left), + Part::new(top_right), + Part::new(bottom_left), + Part::new(bottom_right), + Part::new(left), + Part::new(right), + Part::new(top), + Part::new(bottom), + ], + } + } +} + +pub struct Layout { + rows: Vec>, + width: f64, + height: f64, + row_width: f64, + in_row: u32, +} + +const KEYSYMS: [(&str, Keysym); 20] = [ + ("\\#", Keysym::numbersign), + ("\\?", Keysym::question), + ("\\@", Keysym::at), + ("\\\\", Keysym::backslash), + ("backspace", Keysym::BackSpace), + ("ctrl", Keysym::Control_L), + ("delete", Keysym::Delete), + ("down", Keysym::Down), + ("enter", Keysym::Return), + ("esc", Keysym::Escape), + ("f11_placeholder", Keysym::F11), + ("f12_placeholder", Keysym::F12), + ("fn", Keysym::XF86_Fn), + ("left", Keysym::Left), + ("loc alt", Keysym::Alt_L), + ("right", Keysym::Right), + ("shift", Keysym::Shift_L), + ("space", Keysym::space), + ("tab", Keysym::Tab), + ("up", Keysym::Up), +]; + +impl Layout { + pub fn is_keysym_modifier(modifier: usize) -> bool + { + match modifier { + MOD_FN => true, + _ => false, + } + } + + pub fn is_label_modifier(modifier: usize) -> bool + { + // Shift does not change the keysym used for input, but changes the + // rendered keysym. + Self::is_keysym_modifier(modifier) || modifier == MOD_SHIFT + } + + pub fn modifier_keysym(modifier: usize) -> Keysym + { + match modifier { + MOD_SHIFT => Keysym::Shift_L, + MOD_CTRL => Keysym::Control_L, + MOD_ALT => Keysym::Alt_L, + MOD_FN => Keysym::XF86_Fn, + _ => Keysym::NoSymbol, + } + } + + fn get_keysym_by_name(name: &str) -> Keysym + { + if let Ok(idx) = KEYSYMS.binary_search_by_key(&name, |&(k, _)| k) { + return KEYSYMS[idx].1; + } + + let mut chars = name.chars(); + + let c1 = chars.next(); + let c2 = chars.next(); + match (c1, c2) { + (Some(c), None) => Keysym::new(c as u32), + _ => Keysym::NoSymbol, + } + } + + fn start_key(&mut self, attrs: &HashMap<&str, &str>) + { + if self.in_row != 1 { + println!("layout: key element not in row element ignored"); + return; + } + + let shift = f64::from_str(attrs.get("shift").unwrap_or(&"")).unwrap_or(0.0); + let x1 = self.row_width + shift; + + let width = f64::from_str(attrs.get("width").unwrap_or(&"")).unwrap_or(1.0); + let x2 = x1 + width; + + self.row_width = x2; + + let key = Key::new( + x1, self.height, x2, self.height + 1.0, + Self::get_keysym_by_name(attrs.get("key0").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key1").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key2").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key3").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key4").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key5").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key6").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key7").unwrap_or(&"")), + Self::get_keysym_by_name(attrs.get("key8").unwrap_or(&"")) + ); + + let idx = self.rows.len() - 1; + self.rows[idx].push(key); + } + + fn start_row(&mut self) + { + self.rows.push(Vec::new()); + self.in_row += 1; + self.row_width = 0.0; + } + + fn start_elem(&mut self, name: &str, attrs: &HashMap<&str, &str>) + { + if name == "key" { + self.start_key(attrs); + } else if name == "row" { + self.start_row(); + } + } + + fn end_row(&mut self) + { + self.in_row -= 1; + + if self.row_width > self.width { + self.width = self.row_width; + } + + self.height += 1.0; + } + + fn end_elem(&mut self, name: &str) + { + if name == "row" { + self.end_row(); + } + } + + pub fn load(dir: &Path, filename: &str) -> Result + { + let mut layout = Layout { + rows: Vec::new(), + width: 0.0, + height: 0.0, + row_width: 0.0, + in_row: 0, + }; + + let mut vec = Vec::new(); + let path = dir.join(filename); + let mut file = File::open(path)?; + file.read_to_end(&mut vec)?; + + let mut vec2 = Vec::new(); + let path = dir.join("bottom_row.xml"); + let mut file = File::open(path)?; + file.read_to_end(&mut vec2)?; + + unsafe { + let parser = expat::XML_ParserCreate(ptr::null()); + if ptr::eq(parser, ptr::null_mut()) { + return Err(Error::new(ErrorKind::OutOfMemory, "Could not parse XML")); + } + + expat::XML_SetElementHandler(parser, Some(start_elem), Some(end_elem)); + expat::XML_SetUserData(parser, &mut layout as *mut Layout as *mut c_void); + + let status = expat::XML_Parse(parser, vec.as_ptr() as *const c_char, + vec.len() as i32, 1); + if status != expat::XML_Status_XML_STATUS_OK { + return Err(Error::new(ErrorKind::InvalidData, "Could not parse XML")); + } + + expat::XML_ParserReset(parser, ptr::null()); + expat::XML_SetElementHandler(parser, Some(start_elem), Some(end_elem)); + expat::XML_SetUserData(parser, &mut layout as *mut Layout as *mut c_void); + + let status = expat::XML_Parse(parser, vec2.as_ptr() as *const c_char, + vec2.len() as i32, 1); + if status != expat::XML_Status_XML_STATUS_OK { + return Err(Error::new(ErrorKind::InvalidData, "Could not parse XML")); + } + + expat::XML_ParserFree(parser); + }; + + Ok(layout) + } + + #[inline(always)] + pub fn width(&self) -> f64 + { + self.width + } + + #[inline(always)] + pub fn height(&self) -> f64 + { + self.height + } + + #[inline(always)] + pub fn rows(&self) -> &Vec> + { + &self.rows + } + + pub fn locate_key(&self, x: f64, y: f64) -> Option<&Key> + { + let row = &self.rows[y as usize]; + let res = row.binary_search_by(|k| { + if k.x2 < x { + Ordering::Less + } else if k.x1 > x { + Ordering::Greater + } else { + Ordering::Equal + } + }); + + match res { + Ok(i) => Some(&row[i]), + Err(_) => None, + } + } + + pub fn locate_key_mut(&mut self, x: f64, y: f64) -> Option<&mut Key> + { + let row = &mut self.rows[y as usize]; + let res = row.binary_search_by(|k| { + if k.x2 < x { + Ordering::Less + } else if k.x1 > x { + Ordering::Greater + } else { + Ordering::Equal + } + }); + + match res { + Ok(i) => Some(&mut row[i]), + Err(_) => None, + } + } + + pub fn update_modifiers(&mut self, mod_state: &[ModState]) + { + for row in self.rows.iter_mut() { + for key in row.iter_mut() { + for part in key.parts.iter_mut() { + part.update_modifiers(mod_state); + } + } + } + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..168b670 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +pub extern crate fontconfig; +pub extern crate freetype; +pub extern crate imgref; +pub extern crate rgb; +pub extern crate xkeysym; + +mod button; +mod expat; +mod graphics; +mod layout; + +pub use self::button::Button; +pub use self::button::Keyboard; +pub use self::button::ModState; +pub use self::graphics::Display; +pub use self::graphics::Graphics; +pub use self::layout::Layout; +pub use self::layout::Part; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e9a80ed --- /dev/null +++ b/src/main.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +extern crate polling; + +mod wayland; +mod core; + +use core::Layout; +use polling::Event; +use polling::Events; +use polling::Poller; +use std::path::Path; +use std::time::Instant; +use wayland::Dispatcher; +use wayland::wayland_client::Connection; +use wayland::wayland_client::globals; + +fn main() +{ + let conn = Connection::connect_to_env().unwrap(); + + let (globals, mut queue) = globals::registry_queue_init::(&conn) + .expect("Registry required"); + + let layouts = Path::new("/usr/share/unfettered-keyboard/layouts"); + let layout = Layout::load(&layouts, "latn_qwerty_us.xml") + .expect("Layout should be loadable"); + let mut dispatcher = Dispatcher::new(layout, queue.handle(), &globals).unwrap(); + + let wl_evt = Event::readable(0); + let poller = Poller::new().unwrap(); + let mut events = Events::new(); + + loop { + queue.flush().unwrap(); + + let guard = queue.prepare_read().unwrap(); + let fd = guard.connection_fd(); + let timer = dispatcher.button().next_time().map(|t| t - Instant::now()); + + unsafe { + poller.add(&fd, wl_evt).unwrap(); + } + + events.clear(); + poller.wait(&mut events, timer).unwrap(); + poller.delete(fd).unwrap(); + + if !events.is_empty() { + guard.read().unwrap(); + queue.dispatch_pending(&mut dispatcher).unwrap(); + } + + dispatcher.dispatch_timers(); + } +} diff --git a/src/wayland/buffer.rs b/src/wayland/buffer.rs new file mode 100644 index 0000000..d940663 --- /dev/null +++ b/src/wayland/buffer.rs @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +extern crate libc; +extern crate memmap2; + +use core::imgref::ImgRef; +use core::imgref::ImgRefMut; +use core::rgb::alt::BGRA; +use core::rgb::FromSlice; +use self::memmap2::MmapMut; +use std::ffi::CString; +use std::fs::File; +use std::io::Error; +use std::io::ErrorKind; +use std::iter; +use std::os::fd::FromRawFd; +use std::os::fd::AsFd; +use std::process; +use wayland::wayland_client::protocol::wl_buffer::WlBuffer; +use wayland::wayland_client::protocol::wl_shm_pool::WlShmPool; +use wayland::wayland_client::protocol::wl_shm; +use wayland::wayland_client::protocol::wl_surface::WlSurface; +use wayland::wayland_client::Dispatch; +use wayland::wayland_client::QueueHandle; + +pub struct Buffer { + file: File, + map: MmapMut, + + id: u32, + capacity: i32, + width: i32, + height: i32, + + queue: QueueHandle, + pool: WlShmPool, + buf: WlBuffer, + used: bool, + resizing: bool, +} + +impl + + Dispatch + + 'static> Buffer { + pub fn new(queue: QueueHandle, shm: &wl_shm::WlShm, id: u32) -> Result + { + // Integers are normally not represented as text using NUL. + let name = match CString::new(format!("/ufkbd_pid{}_{}", process::id(), id)) { + Ok(name) => name, + Err(e) => return Err(Error::new(ErrorKind::InvalidInput, e)), + }; + + let file = unsafe { + let fd = libc::shm_open(name.as_ptr(), + libc::O_RDWR | libc::O_CREAT | libc::O_EXCL, + libc::S_IRUSR | libc::S_IWUSR); + if fd == -1 { + return Err(Error::last_os_error()); + } + + File::from_raw_fd(fd) + }; + + /* + * A buffer must be at least 1x1, and 32 bits per pixel + * (ARGB8888 and XRGB8888) is supported on all Wayland compositors. + */ + file.set_len(4)?; + + let map = unsafe { MmapMut::map_mut(&file) }?; + + let pool = shm.create_pool(file.as_fd(), 4, &queue, id); + let buf = pool.create_buffer(0, 1, 1, 4, wl_shm::Format::Xrgb8888, + &queue, id); + + /* + * This can happen before expanding the file. The shm_unlink(3p) manual + * says: + * + * If one or more references to the shared memory object exist when + * the object is unlinked, the name shall be removed before + * shm_unlink() returns, but the removal of the memory object + * contents shall be postponed until all open and map references to + * the shared memory object have been removed. + */ + unsafe { + libc::shm_unlink(name.as_ptr()); + }; + + Ok(Buffer { + file, map, + id, capacity: 4, width: 1, height: 1, + queue, pool, buf, + used: false, resizing: false, + }) + } + + fn commit_resize(&mut self) + { + if self.resizing { + self.buf = self.pool.create_buffer(0, self.width, self.height, + self.width * 4, + wl_shm::Format::Xrgb8888, + &self.queue, self.id); + self.resizing = false; + } + } + + pub fn resize(&mut self, width: i32, height: i32) -> Result<(), Error> + { + if width <= 0 || height <= 0 { + return Err(Error::new(ErrorKind::InvalidInput, "Buffer must be at least 1x1")); + } + + // Expand as necessary. Shrinking is not supported by wl_shm_pool.resize(). + if self.capacity < width * height * 4 { + self.capacity = width * height * 4; + + // Failure is a bug in the above check or the capacity calculation. + let filelen = self.capacity as u64; + self.file.set_len(filelen)?; + + self.pool.resize(self.capacity); + + self.map = unsafe { MmapMut::map_mut(&self.file) }?; + } + + // Try to resize the buffer now, otherwise defer it. + self.width = width; + self.height = height; + self.resizing = true; + if !self.used { + self.commit_resize(); + } + + Ok(()) + } + + pub fn image(&self) -> ImgRef> + { + let ptr = self.map.as_ref().as_bgra(); + ImgRef::new(ptr, self.width as usize, self.height as usize) + } + + pub fn consume(&mut self, surface: &WlSurface) -> Option>> + { + if self.used { + return None; + } + + self.used = true; + surface.attach(Some(&self.buf), 0, 0); + + // The ARGB format is in little endian. + let ptr = self.map.as_mut().as_bgra_mut(); + let img = ImgRefMut::new(ptr, self.width as usize, self.height as usize); + + Some(img) + } + + pub fn release(&mut self) + { + self.used = false; + self.commit_resize(); + } + + pub fn writeback(&mut self, src: &ImgRef>, x: usize, y: usize) + { + if self.used { + panic!("Writeback must always be on an inactive buffer"); + } + + // The ARGB format is in little endian. + let ptr = self.map.as_mut().as_bgra_mut(); + let mut img = ImgRefMut::new(ptr, self.width as usize, self.height as usize); + let mut subimg = img.sub_image_mut(x, y, src.width(), src.height()); + + for (dest, src) in iter::zip(subimg.pixels_mut(), src.pixels()) { + *dest = src; + } + } + + #[inline(always)] + pub fn size(&self) -> (i32, i32) + { + (self.width, self.height) + } +} diff --git a/src/wayland/dispatcher.rs b/src/wayland/dispatcher.rs new file mode 100644 index 0000000..9ce87d7 --- /dev/null +++ b/src/wayland/dispatcher.rs @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::Button; +use core::Display; +use core::Graphics; +use core::Layout; +use std::io::Error; +use std::sync::Arc; +use std::sync::Mutex; +use wayland::Seat; +use wayland::Surface; +use wayland::wayland_client::globals::GlobalList; +use wayland::wayland_client::globals::GlobalListContents; +use wayland::wayland_client::protocol::wl_buffer; +use wayland::wayland_client::protocol::wl_compositor; +use wayland::wayland_client::protocol::wl_pointer; +use wayland::wayland_client::protocol::wl_registry; +use wayland::wayland_client::protocol::wl_seat; +use wayland::wayland_client::protocol::wl_shm; +use wayland::wayland_client::protocol::wl_shm_pool; +use wayland::wayland_client::protocol::wl_surface; +use wayland::wayland_client::protocol::wl_touch; +use wayland::wayland_client::Connection; +use wayland::wayland_client::Dispatch; +use wayland::wayland_client::Proxy; +use wayland::wayland_client::QueueHandle; +use wayland::wayland_client::WEnum; +use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_shell_v1; +use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1; +use wayland::fractional_scale_v1::wp_fractional_scale_manager_v1; +use wayland::fractional_scale_v1::wp_fractional_scale_v1; +use wayland::viewporter::wp_viewporter; +use wayland::viewporter::wp_viewport; +use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1; +use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1; +use wayland::VirtualKeyboard; + +pub struct Dispatcher { + seat: Seat, VirtualKeyboard, Self>, + gfx: Arc>>>, +} + +impl Dispatcher { + pub fn new(layout: Layout, queue: QueueHandle, globals: &GlobalList) -> Result + { + let shm = globals.bind(&queue, 1..=1, ()) + .expect("Compositor must implement wl_shm"); + let compositor = globals.bind(&queue, 4..=6, ()) + .expect("Compositor must implement wl_compositor"); + let seat = globals.bind(&queue, 5..=9, ()) + .expect("Compositor must implement wl_seat"); + let layer_shell = globals.bind(&queue, 3..=4, ()) + .expect("Compositor must implement zwlr_layer_shell_v1"); + let vk_man = globals.bind(&queue, 1..=1, ()) + .expect("Compositor must implement zwp_virtual_keyboard_manager_v1"); + + let frac_scale_man = match globals.bind(&queue, 1..=1, ()) { + Ok(g) => Some(g), + Err(_) => None, + }; + + let vper = match globals.bind(&queue, 1..=1, ()) { + Ok(g) => Some(g), + Err(_) => None, + }; + + let disp = Surface::new(queue.clone(), + &shm, &compositor, &layer_shell, + frac_scale_man, vper, 185)?; + let gfx = Graphics::new(disp); + let gfx = Mutex::new(gfx); + let gfx = Arc::new(gfx); + + let vk = VirtualKeyboard::new(&queue, &vk_man, &seat); + + let seat = Seat::new(layout, vk, gfx.clone(), queue.clone(), seat); + + Ok(Dispatcher { + seat, + gfx, + }) + } + + #[inline(always)] + pub fn button(&self) -> &Button, VirtualKeyboard> + { + self.seat.button() + } + + pub fn dispatch_timers(&mut self) + { + self.seat.button_mut().dispatch_timers(); + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _buf: &wl_buffer::WlBuffer, + _evt: ::Event, + _data: &u32, + _conn: &Connection, + _qh: &QueueHandle) + { + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _comp: &wl_compositor::WlCompositor, + _evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + } +} + +impl Dispatch for Dispatcher { + fn event(ctx: &mut Dispatcher, + _ptr: &wl_pointer::WlPointer, + evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wl_pointer::Event::Motion { surface_x, surface_y, .. } => { + ctx.seat.ptr_motion(surface_x, surface_y); + }, + wl_pointer::Event::Button { state: WEnum::Value(state), .. } => { + ctx.seat.ptr_button(state); + }, + wl_pointer::Event::Frame => { + ctx.seat.commit(); + }, + wl_pointer::Event::Enter { .. } => (), + wl_pointer::Event::Leave { .. } => (), + _ => eprintln!("warn: unknown wl_pointer event emitted"), + }; + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _reg: &wl_registry::WlRegistry, + _evt: ::Event, + _data: &GlobalListContents, + _conn: &Connection, + _qh: &QueueHandle) + { + } +} + +impl Dispatch for Dispatcher { + fn event(ctx: &mut Dispatcher, + _seat: &wl_seat::WlSeat, + evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wl_seat::Event::Name { .. } => (), + wl_seat::Event::Capabilities { capabilities: WEnum::Value(caps) } => { + ctx.seat.set_capabilities(caps); + }, + _ => eprintln!("warn: unknown wl_seat event emitted"), + }; + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _shm: &wl_shm::WlShm, + evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wl_shm::Event::Format { .. } => (), + _ => eprintln!("warn: unknown wl_shm event emitted"), + }; + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &wl_shm_pool::WlShmPool, + _evt: ::Event, + _data: &u32, + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown wl_shm_pool event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &wl_surface::WlSurface, + evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wl_surface::Event::PreferredBufferTransform { .. } => (), + wl_surface::Event::PreferredBufferScale { .. } => (), // TODO + _ => eprintln!("warn: unknown wl_surface event emitted"), + } + } +} + +impl Dispatch for Dispatcher { + fn event(ctx: &mut Dispatcher, + _ptr: &wl_touch::WlTouch, + evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wl_touch::Event::Down { id, x, y, .. } => { + ctx.seat.touch_press(id as u32, x, y); + }, + wl_touch::Event::Motion { id, x, y, .. } => { + ctx.seat.touch_pos(id as u32, x, y); + }, + wl_touch::Event::Up { id, .. } => { + ctx.seat.touch_release(id as u32); + }, + wl_touch::Event::Frame => { + ctx.seat.commit(); + }, + _ => eprintln!("warn: unknown wl_touch event emitted"), + }; + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, + _evt: wp_fractional_scale_manager_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown wp_fractional_scale_manager_v1 event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(ctx: &mut Dispatcher, + _pool: &wp_fractional_scale_v1::WpFractionalScaleV1, + evt: wp_fractional_scale_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + wp_fractional_scale_v1::Event::PreferredScale { scale } => { + let mut gfx = ctx.gfx.lock().unwrap(); + + if scale == gfx.display().scale() { + return; + } + + let old_scale = gfx.display().scale(); + let (width, height) = gfx.display().size(); + let (width, height) = (width * scale / old_scale, + height * scale / old_scale); + + gfx.display_mut().update_scale(scale); + + if gfx.display().configured() { + let layout = ctx.seat.layout(); + let mod_state = ctx.seat.mod_state(); + + gfx.resize(layout, mod_state, width, height); + + let (width, height) = gfx.display().size(); + let width = width as f64 * 120.0 / scale as f64; + let height = height as f64 * 120.0 / scale as f64; + + ctx.seat.set_scale(layout.width() / width, + layout.height() / height); + } + }, + _ => eprintln!("warn: unknown wp_fractional_scale_v1 event emitted"), + }; + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &wp_viewporter::WpViewporter, + _evt: wp_viewporter::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown wp_viewporter event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &wp_viewport::WpViewport, + _evt: wp_viewport::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown wp_viewport event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _pool: &zwlr_layer_shell_v1::ZwlrLayerShellV1, + _evt: ::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown zwlr_layer_shell_v1 event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(ctx: &mut Dispatcher, + _surface: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + evt: zwlr_layer_surface_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + match evt { + zwlr_layer_surface_v1::Event::Configure { width, height, serial } => { + let mut gfx = ctx.gfx.lock().unwrap(); + + gfx.display_mut().ack_configure(serial); + + let layout = ctx.seat.layout(); + let mod_state = ctx.seat.mod_state(); + + let scale = gfx.display().scale() / 120; + let (width, height) = (width * scale, height * scale); + gfx.resize(layout, mod_state, width, height); + + let disp = gfx.display(); + let scale = disp.scale() as f64; + let (width, height) = disp.size(); + let width = width as f64 * 120.0 / scale; + let height = height as f64 * 120.0 / scale; + + ctx.seat.set_scale(layout.width() / width, + layout.height() / height); + }, + _ => eprintln!("warn: unknown zwlr_layer_surface_v1 event emitted"), + } + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _vk_man: &zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1, + _evt: zwp_virtual_keyboard_manager_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown zwp_virtual_keyboard_manager_v1 event emitted"); + } +} + +impl Dispatch for Dispatcher { + fn event(_ctx: &mut Dispatcher, + _vk: &zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1, + _evt: zwp_virtual_keyboard_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle) + { + eprintln!("warn: unknown zwp_virtual_keyboard_v1 event emitted"); + } +} diff --git a/src/wayland/keyboard.rs b/src/wayland/keyboard.rs new file mode 100644 index 0000000..279ecac --- /dev/null +++ b/src/wayland/keyboard.rs @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::Keyboard; +use core::Layout; +use core::Part; +use core::xkeysym::Keysym; +use std::collections::HashMap; +use std::fs::File; +use std::fs::OpenOptions; +use std::io::Seek; +use std::io::Write; +use std::os::fd::AsFd; +use std::process; +use wayland::wayland_client::Dispatch; +use wayland::wayland_client::QueueHandle; +use wayland::wayland_client::protocol::wl_seat::WlSeat; +use wayland::wayland_client::protocol::wl_keyboard::KeymapFormat; +use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1; +use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1; + +pub struct VirtualKeyboard { + vk: ZwpVirtualKeyboardV1, + keymap: File, + keymap_id: u8, + + keycodes: HashMap, + mod_state: u32, +} + +impl VirtualKeyboard { + pub fn new + + 'static>(queue: &QueueHandle, + vk_man: &ZwpVirtualKeyboardManagerV1, + seat: &WlSeat) + -> VirtualKeyboard + { + let vk = vk_man.create_virtual_keyboard(seat, queue, ()); + + let path = format!("/tmp/ufkbd-keymap-pid{}-1", process::id()); + let keymap = File::create(path).unwrap(); + + VirtualKeyboard { + vk, + keymap, + keymap_id: 1, + + keycodes: HashMap::new(), + mod_state: 0, + } + } + + fn write_key(&mut self, part: &Part, keycode: u8) + { + let sym = part.sym(); + let lower = &sym.name().unwrap()[3..]; + let upper = &Part::modify_shift(sym).name().unwrap()[3..]; + + write!(self.keymap, " key {{ [ {}, {} ] }};\n", + keycode, lower, upper).unwrap(); + + if sym == Keysym::Shift_L { + write!(self.keymap, + " modifier_map Shift {{ }};\n", + keycode).unwrap(); + } else if sym == Keysym::Control_L { + write!(self.keymap, + " modifier_map Control {{ }};\n", + keycode).unwrap(); + } else if sym == Keysym::Alt_L { + write!(self.keymap, + " modifier_map Mod1 {{ }};\n", + keycode).unwrap(); + } + } +} + +impl Keyboard for VirtualKeyboard { + fn press(&mut self, sym: Keysym) + { + if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn { + return; + } + + match sym { + Keysym::Shift_L => { + self.mod_state |= 0x1; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + Keysym::Control_L => { + self.mod_state |= 0x4; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + Keysym::Alt_L => { + self.mod_state |= 0x8; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + _ => (), + } + + let keycode = *self.keycodes.get(&sym).unwrap(); + self.vk.key(0, keycode as u32, 1); + } + + fn release(&mut self, sym: Keysym) + { + if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn { + return; + } + + match sym { + Keysym::Shift_L => { + self.mod_state &= !0x1; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + Keysym::Control_L => { + self.mod_state &= !0x4; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + Keysym::Alt_L => { + self.mod_state &= !0x8; + self.vk.modifiers(self.mod_state, 0, 0, 0); + }, + _ => (), + } + + let keycode = *self.keycodes.get(&sym).unwrap(); + self.vk.key(0, keycode as u32, 0); + } + + fn change_layout(&mut self, layout: &Layout) + { + let mut keycode = 8; + + self.keymap_id = match self.keymap_id { + 0 => 1, + 1 => 0, + _ => panic!("There should only be up to two keymaps"), + }; + + let path = format!("/tmp/ufkbd-keymap-pid{}-{}", + process::id(), self.keymap_id); + self.keymap = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + self.keymap.write(b"xkb_keymap {\n").unwrap(); + self.keymap.write(b" xkb_symbols \"ufkbd\" {\n").unwrap(); + + for row in layout.rows() { + for key in row { + for part in &key.parts { + if part.sym() == Keysym::NoSymbol || part.sym() == Keysym::XF86_Fn { + continue; + } + + self.keycodes.insert(part.sym(), keycode - 8); + self.write_key(part, keycode); + keycode += 1; + } + } + } + + self.keymap.write(b" };\n").unwrap(); + self.keymap.write(b"\n").unwrap(); + self.keymap.write(b" xkb_keycodes \"ufkbd\" {\n").unwrap(); + self.keymap.write(b" minimum = 8;\n").unwrap(); + self.keymap.write(b" maximum = 255;\n").unwrap(); + + for i in 8..keycode { + write!(self.keymap, " = {};\n", i, i).unwrap(); + } + + self.keymap.write(b" indicator 1 = \"Caps Lock\";\n").unwrap(); + self.keymap.write(b" };\n").unwrap(); + self.keymap.write(b"\n").unwrap(); + self.keymap.write(b" xkb_types \"ufkbd\" {\n").unwrap(); + self.keymap.write(b" type \"TWO_LEVEL\" {\n").unwrap(); + self.keymap.write(b" modifiers = Shift;\n").unwrap(); + self.keymap.write(b" map[Shift] = Level2;\n").unwrap(); + self.keymap.write(b" level_name[Level1] = \"Base\";\n").unwrap(); + self.keymap.write(b" level_name[Level2] = \"Shift\";\n").unwrap(); + self.keymap.write(b" };\n").unwrap(); + self.keymap.write(b" };\n").unwrap(); + self.keymap.write(b"\n").unwrap(); + self.keymap.write(b" xkb_compatibility \"ufkbd\" {\n").unwrap(); + self.keymap.write(b" };\n").unwrap(); + self.keymap.write(b"};\n").unwrap(); + + let len = self.keymap.stream_position().unwrap() as u32; + self.vk.keymap(KeymapFormat::XkbV1 as u32, self.keymap.as_fd(), len); + } +} diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs new file mode 100644 index 0000000..11fd815 --- /dev/null +++ b/src/wayland/mod.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +pub extern crate wayland_client; +pub extern crate wayland_protocols; +pub extern crate wayland_protocols_wlr; +pub extern crate wayland_scanner; + +mod buffer; +mod dispatcher; +mod keyboard; +mod protocols; +mod seat; +mod surface; + +pub use self::buffer::Buffer; +pub use self::dispatcher::Dispatcher; +pub use self::keyboard::VirtualKeyboard; +pub use self::seat::Seat; +pub use self::surface::Surface; + +pub use self::wayland_protocols_wlr::layer_shell::v1::client as wlr_layer_shell_unstable_v1; +pub use self::wayland_protocols::wp::fractional_scale::v1::client as fractional_scale_v1; +pub use self::wayland_protocols::wp::text_input::zv3::client as text_input_unstable_v3; +pub use self::wayland_protocols::wp::viewporter::client as viewporter; + +pub use self::protocols::input_method_unstable_v2; +pub use self::protocols::virtual_keyboard_unstable_v1; diff --git a/src/wayland/protocols.rs b/src/wayland/protocols.rs new file mode 100644 index 0000000..bc96c25 --- /dev/null +++ b/src/wayland/protocols.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +pub mod input_method_unstable_v2 { + use wayland::wayland_client; + use wayland::wayland_client::protocol::*; + use wayland::text_input_unstable_v3::*; + + pub mod __interfaces { + use wayland::wayland_client::protocol::__interfaces::*; + + wayland_scanner::generate_interfaces!("wayland-protocols/input-method-unstable-v2.xml"); + } + + use self::__interfaces::*; + + wayland_scanner::generate_client_code!("wayland-protocols/input-method-unstable-v2.xml"); +} + +pub mod virtual_keyboard_unstable_v1 { + use wayland::wayland_client; + use wayland::wayland_client::protocol::*; + + pub mod __interfaces { + use wayland::wayland_client::protocol::__interfaces::*; + + wayland_scanner::generate_interfaces!("wayland-protocols/virtual-keyboard-unstable-v1.xml"); + } + + use self::__interfaces::*; + + wayland_scanner::generate_client_code!("wayland-protocols/virtual-keyboard-unstable-v1.xml"); +} diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs new file mode 100644 index 0000000..9cf566e --- /dev/null +++ b/src/wayland/seat.rs @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::Button; +use core::ModState; +use core::Display; +use core::Graphics; +use core::Keyboard; +use core::Layout; +use std::sync::Arc; +use std::sync::Mutex; +use wayland::wayland_client::protocol::wl_pointer; +use wayland::wayland_client::protocol::wl_seat; +use wayland::wayland_client::protocol::wl_touch::WlTouch; +use wayland::wayland_client::Dispatch; +use wayland::wayland_client::QueueHandle; + +enum PressAction { + Pos(f64, f64), + Press(f64, f64), + Release, +} + +struct TouchAction { + id: usize, + act: PressAction, +} + +pub struct Seat { + seat: wl_seat::WlSeat, + queue: QueueHandle, + + ptr: Option, + touch: Option, + + button: Button, + + x_scale: f64, + y_scale: f64, + + mouse_x: f64, + mouse_y: f64, + actions: Vec, +} + +impl + + Dispatch + + 'static> Seat { + pub fn new(layout: Layout, kbd: K, gfx: Arc>>, + queue: QueueHandle, seat: wl_seat::WlSeat) -> Seat + { + let actions = Vec::new(); + let button = Button::new(layout, kbd, gfx); + + Seat { + seat, + queue, + + ptr: None, + touch: None, + + button, + + x_scale: 0.0, + y_scale: 0.0, + + mouse_x: 0.0, + mouse_y: 0.0, + actions, + } + } + + #[inline(always)] + pub fn button(&self) -> &Button + { + &self.button + } + + #[inline(always)] + pub fn button_mut(&mut self) -> &mut Button + { + &mut self.button + } + + #[inline(always)] + pub fn layout(&self) -> &Layout + { + self.button.layout() + } + + #[inline(always)] + pub fn mod_state(&self) -> &[ModState] + { + self.button.mod_state() + } + + pub fn set_capabilities(&mut self, caps: wl_seat::Capability) + { + if caps.contains(wl_seat::Capability::Pointer) { + self.ptr = Some(self.seat.get_pointer(&self.queue, ())); + } + + if caps.contains(wl_seat::Capability::Touch) { + self.touch = Some(self.seat.get_touch(&self.queue, ())); + } + } + + pub fn set_scale(&mut self, x_scale: f64, y_scale: f64) + { + self.x_scale = x_scale; + self.y_scale = y_scale; + } + + pub fn ptr_motion(&mut self, x: f64, y: f64) + { + let (x, y) = (x * self.x_scale, y * self.y_scale); + + self.mouse_x = x; + self.mouse_y = y; + + let act = TouchAction { id: 0, act: PressAction::Pos(x, y), }; + self.actions.push(act); + } + + pub fn ptr_button(&mut self, state: wl_pointer::ButtonState) + { + match state { + wl_pointer::ButtonState::Pressed => { + let (x, y) = (self.mouse_x, self.mouse_y); + let act = TouchAction { id: 0, act: PressAction::Press(x, y), }; + self.actions.push(act); + }, + wl_pointer::ButtonState::Released => { + let act = TouchAction { id: 0, act: PressAction::Release, }; + self.actions.push(act); + }, + _ => eprintln!("warn: ignoring unknown pointer event"), + } + } + + pub fn touch_press(&mut self, id: u32, x: f64, y: f64) + { + let id = id as usize + 1; + let (x, y) = (x * self.x_scale, y * self.y_scale); + let act = TouchAction { id, act: PressAction::Press(x, y), }; + self.actions.push(act); + } + + pub fn touch_pos(&mut self, id: u32, x: f64, y: f64) + { + let id = id as usize + 1; + let (x, y) = (x * self.x_scale, y * self.y_scale); + let act = TouchAction { id, act: PressAction::Pos(x, y), }; + self.actions.push(act); + } + + pub fn touch_release(&mut self, id: u32) + { + let id = id as usize + 1; + let act = TouchAction { id, act: PressAction::Release, }; + self.actions.push(act); + } + + pub fn commit(&mut self) + { + for action in &self.actions { + match action.act { + PressAction::Press(x, y) => { + self.button.press(action.id, x, y); + }, + PressAction::Pos(x, y) => { + self.button.pos(action.id, x, y); + }, + PressAction::Release => { + self.button.release(action.id); + }, + } + } + + // Reset the action for the next frame. + self.actions.clear(); + } +} diff --git a/src/wayland/surface.rs b/src/wayland/surface.rs new file mode 100644 index 0000000..149acb0 --- /dev/null +++ b/src/wayland/surface.rs @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Copyright (c) 2024, Richard Acayan. All rights reserved. + */ + +use core::Display; +use core::imgref::ImgRefMut; +use core::rgb::alt::BGRA; +use std::io::Error; +use wayland::Buffer; +use wayland::wayland_client::protocol::wl_buffer::WlBuffer; +use wayland::wayland_client::protocol::wl_compositor::WlCompositor; +use wayland::wayland_client::protocol::wl_shm_pool::WlShmPool; +use wayland::wayland_client::protocol::wl_shm::WlShm; +use wayland::wayland_client::protocol::wl_surface::WlSurface; +use wayland::wayland_client::Dispatch; +use wayland::wayland_client::QueueHandle; +use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_shell_v1; +use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1; +use wayland::fractional_scale_v1::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1; +use wayland::fractional_scale_v1::wp_fractional_scale_v1::WpFractionalScaleV1; +use wayland::viewporter::wp_viewporter::WpViewporter; +use wayland::viewporter::wp_viewport::WpViewport; + +pub struct Surface { + bufs: [Buffer; 2], + surface: WlSurface, + layer_surf: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + vp: Option, + + used_buf: usize, + configured: bool, + scale: u32, +} + +const LAYER_ANCHOR: zwlr_layer_surface_v1::Anchor + = zwlr_layer_surface_v1::Anchor::from_bits_truncate(0) + .union(zwlr_layer_surface_v1::Anchor::Bottom) + .union(zwlr_layer_surface_v1::Anchor::Left) + .union(zwlr_layer_surface_v1::Anchor::Right); + +impl + + Dispatch + + Dispatch + + Dispatch + + Dispatch + + Dispatch + + 'static> Surface { + pub fn new(queue: QueueHandle, shm: &WlShm, comp: &WlCompositor, + layer_shell: &zwlr_layer_shell_v1::ZwlrLayerShellV1, + frac_scale_man: Option, + vper: Option, + size: i32) + -> Result, Error> + { + let buf1 = Buffer::new(queue.clone(), shm, 0)?; + let buf2 = Buffer::new(queue.clone(), shm, 1)?; + + let surface = comp.create_surface(&queue, ()); + + let layer_surf = layer_shell.get_layer_surface(&surface, None, + zwlr_layer_shell_v1::Layer::Top, + String::from("osk-ufkbd"), + &queue, ()); + + frac_scale_man.map(|fsm| fsm.get_fractional_scale(&surface, &queue, ())); + + let vp = vper.map(|vper| vper.get_viewport(&surface, &queue, ())); + + layer_surf.set_size(0, size as u32); + layer_surf.set_exclusive_zone(size); + layer_surf.set_anchor(LAYER_ANCHOR); + + surface.commit(); + + Ok(Surface { + bufs: [buf1, buf2], + surface, + layer_surf, + vp, + used_buf: 1, + configured: false, + scale: 120, + }) + } + + pub fn configured(&self) -> bool + { + self.configured + } + + pub fn ack_configure(&mut self, serial: u32) + { + self.configured = true; + self.layer_surf.ack_configure(serial); + } + + pub fn scale(&self) -> u32 + { + self.scale + } + + pub fn update_scale(&mut self, scale: u32) + { + self.scale = scale; + } +} + +impl + + Dispatch + + Dispatch + + Dispatch + + Dispatch + + Dispatch + + 'static> Display for Surface { + #[inline(always)] + fn size(&self) -> (u32, u32) + { + let (width, height) = self.bufs[self.used_buf].size(); + (width as u32, height as u32) + } + + fn begin(&mut self) -> ImgRefMut> + { + for (id, buf) in self.bufs.iter_mut().enumerate() { + if let Some(img) = buf.consume(&self.surface) { + self.used_buf = id; + return img; + } + } + + panic!("No buffers available") + } + + fn resize(&mut self, width: u32, height: u32) + { + let width_unscaled = (width * 120 / self.scale) as i32; + let height_unscaled = (height * 120 / self.scale) as i32; + + for buf in &mut self.bufs { + buf.resize(width as i32, height as i32).unwrap(); + } + + if let Some(vp) = &self.vp { + vp.set_source(0.0, 0.0, width as f64, height as f64); + vp.set_destination(width_unscaled, height_unscaled); + } + } + + fn end(&mut self, x: u32, y: u32, width: u32, height: u32) + { + self.surface.damage_buffer(x as i32, y as i32, width as i32, height as i32); + self.surface.commit(); + + for (id, buf) in self.bufs.iter_mut().enumerate() { + if id != self.used_buf { + buf.release(); + } + } + + let (src, dest) = match self.used_buf { + 0 => { + let [src, ref mut dest] = &mut self.bufs; + (src, dest) + }, + 1 => { + let [ref mut dest, src] = &mut self.bufs; + (src, dest) + }, + 2.. => panic!("Surface must only use two buffers"), + }; + + let img = src.image().sub_image(x as usize, + y as usize, + width as usize, + height as usize); + dest.writeback(&img, x as usize, y as usize); + } +} diff --git a/wayland/protocols/input-method-unstable-v2.xml b/wayland-protocols/input-method-unstable-v2.xml similarity index 100% rename from wayland/protocols/input-method-unstable-v2.xml rename to wayland-protocols/input-method-unstable-v2.xml diff --git a/wayland/protocols/virtual-keyboard-unstable-v1.xml b/wayland-protocols/virtual-keyboard-unstable-v1.xml similarity index 100% rename from wayland/protocols/virtual-keyboard-unstable-v1.xml rename to wayland-protocols/virtual-keyboard-unstable-v1.xml diff --git a/wayland/buffer.c b/wayland/buffer.c deleted file mode 100644 index 92c7448..0000000 --- a/wayland/buffer.c +++ /dev/null @@ -1,218 +0,0 @@ -// 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 void on_buffer_release(void *data, struct wl_buffer *buf) -{ - struct ufkbd_wl_buffer *ctx = data; - - ufkbd_wl_buffer_release(ctx); -} - -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; -} - -void ufkbd_wl_buffer_release(struct ufkbd_wl_buffer *ctx) -{ - if (ctx->resize) - commit_buffer_resize(ctx); - - ctx->avail = true; -} - -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 deleted file mode 100644 index 887f47e..0000000 --- a/wayland/driver.c +++ /dev/null @@ -1,246 +0,0 @@ -// 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; - } - - // 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); - ufkbd_wl_surface_release_unused(ctx->surface); -} - -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 deleted file mode 100644 index 0454e6e..0000000 --- a/wayland/input.c +++ /dev/null @@ -1,316 +0,0 @@ -// 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 deleted file mode 100644 index 090166b..0000000 --- a/wayland/protocols/fractional-scale-v1.c +++ /dev/null @@ -1,73 +0,0 @@ -/* 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 deleted file mode 100644 index 41a7b45..0000000 --- a/wayland/protocols/input-method-unstable-v2.c +++ /dev/null @@ -1,132 +0,0 @@ -/* 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/viewporter.c b/wayland/protocols/viewporter.c deleted file mode 100644 index fa70d5d..0000000 --- a/wayland/protocols/viewporter.c +++ /dev/null @@ -1,74 +0,0 @@ -/* 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 deleted file mode 100644 index 60b847e..0000000 --- a/wayland/protocols/virtual-keyboard-unstable-v1.c +++ /dev/null @@ -1,77 +0,0 @@ -/* 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/wlr-layer-shell-unstable-v1.c b/wayland/protocols/wlr-layer-shell-unstable-v1.c deleted file mode 100644 index ecf00c5..0000000 --- a/wayland/protocols/wlr-layer-shell-unstable-v1.c +++ /dev/null @@ -1,93 +0,0 @@ -/* 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 deleted file mode 100644 index d62fd51..0000000 --- a/wayland/protocols/wlr-layer-shell-unstable-v1.xml +++ /dev/null @@ -1,390 +0,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. - - - - - 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 deleted file mode 100644 index 03826cd..0000000 --- a/wayland/protocols/xdg-shell.c +++ /dev/null @@ -1,183 +0,0 @@ -/* 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 deleted file mode 100644 index 22257ac..0000000 --- a/wayland/surface.c +++ /dev/null @@ -1,299 +0,0 @@ -// 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, i; - - if (buf == NULL || ptr == NULL) - return -EINVAL; - - for (i = 0; i < 2; i++) { - ret = ufkbd_wl_buffer_consume(&ctx->bufs[i], buf, ptr); - if (!ret) { - wl_surface_attach(ctx->wl, *buf, 0, 0); - ctx->used_buf = i; - break; - } - - if (ret != -EBUSY) - break; - } - - 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); -} - -void ufkbd_wl_surface_release_unused(struct ufkbd_wl_surface *ctx) -{ - int i; - - for (i = 0; i < 2; i++) { - if (i != ctx->used_buf) - ufkbd_wl_buffer_release(&ctx->bufs[i]); - } -} - -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; - ctx->used_buf = -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 deleted file mode 100644 index a409fc4..0000000 --- a/wayland/wayland.h +++ /dev/null @@ -1,152 +0,0 @@ -/* 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; - - int used_buf; - 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); -void ufkbd_wl_buffer_release(struct ufkbd_wl_buffer *ctx); -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); -void ufkbd_wl_surface_release_unused(struct ufkbd_wl_surface *ctx); -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 */