From 95eaad7ce4b40d1401cbc982966a9c7a0036e1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 5 Nov 2019 13:27:37 +0100 Subject: [PATCH] csi: implement DECOM - switch cursor origin between absolute and relative The default is absolute mode, where 0,0 is the upper left corner of the screen. In relative mode, the origin is relative the top scroll margin. Internally, we always track the current cursor position in absolute mode. Every time we the client *sets* or *queries* the cursor position in relative mode, we translate it to absolute. --- csi.c | 40 +++++++++++++++++++++++++++------------- terminal.c | 32 ++++++++++++++++++++++++++++++++ terminal.h | 6 +++++- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/csi.c b/csi.c index af591325..8f407f0f 100644 --- a/csi.c +++ b/csi.c @@ -330,8 +330,9 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'd': { /* VPA - vertical line position absolute */ - int row = min(vt_param_get(term, 0, 1), term->rows); - term_cursor_to(term, row - 1, term->cursor.col); + struct coord new_cursor = term_cursor_rel_to_abs( + term, vt_param_get(term, 0, 1) - 1, term->cursor.col); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } @@ -358,17 +359,20 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'G': { /* Cursor horizontal absolute */ - int col = min(vt_param_get(term, 0, 1), term->cols); - term_cursor_to(term, term->cursor.row, col - 1); + struct coord new_cursor = term_cursor_rel_to_abs( + term, term->cursor.row, vt_param_get(term, 0, 1) - 1); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } case 'f': case 'H': { /* Move cursor */ - int row = min(vt_param_get(term, 0, 1), term->rows); - int col = min(vt_param_get(term, 1, 1), term->cols); - term_cursor_to(term, row - 1, col - 1); + struct coord new_cursor = term_cursor_rel_to_abs( + term, + vt_param_get(term, 0, 1) - 1, + vt_param_get(term, 1, 1) - 1); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } @@ -623,8 +627,7 @@ csi_dispatch(struct terminal *term, uint8_t final) /* 1-based */ term->scroll_region.start = start - 1; term->scroll_region.end = end; - - term_cursor_to(term, start - 1, 0); + term_cursor_home(term); LOG_DBG("scroll region: %d-%d", term->scroll_region.start, @@ -684,13 +687,17 @@ csi_dispatch(struct terminal *term, uint8_t final) switch (param) { case 6: { /* u7 - cursor position query */ + + int row = term->origin == ORIGIN_ABSOLUTE + ? term->cursor.row + : term->cursor.row - term->scroll_region.start; + /* TODO: we use 0-based position, while the xterm * terminfo says the receiver of the reply should * decrement, hence we must add 1 */ char reply[64]; snprintf(reply, sizeof(reply), "\x1b[%d;%dR", - term->cursor.row + 1, - term->cursor.col + 1); + row + 1, term->cursor.col + 1); term_to_slave(term, reply, strlen(reply)); break; } @@ -729,6 +736,7 @@ csi_dispatch(struct terminal *term, uint8_t final) term, &(struct coord){0, 0}, &(struct coord){term->cols - 1, term->rows - 1}); + term_cursor_home(term); break; case 5: @@ -736,6 +744,12 @@ csi_dispatch(struct terminal *term, uint8_t final) term_damage_all(term); break; + case 6: { /* DECOM */ + term->origin = ORIGIN_RELATIVE; + term_cursor_home(term); + break; + } + case 7: term->auto_margin = true; break; @@ -839,6 +853,7 @@ csi_dispatch(struct terminal *term, uint8_t final) term, &(struct coord){0, 0}, &(struct coord){term->cols - 1, term->rows - 1}); + term_cursor_home(term); break; case 4: @@ -853,8 +868,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 6: { /* DECOM */ term->origin = ORIGIN_ABSOLUTE; - struct coord new_home = term_cursor_rel_to_abs(term, 0, 0); - term_cursor_to(term, new_home.row, new_home.col); + term_cursor_home(term); break; } diff --git a/terminal.c b/terminal.c index b7523d1b..2be46130 100644 --- a/terminal.c +++ b/terminal.c @@ -486,6 +486,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, }, .alpha = conf->colors.alpha, }, + .origin = ORIGIN_ABSOLUTE, .default_cursor_style = conf->cursor.style, .cursor_style = conf->cursor.style, .default_cursor_color = { @@ -991,6 +992,30 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord erase_cell_range(term, grid_row(term->grid, end->row), 0, end->col); } +struct coord +term_cursor_rel_to_abs(const struct terminal *term, int row, int col) +{ + switch (term->origin) { + case ORIGIN_ABSOLUTE: + return (struct coord) { + .col = min(col, term->cols - 1), + .row = min(row, term->rows - 1), + }; + break; + + case ORIGIN_RELATIVE: { + return (struct coord) { + .col = min(col, term->cols - 1), + .row = min(row + term->scroll_region.start, term->rows - 1), + }; + break; + } + } + + assert(false); + return (struct coord){-1, -1}; +} + void term_cursor_to(struct terminal *term, int row, int col) { @@ -1005,6 +1030,13 @@ term_cursor_to(struct terminal *term, int row, int col) term->grid->cur_row = grid_row(term->grid, row); } +void +term_cursor_home(struct terminal *term) +{ + struct coord new_cursor = term_cursor_rel_to_abs(term, 0, 0); + term_cursor_to(term, new_cursor.row, new_cursor.col); +} + void term_cursor_left(struct terminal *term, int count) { diff --git a/terminal.h b/terminal.h index 0ed83877..5339d367 100644 --- a/terminal.h +++ b/terminal.h @@ -122,7 +122,8 @@ struct vt { struct attributes saved_attrs; }; -enum cursor_keys { CURSOR_KEYS_DONTCARE, CURSOR_KEYS_NORMAL, CURSOR_KEYS_APPLICATION}; +enum cursor_origin { ORIGIN_ABSOLUTE, ORIGIN_RELATIVE }; +enum cursor_keys { CURSOR_KEYS_DONTCARE, CURSOR_KEYS_NORMAL, CURSOR_KEYS_APPLICATION }; enum keypad_keys { KEYPAD_DONTCARE, KEYPAD_NUMERICAL, KEYPAD_APPLICATION }; enum charset { CHARSET_ASCII, CHARSET_GRAPHIC }; @@ -214,6 +215,7 @@ struct terminal { uint32_t default_table[256]; } colors; + enum cursor_origin origin; struct coord cursor; struct coord saved_cursor; struct coord alt_saved_cursor; @@ -328,6 +330,8 @@ void term_damage_scroll( void term_erase( struct terminal *term, const struct coord *start, const struct coord *end); +struct coord term_cursor_rel_to_abs(const struct terminal *term, int row, int col); +void term_cursor_home(struct terminal *term); void term_cursor_to(struct terminal *term, int row, int col); void term_cursor_left(struct terminal *term, int count); void term_cursor_right(struct terminal *term, int count);