mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
ime: render pre-edit text
This is done by allocating cells for the pre-edit text when receiving the text-input::done() call, and populating them by converting the utf-8 formatted pre-edit text to wchars. We also convert the pre-edit cursor position to cell positions (it can cover multiple cells). When rendering, we simply render the pre-edit cells on-top off the regular grid. While doing so, we also mark the underlying, “real”, cells as dirty, to ensure they are re-rendered when the pre-edit text is modified or removed.
This commit is contained in:
parent
5745c610ac
commit
8c3d48c5cd
8 changed files with 364 additions and 60 deletions
209
ime.c
209
ime.c
|
|
@ -5,9 +5,11 @@
|
|||
#include "text-input-unstable-v3.h"
|
||||
|
||||
#define LOG_MODULE "ime"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "render.h"
|
||||
#include "terminal.h"
|
||||
#include "util.h"
|
||||
#include "wayland.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
|
|
@ -64,6 +66,12 @@ leave(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
|
|||
zwp_text_input_v3_disable(seat->wl_text_input);
|
||||
zwp_text_input_v3_commit(seat->wl_text_input);
|
||||
seat->ime.serial++;
|
||||
|
||||
free(seat->ime.preedit.pending.text);
|
||||
seat->ime.preedit.pending.text = NULL;
|
||||
|
||||
free(seat->ime.commit.pending.text);
|
||||
seat->ime.commit.pending.text = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -71,12 +79,13 @@ preedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
|
|||
const char *text, int32_t cursor_begin, int32_t cursor_end)
|
||||
{
|
||||
LOG_DBG("preedit-string: text=%s, begin=%d, end=%d", text, cursor_begin, cursor_end);
|
||||
|
||||
struct seat *seat = data;
|
||||
|
||||
free(seat->ime.preedit.text);
|
||||
seat->ime.preedit.text = text != NULL ? xstrdup(text) : NULL;
|
||||
seat->ime.preedit.cursor_begin = cursor_begin;
|
||||
seat->ime.preedit.cursor_end = cursor_end;
|
||||
free(seat->ime.preedit.pending.text);
|
||||
seat->ime.preedit.pending.text = text != NULL ? xstrdup(text) : NULL;
|
||||
seat->ime.preedit.pending.cursor_begin = cursor_begin;
|
||||
seat->ime.preedit.pending.cursor_end = cursor_end;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -84,10 +93,10 @@ commit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
|
|||
const char *text)
|
||||
{
|
||||
LOG_DBG("commit: text=%s", text);
|
||||
|
||||
struct seat *seat = data;
|
||||
free(seat->ime.commit.text);
|
||||
seat->ime.commit.text = text != NULL ? xstrdup(text) : NULL;
|
||||
//term_to_slave(seat->kbd_focus, text, strlen(text));
|
||||
free(seat->ime.commit.pending.text);
|
||||
seat->ime.commit.pending.text = text != NULL ? xstrdup(text) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -95,9 +104,10 @@ delete_surrounding_text(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
|
|||
uint32_t before_length, uint32_t after_length)
|
||||
{
|
||||
LOG_DBG("delete-surrounding: before=%d, after=%d", before_length, after_length);
|
||||
|
||||
struct seat *seat = data;
|
||||
seat->ime.surrounding.before_length = before_length;
|
||||
seat->ime.surrounding.after_length = after_length;
|
||||
seat->ime.surrounding.pending.before_length = before_length;
|
||||
seat->ime.surrounding.pending.after_length = after_length;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -105,30 +115,185 @@ done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
|
|||
uint32_t serial)
|
||||
{
|
||||
/*
|
||||
* From text-input-unstable-v3.h:
|
||||
*
|
||||
* The application must proceed by evaluating the changes in the
|
||||
* following order:
|
||||
*
|
||||
* 1. Replace existing preedit string with the cursor. 2. Delete
|
||||
* requested surrounding text. 3. Insert commit string with the
|
||||
* cursor at its end. 4. Calculate surrounding text to send. 5.
|
||||
* Insert new preedit text in cursor position. 6. Place cursor
|
||||
* inside preedit text.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
LOG_DBG("done: serial=%u", serial);
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->ime.serial != serial)
|
||||
LOG_WARN("IME serial mismatch: expected=0x%08x, got 0x%08x",
|
||||
seat->ime.serial, serial);
|
||||
if (seat->ime.serial != serial) {
|
||||
LOG_DBG("IME serial mismatch: expected=0x%08x, got 0x%08x",
|
||||
seat->ime.serial, serial);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(seat->kbd_focus);
|
||||
struct terminal *term = seat->kbd_focus;
|
||||
|
||||
if (seat->ime.commit.text != NULL)
|
||||
term_to_slave(seat->kbd_focus, seat->ime.commit.text, strlen(seat->ime.commit.text));
|
||||
/* 1. Delete existing pre-edit text */
|
||||
if (term->ime.preedit.cells != NULL) {
|
||||
free(term->ime.preedit.cells);
|
||||
term->ime.preedit.cells = NULL;
|
||||
term->ime.preedit.count = 0;
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
free(seat->ime.commit.text);
|
||||
seat->ime.commit.text = NULL;
|
||||
/*
|
||||
* 2. Delete requested surroundin text
|
||||
*
|
||||
* We don't support deleting surrounding text. But, we also never
|
||||
* call set_surrounding_text() so hopefully we should never
|
||||
* receive any requests to delete surrounding text.
|
||||
*/
|
||||
|
||||
/* 3. Insert commit string */
|
||||
if (seat->ime.commit.pending.text != NULL) {
|
||||
term_to_slave(
|
||||
term,
|
||||
seat->ime.commit.pending.text,
|
||||
strlen(seat->ime.commit.pending.text));
|
||||
|
||||
free(seat->ime.commit.pending.text);
|
||||
seat->ime.commit.pending.text = NULL;
|
||||
}
|
||||
|
||||
/* 4. Calculate surrounding text to send - not supported */
|
||||
|
||||
/* 5. Insert new pre-edit text */
|
||||
size_t wchars = seat->ime.preedit.pending.text != NULL
|
||||
? mbstowcs(NULL, seat->ime.preedit.pending.text, 0)
|
||||
: 0;
|
||||
|
||||
if (wchars > 0) {
|
||||
/* First, convert to unicode */
|
||||
wchar_t wcs[wchars + 1];
|
||||
mbstowcs(wcs, seat->ime.preedit.pending.text, wchars);
|
||||
|
||||
/* Next, count number of cells needed */
|
||||
size_t cell_count = 0;
|
||||
for (size_t i = 0; i < wchars; i++)
|
||||
cell_count += max(wcwidth(wcs[i]), 1);
|
||||
|
||||
/* Allocate cells */
|
||||
term->ime.preedit.cells = xmalloc(
|
||||
cell_count * sizeof(term->ime.preedit.cells[0]));
|
||||
term->ime.preedit.count = cell_count;
|
||||
|
||||
/* Populate cells */
|
||||
for (size_t i = 0, cell_idx = 0; i < wchars; i++) {
|
||||
struct cell *cell = &term->ime.preedit.cells[cell_idx];
|
||||
|
||||
int width = max(wcwidth(wcs[i]), 1);
|
||||
|
||||
cell->wc = wcs[i];
|
||||
cell->attrs = (struct attributes){.clean = 0, .underline = 1};
|
||||
|
||||
for (int j = 1; j < width; j++) {
|
||||
cell = &term->ime.preedit.cells[cell_idx + j];
|
||||
cell->wc = CELL_MULT_COL_SPACER;
|
||||
cell->attrs = (struct attributes){.clean = 1};
|
||||
}
|
||||
|
||||
cell_idx += width;
|
||||
}
|
||||
|
||||
/* Pre-edit cursor - hidden */
|
||||
if (seat->ime.preedit.pending.cursor_begin == -1 ||
|
||||
seat->ime.preedit.pending.cursor_end == -1)
|
||||
{
|
||||
/* Note: docs says *both* begin and end should be -1,
|
||||
* but what else can we do if only one is -1? */
|
||||
LOG_DBG("pre-edit cursor is hidden");
|
||||
term->ime.preedit.cursor.hidden = true;
|
||||
term->ime.preedit.cursor.start = -1;
|
||||
term->ime.preedit.cursor.end = -1;
|
||||
}
|
||||
|
||||
else {
|
||||
/*
|
||||
* Translate cursor position to cell indices
|
||||
*
|
||||
* The cursor_begin and cursor_end are counted in
|
||||
* *bytes*. We want to map them to *cell* indices.
|
||||
*
|
||||
* To do this, we use mblen() to step though the utf-8
|
||||
* pre-edit string, advancing a unicode character index as
|
||||
* we go, *and* advancing a *cell* index using wcwidth()
|
||||
* of the unicode character.
|
||||
*
|
||||
* When we find the matching *byte* index, we at the same
|
||||
* time know both the unicode *and* cell index.
|
||||
*
|
||||
* Note that this has only been tested with
|
||||
*
|
||||
* cursor_begin == cursor_end == 0
|
||||
*
|
||||
* I haven't found an IME that requests anything else
|
||||
*/
|
||||
|
||||
const size_t byte_len = strlen(seat->ime.preedit.pending.text);
|
||||
|
||||
int cell_begin = -1, cell_end = -1;
|
||||
for (size_t byte_idx = 0, wc_idx = 0, cell_idx = 0;
|
||||
byte_idx < byte_len &&
|
||||
wc_idx < wchars &&
|
||||
cell_idx < cell_count &&
|
||||
(cell_begin < 0 || cell_end < 0);
|
||||
)
|
||||
{
|
||||
if (seat->ime.preedit.pending.cursor_begin == byte_idx)
|
||||
cell_begin = cell_idx;
|
||||
if (seat->ime.preedit.pending.cursor_end == byte_idx)
|
||||
cell_end = cell_idx;
|
||||
|
||||
/* Number of bytes of *next* utf-8 character */
|
||||
size_t left = byte_len - byte_idx;
|
||||
int wc_bytes = mblen(&seat->ime.preedit.pending.text[byte_idx], left);
|
||||
|
||||
if (wc_bytes <= 0)
|
||||
break;
|
||||
|
||||
byte_idx += wc_bytes;
|
||||
cell_idx += max(wcwidth(term->ime.preedit.cells[wc_idx].wc), 1);
|
||||
wc_idx++;
|
||||
}
|
||||
|
||||
/* Bounded by number of screen columns */
|
||||
cell_begin = min(max(cell_begin, 0), cell_count - 1);
|
||||
|
||||
/* Ensure end comes *after* begin, and is bounded by screen */
|
||||
if (cell_end <= cell_begin)
|
||||
cell_end = cell_begin + max(wcwidth(term->ime.preedit.cells[cell_begin].wc), 1);
|
||||
cell_end = min(max(cell_end, 0), cell_count);
|
||||
|
||||
LOG_DBG("pre-edit cursor: begin=%d, end=%d", cell_begin, cell_end);
|
||||
|
||||
assert(cell_begin >= 0);
|
||||
assert(cell_begin < cell_count);
|
||||
assert(cell_end >= 1);
|
||||
assert(cell_end <= cell_count);
|
||||
assert(cell_begin < cell_end);
|
||||
|
||||
term->ime.preedit.cursor.hidden = false;
|
||||
term->ime.preedit.cursor.start = cell_begin;
|
||||
term->ime.preedit.cursor.end = cell_end;
|
||||
}
|
||||
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
free(seat->ime.preedit.pending.text);
|
||||
seat->ime.preedit.pending.text = NULL;
|
||||
}
|
||||
|
||||
const struct zwp_text_input_v3_listener text_input_listener = {
|
||||
|
|
|
|||
4
input.c
4
input.c
|
|
@ -21,7 +21,7 @@
|
|||
#include <xdg-shell.h>
|
||||
|
||||
#define LOG_MODULE "input"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "commands.h"
|
||||
|
|
@ -752,7 +752,7 @@ keymap_lookup(struct seat *seat, struct terminal *term,
|
|||
const enum keypad_keys keypad_keys_mode
|
||||
= term->num_lock_modifier ? KEYPAD_NUMERICAL : term->keypad_keys_mode;
|
||||
|
||||
log_dbg("keypad mode: %d, num-lock=%d", keypad_keys_mode, seat->kbd.num);
|
||||
LOG_DBG("keypad mode: %d, num-lock=%d", keypad_keys_mode, seat->kbd.num);
|
||||
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
if (info[j].modifiers != MOD_ANY && info[j].modifiers != mods)
|
||||
|
|
|
|||
162
render.c
162
render.c
|
|
@ -313,6 +313,35 @@ draw_strikeout(const struct terminal *term, pixman_image_t *pix,
|
|||
cols * term->cell_width, font->strikeout.thickness});
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_colors_for_cell(const struct terminal *term, const struct cell *cell,
|
||||
const pixman_color_t *fg, const pixman_color_t *bg,
|
||||
pixman_color_t *cursor_color, pixman_color_t *text_color)
|
||||
{
|
||||
bool is_selected = cell->attrs.selected;
|
||||
|
||||
if (term->cursor_color.cursor >> 31) {
|
||||
*cursor_color = color_hex_to_pixman(term->cursor_color.cursor);
|
||||
*text_color = color_hex_to_pixman(
|
||||
term->cursor_color.text >> 31
|
||||
? term->cursor_color.text : term->colors.bg);
|
||||
|
||||
if (term->reverse ^ cell->attrs.reverse ^ is_selected) {
|
||||
pixman_color_t swap = *cursor_color;
|
||||
*cursor_color = *text_color;
|
||||
*text_color = swap;
|
||||
}
|
||||
|
||||
if (term->is_searching && !is_selected) {
|
||||
color_dim_for_search(cursor_color);
|
||||
color_dim_for_search(text_color);
|
||||
}
|
||||
} else {
|
||||
*cursor_color = *fg;
|
||||
*text_color = *bg;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_cursor(const struct terminal *term, const struct cell *cell,
|
||||
const struct fcft_font *font, pixman_image_t *pix, pixman_color_t *fg,
|
||||
|
|
@ -320,36 +349,14 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
|
|||
{
|
||||
pixman_color_t cursor_color;
|
||||
pixman_color_t text_color;
|
||||
|
||||
bool is_selected = cell->attrs.selected;
|
||||
|
||||
if (term->cursor_color.cursor >> 31) {
|
||||
cursor_color = color_hex_to_pixman(term->cursor_color.cursor);
|
||||
text_color = color_hex_to_pixman(
|
||||
term->cursor_color.text >> 31
|
||||
? term->cursor_color.text : term->colors.bg);
|
||||
|
||||
if (term->reverse ^ cell->attrs.reverse ^ is_selected) {
|
||||
pixman_color_t swap = cursor_color;
|
||||
cursor_color = text_color;
|
||||
text_color = swap;
|
||||
}
|
||||
|
||||
if (term->is_searching && !is_selected) {
|
||||
color_dim_for_search(&cursor_color);
|
||||
color_dim_for_search(&text_color);
|
||||
}
|
||||
} else {
|
||||
cursor_color = *fg;
|
||||
text_color = *bg;
|
||||
}
|
||||
cursor_colors_for_cell(term, cell, fg, bg, &cursor_color, &text_color);
|
||||
|
||||
switch (term->cursor_style) {
|
||||
case CURSOR_BLOCK:
|
||||
if (!term->kbd_focus)
|
||||
if (unlikely(!term->kbd_focus || term->ime.preedit.cells != NULL))
|
||||
draw_unfocused_block(term, pix, &cursor_color, x, y, cols);
|
||||
|
||||
else if (term->cursor_blink.state == CURSOR_BLINK_ON) {
|
||||
else if (likely(term->cursor_blink.state == CURSOR_BLINK_ON)) {
|
||||
*fg = text_color;
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, &cursor_color, 1,
|
||||
|
|
@ -358,12 +365,17 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
|
|||
break;
|
||||
|
||||
case CURSOR_BAR:
|
||||
if (term->cursor_blink.state == CURSOR_BLINK_ON || !term->kbd_focus)
|
||||
if (likely(term->cursor_blink.state == CURSOR_BLINK_ON ||
|
||||
!term->kbd_focus))
|
||||
{
|
||||
draw_bar(term, pix, font, &cursor_color, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case CURSOR_UNDERLINE:
|
||||
if (term->cursor_blink.state == CURSOR_BLINK_ON || !term->kbd_focus) {
|
||||
if (likely(term->cursor_blink.state == CURSOR_BLINK_ON ||
|
||||
!term->kbd_focus))
|
||||
{
|
||||
draw_underline(
|
||||
term, pix, attrs_to_font(term, &cell->attrs), &cursor_color,
|
||||
x, y, cols);
|
||||
|
|
@ -1009,6 +1021,99 @@ render_sixel_images(struct terminal *term, pixman_image_t *pix)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_ime_preedit(struct terminal *term, struct buffer *buf,
|
||||
struct coord cursor)
|
||||
{
|
||||
if (likely(term->ime.preedit.cells == NULL))
|
||||
return;
|
||||
|
||||
int cells_needed = term->ime.preedit.count;
|
||||
|
||||
int row_idx = cursor.row;
|
||||
int col_idx = cursor.col;
|
||||
|
||||
int cells_left = term->cols - cursor.col;
|
||||
int cells_used = min(cells_needed, term->cols);
|
||||
|
||||
/* Adjust start of pre-edit text to the left if string doesn't fit on row */
|
||||
if (cells_left < cells_used)
|
||||
col_idx -= cells_used - cells_left;
|
||||
|
||||
assert(col_idx >= 0);
|
||||
assert(col_idx < term->cols);
|
||||
|
||||
struct row *row = grid_row_in_view(term->grid, row_idx);
|
||||
|
||||
/* Don't start pre-edit text in the middle of a double-width character */
|
||||
while (col_idx > 0 && row->cells[col_idx].wc == CELL_MULT_COL_SPACER) {
|
||||
cells_used++;
|
||||
col_idx--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy original content (render_cell() reads cell data directly
|
||||
* from grid), and mark all cells as dirty. This ensures they are
|
||||
* re-rendered when the pre-edit text is modified or removed.
|
||||
*/
|
||||
struct cell *real_cells = malloc(cells_used * sizeof(real_cells[0]));
|
||||
for (int i = 0; i < cells_used; i++) {
|
||||
assert(col_idx + i < term->cols);
|
||||
real_cells[i] = row->cells[col_idx + i];
|
||||
real_cells[i].attrs.clean = 0;
|
||||
}
|
||||
row->dirty = true;
|
||||
|
||||
/* Render pre-edit text */
|
||||
for (int i = 0; i < term->ime.preedit.count; i++) {
|
||||
const struct cell *cell = &term->ime.preedit.cells[i];
|
||||
|
||||
if (cell->wc == CELL_MULT_COL_SPACER)
|
||||
continue;
|
||||
|
||||
int width = wcwidth(term->ime.preedit.cells[i].wc);
|
||||
width = max(1, width);
|
||||
|
||||
if (col_idx + i + width > term->cols)
|
||||
break;
|
||||
|
||||
row->cells[col_idx + i] = term->ime.preedit.cells[i];
|
||||
render_cell(term, buf->pix[0], row, col_idx + i, row_idx, false);
|
||||
}
|
||||
|
||||
/* Hollow cursor */
|
||||
if (!term->ime.preedit.cursor.hidden) {
|
||||
int start = term->ime.preedit.cursor.start;
|
||||
int end = term->ime.preedit.cursor.end;
|
||||
|
||||
pixman_color_t fg = color_hex_to_pixman(term->colors.fg);
|
||||
pixman_color_t bg = color_hex_to_pixman(term->colors.bg);
|
||||
|
||||
pixman_color_t cursor_color, text_color;
|
||||
cursor_colors_for_cell(
|
||||
term, &term->ime.preedit.cells[start],
|
||||
&fg, &bg, &cursor_color, &text_color);
|
||||
|
||||
int x = term->margins.left + (col_idx + start) * term->cell_width;
|
||||
int y = term->margins.top + row_idx * term->cell_height;
|
||||
|
||||
int cols = end - start;
|
||||
draw_unfocused_block(term, buf->pix[0], &cursor_color, x, y, cols);
|
||||
}
|
||||
|
||||
/* Restore original content (but do not render) */
|
||||
for (int i = 0; i < cells_used; i++)
|
||||
row->cells[col_idx + i] = real_cells[i];
|
||||
free(real_cells);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window->surface,
|
||||
term->margins.left,
|
||||
term->margins.top + row_idx * term->cell_height,
|
||||
term->width - term->margins.left - term->margins.right,
|
||||
1 * term->cell_height);
|
||||
}
|
||||
|
||||
static void
|
||||
render_row(struct terminal *term, pixman_image_t *pix, struct row *row,
|
||||
int row_no, int cursor_col)
|
||||
|
|
@ -1903,6 +2008,9 @@ grid_render(struct terminal *term)
|
|||
term->render.workers.buf = NULL;
|
||||
}
|
||||
|
||||
/* Render IME pre-edit text */
|
||||
render_ime_preedit(term, buf, cursor);
|
||||
|
||||
if (term->flash.active) {
|
||||
/* Note: alpha is pre-computed in each color component */
|
||||
/* TODO: dim while searching */
|
||||
|
|
|
|||
|
|
@ -1403,6 +1403,8 @@ term_destroy(struct terminal *term)
|
|||
tll_free(term->alt.sixel_images);
|
||||
sixel_fini(term);
|
||||
|
||||
free(term->ime.preedit.cells);
|
||||
|
||||
free(term->foot_exe);
|
||||
free(term->cwd);
|
||||
|
||||
|
|
@ -2216,6 +2218,13 @@ term_kbd_focus_out(struct terminal *term)
|
|||
if (it->item.kbd_focus == term)
|
||||
return;
|
||||
|
||||
if (term->ime.preedit.cells != NULL) {
|
||||
free(term->ime.preedit.cells);
|
||||
term->ime.preedit.cells = NULL;
|
||||
term->ime.preedit.count = 0;
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
term->kbd_focus = false;
|
||||
cursor_refresh(term);
|
||||
|
||||
|
|
|
|||
13
terminal.h
13
terminal.h
|
|
@ -470,6 +470,19 @@ struct terminal {
|
|||
unsigned max_height; /* Maximum image height, in pixels */
|
||||
} sixel;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
struct cell *cells;
|
||||
int count;
|
||||
|
||||
struct {
|
||||
bool hidden;
|
||||
int start; /* Cell index, inclusive */
|
||||
int end; /* Cell index, exclusive */
|
||||
} cursor;
|
||||
} preedit;
|
||||
} ime;
|
||||
|
||||
bool quit;
|
||||
bool is_shutting_down;
|
||||
void (*shutdown_cb)(void *data, int exit_code);
|
||||
|
|
|
|||
2
vt.c
2
vt.c
|
|
@ -408,7 +408,7 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
|
|||
case '=':
|
||||
term->keypad_keys_mode = KEYPAD_APPLICATION;
|
||||
break;
|
||||
ö
|
||||
|
||||
case '>':
|
||||
term->keypad_keys_mode = KEYPAD_NUMERICAL;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ seat_destroy(struct seat *seat)
|
|||
|
||||
free(seat->clipboard.text);
|
||||
free(seat->primary.text);
|
||||
free(seat->ime.preedit.text);
|
||||
free(seat->ime.commit.text);
|
||||
free(seat->ime.preedit.pending.text);
|
||||
free(seat->ime.commit.pending.text);
|
||||
free(seat->name);
|
||||
}
|
||||
|
||||
|
|
|
|||
21
wayland.h
21
wayland.h
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
#include "fdm.h"
|
||||
|
||||
/* Forward declarations */
|
||||
struct terminal;
|
||||
|
||||
typedef tll(xkb_keycode_t) xkb_keycode_list_t;
|
||||
|
||||
struct key_binding {
|
||||
|
|
@ -225,18 +228,24 @@ struct seat {
|
|||
struct zwp_text_input_v3 *wl_text_input;
|
||||
struct {
|
||||
struct {
|
||||
char *text;
|
||||
int32_t cursor_begin;
|
||||
int32_t cursor_end;
|
||||
struct {
|
||||
char *text;
|
||||
int32_t cursor_begin;
|
||||
int32_t cursor_end;
|
||||
} pending;
|
||||
} preedit;
|
||||
|
||||
struct {
|
||||
char *text;
|
||||
struct {
|
||||
char *text;
|
||||
} pending;
|
||||
} commit;
|
||||
|
||||
struct {
|
||||
uint32_t before_length;
|
||||
uint32_t after_length;
|
||||
struct {
|
||||
uint32_t before_length;
|
||||
uint32_t after_length;
|
||||
} pending;
|
||||
} surrounding;
|
||||
|
||||
uint32_t serial;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue