tsm: screen: add support for multi-cell characters
The wcwidth() POSIX helper returns the number of cells that a character occupies. This is normally 1, however, if it is 0 we simply discard this input (this should never happen as all characters that wcwidth() returns 0 for should already be handled by the VTE layer). But if it is >1, we write the character in the first cell, set the width correctly and mark all following characters as width=0. Everything else is left unchanged, that means, the running application has to be aware of wcwidth() and correctly send two backspaces to clear a width=2 character and so on. This behavior almost exactly matches the xterm behavior. There are some corner cases like erasing only one part of a multi-cell character etc. that might differ. However, these are non-standard cases that no application should never rely on. Anyway, if we spot any of these differences between xterm and kmscon, we should fix kmscon to behave like xterm does. Thanks to Shixin for looking this up in other emulators. Reported-by: Shixin Zeng Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
1657bb9a3a
commit
03aab2b54b
@ -358,10 +358,14 @@ static void screen_scroll_down(struct tsm_screen *con, unsigned int num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void screen_write(struct tsm_screen *con, unsigned int x,
|
static void screen_write(struct tsm_screen *con, unsigned int x,
|
||||||
unsigned int y, tsm_symbol_t ch,
|
unsigned int y, tsm_symbol_t ch, unsigned int len,
|
||||||
const struct tsm_screen_attr *attr)
|
const struct tsm_screen_attr *attr)
|
||||||
{
|
{
|
||||||
struct line *line;
|
struct line *line;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
|
||||||
if (x >= con->size_x || y >= con->size_y) {
|
if (x >= con->size_x || y >= con->size_y) {
|
||||||
llog_warn(con, "writing beyond buffer boundary");
|
llog_warn(con, "writing beyond buffer boundary");
|
||||||
@ -370,11 +374,17 @@ static void screen_write(struct tsm_screen *con, unsigned int x,
|
|||||||
|
|
||||||
line = con->lines[y];
|
line = con->lines[y];
|
||||||
|
|
||||||
if ((con->flags & TSM_SCREEN_INSERT_MODE) && x < (con->size_x - 1))
|
if ((con->flags & TSM_SCREEN_INSERT_MODE) &&
|
||||||
memmove(&line->cells[x + 1], &line->cells[x],
|
(int)x < ((int)con->size_x - len))
|
||||||
sizeof(struct cell) * (con->size_x - 1 - x));
|
memmove(&line->cells[x + len], &line->cells[x],
|
||||||
|
sizeof(struct cell) * (con->size_x - len - x));
|
||||||
|
|
||||||
line->cells[x].ch = ch;
|
line->cells[x].ch = ch;
|
||||||
|
line->cells[x].width = len;
|
||||||
memcpy(&line->cells[x].attr, attr, sizeof(*attr));
|
memcpy(&line->cells[x].attr, attr, sizeof(*attr));
|
||||||
|
|
||||||
|
for (i = 1; i < len && i + x < con->size_x; ++i)
|
||||||
|
line->cells[x + i].width = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void screen_erase_region(struct tsm_screen *con,
|
static void screen_erase_region(struct tsm_screen *con,
|
||||||
@ -951,11 +961,15 @@ void tsm_screen_reset_all_tabstops(struct tsm_screen *con)
|
|||||||
void tsm_screen_write(struct tsm_screen *con, tsm_symbol_t ch,
|
void tsm_screen_write(struct tsm_screen *con, tsm_symbol_t ch,
|
||||||
const struct tsm_screen_attr *attr)
|
const struct tsm_screen_attr *attr)
|
||||||
{
|
{
|
||||||
unsigned int last;
|
unsigned int last, len;
|
||||||
|
|
||||||
if (!con)
|
if (!con)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
len = tsm_symbol_get_width(NULL, ch);
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
|
||||||
if (con->cursor_y <= con->margin_bottom ||
|
if (con->cursor_y <= con->margin_bottom ||
|
||||||
con->cursor_y >= con->size_y)
|
con->cursor_y >= con->size_y)
|
||||||
last = con->margin_bottom;
|
last = con->margin_bottom;
|
||||||
@ -976,8 +990,8 @@ void tsm_screen_write(struct tsm_screen *con, tsm_symbol_t ch,
|
|||||||
screen_scroll_up(con, 1);
|
screen_scroll_up(con, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_write(con, con->cursor_x, con->cursor_y, ch, attr);
|
screen_write(con, con->cursor_x, con->cursor_y, ch, len, attr);
|
||||||
++con->cursor_x;
|
con->cursor_x += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsm_screen_newline(struct tsm_screen *con)
|
void tsm_screen_newline(struct tsm_screen *con)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user