diff options
Diffstat (limited to 'screen.c')
-rw-r--r-- | screen.c | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/screen.c b/screen.c new file mode 100644 index 00000000..d997cb66 --- /dev/null +++ b/screen.c @@ -0,0 +1,827 @@ +/* $Id: screen.c,v 1.1.1.1 2007-07-09 19:03:54 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <string.h> + +#include "tmux.h" + +/* + * Virtual screen and basic ANSI terminal emulator. + */ + +size_t screen_store_attributes(struct buffer *, u_char); +size_t screen_store_colours(struct buffer *, u_char); +void screen_free_lines(struct screen *, u_int, u_int); +void screen_make_lines(struct screen *, u_int, u_int); +void screen_move_lines(struct screen *, u_int, u_int, u_int); +void screen_fill_lines( + struct screen *, u_int, u_int, u_char, u_char, u_char); +uint16_t screen_extract(u_char *); +void screen_write_character(struct screen *, u_char); +void screen_cursor_up_scroll(struct screen *, u_int); +void screen_cursor_down_scroll(struct screen *, u_int); +void screen_scroll_up(struct screen *, u_int); +void screen_scroll_down(struct screen *, u_int); +void screen_fill_screen(struct screen *, u_char, u_char, u_char); +void screen_fill_line(struct screen *, u_int, u_char, u_char, u_char); +void screen_fill_end_of_screen( + struct screen *, u_int, u_int, u_char, u_char, u_char); +void screen_fill_end_of_line( + struct screen *, u_int, u_int, u_char, u_char, u_char); +void screen_fill_start_of_line( + struct screen *, u_int, u_int, u_char, u_char, u_char); +void screen_insert_lines(struct screen *, u_int, u_int); +void screen_delete_lines(struct screen *, u_int, u_int); +void screen_insert_characters(struct screen *, u_int, u_int, u_int); +void screen_delete_characters(struct screen *, u_int, u_int, u_int); + +#define SCREEN_DEFDATA ' ' +#define SCREEN_DEFATTR 0 +#define SCREEN_DEFCOLR 0x88 + +#define screen_last_y(s) ((s)->sy - 1) +#define screen_last_x(s) ((s)->sx - 1) + +/* Create a new screen. */ +void +screen_create(struct screen *s, u_int sx, u_int sy) +{ + s->sx = sx; + s->sy = sy; + s->cx = 0; + s->cy = 0; + + s->ry_upper = 0; + s->ry_lower = sy - 1; + + s->attr = SCREEN_DEFATTR; + s->colr = SCREEN_DEFCOLR; + + s->mode = MODE_CURSOR; + *s->title = '\0'; + + s->grid_data = xmalloc(sy * (sizeof *s->grid_data)); + s->grid_attr = xmalloc(sy * (sizeof *s->grid_attr)); + s->grid_colr = xmalloc(sy * (sizeof *s->grid_colr)); + screen_make_lines(s, 0, screen_last_y(s)); + screen_fill_screen(s, SCREEN_DEFDATA, 0, SCREEN_DEFCOLR); +} + +/* Resize screen. */ +void +screen_resize(struct screen *s, u_int sx, u_int sy) +{ + u_int i, ox, oy, ny; + + if (sx < 1) + sx = 1; + if (sy < 1) + sy = 1; + + ox = s->sx; + oy = s->sy; + s->sx = sx; + s->sy = sy; + + log_debug("resizing screen (%u, %u) -> (%u, %u)", ox, oy, sx, sy); + + if (sy < oy) { + ny = oy - sy; + if (ny > s->cy) + ny = s->cy; + + if (ny != 0) { + log_debug("removing %u lines from top", ny); + for (i = 0; i < ny; i++) { + log_debug("freeing line %u", i); + xfree(s->grid_data[i]); + xfree(s->grid_attr[i]); + xfree(s->grid_colr[i]); + } + memmove(s->grid_data, s->grid_data + ny, + (oy - ny) * (sizeof *s->grid_data)); + memmove(s->grid_attr, s->grid_attr + ny, + (oy - ny) * (sizeof *s->grid_attr)); + memmove(s->grid_colr, s->grid_colr + ny, + (oy - ny) * (sizeof *s->grid_colr)); + s->cy -= ny; + } + if (ny < oy - sy) { + log_debug( + "removing %u lines from bottom", oy - sy - ny); + for (i = sy; i < oy - ny; i++) { + log_debug("freeing line %u", i); + xfree(s->grid_data[i]); + xfree(s->grid_attr[i]); + xfree(s->grid_colr[i]); + } + if (s->cy >= sy) + s->cy = sy - 1; + } + } + if (sy != oy) { + s->grid_data = xrealloc(s->grid_data, sy, sizeof *s->grid_data); + s->grid_attr = xrealloc(s->grid_attr, sy, sizeof *s->grid_attr); + s->grid_colr = xrealloc(s->grid_colr, sy, sizeof *s->grid_colr); + } + if (sy > oy) { + for (i = oy; i < sy; i++) { + log_debug("allocating line %u", i); + s->grid_data[i] = xmalloc(sx); + s->grid_attr[i] = xmalloc(sx); + s->grid_colr[i] = xmalloc(sx); + screen_fill_line(s, i, + SCREEN_DEFDATA, SCREEN_DEFATTR, SCREEN_DEFCOLR); + } + sy = oy; + } + + if (sx != ox) { + for (i = 0; i < sy; i++) { + log_debug("adjusting line %u to %u", i, sx); + s->grid_data[i] = xrealloc(s->grid_data[i], sx, 1); + s->grid_attr[i] = xrealloc(s->grid_attr[i], sx, 1); + s->grid_colr[i] = xrealloc(s->grid_colr[i], sx, 1); + if (sx > ox) { + screen_fill_end_of_line(s, ox, i, + SCREEN_DEFDATA, SCREEN_DEFATTR, + SCREEN_DEFCOLR); + } + } + if (s->cx >= sx) + s->cx = sx - 1; + } +} + +/* Draw a set of lines on the screen. */ +void +screen_draw(struct screen *s, struct buffer *b, u_int py_upper, u_int py_lower) +{ + u_char attr, colr; + size_t size; + u_int i, j; + uint16_t n; + + if (py_upper > s->sy || py_lower > s->sy || py_upper > py_lower) { + log_fatalx( + "screen_draw_lines: invalid, %u to %u", py_upper, py_lower); + } + + /* XXX. This is naive and rough right now. */ + attr = 0; + colr = SCREEN_DEFCOLR; + + input_store_zero(b, CODE_CURSOROFF); + + input_store_one(b, CODE_ATTRIBUTES, 0); + + for (j = py_upper; j <= py_lower; j++) { + input_store_two(b, CODE_CURSORMOVE, j + 1, 1); + + for (i = 0; i < s->sx; i++) { + + size = BUFFER_USED(b); + input_store_one(b, CODE_ATTRIBUTES, 0); + + n = 0; + if (s->grid_attr[j][i] != attr) { + attr = s->grid_attr[j][i]; + n += screen_store_attributes(b, attr); + if (attr == 0) + colr = SCREEN_DEFCOLR; + } + if (s->grid_colr[j][i] != colr) { + colr = s->grid_colr[j][i]; + n += screen_store_colours(b, colr); + } + if (n == 0) + buffer_reverse_add(b, 4); + else { + size = BUFFER_USED(b) - size; + memcpy(BUFFER_IN(b) - size + 2, &n, 2); + } + + input_store8(b, s->grid_data[j][i]); + } + } + + size = BUFFER_USED(b); + input_store_one(b, CODE_ATTRIBUTES, 0); + n = screen_store_attributes(b, s->attr); + n += screen_store_colours(b, s->colr); + size = BUFFER_USED(b) - size; + memcpy(BUFFER_IN(b) - size + 2, &n, 2); + + input_store_two(b, CODE_CURSORMOVE, s->cy + 1, s->cx + 1); + + if (s->mode & MODE_CURSOR) + input_store_zero(b, CODE_CURSORON); +} + +/* Store screen atttributes in buffer. */ +size_t +screen_store_attributes(struct buffer *b, u_char attr) +{ + size_t n; + + if (attr == 0) { + input_store16(b, 0); + return (1); + } + + n = 0; + if (attr & ATTR_BRIGHT) { + input_store16(b, 1); + n++; + } + if (attr & ATTR_DIM) { + input_store16(b, 2); + n++; + } + if (attr & ATTR_ITALICS) { + input_store16(b, 3); + n++; + } + if (attr & ATTR_UNDERSCORE) { + input_store16(b, 4); + n++; + } + if (attr & ATTR_BLINK) { + input_store16(b, 5); + n++; + } + if (attr & ATTR_REVERSE) { + input_store16(b, 7); + n++; + } + if (attr & ATTR_HIDDEN) { + input_store16(b, 8); + n++; + } + return (n); +} + +/* Store screen colours in buffer. */ +size_t +screen_store_colours(struct buffer *b, u_char colr) +{ + uint16_t v; + + v = colr >> 4; + if (v == 8) + v = 9; + input_store16(b, 30 + v); + v = colr & 0xf; + if (v == 8) + v = 9; + input_store16(b, 40 + v); + + return (2); +} + +/* Make a range of lines. */ +void +screen_make_lines(struct screen *s, u_int uy, u_int ly) +{ + u_int i; + + log_debug("making lines %u:%u", uy, ly); + + if (uy > screen_last_y(s) || ly > screen_last_y(s) || ly < uy) + log_fatalx("screen_make_lines: bad range"); + + for (i = uy; i <= ly; i++) { + s->grid_data[i] = xmalloc(s->sx); + s->grid_attr[i] = xmalloc(s->sx); + s->grid_colr[i] = xmalloc(s->sx); + } +} + +/* Free a range of lines. */ +void +screen_free_lines(struct screen *s, u_int uy, u_int ly) +{ + u_int i; + + log_debug("freeing lines %u:%u", uy, ly); + + if (uy > screen_last_y(s) || ly > screen_last_y(s) || ly < uy) + log_fatalx("screen_free_lines: bad range"); + + for (i = uy; i <= ly; i++) { + xfree(s->grid_data[i]); + s->grid_data[i] = (u_char *) 0xabcdabcd; + xfree(s->grid_attr[i]); + s->grid_attr[i] = (u_char *) 0xabcdabcd; + xfree(s->grid_colr[i]); + s->grid_colr[i] = (u_char *) 0xabcdabcd; + } +} + +/* Move a range of lines. */ +void +screen_move_lines(struct screen *s, u_int dy, u_int uy, u_int ly) +{ + u_int ny; + + log_debug("moving lines %u:%u to %u", uy, ly, dy); + + if (uy > screen_last_y(s) || ly > screen_last_y(s) || ly < uy) + log_fatalx("screen_move_lines: bad range"); + if (dy > screen_last_y(s)) + log_fatalx("screen_move_lines: bad destination"); + + ny = (ly - uy) + 1; + memmove( + s->grid_data + dy, s->grid_data + uy, ny * (sizeof *s->grid_data)); + memmove( + s->grid_attr + dy, s->grid_attr + uy, ny * (sizeof *s->grid_attr)); + memmove( + s->grid_colr + dy, s->grid_colr + uy, ny * (sizeof *s->grid_colr)); +} + +/* Fill a range of lines. */ +void +screen_fill_lines( + struct screen *s, u_int uy, u_int ly, u_char data, u_char attr, u_char colr) +{ + u_int i; + + log_debug("filling lines %u:%u", uy, ly); + + if (uy > screen_last_y(s) || ly > screen_last_y(s) || ly < uy) + log_fatalx("screen_fill_lines: bad range"); + + for (i = uy; i <= ly; i++) + screen_fill_line(s, i, data, attr, colr); +} + +/* Update screen with character. */ +void +screen_character(struct screen *s, u_char ch) +{ + switch (ch) { + case '\n': /* LF */ + screen_cursor_down_scroll(s, 1); + break; + case '\r': /* CR */ + s->cx = 0; + break; + case '\010': /* BS */ + if (s->cx > 0) + s->cx--; + break; + default: + if (ch < ' ') + log_fatalx("screen_character: bad control: %hhu", ch); + screen_write_character(s, ch); + break; + } +} + +/* Extract 16-bit value from pointer. */ +uint16_t +screen_extract(u_char *ptr) +{ + uint16_t n; + + memcpy(&n, ptr, sizeof n); + return (n); +} + +/* Update screen with escape sequence. */ +void +screen_sequence(struct screen *s, u_char *ptr) +{ + uint16_t ua, ub; + + ptr++; + log_debug("processing code %hhu", *ptr); + switch (*ptr++) { + case CODE_CURSORUP: + ua = screen_extract(ptr); + if (ua > s->cy) + ua = s->cy; + s->cy -= ua; + break; + case CODE_CURSORDOWN: + ua = screen_extract(ptr); + if (s->cy + ua >= s->sy) + ua = s->sy - 1 - s->cy; + s->cy += ua; + break; + case CODE_CURSORLEFT: + ua = screen_extract(ptr); + if (ua > s->cx) + ua = s->cx; + s->cx -= ua; + break; + case CODE_CURSORRIGHT: + ua = screen_extract(ptr); + if (s->cx + ua >= s->sx) + ua = s->sx - 1 - s->cx; + s->cx += ua; + break; + case CODE_CURSORMOVE: + ua = screen_extract(ptr); + ptr += 2; + ub = screen_extract(ptr); + if (ub > s->sx) + ub = s->sx; + s->cx = ub - 1; + if (ua > s->sy) + ua = s->sy; + s->cy = ua - 1; + break; + case CODE_CLEARENDOFSCREEN: + screen_fill_end_of_screen( + s, s->cx, s->cy, SCREEN_DEFDATA, s->attr, s->colr); + break; + case CODE_CLEARSCREEN: + screen_fill_screen(s, SCREEN_DEFDATA, s->attr, s->colr); + break; + case CODE_CLEARENDOFLINE: + screen_fill_end_of_line( + s, s->cx, s->cy, SCREEN_DEFDATA, s->attr, s->colr); + break; + case CODE_CLEARSTARTOFLINE: + screen_fill_start_of_line( + s, s->cx, s->cy, SCREEN_DEFDATA, s->attr, s->colr); + break; + case CODE_CLEARLINE: + screen_fill_line(s, s->cy, SCREEN_DEFDATA, s->attr, s->colr); + break; + case CODE_INSERTLINE: + ua = screen_extract(ptr); + screen_insert_lines(s, s->cy, ua); + break; + case CODE_DELETELINE: + ua = screen_extract(ptr); + screen_delete_lines(s, s->cy, ua); + break; + case CODE_INSERTCHARACTER: + ua = screen_extract(ptr); + screen_insert_characters(s, s->cx, s->cy, ua); + break; + case CODE_DELETECHARACTER: + ua = screen_extract(ptr); + screen_delete_characters(s, s->cx, s->cy, ua); + break; + case CODE_CURSORON: + s->mode |= MODE_CURSOR; + break; + case CODE_CURSOROFF: + s->mode &= ~MODE_CURSOR; + break; + case CODE_CURSORDOWNSCROLL: + ua = screen_extract(ptr); + screen_cursor_down_scroll(s, ua); + break; + case CODE_CURSORUPSCROLL: + ua = screen_extract(ptr); + screen_cursor_up_scroll(s, ua); + break; + case CODE_SCROLLREGION: + ua = screen_extract(ptr); + ptr += 2; + ub = screen_extract(ptr); + if (ua > s->sy) + ua = s->sy; + s->ry_upper = ua - 1; + if (ub > s->sy) + ub = s->sy; + s->ry_lower = ub - 1; + break; + case CODE_INSERTOFF: + s->mode &= ~MODE_INSERT; + break; + case CODE_INSERTON: + s->mode |= MODE_INSERT; + break; + case CODE_KCURSOROFF: + s->mode &= ~MODE_KCURSOR; + break; + case CODE_KCURSORON: + s->mode |= MODE_KCURSOR; + break; + case CODE_KKEYPADOFF: + s->mode &= ~MODE_KKEYPAD; + break; + case CODE_KKEYPADON: + s->mode |= MODE_KKEYPAD; + break; + case CODE_TITLE: + ua = screen_extract(ptr); + ptr += 2; + log_debug("new title: %u:%.*s", ua, (int) ua, ptr); + if (ua > MAXTITLELEN - 1) + ua = MAXTITLELEN - 1; + memcpy(s->title, ptr, ua); + s->title[ua] = '\0'; + break; + case CODE_ATTRIBUTES: + ua = screen_extract(ptr); + if (ua == 0) { + s->attr = 0; + s->colr = SCREEN_DEFCOLR; + break; + } + + while (ua-- > 0) { + ptr += 2; + ub = screen_extract(ptr); + switch (ub) { + case 0: + case 10: + s->attr = 0; + s->colr = SCREEN_DEFCOLR; + break; + case 1: + s->attr |= ATTR_BRIGHT; + break; + case 2: + s->attr |= ATTR_DIM; + break; + case 3: + s->attr |= ATTR_ITALICS; + break; + case 4: + s->attr |= ATTR_UNDERSCORE; + break; + case 5: + s->attr |= ATTR_BLINK; + break; + case 7: + s->attr |= ATTR_REVERSE; + break; + case 8: + s->attr |= ATTR_HIDDEN; + break; + case 23: + s->attr &= ~ATTR_ITALICS; + break; + case 24: + s->attr &= ~ATTR_UNDERSCORE; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + s->colr &= 0x0f; + s->colr |= (ub - 30) << 4; + break; + case 39: + s->colr &= 0x0f; + s->colr |= 0x80; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + s->colr &= 0xf0; + s->colr |= ub - 40; + break; + case 49: + s->colr &= 0xf0; + s->colr |= 0x08; + break; + } + } + } +} + +/* Write a single character to the screen at the cursor and move forward. */ +void +screen_write_character(struct screen *s, u_char ch) +{ + s->grid_data[s->cy][s->cx] = ch; + s->grid_attr[s->cy][s->cx] = s->attr; + s->grid_colr[s->cy][s->cx] = s->colr; + + s->cx++; + if (s->cx >= s->sx) { + s->cx = 0; + screen_cursor_down_scroll(s, 1); + } +} + +/* Move cursor up and scroll if necessary. */ +void +screen_cursor_up_scroll(struct screen *s, u_int ny) +{ + if (s->cy < ny) { + screen_scroll_down(s, ny - s->cy); + s->cy = 0; + } else + s->cy -= ny; +} + +/* Move cursor down and scroll if necessary. */ +void +screen_cursor_down_scroll(struct screen *s, u_int ny) +{ + if (s->sy - 1 - s->cy < ny) { + screen_scroll_up(s, ny - (s->sy - 1 - s->cy)); + s->cy = s->sy - 1; + } else + s->cy += ny; +} + +/* Scroll screen up. */ +void +screen_scroll_up(struct screen *s, u_int ny) +{ + if (s->ry_upper == 0 && s->ry_lower == s->sy - 1) { + screen_delete_lines(s, 0, ny); + return; + } + + log_fatalx("screen_scroll_up: %u %u", s->ry_upper, s->ry_lower); +} + +/* Scroll screen down. */ +void +screen_scroll_down(struct screen *s, u_int ny) +{ + if (s->ry_upper == 0 && s->ry_lower == s->sy - 1) { + screen_insert_lines(s, 0, ny); + return; + } + + log_fatalx("screen_scroll_down: %u %u", s->ry_upper, s->ry_lower); +} + +/* Fill entire screen. */ +void +screen_fill_screen(struct screen *s, u_char data, u_char attr, u_char colr) +{ + screen_fill_end_of_screen(s, 0, 0, data, attr, colr); +} + +/* Fill single line. */ +void +screen_fill_line( + struct screen *s, u_int py, u_char data, u_char attr, u_char colr) +{ + screen_fill_end_of_line(s, 0, py, data, attr, colr); +} + +/* Fill to end of screen. */ +void +screen_fill_end_of_screen( + struct screen *s, u_int px, u_int py, u_char data, u_char attr, u_char colr) +{ + if (py >= s->sy) + return; + + if (px != 0) { + screen_fill_end_of_line(s, px, py, data, attr, colr); + if (py++ >= s->sy) + return; + } + + while (py++ < s->sy) + screen_fill_line(s, py - 1, data, attr, colr); +} + +/* Fill to end of line. */ +void +screen_fill_end_of_line( + struct screen *s, u_int px, u_int py, u_char data, u_char attr, u_char colr) +{ + if (px >= s->sx) + return; + if (py >= s->sy) + return; + + memset(s->grid_data[py] + px, data, s->sx - px); + memset(s->grid_attr[py] + px, attr, s->sx - px); + memset(s->grid_colr[py] + px, colr, s->sx - px); +} + +/* Fill to start of line. */ +void +screen_fill_start_of_line( + struct screen *s, u_int px, u_int py, u_char data, u_char attr, u_char colr) +{ + if (px >= s->sx) + return; + if (py >= s->sy) + return; + + memset(s->grid_data[py], data, px); + memset(s->grid_attr[py], attr, px); + memset(s->grid_colr[py], colr, px); +} + +/* Insert lines. */ +void +screen_insert_lines(struct screen *s, u_int py, u_int ny) +{ + if (py > screen_last_y(s)) + return; + + if (py + ny > screen_last_y(s)) + ny = screen_last_y(s) - py; + log_debug("inserting lines: %u,%u", py, ny); + + screen_free_lines(s, (screen_last_y(s) - ny) + 1, screen_last_y(s)); + + if (py != screen_last_y(s)) + screen_move_lines(s, py + ny, py, screen_last_y(s) - ny); + + screen_fill_lines( + s, py, py + ny - 1, SCREEN_DEFDATA, SCREEN_DEFATTR, SCREEN_DEFCOLR); +} + +/* Delete lines. */ +void +screen_delete_lines(struct screen *s, u_int py, u_int ny) +{ + if (py > screen_last_y(s)) + return; + + if (py + ny > screen_last_y(s)) + ny = screen_last_y(s) - py; + log_debug("deleting lines: %u,%u", py, ny); + + screen_free_lines(s, py, py + ny - 1); + + if (py != screen_last_y(s)) + screen_move_lines(s, py, py + ny, screen_last_y(s)); + + screen_make_lines(s, (screen_last_y(s) - ny) + 1, screen_last_y(s)); + screen_fill_lines(s, (screen_last_y(s) - ny) + 1, + screen_last_y(s), SCREEN_DEFDATA, SCREEN_DEFATTR, SCREEN_DEFCOLR); +} + +/* Insert characters. */ +void +screen_insert_characters(struct screen *s, u_int px, u_int py, u_int nx) +{ + if (px >= s->sx || py >= s->sy) + return; + + if (px + nx > s->sx) + nx = s->sx - px; + + if (px - nx != s->sx) { + memmove(s->grid_data[py] + px + nx, + s->grid_data[py] + px, s->sx - px - nx); + memmove(s->grid_attr[py] + px + nx, + s->grid_attr[py] + px, s->sx - px - nx); + memmove(s->grid_colr[py] + px + nx, + s->grid_colr[py] + px, s->sx - px - nx); + } + memset(s->grid_data[py] + px, SCREEN_DEFDATA, nx); + memset(s->grid_attr[py] + px, SCREEN_DEFATTR, nx); + memset(s->grid_colr[py] + px, SCREEN_DEFCOLR, nx); +} + +/* Delete characters. */ +void +screen_delete_characters(struct screen *s, u_int px, u_int py, u_int nx) +{ + if (px >= s->sx || py >= s->sy) + return; + + if (px + nx > s->sx) + nx = s->sx - px; + + if (px - nx != s->sx) { + memmove(s->grid_data[py] + px, + s->grid_data[py] + px + nx, s->sx - px - nx); + memmove(s->grid_attr[py] + px, + s->grid_attr[py] + px + nx, s->sx - px - nx); + memmove(s->grid_colr[py] + px, + s->grid_colr[py] + px + nx, s->sx - px - nx); + } + memset(s->grid_data[py] + px + nx, SCREEN_DEFDATA, s->sx - px - nx); + memset(s->grid_attr[py] + px + nx, SCREEN_DEFATTR, s->sx - px - nx); + memset(s->grid_colr[py] + px + nx, SCREEN_DEFCOLR, s->sx - px - nx); +} |