From b0c19c5c4238cebf0cd83746bf6c465584bac4cc Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 17 Jun 2012 15:53:33 +0200 Subject: [PATCH] console: rewrite console layer This is a rewrite of the whole console layer so we can remove the kmscon_buffer object to speed up the console. This removes the split between the scroll region and the two margins so we can resize margins in O(1). This also correctly merges the remaining console modes so vte does not have to track them. Btw. vim runs smoothly on kmscon with this console layer now (finally!). Signed-off-by: David Herrmann --- src/console.c | 1392 ++++++++++++++++--------------------------------- src/console.h | 21 +- src/vte.c | 22 +- 3 files changed, 484 insertions(+), 951 deletions(-) diff --git a/src/console.c b/src/console.c index da4a728..b32ddf0 100644 --- a/src/console.c +++ b/src/console.c @@ -43,9 +43,6 @@ #define LOG_SUBSYSTEM "console" -#define DEFAULT_WIDTH 80 -#define DEFAULT_HEIGHT 24 - struct cell { kmscon_symbol_t ch; struct font_char_attr attr; @@ -59,305 +56,175 @@ struct line { struct cell *cells; }; -struct kmscon_buffer { +struct kmscon_console { + size_t ref; + unsigned int flags; + + /* default attributes for new cells */ + struct font_char_attr def_attr; + + /* current buffer */ + unsigned int size_x; + unsigned int size_y; + unsigned int margin_top; + unsigned int margin_bottom; + unsigned int line_num; + struct line **lines; + /* scroll-back buffer */ unsigned int sb_count; /* number of lines in sb */ struct line *sb_first; /* first line; was moved first */ struct line *sb_last; /* last line; was moved last*/ unsigned int sb_max; /* max-limit of lines in sb */ - - /* current position in sb; if NULL, the main screen is shown */ - struct line *position; - /* fixed=true means that if the current focus is on the sb, then the - * focus will stay on the line even if new lines are added to the sb or - * removed. fixed=false means the distance from the current position to - * the main-buffer is kept constant. In most situations this means that - * the sb seems to scroll-up while staying on the line - */ - bool fixed_position; - unsigned int flags; - - /* current cell/row count of the main screen */ - unsigned int size_x; /* cell count */ - unsigned int size_y; /* row count */ - - /* main scroll buffer */ - unsigned int scroll_y; /* number of rows in this buffer */ - unsigned int scroll_fill; /* current fill; last line pushed */ - struct line **scroll_buf; /* lines of the buffer */ - - /* margin buffers */ - unsigned int mtop_y; /* number of rows in top margin */ - struct line **mtop_buf; /* lines of the top margin */ - unsigned int mbottom_y; /* number of rows in bottom margin */ - struct line **mbottom_buf; /* lines of the bottom margin */ -}; - -struct kmscon_console { - size_t ref; - - /* console cells */ - struct kmscon_buffer *cells; + struct line *sb_pos; /* current position in sb or NULL */ /* cursor */ unsigned int cursor_x; unsigned int cursor_y; }; -/* Console Buffer and Cell Objects - * A console buffer maintains an array of lines of the current screen buffer - * and a list of lines in the scrollback buffer. The screen buffer can be - * modified, the scrollback buffer is constant. - * - * Buffers: - * The buffer object consists of three buffers. The top margin, the bottom - * margin and the scroll buffer. The margins are non-existent by default. The - * scroll buffer is the main buffer. If the terminal is rotated then the lines - * of this buffer go to the scroll-back buffer and vice versa. - * The margin buffers are static. They can be modified but they are never - * rotated. If the margins are created, the lines are copied from the scroll - * buffer and then removed from the scroll buffer. If the margins are removed, - * the lines are linked back into the scroll buffer at the current position. - * Each buffer is an array of lines. The lines can be modified very fast and - * rotations do not require heavy memory-moves. If a line is NULL we consider - * this line empty so we can resize the buffer without reallocating new lines. - * - * Scrollback buffer: - * The scrollback buffer contains all lines that were pushed out of the current - * screen. It's a linked list of lines which cannot be accessed by the - * application. It has an upper bound so we do not consume too much memory. - * If the current buffer is resized to a bigger size, then lines from the - * scrollback buffer may get back into the current buffer to fill the screen. - * - * Lines: - * A single line is represented by a "struct line". It has an array of cells - * which can be accessed directly. The length of each line may vary and for - * faster resizing we also keep a \size member. - * Lines may be shorter than the current buffer width. We do not resize them to - * speed up the buffer operations. If a line is printed which is longer or - * shorted than the screen width, it is simply filled with spaces or truncated - * to screen width. - * If such a line is accessed outside the bounds, the line is resized to the - * current screen width to allow access. - * - * Screen position: - * The current screen position may be any line inside the scrollback buffer. If - * it is NULL, the current position is set to the current screen buffer. - * If it is non-NULL it will stick to the given line and will not scroll back - * on new input. - * - * Cells - * A single cell describes a single character that is printed in that cell. The - * character itself is a kmscon_char unicode character. The cell also contains - * the color of the character and some other metadata. - */ - -static void destroy_cell(struct cell *cell) +static void cell_init(struct kmscon_console *con, struct cell *cell) { - if (!cell) - return; + cell->ch = 0; + memcpy(&cell->attr, &con->def_attr, sizeof(cell->attr)); } -static int init_cell(struct cell *cell) -{ - if (!cell) - return -EINVAL; - - memset(cell, 0, sizeof(*cell)); - cell->attr.fr = 255; - cell->attr.fg = 255; - cell->attr.fb = 255; - return 0; -} - -static void reset_cell(struct cell *cell) -{ - if (!cell) - return; - - memset(cell, 0, sizeof(*cell)); - cell->attr.fr = 255; - cell->attr.fg = 255; - cell->attr.fb = 255; -} - -static void free_line(struct line *line) -{ - unsigned int i; - - if (!line) - return; - - for (i = 0; i < line->size; ++i) - destroy_cell(&line->cells[i]); - - free(line->cells); - free(line); -} - -static int new_line(struct line **out) +static int line_new(struct kmscon_console *con, struct line **out, + unsigned int width) { struct line *line; + unsigned int i; - if (!out) + if (!width) return -EINVAL; line = malloc(sizeof(*line)); if (!line) return -ENOMEM; + line->next = NULL; + line->prev = NULL; + line->size = width; + + line->cells = malloc(sizeof(struct cell) * width); + if (!line->cells) { + free(line); + return -ENOMEM; + } + + for (i = 0; i < width; ++i) + cell_init(con, &line->cells[i]); - memset(line, 0, sizeof(*line)); *out = line; return 0; } -static int resize_line(struct line *line, unsigned int width) +static void line_free(struct line *line) +{ + free(line->cells); + free(line); +} + +static int line_resize(struct kmscon_console *con, struct line *line, + unsigned int width) { struct cell *tmp; - int ret; - if (!line) + if (!line || !width) return -EINVAL; - if (!width) - width = DEFAULT_WIDTH; - if (line->size < width) { tmp = realloc(line->cells, width * sizeof(struct cell)); if (!tmp) return -ENOMEM; line->cells = tmp; + line->size = width; while (line->size < width) { - ret = init_cell(&line->cells[line->size]); - if (ret) - return ret; - line->size++; - } - } else if (line->size > width) { - while (line->size > width) { - line->size--; - destroy_cell(&line->cells[line->size]); + cell_init(con, &line->cells[line->size]); + ++line->size; } } return 0; } -static struct line *get_line(struct kmscon_buffer *buf, unsigned int y) -{ - if (y < buf->mtop_y) { - return buf->mtop_buf[y]; - } else if (y < buf->mtop_y + buf->scroll_y) { - y -= buf->mtop_y; - return buf->scroll_buf[y]; - } else if (y < buf->mtop_y + buf->scroll_y + buf->mbottom_y) { - y = y - buf->mtop_y - buf->scroll_y; - return buf->mbottom_buf[y]; - } - - return NULL; -} - -/* This links the given line into the scrollback-buffer. This always succeeds. - * If \line is NULL then an empty line is created that is pushed to the - * scrollback buffer. - */ -static void link_to_scrollback(struct kmscon_buffer *buf, struct line *line) +/* This links the given line into the scrollback-buffer */ +static void link_to_scrollback(struct kmscon_console *con, struct line *line) { struct line *tmp; - int ret; - if (!buf) + if (con->sb_max == 0) { + line_free(line); return; - - if (buf->sb_max == 0) { - free_line(line); - return; - } - - /* line==NULL means the line is empty. The scrollback buffer cannot - * contain such lines, though. Therefore, explicitely allocate a new - * empty line with line!=NULL but size=0. - */ - if (!line) { - ret = new_line(&line); - if (ret) { - log_warn("cannot allocate line (%d); dropping scrollback-buffer line", ret); - return; - } } /* Remove a line from the scrollback buffer if it reaches its maximum. * We must take care to correctly keep the current position as the new * line is linked in after we remove the top-most line here. * sb_max == 0 is tested earlier so we can assume sb_max > 0 here. In - * other words, buf->sb_first is a valid line if sb_count >= sb_max. - */ - if (buf->sb_count >= buf->sb_max) { - tmp = buf->sb_first; - buf->sb_first = tmp->next; + * other words, buf->sb_first is a valid line if sb_count >= sb_max. */ + if (con->sb_count >= con->sb_max) { + tmp = con->sb_first; + con->sb_first = tmp->next; if (tmp->next) tmp->next->prev = NULL; else - buf->sb_last = NULL; - buf->sb_count--; + con->sb_last = NULL; + --con->sb_count; - /* (position==tmp && !next) means we have sb_max=1 so set + /* (position == tmp && !next) means we have sb_max=1 so set * position to the new line. Otherwise, set to new first line. - * If position!=tmp and we have a fixed_position then nothing + * If position!=tmp and we have a fixed-position then nothing * needs to be done because we can stay at the same line. If we - * have no fixed_position, we need to set the position to the - * next inserted line, which can be "line", too. - */ - if (buf->position) { - if (buf->position == tmp || !buf->fixed_position) { - if (buf->position->next) - buf->position = buf->position->next; + * have no fixed-position, we need to set the position to the + * next inserted line, which can be "line", too. */ + if (con->sb_pos) { + if (con->sb_pos == tmp || + !(con->flags & KMSCON_CONSOLE_FIXED_POS)) { + if (con->sb_pos->next) + con->sb_pos = con->sb_pos->next; else - buf->position = line; + con->sb_pos = line; } } - free_line(tmp); + line_free(tmp); } line->next = NULL; - line->prev = buf->sb_last; - if (buf->sb_last) - buf->sb_last->next = line; + line->prev = con->sb_last; + if (con->sb_last) + con->sb_last->next = line; else - buf->sb_first = line; - buf->sb_last = line; - buf->sb_count++; + con->sb_first = line; + con->sb_last = line; + ++con->sb_count; } /* Unlinks last line from the scrollback buffer, Returns NULL if it is empty */ -static struct line *get_from_scrollback(struct kmscon_buffer *buf) +static struct line *get_from_scrollback(struct kmscon_console *con) { struct line *line; - if (!buf || !buf->sb_last) + if (!con->sb_last) return NULL; - line = buf->sb_last; - buf->sb_last = line->prev; + line = con->sb_last; + con->sb_last = line->prev; if (line->prev) line->prev->next = NULL; else - buf->sb_first = NULL; - buf->sb_count--; + con->sb_first = NULL; + con->sb_count--; /* correctly move the current position if it is set in the sb */ - if (buf->position) { - if (buf->fixed_position) { - if (buf->position == line) - buf->position = NULL; - } else if (!buf->position->prev) { - if (buf->position == line) - buf->position = NULL; + if (con->sb_pos) { + if (con->flags & KMSCON_CONSOLE_FIXED_POS || + !con->sb_pos->prev) { + if (con->sb_pos == line) + con->sb_pos = NULL; } else { - buf->position = buf->position->prev; + con->sb_pos = con->sb_pos->prev; } } @@ -366,601 +233,121 @@ static struct line *get_from_scrollback(struct kmscon_buffer *buf) return line; } -/* Resize scroll buffer. Despite being used for scroll region only, it is kept - * big enough to hold both margins too. We do this to allow fast merges of - * margins and scroll buffer. - */ -static int resize_scrollbuf(struct kmscon_buffer *buf, unsigned int y) -{ - unsigned int fill, i, siz; - struct line *iter, **cache; - - /* Resize y size by adjusting the scroll-buffer size */ - if (y < buf->scroll_y) { - /* Shrink scroll-buffer. First move enough elements from the - * scroll-buffer into the scroll-back buffer so we can shrink - * it without loosing data. - * Then reallocate the buffer (we shrink it so we never fail - * here) and correctly set values in \buf. If the buffer has - * unused lines, we can shrink it down without moving lines - * into the scrollback-buffer so first calculate the current - * fill of the buffer and then move appropriate amount of - * elements to the scrollback buffer. - */ - - if (buf->scroll_fill > y) { - for (i = y; i < buf->scroll_fill; ++i) - link_to_scrollback(buf, buf->scroll_buf[i - y]); - - memmove(buf->scroll_buf, - &buf->scroll_buf[buf->scroll_fill - y], - y * sizeof(struct line*)); - } - - siz = buf->mtop_y + buf->mbottom_y + y; - buf->scroll_buf = realloc(buf->scroll_buf, - siz * sizeof(struct line*)); - buf->scroll_y = y; - if (buf->scroll_fill > y) - buf->scroll_fill = y; - } else if (y > buf->scroll_y) { - /* Increase scroll-buffer to new size. Reset all new elements - * to NULL so they are empty. Copy existing buffer into new - * buffer and correctly set values in \buf. - * If we have more space in the buffer, we simply move lines - * from the scroll-back buffer into our scroll-buffer if they - * are available. Otherwise, we simply add NULL lines. - */ - - siz = buf->mtop_y + buf->mbottom_y + y; - cache = malloc(sizeof(struct line*) * siz); - if (!cache) - return -ENOMEM; - - memset(cache, 0, sizeof(struct line*) * siz); - fill = y - buf->scroll_y; - - for (i = 0; i < fill; ++i) { - iter = get_from_scrollback(buf); - if (!iter) - break; - - cache[y - i - 1] = iter; - } - buf->scroll_fill += i; - memmove(cache, &cache[y - i], i * sizeof(struct line*)); - memset(&cache[i + buf->scroll_y], 0, - (fill - i) * sizeof(struct line*)); - - if (buf->scroll_y) - memcpy(&cache[i], buf->scroll_buf, - sizeof(struct line*) * buf->scroll_y); - - free(buf->scroll_buf); - buf->scroll_buf = cache; - buf->scroll_y = y; - } - - return 0; -} - -static int resize_mtop(struct kmscon_buffer *buf, unsigned int y) -{ - unsigned int mv; - struct line **cache; - - if (y == buf->mtop_y) - return 0; - - if (y < buf->mtop_y) { - mv = buf->mtop_y - y; - memmove(&buf->scroll_buf[mv], buf->scroll_buf, - buf->scroll_y * sizeof(struct line*)); - memcpy(buf->scroll_buf, &buf->mtop_buf[y], - mv * sizeof(struct line*)); - buf->scroll_fill += mv; - buf->scroll_y += mv; - buf->mtop_y -= mv; - } else { - mv = y - buf->mtop_y; - if (mv >= buf->scroll_y) { - log_debug("setting margin size above buffer size; trimming margin"); - if (buf->scroll_y <= 1) - return 0; - mv = buf->scroll_y - 1; - y = buf->mtop_y + mv; - } - - cache = malloc(y * sizeof(struct line*)); - if (!cache) - return -ENOMEM; - - memcpy(cache, buf->mtop_buf, - buf->mtop_y * sizeof(struct line*)); - memcpy(&cache[buf->mtop_y], buf->scroll_buf, - mv * sizeof(struct line*)); - memmove(buf->scroll_buf, &buf->scroll_buf[mv], - (buf->scroll_y - mv) * sizeof(struct line*)); - if (buf->scroll_fill > mv) - buf->scroll_fill -= mv; - else - buf->scroll_fill = 0; - buf->scroll_y -= mv; - buf->mtop_y += mv; - free(buf->mtop_buf); - buf->mtop_buf = cache; - } - - return 0; -} - -static int resize_mbottom(struct kmscon_buffer *buf, unsigned int y) -{ - unsigned int mv; - struct line **cache; - - if (y == buf->mbottom_y) - return 0; - - if (y < buf->mbottom_y) { - mv = buf->mbottom_y - y; - memcpy(&buf->scroll_buf[buf->scroll_y], buf->mbottom_buf, - mv * sizeof(struct line*)); - memmove(buf->mbottom_buf, &buf->mbottom_buf[mv], - (buf->mbottom_y - mv) * sizeof(struct line*)); - buf->scroll_y += mv; - buf->scroll_fill = buf->scroll_y; - buf->mbottom_y -= mv; - } else { - mv = y - buf->mbottom_y; - if (mv >= buf->scroll_y) { - log_debug("setting margin size above buffer size; trimming margin"); - if (buf->scroll_y <= 1) - return 0; - mv = buf->scroll_y - 1; - y = buf->mbottom_y + mv; - } - - cache = malloc(y * sizeof(struct line*)); - if (!cache) - return -ENOMEM; - - memcpy(&cache[mv], buf->mbottom_buf, - buf->mbottom_y * sizeof(struct line*)); - memcpy(cache, &buf->scroll_buf[buf->scroll_y - mv], - mv * sizeof(struct line*)); - buf->scroll_y -= mv; - if (buf->scroll_fill > buf->scroll_y) - buf->scroll_fill = buf->scroll_y; - buf->mbottom_y += mv; - free(buf->mbottom_buf); - buf->mbottom_buf = cache; - } - - return 0; -} - -/* Resize the current console buffer - * This resizes the current buffer. We do not resize the lines or modify them - * in any way. This would take too long if multiple resize-operations are - * performed. - */ -static int kmscon_buffer_resize(struct kmscon_buffer *buf, unsigned int x, - unsigned int y) +static void console_scroll_up(struct kmscon_console *con, unsigned int num) { + unsigned int i, j, max; int ret; - unsigned int margin; - if (!buf) - return -EINVAL; + if (!num) + return; - if (!x) - x = DEFAULT_WIDTH; - if (!y) - y = DEFAULT_HEIGHT; + max = con->margin_bottom + 1 - con->margin_top; + if (num > max) + num = max; - if (buf->size_x == x && buf->size_y == y) - return 0; + /* We cache lines on the stack to speed up the scrolling. However, if + * num is too big we might get overflows here so use recursion if num + * exceeds a hard-coded limit. + * 128 seems to be a sane limit that should never be reached but should + * also be small enough so we do not get stack overflows. */ + if (num > 128) { + console_scroll_up(con, 128); + return console_scroll_up(con, num - 128); + } + struct line *cache[num]; - margin = buf->mtop_y + buf->mbottom_y; - if (y <= margin) { - log_debug("reducing buffer size below margin size; destroying margins"); - resize_mtop(buf, 0); - resize_mbottom(buf, 0); + for (i = 0; i < num; ++i) { + ret = line_new(con, &cache[i], con->size_x); + if (!ret) { + link_to_scrollback(con, + con->lines[con->margin_top + i]); + } else { + cache[i] = con->lines[con->margin_top + i]; + for (j = 0; j < con->size_x; ++j) + cell_init(con, &cache[i]->cells[j]); + } } - ret = resize_scrollbuf(buf, buf->scroll_y + (y - (int)buf->size_y)); - if (ret) - return ret; - buf->size_y = y; + if (num < max) { + memmove(&con->lines[con->margin_top], + &con->lines[con->margin_top + num], + (max - num) * sizeof(struct line*)); + } - /* Adjust x size by simply setting the new value */ - buf->size_x = x; - - log_debug("resize buffer to %ux%u", x, y); - - return 0; + memcpy(&con->lines[con->margin_top + (max - num)], + cache, num * sizeof(struct line*)); } -/* set maximum scrollback buffer size */ -static void kmscon_buffer_set_max_sb(struct kmscon_buffer *buf, - unsigned int max) +static void console_scroll_down(struct kmscon_console *con, unsigned int num) +{ + unsigned int i, j, max; + + if (!num) + return; + + max = con->margin_bottom + 1 - con->margin_top; + if (num > max) + num = max; + + /* see console_scroll_up() for an explanation */ + if (num > 128) { + console_scroll_down(con, 128); + return console_scroll_down(con, num - 128); + } + struct line *cache[num]; + + for (i = 0; i < num; ++i) { + cache[i] = con->lines[con->margin_bottom - i]; + for (j = 0; j < con->size_x; ++j) + cell_init(con, &cache[i]->cells[j]); + } + + if (num < max) { + memmove(&con->lines[con->margin_top + num], + &con->lines[con->margin_top], + (max - num) * sizeof(struct line*)); + } + + memcpy(&con->lines[con->margin_top], + cache, num * sizeof(struct line*)); +} + +static void console_write(struct kmscon_console *con, unsigned int x, + unsigned int y, kmscon_symbol_t ch, + const struct font_char_attr *attr) { struct line *line; - if (!buf) - return; - - while (buf->sb_count > max) { - line = buf->sb_first; - if (!line) - break; - - buf->sb_first = line->next; - if (line->next) - line->next->prev = NULL; - else - buf->sb_last = NULL; - buf->sb_count--; - - /* We treat fixed/unfixed position the same here because we - * remove lines from the TOP of the scrollback buffer. - */ - if (buf->position == line) { - if (buf->sb_first) - buf->position = buf->sb_first; - else - buf->position = NULL; - } - - free_line(line); - } - - buf->sb_max = max; -} - -/* clear scrollback buffer */ -static void kmscon_buffer_clear_sb(struct kmscon_buffer *buf) -{ - struct line *iter, *tmp; - - if (!buf) - return; - - for (iter = buf->sb_first; iter; ) { - tmp = iter; - iter = iter->next; - free_line(tmp); - } - - buf->sb_first = NULL; - buf->sb_last = NULL; - buf->sb_count = 0; - buf->position = NULL; -} - -static int kmscon_buffer_new(struct kmscon_buffer **out, unsigned int x, - unsigned int y) -{ - struct kmscon_buffer *buf; - int ret; - - if (!out) - return -EINVAL; - - buf = malloc(sizeof(*buf)); - if (!buf) - return -ENOMEM; - - memset(buf, 0, sizeof(*buf)); - - ret = kmscon_buffer_resize(buf, x, y); - if (ret) - goto err_free; - - log_debug("new buffer object"); - *out = buf; - return 0; - -err_free: - free(buf); - return ret; -} - -static void kmscon_buffer_free(struct kmscon_buffer *buf) -{ - unsigned int i; - - if (!buf) - return; - - log_debug("destroying buffer object"); - kmscon_buffer_clear_sb(buf); - - for (i = 0; i < buf->scroll_y; ++i) - free_line(buf->scroll_buf[i]); - for (i = 0; i < buf->mtop_y; ++i) - free_line(buf->mtop_buf[i]); - for (i = 0; i < buf->mbottom_y; ++i) - free_line(buf->mbottom_buf[i]); - - free(buf->scroll_buf); - free(buf->mtop_buf); - free(buf->mbottom_buf); - free(buf); -} - -static int kmscon_buffer_set_margins(struct kmscon_buffer *buf, - unsigned int top, - unsigned int bottom) -{ - int ret; - - if (!buf) - return -EINVAL; - - if (top < buf->mtop_y) { - ret = resize_mtop(buf, top); - if (ret) - return ret; - return resize_mbottom(buf, bottom); - } else { - ret = resize_mbottom(buf, bottom); - if (ret) - return ret; - return resize_mtop(buf, top); - } -} - -static void kmscon_buffer_draw(struct kmscon_buffer *buf, - struct font_screen *fscr, - unsigned int cur_x, - unsigned int cur_y) -{ - unsigned int i, j, k, num, o; - struct line *iter, *line = NULL; - struct cell *cell; - int idx; - float m[16]; - bool cursor_done = false; - struct font_char_attr attr; - - if (!buf || !fscr) - return; - - font_screen_draw_start(fscr); - - iter = buf->position; - k = 0; - idx = 0; - o = 0; - for (i = 0; i < buf->size_y; ++i) { - if (iter) { - line = iter; - iter = iter->next; - } else { - if (idx == 0) { - if (k < buf->mtop_y) { - line = buf->mtop_buf[k]; - } else { - k = 0; - idx = 1; - } - } - if (idx == 1) { - if (k < buf->scroll_y) { - line = buf->scroll_buf[k]; - } else { - k = 0; - idx = 2; - } - } - if (idx == 2) { - if (k < buf->mbottom_y) - line = buf->mbottom_buf[k]; - else - break; - } - k++; - o++; - } - - if (!line) - continue; - - if (line->size < buf->size_x) - num = line->size; - else - num = buf->size_x; - - for (j = 0; j < num; ++j) { - cell = &line->cells[j]; - memcpy(&attr, &cell->attr, sizeof(attr)); - - if (o == cur_y + 1 && - j == cur_x) { - cursor_done = true; - attr.inverse = !attr.inverse; - } - - /* TODO: do some more sophisticated inverse here. When - * INVERSE mode is set, we should instead just select - * inverse colors instead of switching background and - * foreground */ - if (buf->flags & KMSCON_CONSOLE_INVERSE) - attr.inverse = !attr.inverse; - font_screen_draw_char(fscr, cell->ch, &attr, - j, i, 1, 1); - } - - if (o == cur_y + 1 && !cursor_done) { - cursor_done = true; - if (!(buf->flags & KMSCON_CONSOLE_INVERSE)) - attr.inverse = !attr.inverse; - font_screen_draw_char(fscr, 0, &attr, - cur_x, i, 1, 1); - } - } - - gl_m4_identity(m); - font_screen_draw_perform(fscr, m); -} - -static void kmscon_buffer_write(struct kmscon_buffer *buf, unsigned int x, - unsigned int y, kmscon_symbol_t ch, - const struct font_char_attr *attr, - unsigned int flags) -{ - struct line *line, **slot; - int ret; - bool scroll = false; - - if (!buf || !attr) - return; - - if (x >= buf->size_x || y >= buf->size_y) { + if (x >= con->size_x || y >= con->size_y) { log_warn("writing beyond buffer boundary"); return; } - if (y < buf->mtop_y) { - slot = &buf->mtop_buf[y]; - } else if (y < buf->mtop_y + buf->scroll_y) { - y -= buf->mtop_y; - slot = &buf->scroll_buf[y]; - scroll = true; - } else if (y < buf->mtop_y + buf->scroll_y + buf->mbottom_y) { - y = y - buf->mtop_y - buf->scroll_y; - slot = &buf->mbottom_buf[y]; - } else { - log_warn("writing to invalid buffer space"); - return; - } + line = con->lines[y]; - line = *slot; - if (!line) { - ret = new_line(&line); - if (ret) { - log_warn("cannot allocate line (%d); dropping input", ret); - return; - } - - *slot = line; - if (scroll && buf->scroll_fill <= y) - buf->scroll_fill = y + 1; - } - - if (line->size < buf->size_x) { - ret = resize_line(line, buf->size_x); - if (ret) { - log_warn("cannot resize line (%d); dropping input", ret); - return; - } - } - - if ((flags & KMSCON_CONSOLE_INSERT) && x < (buf->size_x - 1)) + if ((con->flags & KMSCON_CONSOLE_INSERT_MODE) && x < (con->size_x - 1)) memmove(&line->cells[x + 1], &line->cells[x], - sizeof(struct cell) * (buf->size_x - 1 - x)); + sizeof(struct cell) * (con->size_x - 1 - x)); line->cells[x].ch = ch; memcpy(&line->cells[x].attr, attr, sizeof(*attr)); } -static kmscon_symbol_t kmscon_buffer_read(struct kmscon_buffer *buf, - unsigned int x, - unsigned int y) -{ - struct line *line; - - if (!buf) - return kmscon_symbol_default; - - if (x >= buf->size_x || y >= buf->size_y) { - log_warn("reading out of buffer bounds"); - return kmscon_symbol_default; - } - - if (y < buf->mtop_y) { - line = buf->mtop_buf[y]; - } else if (y < buf->mtop_y + buf->scroll_y) { - y -= buf->mtop_y; - line = buf->scroll_buf[y]; - } else if (y < buf->mtop_y + buf->scroll_y + buf->mbottom_y) { - y = y - buf->mtop_y - buf->scroll_y; - line = buf->mbottom_buf[y]; - } else { - log_warn("reading from invalid buffer space"); - return kmscon_symbol_default; - } - - if (!line) - return kmscon_symbol_default; - - if (x >= line->size) - return kmscon_symbol_default; - - return line->cells[x].ch; -} - -static void kmscon_buffer_scroll_down(struct kmscon_buffer *buf, - unsigned int num) -{ - unsigned int i; - - if (!buf || !num) - return; - - if (num > buf->scroll_y) - num = buf->scroll_y; - - for (i = 0; i < num; ++i) - free_line(buf->scroll_buf[buf->scroll_y - i - 1]); - - memmove(&buf->scroll_buf[num], buf->scroll_buf, - (buf->scroll_y - num) * sizeof(struct line*)); - memset(buf->scroll_buf, 0, num * sizeof(struct line*)); - buf->scroll_fill = buf->scroll_y; -} - -static void kmscon_buffer_scroll_up(struct kmscon_buffer *buf, - unsigned int num) -{ - unsigned int i; - - if (!buf || !num) - return; - - if (num > buf->scroll_y) - num = buf->scroll_y; - - for (i = 0; i < num; ++i) - link_to_scrollback(buf, buf->scroll_buf[i]); - - memmove(buf->scroll_buf, &buf->scroll_buf[num], - (buf->scroll_y - num) * sizeof(struct line*)); - memset(&buf->scroll_buf[buf->scroll_y - num], 0, - num * sizeof(struct line*)); - buf->scroll_fill = buf->scroll_y; -} - -static void kmscon_buffer_erase_region(struct kmscon_buffer *buf, - unsigned int x_from, - unsigned int y_from, - unsigned int x_to, - unsigned int y_to) +static void console_erase_region(struct kmscon_console *con, + unsigned int x_from, + unsigned int y_from, + unsigned int x_to, + unsigned int y_to) { unsigned int to; struct line *line; - if (!buf) - return; - - if (y_to >= buf->size_y) - y_to = buf->size_y - 1; - if (x_to >= buf->size_x) - x_to = buf->size_x - 1; + if (y_to >= con->size_y) + y_to = con->size_y - 1; + if (x_to >= con->size_x) + x_to = con->size_x - 1; for ( ; y_from <= y_to; ++y_from) { - line = get_line(buf, y_from); + line = con->lines[y_from]; if (!line) { x_from = 0; continue; @@ -969,25 +356,13 @@ static void kmscon_buffer_erase_region(struct kmscon_buffer *buf, if (y_from == y_to) to = x_to; else - to = buf->size_x - 1; - for ( ; x_from <= to; ++x_from) { - if (x_from >= line->size) - break; - reset_cell(&line->cells[x_from]); - } + to = con->size_x - 1; + for ( ; x_from <= to; ++x_from) + cell_init(con, &line->cells[x_from]); x_from = 0; } } -/* Console Object - * The console object is a state-machine that represents the current state of - * the whole console. Besides managing the buffer it also controls the current - * cursor position on similar. - * The functions that are provided by this console are exactly the ones that - * are needed to emulate the classic VTs. Therefore, they are designed to have - * the desired behavior and configuration-options. - */ - static inline unsigned int to_abs_x(struct kmscon_console *con, unsigned int x) { return x; @@ -995,16 +370,17 @@ static inline unsigned int to_abs_x(struct kmscon_console *con, unsigned int x) static inline unsigned int to_abs_y(struct kmscon_console *con, unsigned int y) { - if (!(con->cells->flags & KMSCON_CONSOLE_REL_ORIGIN)) + if (!(con->flags & KMSCON_CONSOLE_REL_ORIGIN)) return y; - return con->cells->mtop_y + y; + return con->margin_top + y; } int kmscon_console_new(struct kmscon_console **out) { struct kmscon_console *con; int ret; + unsigned int i; if (!out) return -EINVAL; @@ -1015,8 +391,11 @@ int kmscon_console_new(struct kmscon_console **out) memset(con, 0, sizeof(*con)); con->ref = 1; + con->def_attr.fr = 255; + con->def_attr.fg = 255; + con->def_attr.fb = 255; - ret = kmscon_buffer_new(&con->cells, 0, 0); + ret = kmscon_console_resize(con, 80, 24); if (ret) goto err_free; @@ -1026,6 +405,9 @@ int kmscon_console_new(struct kmscon_console **out) return 0; err_free: + for (i = 0; i < con->line_num; ++i) + line_free(con->lines[i]); + free(con->lines); free(con); return ret; } @@ -1038,20 +420,18 @@ void kmscon_console_ref(struct kmscon_console *con) ++con->ref; } -/* - * Drops one reference. If this is the last reference, the whole console is - * freed and the associated render-images are destroyed. - */ void kmscon_console_unref(struct kmscon_console *con) { - if (!con || !con->ref) - return; + unsigned int i; - if (--con->ref) + if (!con || !con->ref || --con->ref) return; log_debug("destroying console"); - kmscon_buffer_free(con->cells); + + for (i = 0; i < con->line_num; ++i) + line_free(con->lines[i]); + free(con->lines); free(con); } @@ -1060,7 +440,7 @@ unsigned int kmscon_console_get_width(struct kmscon_console *con) if (!con) return 0; - return con->cells->size_x; + return con->size_x; } unsigned int kmscon_console_get_height(struct kmscon_console *con) @@ -1068,7 +448,80 @@ unsigned int kmscon_console_get_height(struct kmscon_console *con) if (!con) return 0; - return con->cells->size_y; + return con->size_y; +} + +int kmscon_console_resize(struct kmscon_console *con, unsigned int x, + unsigned int y) +{ + struct line **cache; + unsigned int i, j, width; + int ret; + + if (!con || !x || !y) + return -EINVAL; + + if (con->size_x == x && con->size_y == y) + return 0; + + /* First make sure the line buffer is big enough for our new console. + * That is, allocate all new lines and make sure each line has enough + * cells to hold the new console or the current console. If we fail, we + * can safely return -ENOMEM and the buffer is still valid. We must + * allocate the new lines to at least the same size as the current + * lines. Otherwise, if this function fails in later turns, we will have + * invalid lines in the buffer. */ + if (y > con->line_num) { + cache = realloc(con->lines, sizeof(struct line*) * y); + if (!cache) + return -ENOMEM; + + con->lines = cache; + if (x > con->size_x) + width = x; + else + width = con->size_x; + + while (con->line_num < y) { + ret = line_new(con, &cache[con->line_num], width); + if (ret) + return ret; + ++con->line_num; + } + } + + /* Resize all lines in the buffer if we increase console width. This + * will guarantee that all lines are big enough so we can resize the + * buffer without reallocating them later. */ + if (x > con->size_x) { + for (i = 0; i < con->line_num; ++i) { + ret = line_resize(con, con->lines[i], x); + if (ret) + return ret; + } + } + + /* When resizing, we need to reset all the new cells, otherwise, the old + * data that was written there will reoccur on the screen. */ + for (j = 0; j < y; ++j) { + for (i = con->size_x; i < x; ++i) + cell_init(con, &con->lines[j]->cells[i]); + } + + /* xterm destroys margins on resize, so do we */ + con->margin_top = 0; + con->margin_bottom = con->size_y - 1; + + /* scroll buffer if console height shrinks */ + if (con->size_y != 0 && y < con->size_y) + console_scroll_up(con, con->size_y - y); + + con->size_x = x; + con->size_y = y; + con->margin_top = 0; + con->margin_bottom = con->size_y - 1; + + return 0; } int kmscon_console_set_margins(struct kmscon_console *con, @@ -1084,16 +537,67 @@ int kmscon_console_set_margins(struct kmscon_console *con, if (bottom <= top) { upper = 0; - lower = 0; - } else if (bottom > con->cells->size_y) { + lower = con->size_y - 1; + } else if (bottom > con->size_y) { upper = 0; - lower = 0; + lower = con->size_y - 1; } else { upper = top - 1; - lower = con->cells->size_y - bottom; + lower = bottom - 1; } - return kmscon_buffer_set_margins(con->cells, upper, lower); + con->margin_top = upper; + con->margin_bottom = lower; + return 0; +} + +/* set maximum scrollback buffer size */ +void kmscon_console_set_max_sb(struct kmscon_console *con, + unsigned int max) +{ + struct line *line; + + if (!con) + return; + + while (con->sb_count > max) { + line = con->sb_first; + con->sb_first = line->next; + if (line->next) + line->next->prev = NULL; + else + con->sb_last = NULL; + con->sb_count--; + + /* We treat fixed/unfixed position the same here because we + * remove lines from the TOP of the scrollback buffer. */ + if (con->sb_pos == line) + con->sb_pos = con->sb_first; + + line_free(line); + } + + con->sb_max = max; +} + +/* clear scrollback buffer */ +void kmscon_console_clear_sb(struct kmscon_console *con) +{ + struct line *iter, *tmp; + + if (!con) + return; + + for (iter = con->sb_first; iter; ) { + tmp = iter; + iter = iter->next; + line_free(tmp); + } + + con->sb_first = NULL; + con->sb_last = NULL; + con->sb_count = 0; + con->sb_pos = NULL; } void kmscon_console_reset(struct kmscon_console *con) @@ -1109,7 +613,7 @@ void kmscon_console_set_flags(struct kmscon_console *con, unsigned int flags) if (!con || !flags) return; - con->cells->flags |= flags; + con->flags |= flags; } void kmscon_console_reset_flags(struct kmscon_console *con, unsigned int flags) @@ -1117,7 +621,7 @@ void kmscon_console_reset_flags(struct kmscon_console *con, unsigned int flags) if (!con || !flags) return; - con->cells->flags &= ~flags; + con->flags &= ~flags; } unsigned int kmscon_console_get_flags(struct kmscon_console *con) @@ -1125,156 +629,183 @@ unsigned int kmscon_console_get_flags(struct kmscon_console *con) if (!con) return 0; - return con->cells->flags; + return con->flags; } void kmscon_console_draw(struct kmscon_console *con, struct font_screen *fscr) { unsigned int cur_x, cur_y; + unsigned int i, j, k; + struct line *iter, *line = NULL; + struct cell *cell; + float m[16]; + bool cursor_done = false; + struct font_char_attr attr; - if (!con) + if (!con || !fscr) return; cur_x = con->cursor_x; - if (con->cursor_x >= con->cells->size_x) - cur_x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + cur_x = con->size_x - 1; cur_y = con->cursor_y; + if (con->cursor_y >= con->size_y) + cur_y = con->size_y - 1; - kmscon_buffer_draw(con->cells, fscr, cur_x, cur_y); + font_screen_draw_start(fscr); + + iter = con->sb_pos; + k = 0; + for (i = 0; i < con->size_y; ++i) { + if (iter) { + line = iter; + iter = iter->next; + } else { + line = con->lines[k]; + k++; + } + + for (j = 0; j < con->size_x; ++j) { + cell = &line->cells[j]; + memcpy(&attr, &cell->attr, sizeof(attr)); + + if (k == cur_y + 1 && + j == cur_x) { + cursor_done = true; + attr.inverse = !attr.inverse; + } + + /* TODO: do some more sophisticated inverse here. When + * INVERSE mode is set, we should instead just select + * inverse colors instead of switching background and + * foreground */ + if (con->flags & KMSCON_CONSOLE_INVERSE) + attr.inverse = !attr.inverse; + font_screen_draw_char(fscr, cell->ch, &attr, + j, i, 1, 1); + } + + if (k == cur_y + 1 && !cursor_done) { + cursor_done = true; + if (!(con->flags & KMSCON_CONSOLE_INVERSE)) + attr.inverse = !attr.inverse; + font_screen_draw_char(fscr, 0, &attr, + cur_x, i, 1, 1); + } + } + + gl_m4_identity(m); + font_screen_draw_perform(fscr, m); } void kmscon_console_write(struct kmscon_console *con, kmscon_symbol_t ch, - const struct font_char_attr *attr, - unsigned int flags) + const struct font_char_attr *attr) { unsigned int last; if (!con) return; - last = con->cells->scroll_y + con->cells->mtop_y; + if (con->cursor_y <= con->margin_bottom || + con->cursor_y >= con->size_y) + last = con->margin_bottom; + else + last = con->size_y - 1; - if (con->cursor_x >= con->cells->size_x) { - if (flags & KMSCON_CONSOLE_WRAP) { + if (con->cursor_x >= con->size_x) { + if (con->flags & KMSCON_CONSOLE_AUTO_WRAP) { con->cursor_x = 0; - con->cursor_y++; - if (con->cursor_y >= last) { - con->cursor_y--; - kmscon_buffer_scroll_up(con->cells, 1); - } + ++con->cursor_y; } else { - con->cursor_x = con->cells->size_x - 1; + con->cursor_x = con->size_x - 1; } } - kmscon_buffer_write(con->cells, con->cursor_x, con->cursor_y, ch, attr, - flags); - con->cursor_x++; + if (con->cursor_y > last) { + con->cursor_y = last; + console_scroll_up(con, 1); + } + + console_write(con, con->cursor_x, con->cursor_y, ch, attr); + ++con->cursor_x; } void kmscon_console_newline(struct kmscon_console *con) { - unsigned int last; - if (!con) return; - last = con->cells->scroll_y + con->cells->mtop_y; - con->cursor_x = 0; - con->cursor_y++; - if (con->cursor_y >= last) { - con->cursor_y--; - kmscon_buffer_scroll_up(con->cells, 1); - } + kmscon_console_move_down(con, 1, true); + kmscon_console_move_line_home(con); } void kmscon_console_move_to(struct kmscon_console *con, unsigned int x, - unsigned int y) + unsigned int y) { unsigned int last; if (!con) return; - last = con->cells->scroll_y + con->cells->mtop_y; + if (con->flags & KMSCON_CONSOLE_REL_ORIGIN) + last = con->margin_bottom; + else + last = con->size_y - 1; + con->cursor_x = to_abs_x(con, x); - if (con->cursor_x >= con->cells->size_x) - con->cursor_x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + con->cursor_x = con->size_x - 1; con->cursor_y = to_abs_y(con, y); - if (con->cursor_y >= last) { - if (con->cells->flags & KMSCON_CONSOLE_REL_ORIGIN) - con->cursor_y = last - 1; - else if (con->cursor_y >= con->cells->size_y) - con->cursor_y = con->cells->size_y - 1; - } + if (con->cursor_y > last) + con->cursor_y = last; } void kmscon_console_move_up(struct kmscon_console *con, unsigned int num, - bool scroll) + bool scroll) { - unsigned int diff; + unsigned int diff, size; if (!con || !num) return; - if (num > con->cells->size_y) - num = con->cells->size_y; + if (con->cursor_y >= con->margin_top) + size = con->margin_top; + else + size = 0; - if (con->cells->flags & KMSCON_CONSOLE_REL_ORIGIN) { - diff = con->cursor_y - con->cells->mtop_y; - if (num > diff) { - num -= diff; - if (scroll) - kmscon_buffer_scroll_down(con->cells, num); - con->cursor_y = con->cells->mtop_y; - } else { - con->cursor_y -= num; - } + diff = con->cursor_y - size; + if (num > diff) { + num -= diff; + if (scroll) + console_scroll_down(con, num); + con->cursor_y = size; } else { - if (num > con->cursor_y) { - num -= con->cursor_y; - if (scroll) - kmscon_buffer_scroll_down(con->cells, num); - con->cursor_y = 0; - } else { - con->cursor_y -= num; - } + con->cursor_y -= num; } } void kmscon_console_move_down(struct kmscon_console *con, unsigned int num, - bool scroll) + bool scroll) { - unsigned int diff, last; + unsigned int diff, size; if (!con || !num) return; - last = con->cells->scroll_y + con->cells->mtop_y; - if (num > con->cells->size_y) - num = con->cells->size_y; + if (con->cursor_y <= con->margin_bottom) + size = con->margin_bottom + 1; + else + size = con->size_y; - if (con->cells->flags & KMSCON_CONSOLE_REL_ORIGIN) { - diff = last - 1 - con->cursor_y; - if (num > diff) { - num -= diff; - if (scroll) - kmscon_buffer_scroll_up(con->cells, num); - con->cursor_y = last - 1; - } else { - con->cursor_y += num; - } + diff = size - con->cursor_y - 1; + if (num > diff) { + num -= diff; + if (scroll) + console_scroll_up(con, num); + con->cursor_y = size - 1; } else { - diff = con->cells->size_y - con->cursor_y - 1; - if (num > diff) { - num -= diff; - if (scroll) - kmscon_buffer_scroll_up(con->cells, num); - con->cursor_y = con->cells->size_y - 1; - } else { - con->cursor_y += num; - } + con->cursor_y += num; } } @@ -1283,11 +814,11 @@ void kmscon_console_move_left(struct kmscon_console *con, unsigned int num) if (!con || !num) return; - if (num > con->cells->size_x) - num = con->cells->size_x; + if (num > con->size_x) + num = con->size_x; - if (con->cursor_x >= con->cells->size_x) - con->cursor_x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + con->cursor_x = con->size_x - 1; if (num > con->cursor_x) con->cursor_x = 0; @@ -1300,11 +831,11 @@ void kmscon_console_move_right(struct kmscon_console *con, unsigned int num) if (!con || !num) return; - if (num > con->cells->size_x) - num = con->cells->size_x; + if (num > con->size_x) + num = con->size_x; - if (num + con->cursor_x >= con->cells->size_x) - con->cursor_x = con->cells->size_x - 1; + if (num + con->cursor_x >= con->size_x) + con->cursor_x = con->size_x - 1; else con->cursor_x += num; } @@ -1314,7 +845,7 @@ void kmscon_console_move_line_end(struct kmscon_console *con) if (!con) return; - con->cursor_x = con->cells->size_x - 1; + con->cursor_x = con->size_x - 1; } void kmscon_console_move_line_home(struct kmscon_console *con) @@ -1332,13 +863,12 @@ void kmscon_console_erase_cursor(struct kmscon_console *con) if (!con) return; - if (con->cursor_x >= con->cells->size_x) - x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + x = con->size_x - 1; else x = con->cursor_x; - kmscon_buffer_erase_region(con->cells, x, con->cursor_y, - x, con->cursor_y); + console_erase_region(con, x, con->cursor_y, x, con->cursor_y); } void kmscon_console_erase_cursor_to_end(struct kmscon_console *con) @@ -1348,13 +878,13 @@ void kmscon_console_erase_cursor_to_end(struct kmscon_console *con) if (!con) return; - if (con->cursor_x >= con->cells->size_x) - x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + x = con->size_x - 1; else x = con->cursor_x; - kmscon_buffer_erase_region(con->cells, x, con->cursor_y, - con->cells->size_x - 1, con->cursor_y); + console_erase_region(con, x, con->cursor_y, con->size_x - 1, + con->cursor_y); } void kmscon_console_erase_home_to_cursor(struct kmscon_console *con) @@ -1362,8 +892,8 @@ void kmscon_console_erase_home_to_cursor(struct kmscon_console *con) if (!con) return; - kmscon_buffer_erase_region(con->cells, 0, con->cursor_y, - con->cursor_x, con->cursor_y); + console_erase_region(con, 0, con->cursor_y, con->cursor_x, + con->cursor_y); } void kmscon_console_erase_current_line(struct kmscon_console *con) @@ -1371,8 +901,8 @@ void kmscon_console_erase_current_line(struct kmscon_console *con) if (!con) return; - kmscon_buffer_erase_region(con->cells, 0, con->cursor_y, - con->cells->size_x - 1, con->cursor_y); + console_erase_region(con, 0, con->cursor_y, con->size_x - 1, + con->cursor_y); } void kmscon_console_erase_screen_to_cursor(struct kmscon_console *con) @@ -1380,8 +910,7 @@ void kmscon_console_erase_screen_to_cursor(struct kmscon_console *con) if (!con) return; - kmscon_buffer_erase_region(con->cells, 0, 0, - con->cursor_x, con->cursor_y); + console_erase_region(con, 0, 0, con->cursor_x, con->cursor_y); } void kmscon_console_erase_cursor_to_screen(struct kmscon_console *con) @@ -1391,13 +920,13 @@ void kmscon_console_erase_cursor_to_screen(struct kmscon_console *con) if (!con) return; - if (con->cursor_x >= con->cells->size_x) - x = con->cells->size_x - 1; + if (con->cursor_x >= con->size_x) + x = con->size_x - 1; else x = con->cursor_x; - kmscon_buffer_erase_region(con->cells, x, con->cursor_y, - con->cells->size_x - 1, con->cells->size_y - 1); + console_erase_region(con, x, con->cursor_y, con->size_x - 1, + con->size_y - 1); } void kmscon_console_erase_screen(struct kmscon_console *con) @@ -1405,6 +934,5 @@ void kmscon_console_erase_screen(struct kmscon_console *con) if (!con) return; - kmscon_buffer_erase_region(con->cells, 0, 0, - con->cells->size_x - 1, con->cells->size_y - 1); + console_erase_region(con, 0, 0, con->size_x - 1, con->size_y - 1); } diff --git a/src/console.h b/src/console.h index f867fbe..c23bf2f 100644 --- a/src/console.h +++ b/src/console.h @@ -44,13 +44,12 @@ struct kmscon_console; /* console objects */ -/* modes for kmscon_console_write() */ -#define KMSCON_CONSOLE_INSERT 0x01 -#define KMSCON_CONSOLE_WRAP 0x02 -/* modes for kmscon_console_re/set() */ +#define KMSCON_CONSOLE_INSERT_MODE 0x01 +#define KMSCON_CONSOLE_AUTO_WRAP 0x02 #define KMSCON_CONSOLE_REL_ORIGIN 0x04 #define KMSCON_CONSOLE_INVERSE 0x08 #define KMSCON_CONSOLE_HIDE_CURSOR 0x10 +#define KMSCON_CONSOLE_FIXED_POS 0x20 int kmscon_console_new(struct kmscon_console **out); void kmscon_console_ref(struct kmscon_console *con); @@ -59,9 +58,12 @@ void kmscon_console_unref(struct kmscon_console *con); unsigned int kmscon_console_get_width(struct kmscon_console *con); unsigned int kmscon_console_get_height(struct kmscon_console *con); int kmscon_console_resize(struct kmscon_console *con, unsigned int x, - unsigned int y, unsigned int height); + unsigned int y); int kmscon_console_set_margins(struct kmscon_console *con, unsigned int top, unsigned int bottom); +void kmscon_console_set_max_sb(struct kmscon_console *con, unsigned int max); +void kmscon_console_clear_sb(struct kmscon_console *con); + void kmscon_console_reset(struct kmscon_console *con); void kmscon_console_set_flags(struct kmscon_console *con, unsigned int flags); void kmscon_console_reset_flags(struct kmscon_console *con, unsigned int flags); @@ -70,15 +72,14 @@ unsigned int kmscon_console_get_flags(struct kmscon_console *con); void kmscon_console_draw(struct kmscon_console *con, struct font_screen *fscr); void kmscon_console_write(struct kmscon_console *con, kmscon_symbol_t ch, - const struct font_char_attr *attr, - unsigned int flags); + const struct font_char_attr *attr); void kmscon_console_newline(struct kmscon_console *con); void kmscon_console_move_to(struct kmscon_console *con, unsigned int x, - unsigned int y); + unsigned int y); void kmscon_console_move_up(struct kmscon_console *con, unsigned int num, - bool scroll); + bool scroll); void kmscon_console_move_down(struct kmscon_console *con, unsigned int num, - bool scroll); + bool scroll); void kmscon_console_move_left(struct kmscon_console *con, unsigned int num); void kmscon_console_move_right(struct kmscon_console *con, unsigned int num); void kmscon_console_move_line_end(struct kmscon_console *con); diff --git a/src/vte.c b/src/vte.c index 4b8b256..865eff4 100644 --- a/src/vte.c +++ b/src/vte.c @@ -282,15 +282,7 @@ static void vte_write_debug(struct kmscon_vte *vte, const char *u8, size_t len, /* write to console */ static void write_console(struct kmscon_vte *vte, kmscon_symbol_t sym) { - unsigned int flags; - - flags = 0; - if (vte->flags & FLAG_INSERT_REPLACE_MODE) - flags |= KMSCON_CONSOLE_INSERT; - if (vte->flags & FLAG_AUTO_WRAP_MODE) - flags |= KMSCON_CONSOLE_WRAP; - - kmscon_console_write(vte->con, sym, &vte->cattr, flags); + kmscon_console_write(vte->con, sym, &vte->cattr); } /* @@ -856,6 +848,12 @@ static void csi_mode(struct kmscon_vte *vte, bool set) case 4: /* IRM */ set_reset_flag(vte, set, FLAG_INSERT_REPLACE_MODE); + if (set) + kmscon_console_set_flags(vte->con, + KMSCON_CONSOLE_INSERT_MODE); + else + kmscon_console_reset_flags(vte->con, + KMSCON_CONSOLE_INSERT_MODE); continue; case 12: /* SRM */ set_reset_flag(vte, set, @@ -926,6 +924,12 @@ static void csi_mode(struct kmscon_vte *vte, bool set) continue; case 7: /* DECAWN */ set_reset_flag(vte, set, FLAG_AUTO_WRAP_MODE); + if (set) + kmscon_console_set_flags(vte->con, + KMSCON_CONSOLE_AUTO_WRAP); + else + kmscon_console_reset_flags(vte->con, + KMSCON_CONSOLE_AUTO_WRAP); continue; case 8: /* DECARM */ set_reset_flag(vte, set, FLAG_AUTO_REPEAT_MODE);