From 4d6e1b801a6cdad7ff66b372ee273eaa7f802810 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Tue, 18 Jan 2022 23:46:25 +0100 Subject: [PATCH] term: Support for reverse scroll, save/restore, and bug fixes --- stage23/drivers/vga_textmode.h | 3 ++ stage23/drivers/vga_textmode.s2.c | 31 ++++++++++++++++ stage23/lib/gterm.c | 60 +++++++++++++++++++++++++++---- stage23/lib/gterm.h | 3 ++ stage23/lib/term.c | 3 ++ stage23/lib/term.h | 8 +++++ stage23/lib/term.s2.c | 45 ++++++++++++++++++++++- 7 files changed, 145 insertions(+), 8 deletions(-) diff --git a/stage23/drivers/vga_textmode.h b/stage23/drivers/vga_textmode.h index 8800e9df..1c76c357 100644 --- a/stage23/drivers/vga_textmode.h +++ b/stage23/drivers/vga_textmode.h @@ -23,7 +23,10 @@ bool text_scroll_disable(void); void text_scroll_enable(void); void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y); void text_scroll(void); +void text_revscroll(void); void text_swap_palette(void); +void text_save_state(void); +void text_restore_state(void); void text_double_buffer(bool state); void text_double_buffer_flush(void); diff --git a/stage23/drivers/vga_textmode.s2.c b/stage23/drivers/vga_textmode.s2.c index f3a97cfb..1982f11b 100644 --- a/stage23/drivers/vga_textmode.s2.c +++ b/stage23/drivers/vga_textmode.s2.c @@ -29,6 +29,11 @@ static struct context { #define text_palette context.text_palette bool scroll_enabled; #define scroll_enabled context.scroll_enabled + + uint8_t saved_state_text_palette; +#define saved_state_text_palette context.saved_state_text_palette + size_t saved_state_cursor_offset; +#define saved_state_cursor_offset context.saved_state_cursor_offset } context; static size_t old_cursor_offset = 0; @@ -38,6 +43,16 @@ static void draw_cursor(void) { video_mem[cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4); } +void text_save_state(void) { + saved_state_text_palette = text_palette; + saved_state_cursor_offset = cursor_offset; +} + +void text_restore_state(void) { + text_palette = saved_state_text_palette; + cursor_offset = saved_state_cursor_offset; +} + void text_swap_palette(void) { text_palette = (text_palette << 4) | (text_palette >> 4); } @@ -66,6 +81,22 @@ void text_scroll(void) { } } +void text_revscroll(void) { + // move the text up by one row + for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) { + back_buffer[i + VD_COLS] = back_buffer[i]; + if (i == term_context.scroll_top_margin * VD_COLS) { + break; + } + } + // clear the first line of the screen + for (size_t i = term_context.scroll_top_margin * VD_COLS; + i < (term_context.scroll_top_margin + 1) * VD_COLS; i += 2) { + back_buffer[i] = ' '; + back_buffer[i + 1] = text_palette; + } +} + void text_clear(bool move) { for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) { back_buffer[i] = ' '; diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 94681c3d..ce685547 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -89,19 +89,40 @@ static struct context { #define cursor_x context.cursor_x size_t cursor_y; #define cursor_y context.cursor_y + bool scroll_enabled; +#define scroll_enabled context.scroll_enabled + + uint32_t saved_state_text_fg; +#define saved_state_text_fg context.saved_state_text_fg + uint32_t saved_state_text_bg; +#define saved_state_text_bg context.saved_state_text_bg + size_t saved_state_cursor_x; +#define saved_state_cursor_x context.saved_state_cursor_x + size_t saved_state_cursor_y; +#define saved_state_cursor_y context.saved_state_cursor_y } context; static size_t old_cursor_x = 0; static size_t old_cursor_y = 0; +void gterm_save_state(void) { + saved_state_text_fg = text_fg; + saved_state_text_bg = text_bg; + saved_state_cursor_x = cursor_x; + saved_state_cursor_y = cursor_y; +} + +void gterm_restore_state(void) { + text_fg = saved_state_text_fg; + text_bg = saved_state_text_bg; + cursor_x = saved_state_cursor_x; + cursor_y = saved_state_cursor_y; +} + void gterm_swap_palette(void) { uint32_t tmp = text_bg; text_bg = text_fg; - if (tmp == 0xffffffff) { - text_fg = default_bg; - } else { - text_fg = tmp; - } + text_fg = tmp; } #define A(rgb) (uint8_t)(rgb >> 24) @@ -353,8 +374,6 @@ static void push_to_queue(struct gterm_char *c, size_t x, size_t y) { q->c = *c; } -static bool scroll_enabled = true; - bool gterm_scroll_disable(void) { bool ret = scroll_enabled; scroll_enabled = false; @@ -365,6 +384,32 @@ void gterm_scroll_enable(void) { scroll_enabled = true; } +void gterm_revscroll(void) { + for (size_t i = (term_context.scroll_bottom_margin - 1) * cols - 1; ; i--) { + struct gterm_char *c; + struct queue_item *q = map[i]; + if (q != NULL) { + c = &q->c; + } else { + c = &grid[i]; + } + push_to_queue(c, (i + cols) % cols, (i + cols) / cols); + if (i == term_context.scroll_top_margin * cols) { + break; + } + } + + // Clear the first line of the screen. + struct gterm_char empty; + empty.c = ' '; + empty.fg = text_fg; + empty.bg = text_bg; + for (size_t i = term_context.scroll_top_margin * cols; + i < (term_context.scroll_top_margin + 1) * cols; i++) { + push_to_queue(&empty, i % cols, i / cols); + } +} + void gterm_scroll(void) { for (size_t i = (term_context.scroll_top_margin + 1) * cols; i < term_context.scroll_bottom_margin * cols; i++) { @@ -578,6 +623,7 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) { return false; cursor_status = true; + scroll_enabled = true; // default scheme margin = 64; diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h index 65a39282..d37aaa13 100644 --- a/stage23/lib/gterm.h +++ b/stage23/lib/gterm.h @@ -27,7 +27,10 @@ bool gterm_scroll_disable(void); void gterm_scroll_enable(void); void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y); void gterm_scroll(void); +void gterm_revscroll(void); void gterm_swap_palette(void); +void gterm_save_state(void); +void gterm_restore_state(void); void gterm_double_buffer_flush(void); diff --git a/stage23/lib/term.c b/stage23/lib/term.c index 21fa0dea..91e612ee 100644 --- a/stage23/lib/term.c +++ b/stage23/lib/term.c @@ -51,7 +51,10 @@ void term_vbe(size_t width, size_t height) { scroll_enable = gterm_scroll_enable; term_move_character = gterm_move_character; term_scroll = gterm_scroll; + term_revscroll = gterm_revscroll; term_swap_palette = gterm_swap_palette; + term_save_state = gterm_save_state; + term_restore_state = gterm_restore_state; term_double_buffer_flush = gterm_double_buffer_flush; diff --git a/stage23/lib/term.h b/stage23/lib/term.h index 13a9a2d3..c113f669 100644 --- a/stage23/lib/term.h +++ b/stage23/lib/term.h @@ -30,6 +30,11 @@ extern struct term_context { size_t scroll_top_margin; size_t scroll_bottom_margin; uint32_t esc_values[MAX_ESC_VALUES]; + + bool saved_state_bold; + bool saved_state_reverse_video; + size_t saved_state_current_charset; + size_t saved_state_current_primary; } term_context; enum { @@ -71,7 +76,10 @@ extern bool (*scroll_disable)(void); extern void (*scroll_enable)(void); extern void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y); extern void (*term_scroll)(void); +extern void (*term_revscroll)(void); extern void (*term_swap_palette)(void); +extern void (*term_save_state)(void); +extern void (*term_restore_state)(void); extern void (*term_double_buffer_flush)(void); diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c index c0543796..4622877c 100644 --- a/stage23/lib/term.s2.c +++ b/stage23/lib/term.s2.c @@ -66,7 +66,10 @@ void term_notready(void) { scroll_enable = notready_void; term_move_character = notready_move_character; term_scroll = notready_void; + term_revscroll = notready_void; term_swap_palette = notready_void; + term_save_state = notready_void; + term_restore_state = notready_void; term_double_buffer_flush = notready_void; term_context_size = notready_context_size; term_context_save = notready_uint64_t; @@ -207,7 +210,10 @@ bool (*scroll_disable)(void); void (*scroll_enable)(void); void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y); void (*term_scroll)(void); +void (*term_revscroll)(void); void (*term_swap_palette)(void); +void (*term_save_state)(void); +void (*term_restore_state)(void); void (*term_double_buffer_flush)(void); @@ -241,6 +247,11 @@ struct term_context term_context; #define charsets term_context.charsets #define g_select term_context.g_select +#define saved_state_bold term_context.saved_state_bold +#define saved_state_reverse_video term_context.saved_state_reverse_video +#define saved_state_current_charset term_context.saved_state_current_charset +#define saved_state_current_primary term_context.saved_state_current_primary + #define CHARSET_DEFAULT 0 #define CHARSET_DEC_SPECIAL 1 @@ -296,7 +307,10 @@ void term_textmode(void) { scroll_enable = text_scroll_enable; term_move_character = text_move_character; term_scroll = text_scroll; + term_revscroll = text_revscroll; term_swap_palette = text_swap_palette; + term_save_state = text_save_state; + term_restore_state = text_restore_state; term_double_buffer_flush = text_double_buffer_flush; @@ -897,6 +911,24 @@ cleanup: escape = false; } +static void restore_state(void) { + bold = saved_state_bold; + reverse_video = saved_state_reverse_video; + current_charset = saved_state_current_charset; + current_primary = saved_state_current_primary; + + term_restore_state(); +} + +static void save_state(void) { + term_save_state(); + + saved_state_bold = bold; + saved_state_reverse_video = reverse_video; + saved_state_current_charset = current_charset; + saved_state_current_primary = current_primary; +} + static void escape_parse(uint8_t c) { escape_offset++; @@ -922,6 +954,12 @@ is_csi: rrr = false; control_sequence = true; return; + case '7': + save_state(); + break; + case '8': + restore_state(); + break; case 'c': term_reinit(); clear(true); @@ -944,7 +982,12 @@ is_csi: break; case 'M': // "Reverse linefeed" - set_cursor_pos(x, y - 1); + if (y == scroll_top_margin) { + term_revscroll(); + set_cursor_pos(0, y); + } else { + set_cursor_pos(0, y - 1); + } break; case 'Z': if (term_callback != NULL) {