diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 13:44:13 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 13:44:13 +0300 |
| commit | c059e3aa7f93da470f052a5cd8ee0d8dc969e679 (patch) | |
| tree | 63ffa378287ed2c606eda2e940501b9edc3d2b8b /src/platform/wayland/ime.c | |
| parent | 87d0bc50d53dc216efb2b04495f090616318bc5c (diff) | |
rename and simplification
Diffstat (limited to 'src/platform/wayland/ime.c')
| -rw-r--r-- | src/platform/wayland/ime.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/platform/wayland/ime.c b/src/platform/wayland/ime.c new file mode 100644 index 0000000..bd9375b --- /dev/null +++ b/src/platform/wayland/ime.c @@ -0,0 +1,176 @@ +#include "internal.h" + +#define IME_TEXT_MAX (256u * 1024) + +static void show_preedit(struct wayland_surface *w, char *text, int begin, int end) +{ + bool changed = (text || w->ime_shown) && + (!text || !w->ime_shown || strcmp(text, w->ime_shown) || + begin != w->ime_shown_begin || end != w->ime_shown_end); + free(w->ime_shown); + w->ime_shown = text; + w->ime_shown_begin = begin; + w->ime_shown_end = end; + if (changed) + wayland_surface_schedule_redraw(w); +} + +void ime_reset(struct wayland_surface *w) +{ + free(w->ime_preedit); + w->ime_preedit = NULL; + free(w->ime_commit); + w->ime_commit = NULL; + show_preedit(w, NULL, -1, -1); +} + +void ime_send_caret(struct wayland_surface *w) +{ + struct seat *seat = w->ime_seat; + if (!seat || !seat->text_input) + return; + uint32_t scale = w->scale_120 ? w->scale_120 : YASL_SCALE_UNIT; + zwp_text_input_v3_set_cursor_rectangle(seat->text_input, + yasl_scale_to_logical(w->ime_caret.x, scale), + yasl_scale_to_logical(w->ime_caret.y, scale), + yasl_scale_to_logical(w->ime_caret.width, scale), + yasl_scale_to_logical(w->ime_caret.height, scale)); + zwp_text_input_v3_commit(seat->text_input); +} + +const char *wayland_surface_ime_preedit(const struct wayland_surface *w) +{ + return w ? w->ime_shown : NULL; +} + +bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *w, int *begin, int *end) +{ + if (!w || !w->ime_shown || w->ime_shown_begin < 0) + return false; + *begin = w->ime_shown_begin; + *end = w->ime_shown_end; + return true; +} + +void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_rect2i caret) +{ + if (!w || (w->ime_caret.x == caret.x && w->ime_caret.y == caret.y && + w->ime_caret.width == caret.width && w->ime_caret.height == caret.height)) + return; + w->ime_caret = caret; + ime_send_caret(w); +} + +static void text_input_enter(void *data, struct zwp_text_input_v3 *text_input, + struct wl_surface *surface) +{ + struct seat *s = data; + struct wayland_surface *w = surface_root(conn_surface_for(s->conn, surface)); + s->ime_focus = w; + if (!w) return; + zwp_text_input_v3_enable(text_input); + zwp_text_input_v3_set_content_type(text_input, + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL); + w->ime_seat = s; + ime_send_caret(w); +} + +static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input, + struct wl_surface *surface) +{ + (void)surface; + struct seat *s = data; + struct wayland_surface *w = s->ime_focus; + s->ime_focus = NULL; + if (!w) return; + zwp_text_input_v3_disable(text_input); + zwp_text_input_v3_commit(text_input); + if (w->ime_seat == s) + w->ime_seat = NULL; + ime_reset(w); +} + +static void text_input_preedit_string(void *data, + struct zwp_text_input_v3 *text_input, const char *text, + int32_t cursor_begin, int32_t cursor_end) +{ + (void)text_input; + struct wayland_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + keyboard_text_reset((struct seat *)data); + free(w->ime_preedit); + w->ime_preedit = text ? strndup(text, IME_TEXT_MAX) : NULL; + int len = w->ime_preedit ? (int)strlen(w->ime_preedit) : 0; + bool shown = cursor_begin >= 0 && cursor_end >= cursor_begin && + cursor_end <= len; + w->ime_cursor_begin = shown ? cursor_begin : -1; + w->ime_cursor_end = shown ? cursor_end : -1; +} + +static void text_input_commit_string(void *data, + struct zwp_text_input_v3 *text_input, const char *text) +{ + (void)text_input; + struct wayland_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + keyboard_text_reset((struct seat *)data); + free(w->ime_commit); + w->ime_commit = (text && text[0]) ? strndup(text, IME_TEXT_MAX) : NULL; +} + +static void text_input_delete_surrounding_text(void *data, + struct zwp_text_input_v3 *text_input, uint32_t before_length, + uint32_t after_length) +{ + (void)data; (void)text_input; (void)before_length; (void)after_length; +} + +static void text_input_done(void *data, struct zwp_text_input_v3 *text_input, + uint32_t serial) +{ + (void)text_input; (void)serial; + struct wayland_surface *w = ((struct seat *)data)->ime_focus; + if (!w) return; + if (w->ime_commit) { + struct yasl_input_event ev = { + .kind = YASL_INPUT_TEXT, + .surface = &w->base, + .text = { .text = w->ime_commit, .len = strlen(w->ime_commit) }, + }; + input_queue_push(&w->input, &ev); + free(w->ime_commit); + w->ime_commit = NULL; + } + char *preedit = w->ime_preedit && w->ime_preedit[0] ? w->ime_preedit : NULL; + if (!preedit) + free(w->ime_preedit); + w->ime_preedit = NULL; + show_preedit(w, preedit, preedit ? w->ime_cursor_begin : -1, + preedit ? w->ime_cursor_end : -1); + w->ime_cursor_begin = w->ime_cursor_end = -1; +} + +static void text_input_action(void *data, struct zwp_text_input_v3 *text_input, + uint32_t action, uint32_t serial) +{ (void)data; (void)text_input; (void)action; (void)serial; } + +static void text_input_language(void *data, struct zwp_text_input_v3 *text_input, + const char *language) +{ (void)data; (void)text_input; (void)language; } + +static void text_input_preedit_hint(void *data, struct zwp_text_input_v3 *text_input, + uint32_t start, uint32_t end, uint32_t hint) +{ (void)data; (void)text_input; (void)start; (void)end; (void)hint; } + +const struct zwp_text_input_v3_listener text_input_listener = { + .action = text_input_action, + .language = text_input_language, + .preedit_hint = text_input_preedit_hint, + .enter = text_input_enter, + .leave = text_input_leave, + .preedit_string = text_input_preedit_string, + .commit_string = text_input_commit_string, + .delete_surrounding_text = text_input_delete_surrounding_text, + .done = text_input_done, +}; |
