static void screen_scroll_up(struct tsm_screen *con, unsigned int num) { unsigned int i, j, max; int ret; if (!num) return; max = con->margin_bottom + 1 - con->margin_top; if (num > max) num = max; /* 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) { screen_scroll_up(con, 128); return screen_scroll_up(con, num - 128); } struct line *cache[num]; 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]); } } if (num < max) { memmove(&con->lines[con->margin_top], &con->lines[con->margin_top + num], (max - num) * sizeof(struct line*)); } memcpy(&con->lines[con->margin_top + (max - num)], cache, num * sizeof(struct line*)); }
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 screen_scroll_up(struct tsm_screen *con, unsigned int num) { unsigned int i, j, max, pos; int ret; if (!num) return; /* TODO: more sophisticated ageing */ con->age = con->age_cnt; max = con->margin_bottom + 1 - con->margin_top; if (num > max) num = max; /* 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) { screen_scroll_up(con, 128); return screen_scroll_up(con, num - 128); } struct line *cache[num]; for (i = 0; i < num; ++i) { pos = con->margin_top + i; if (!(con->flags & TSM_SCREEN_ALTERNATE)) ret = line_new(con, &cache[i], con->size_x); else ret = -EAGAIN; if (!ret) { link_to_scrollback(con, con->lines[pos]); } else { cache[i] = con->lines[pos]; for (j = 0; j < con->size_x; ++j) screen_cell_init(con, &cache[i]->cells[j]); } } if (num < max) { memmove(&con->lines[con->margin_top], &con->lines[con->margin_top + num], (max - num) * sizeof(struct line*)); } memcpy(&con->lines[con->margin_top + (max - num)], cache, num * sizeof(struct line*)); if (con->sel_active) { if (!con->sel_start.line && con->sel_start.y >= 0) { con->sel_start.y -= num; if (con->sel_start.y < 0) { con->sel_start.line = con->sb_last; while (con->sel_start.line && ++con->sel_start.y < 0) con->sel_start.line = con->sel_start.line->prev; con->sel_start.y = SELECTION_TOP; } } if (!con->sel_end.line && con->sel_end.y >= 0) { con->sel_end.y -= num; if (con->sel_end.y < 0) { con->sel_end.line = con->sb_last; while (con->sel_end.line && ++con->sel_end.y < 0) con->sel_end.line = con->sel_end.line->prev; con->sel_end.y = SELECTION_TOP; } } } }
/* 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; }