From 60505314a45587895ddc76cd2ebcd106e155ea30 Mon Sep 17 00:00:00 2001 From: cowmonk Date: Mon, 20 Jan 2025 01:19:54 -0700 Subject: [PATCH] huge revamp of scrolling system | more ansi_code support I'm syncing now before I lose this update... again (This is from a backup drive) --- cowterm.c | 859 ++++++++++++++++++++++++++---------------------------- 1 file changed, 411 insertions(+), 448 deletions(-) diff --git a/cowterm.c b/cowterm.c index 4ff4b52..4ee3dfa 100644 --- a/cowterm.c +++ b/cowterm.c @@ -68,7 +68,6 @@ static int using_alternate = 0; #define ATTR_BOLD (1 << 0) #define ATTR_ITALIC (1 << 1) #define ATTR_REVERSE (1 << 2) -// #define ATTR_UNDERLINE (1 << 3) // Underline currently is buggy #define ATTR_DIM (1 << 4) #define ATTR_BLINK (1 << 5) @@ -305,54 +304,45 @@ static void draw_char(Display *display, Drawable d, int x, int y) { if (x < 0 || x >= term_cols || y < 0 || y >= term_rows) return; - unsigned long fg_color = color_buffer[y][x]; - unsigned long bg_color = bg_color_buffer[y][x]; - int attrs = attr_buffer[y][x]; - static unsigned long last_bg_color = 0; + unsigned long fg = color_buffer[y][x]; + unsigned long bg = bg_color_buffer[y][x]; + int attr = attr_buffer[y][x]; + static unsigned long last_bg = 0; static int last_x = -1; static int last_y = -1; - if (attrs & ATTR_REVERSE) { - unsigned long temp = fg_color; - fg_color = bg_color; - bg_color = temp; + if (attr & ATTR_REVERSE) { + unsigned long tmp = fg; + fg = bg; + bg = tmp; } - if (last_x != x || last_y != y || last_bg_color != bg_color) { - XSetForeground(display, gc, bg_color); - XFillRectangle(display, d, gc, x * CHAR_WIDTH, y * CHAR_HEIGHT, CHAR_WIDTH, - CHAR_HEIGHT); + if (last_x != x || last_y != y || last_bg != bg) { + XSetForeground(display, gc, bg); + XFillRectangle(display, d, gc, x * CHAR_WIDTH, y * CHAR_HEIGHT, + CHAR_WIDTH + 1, CHAR_HEIGHT); last_x = x; last_y = y; - last_bg_color = bg_color; + last_bg = bg; } - XSetForeground(display, gc, fg_color); + XSetForeground(display, gc, fg); - char str[2] = {terminal_buffer[y][x], '\0'}; - - // Select appropriate font based on attributes + char c[2] = {terminal_buffer[y][x], '\0'}; XFontStruct *font = regular_font; - if (attrs & ATTR_BOLD) { + + if (attr & ATTR_BOLD) font = bold_font; - } else if (attrs & ATTR_ITALIC) { + else if (attr & ATTR_ITALIC) font = italic_font; - } + XSetFont(display, gc, font->fid); - - XDrawString(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 2, str, - 1); - - // if (attrs & ATTR_UNDERLINE) { - // XDrawLine(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 1, - // (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 1); - // } + XDrawString(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 4, c, 1); } static void draw_terminal(Display *display, Window window) { if (!gc) { gc = XCreateGC(display, window, 0, NULL); - regular_font = XLoadQueryFont(display, REGULAR_FONT); bold_font = XLoadQueryFont(display, BOLD_FONT); italic_font = XLoadQueryFont(display, ITALICS_FONT); @@ -370,22 +360,36 @@ static void draw_terminal(Display *display, Window window) { if (!terminal_buffer || !color_buffer || !attr_buffer) return; - if (buffer_pixmap == None) { + if (buffer_pixmap == None) buffer_pixmap = XCreatePixmap( display, DefaultRootWindow(display), term_cols * CHAR_WIDTH, term_rows * CHAR_HEIGHT, DefaultDepth(display, DefaultScreen(display))); - } - // Only draw the changed parts of the terminal to the buffer if (needs_refresh) { - for (int y = 0; y < term_rows; y++) { - for (int x = 0; x < term_cols; x++) { - draw_char(display, buffer_pixmap, x, y); + int start_y = scroll_top ? scroll_top - 1 : 0; + int end_y = scroll_bottom ? scroll_bottom : term_rows; + + if (end_y > term_rows) { + end_y = term_rows; + } + + if (scroll_top == 0 && scroll_bottom == 0) { + // Full screen refresh + for (int y = 0; y < term_rows; y++) { + for (int x = 0; x < term_cols; x++) { + draw_char(display, buffer_pixmap, x, y); + } + } + } else { + // Only refresh scroll region + for (int y = start_y; y < end_y; y++) { + for (int x = 0; x < term_cols; x++) { + draw_char(display, buffer_pixmap, x, y); + } } } } - // Copy buffer to window XCopyArea(display, buffer_pixmap, window, gc, 0, 0, term_cols * CHAR_WIDTH, term_rows * CHAR_HEIGHT, 0, 0); @@ -410,196 +414,78 @@ static void check_refresh(Display *display, Window window) { } } -// Scroll the terminal up one line -static void scroll_up(void) { - // Move all lines up one position - for (int y = 0; y < term_rows - 1; y++) { - memcpy(terminal_buffer[y], terminal_buffer[y + 1], term_cols); - memcpy(color_buffer[y], color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - memcpy(attr_buffer[y], attr_buffer[y + 1], term_cols * sizeof(int)); - memcpy(bg_color_buffer[y], bg_color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - } - - // Clear the bottom line - memset(terminal_buffer[term_rows - 1], ' ', term_cols); - for (int x = 0; x < term_cols; x++) { - color_buffer[term_rows - 1][x] = current_color; - attr_buffer[term_rows - 1][x] = current_attr; - bg_color_buffer[term_rows - 1][x] = current_bg_color; - } - needs_refresh = 1; -} - static void scroll_region_up(int amount) { - char **temp_buffer = NULL; - unsigned long **temp_color_buffer = NULL; - int **temp_attr_buffer = NULL; - unsigned long **temp_bg_color_buffer = NULL; - - temp_buffer = malloc(term_rows * sizeof(char *)); - temp_color_buffer = malloc(term_rows * sizeof(unsigned long *)); - temp_attr_buffer = malloc(term_rows * sizeof(int *)); - temp_bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); - - if (!temp_buffer || !temp_color_buffer || !temp_attr_buffer || - !temp_bg_color_buffer) { - fprintf(stderr, "Failed to allocate memory for temp buffers\n"); + int start = scroll_top ? scroll_top - 1 : 0; + int end = scroll_bottom ? scroll_bottom - 1 : term_rows - 1; + if (end >= term_rows) + end = term_rows - 1; + if (start > end) return; + + for (int i = start; i <= end - amount; i++) { + memcpy(terminal_buffer[i], terminal_buffer[i + amount], term_cols); + memcpy(color_buffer[i], color_buffer[i + amount], + term_cols * sizeof(unsigned long)); + memcpy(attr_buffer[i], attr_buffer[i + amount], term_cols * sizeof(int)); + memcpy(bg_color_buffer[i], bg_color_buffer[i + amount], + term_cols * sizeof(unsigned long)); } - for (int i = 0; i < term_rows; i++) { - temp_buffer[i] = malloc(term_cols * sizeof(char)); - temp_color_buffer[i] = malloc(term_cols * sizeof(unsigned long)); - temp_attr_buffer[i] = malloc(term_cols * sizeof(int)); - temp_bg_color_buffer[i] = malloc(term_cols * sizeof(unsigned long)); - if (!temp_buffer[i] || !temp_color_buffer[i] || !temp_attr_buffer[i] || - !temp_bg_color_buffer[i]) { - fprintf(stderr, "Failed to allocate memory for temp buffer row\n"); - free(temp_buffer); - free(temp_color_buffer); - free(temp_attr_buffer); - free(temp_bg_color_buffer); - return; + for (int i = end - amount + 1; i <= end; i++) { + memset(terminal_buffer[i], ' ', term_cols); + for (int x = 0; x < term_cols; x++) { + color_buffer[i][x] = current_color; + attr_buffer[i][x] = current_attr; + bg_color_buffer[i][x] = current_bg_color; } } - if (scroll_top == 0 && scroll_bottom == 0) { - for (int i = 0; i < term_rows; i++) { - memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char)); - memcpy(temp_color_buffer[i], color_buffer[i], - term_cols * sizeof(unsigned long)); - memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int)); - memcpy(temp_bg_color_buffer[i], bg_color_buffer[i], - term_cols * sizeof(unsigned long)); - } - for (int j = 0; j < amount; j++) { - // Move all lines up one position - for (int y = 0; y < term_rows - 1; y++) { - memcpy(terminal_buffer[y], temp_buffer[y + 1], term_cols); - memcpy(color_buffer[y], temp_color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - memcpy(attr_buffer[y], temp_attr_buffer[y + 1], - term_cols * sizeof(int)); - memcpy(bg_color_buffer[y], temp_bg_color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - } - - // Clear the bottom line - memset(terminal_buffer[term_rows - 1], ' ', term_cols); - for (int x = 0; x < term_cols; x++) { - color_buffer[term_rows - 1][x] = current_color; - attr_buffer[term_rows - 1][x] = current_attr; - bg_color_buffer[term_rows - 1][x] = current_bg_color; - } - } - } else { - for (int i = 0; i < term_rows; i++) { - memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char)); - memcpy(temp_color_buffer[i], color_buffer[i], - term_cols * sizeof(unsigned long)); - memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int)); - memcpy(temp_bg_color_buffer[i], bg_color_buffer[i], - term_cols * sizeof(unsigned long)); - } - for (int j = 0; j < amount; j++) { - int start = (scroll_top - 1); - int end = (scroll_bottom - 1); - if (start < 0) - start = 0; - if (end < 0) - end = 0; - if (end >= term_rows) - end = term_rows - 1; - // Move all lines up one position - for (int y = start; y < end; y++) { - memcpy(terminal_buffer[y], temp_buffer[y + 1], term_cols); - memcpy(color_buffer[y], temp_color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - memcpy(attr_buffer[y], temp_attr_buffer[y + 1], - term_cols * sizeof(int)); - memcpy(bg_color_buffer[y], temp_bg_color_buffer[y + 1], - term_cols * sizeof(unsigned long)); - } - - // Clear the bottom line - memset(terminal_buffer[end], ' ', term_cols); - for (int x = 0; x < term_cols; x++) { - color_buffer[end][x] = current_color; - attr_buffer[end][x] = current_attr; - bg_color_buffer[end][x] = current_bg_color; - } - } - } - - for (int i = 0; i < term_rows; i++) { - free(temp_buffer[i]); - free(temp_color_buffer[i]); - free(temp_attr_buffer[i]); - free(temp_bg_color_buffer[i]); - } - free(temp_buffer); - free(temp_color_buffer); - free(temp_attr_buffer); - free(temp_bg_color_buffer); needs_refresh = 1; } static void scroll_region_down(int amount) { - char **temp_buffer = NULL; - unsigned long **temp_color_buffer = NULL; - int **temp_attr_buffer = NULL; - unsigned long **temp_bg_color_buffer = NULL; + int start = ((scroll_top - 1) < 0) ? 0 : scroll_top - 1; + int end = ((scroll_bottom - 1) < 0) ? 0 : scroll_bottom - 1; + if (end >= term_rows) + end = term_rows - 1; - temp_buffer = malloc(term_rows * sizeof(char *)); - temp_color_buffer = malloc(term_rows * sizeof(unsigned long *)); - temp_attr_buffer = malloc(term_rows * sizeof(int *)); - temp_bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); + char **tbuf = malloc(term_rows * sizeof(char *)); + unsigned long **cbuf = malloc(term_rows * sizeof(unsigned long *)); + int **abuf = malloc(term_rows * sizeof(int *)); + unsigned long **bbuf = malloc(term_rows * sizeof(unsigned long *)); - if (!temp_buffer || !temp_color_buffer || !temp_attr_buffer || - !temp_bg_color_buffer) { - fprintf(stderr, "Failed to allocate memory for temp buffers\n"); - return; + if (!tbuf || !cbuf || !abuf || !bbuf) { + fprintf(stderr, "scroll down: malloc failed\n"); + goto cleanup; } - for (int i = 0; i < term_rows; i++) { - temp_buffer[i] = malloc(term_cols * sizeof(char)); - temp_color_buffer[i] = malloc(term_cols * sizeof(unsigned long)); - temp_attr_buffer[i] = malloc(term_cols * sizeof(int)); - temp_bg_color_buffer[i] = malloc(term_cols * sizeof(unsigned long)); - if (!temp_buffer[i] || !temp_color_buffer[i] || !temp_attr_buffer[i] || - !temp_bg_color_buffer[i]) { - fprintf(stderr, "Failed to allocate memory for temp buffer row\n"); - free(temp_buffer); - free(temp_color_buffer); - free(temp_attr_buffer); - free(temp_bg_color_buffer); - return; + for (int i = 0; i < term_rows; i++) { + tbuf[i] = malloc(term_cols); + cbuf[i] = malloc(term_cols * sizeof(unsigned long)); + abuf[i] = malloc(term_cols * sizeof(int)); + bbuf[i] = malloc(term_cols * sizeof(unsigned long)); + + if (!tbuf[i] || !cbuf[i] || !abuf[i] || !bbuf[i]) { + fprintf(stderr, "scroll down: malloc failed\n"); + goto cleanup; } } if (scroll_top == 0 && scroll_bottom == 0) { for (int i = 0; i < term_rows; i++) { - memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char)); - memcpy(temp_color_buffer[i], color_buffer[i], - term_cols * sizeof(unsigned long)); - memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int)); - memcpy(temp_bg_color_buffer[i], bg_color_buffer[i], - term_cols * sizeof(unsigned long)); + memcpy(tbuf[i], terminal_buffer[i], term_cols); + memcpy(cbuf[i], color_buffer[i], term_cols * sizeof(unsigned long)); + memcpy(abuf[i], attr_buffer[i], term_cols * sizeof(int)); + memcpy(bbuf[i], bg_color_buffer[i], term_cols * sizeof(unsigned long)); } for (int j = 0; j < amount; j++) { - // Move all lines down one position for (int y = term_rows - 1; y > 0; y--) { - memcpy(terminal_buffer[y], temp_buffer[y - 1], term_cols); - memcpy(color_buffer[y], temp_color_buffer[y - 1], - term_cols * sizeof(unsigned long)); - memcpy(attr_buffer[y], temp_attr_buffer[y - 1], - term_cols * sizeof(int)); - memcpy(bg_color_buffer[y], temp_bg_color_buffer[y - 1], + memcpy(terminal_buffer[y], tbuf[y - 1], term_cols); + memcpy(color_buffer[y], cbuf[y - 1], term_cols * sizeof(unsigned long)); + memcpy(attr_buffer[y], abuf[y - 1], term_cols * sizeof(int)); + memcpy(bg_color_buffer[y], bbuf[y - 1], term_cols * sizeof(unsigned long)); } - // Clear the top line memset(terminal_buffer[0], ' ', term_cols); for (int x = 0; x < term_cols; x++) { color_buffer[0][x] = current_color; @@ -609,35 +495,19 @@ static void scroll_region_down(int amount) { } } else { for (int i = 0; i < term_rows; i++) { - memcpy(temp_buffer[i], terminal_buffer[i], term_cols * sizeof(char)); - memcpy(temp_color_buffer[i], color_buffer[i], - term_cols * sizeof(unsigned long)); - memcpy(temp_attr_buffer[i], attr_buffer[i], term_cols * sizeof(int)); - memcpy(temp_bg_color_buffer[i], bg_color_buffer[i], - term_cols * sizeof(unsigned long)); + memcpy(tbuf[i], terminal_buffer[i], term_cols); + memcpy(cbuf[i], color_buffer[i], term_cols * sizeof(unsigned long)); + memcpy(abuf[i], attr_buffer[i], term_cols * sizeof(int)); + memcpy(bbuf[i], bg_color_buffer[i], term_cols * sizeof(unsigned long)); } for (int j = 0; j < amount; j++) { - int start = (scroll_top - 1); - int end = (scroll_bottom - 1); - if (start < 0) - start = 0; - if (end < 0) - end = 0; - if (end >= term_rows) - end = term_rows - 1; - - // Move all lines down one position for (int y = end; y > start; y--) { - memcpy(terminal_buffer[y], temp_buffer[y - 1], term_cols); - memcpy(color_buffer[y], temp_color_buffer[y - 1], - term_cols * sizeof(unsigned long)); - memcpy(attr_buffer[y], temp_attr_buffer[y - 1], - term_cols * sizeof(int)); - memcpy(bg_color_buffer[y], temp_bg_color_buffer[y - 1], + memcpy(terminal_buffer[y], tbuf[y - 1], term_cols); + memcpy(color_buffer[y], cbuf[y - 1], term_cols * sizeof(unsigned long)); + memcpy(attr_buffer[y], abuf[y - 1], term_cols * sizeof(int)); + memcpy(bg_color_buffer[y], bbuf[y - 1], term_cols * sizeof(unsigned long)); } - - // Clear the top line memset(terminal_buffer[start], ' ', term_cols); for (int x = 0; x < term_cols; x++) { color_buffer[start][x] = current_color; @@ -646,16 +516,28 @@ static void scroll_region_down(int amount) { } } } - for (int i = 0; i < term_rows; i++) { - free(temp_buffer[i]); - free(temp_color_buffer[i]); - free(temp_attr_buffer[i]); - free(temp_bg_color_buffer[i]); + +cleanup: + if (tbuf) { + for (int i = 0; i < term_rows; i++) + free(tbuf[i]); + free(tbuf); + } + if (cbuf) { + for (int i = 0; i < term_rows; i++) + free(cbuf[i]); + free(cbuf); + } + if (abuf) { + for (int i = 0; i < term_rows; i++) + free(abuf[i]); + free(abuf); + } + if (bbuf) { + for (int i = 0; i < term_rows; i++) + free(bbuf[i]); + free(bbuf); } - free(temp_buffer); - free(temp_color_buffer); - free(temp_attr_buffer); - free(temp_bg_color_buffer); needs_refresh = 1; } @@ -686,114 +568,154 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len, while (*idx < max_len && buf[*idx] != 'h' && buf[*idx] != 'l') { if (num_idx >= sizeof(num_buf) - 1) break; - if (buf[*idx] >= '0' && buf[*idx] <= '9') { + if (buf[*idx] >= '0' && buf[*idx] <= '9') num_buf[num_idx++] = buf[*idx]; - } (*idx)++; } - if (num_buf[0] != '\0') { - int code = atoi(num_buf); - if (buf[*idx] == 'h' || buf[*idx] == 'l') { - switch (code) { - case 1047: // Alternate screen buffer - if (buf[*idx] == 'h') { - if (!saved_terminal) { - saved_terminal = terminal_buffer; - saved_colors = color_buffer; - saved_attrs = attr_buffer; - saved_colors = bg_color_buffer; - terminal_buffer = malloc(term_rows * sizeof(char *)); - color_buffer = malloc(term_rows * sizeof(unsigned long *)); - attr_buffer = malloc(term_rows * sizeof(int *)); - bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); - for (int i = 0; i < term_rows; i++) { - terminal_buffer[i] = calloc(term_cols, sizeof(char)); - color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); - attr_buffer[i] = calloc(term_cols, sizeof(int)); - bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); - } - using_alternate = 1; - needs_refresh = 1; - draw_terminal(display, window); - } - } else if (using_alternate) { - for (int i = 0; i < term_rows; i++) { - free(terminal_buffer[i]); - free(color_buffer[i]); - free(attr_buffer[i]); - free(bg_color_buffer[i]); - } - free(terminal_buffer); - free(color_buffer); - free(attr_buffer); - free(bg_color_buffer); - terminal_buffer = saved_terminal; - color_buffer = saved_colors; - attr_buffer = saved_attrs; - bg_color_buffer = saved_colors; - saved_terminal = NULL; - using_alternate = 0; - needs_refresh = 1; - draw_terminal(display, window); - } - break; - case 1048: // Save/restore cursor - if (buf[*idx] == 'h') { - saved_cursor_x = cursor_x; - saved_cursor_y = cursor_y; - } else { - cursor_x = saved_cursor_x; - cursor_y = saved_cursor_y; - } - break; - case 1049: // Combined alternate buffer + cursor - if (buf[*idx] == 'h') { - saved_cursor_x = cursor_x; - saved_cursor_y = cursor_y; - if (!saved_terminal) { - saved_terminal = terminal_buffer; - saved_colors = color_buffer; - saved_attrs = attr_buffer; - saved_colors = bg_color_buffer; - terminal_buffer = malloc(term_rows * sizeof(char *)); - color_buffer = malloc(term_rows * sizeof(unsigned long *)); - attr_buffer = malloc(term_rows * sizeof(int *)); - bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); - for (int i = 0; i < term_rows; i++) { - terminal_buffer[i] = calloc(term_cols, sizeof(char)); - color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); - attr_buffer[i] = calloc(term_cols, sizeof(int)); - bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); - } - using_alternate = 1; - needs_refresh = 1; - draw_terminal(display, window); - } - } else if (using_alternate) { - for (int i = 0; i < term_rows; i++) { - free(terminal_buffer[i]); - free(color_buffer[i]); - free(attr_buffer[i]); - free(bg_color_buffer[i]); - } - free(terminal_buffer); - free(color_buffer); - free(attr_buffer); - free(bg_color_buffer); - terminal_buffer = saved_terminal; - color_buffer = saved_colors; - attr_buffer = saved_attrs; - bg_color_buffer = saved_colors; - saved_terminal = NULL; - cursor_x = saved_cursor_x; - cursor_y = saved_cursor_y; - using_alternate = 0; - needs_refresh = 1; - draw_terminal(display, window); - } - break; + + if (!num_buf[0]) + return; + + int code = atoi(num_buf); + if (buf[*idx] != 'h' && buf[*idx] != 'l') + return; + + switch (code) { + case 1047: // Alt buffer + if (buf[*idx] == 'h') { + if (saved_terminal) + return; + + saved_terminal = terminal_buffer; + saved_colors = color_buffer; + saved_attrs = attr_buffer; + saved_colors = bg_color_buffer; + + terminal_buffer = malloc(term_rows * sizeof(char *)); + color_buffer = malloc(term_rows * sizeof(unsigned long *)); + attr_buffer = malloc(term_rows * sizeof(int *)); + bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); + + if (!terminal_buffer || !color_buffer || !attr_buffer || !bg_color_buffer) + return; + + for (int i = 0; i < term_rows; i++) { + terminal_buffer[i] = calloc(term_cols, 1); + color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); + attr_buffer[i] = calloc(term_cols, sizeof(int)); + bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); + + if (!terminal_buffer[i] || !color_buffer[i] || !attr_buffer[i] || + !bg_color_buffer[i]) + return; + + memset(terminal_buffer[i], ' ', term_cols); + memset(attr_buffer[i], 0, term_cols * sizeof(int)); + memset(color_buffer[i], current_color, + term_cols * sizeof(unsigned long)); + memset(bg_color_buffer[i], current_bg_color, + term_cols * sizeof(unsigned long)); } + using_alternate = 1; + needs_refresh = 1; + draw_terminal(display, window); + } else if (using_alternate) { + for (int i = 0; i < term_rows; i++) { + free(terminal_buffer[i]); + free(color_buffer[i]); + free(attr_buffer[i]); + free(bg_color_buffer[i]); + } + free(terminal_buffer); + free(color_buffer); + free(attr_buffer); + free(bg_color_buffer); + + terminal_buffer = saved_terminal; + color_buffer = saved_colors; + attr_buffer = saved_attrs; + bg_color_buffer = saved_colors; + saved_terminal = NULL; + using_alternate = 0; + needs_refresh = 1; + draw_terminal(display, window); } + break; + + case 1048: // Save/restore cursor + if (buf[*idx] == 'h') { + saved_cursor_x = cursor_x; + saved_cursor_y = cursor_y; + } else { + cursor_x = saved_cursor_x; + cursor_y = saved_cursor_y; + } + break; + + case 1049: // Alt buffer + cursor + if (buf[*idx] == 'h') { + saved_cursor_x = cursor_x; + saved_cursor_y = cursor_y; + if (saved_terminal) + return; + + saved_terminal = terminal_buffer; + saved_colors = color_buffer; + saved_attrs = attr_buffer; + saved_colors = bg_color_buffer; + + terminal_buffer = malloc(term_rows * sizeof(char *)); + color_buffer = malloc(term_rows * sizeof(unsigned long *)); + attr_buffer = malloc(term_rows * sizeof(int *)); + bg_color_buffer = malloc(term_rows * sizeof(unsigned long *)); + + if (!terminal_buffer || !color_buffer || !attr_buffer || !bg_color_buffer) + return; + + for (int i = 0; i < term_rows; i++) { + terminal_buffer[i] = calloc(term_cols, 1); + color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); + attr_buffer[i] = calloc(term_cols, sizeof(int)); + bg_color_buffer[i] = calloc(term_cols, sizeof(unsigned long)); + + if (!terminal_buffer[i] || !color_buffer[i] || !attr_buffer[i] || + !bg_color_buffer[i]) + return; + + memset(terminal_buffer[i], ' ', term_cols); + memset(attr_buffer[i], 0, term_cols * sizeof(int)); + memset(color_buffer[i], current_color, + term_cols * sizeof(unsigned long)); + memset(bg_color_buffer[i], current_bg_color, + term_cols * sizeof(unsigned long)); + } + using_alternate = 1; + needs_refresh = 1; + draw_terminal(display, window); + } else if (using_alternate) { + for (int i = 0; i < term_rows; i++) { + free(terminal_buffer[i]); + free(color_buffer[i]); + free(attr_buffer[i]); + free(bg_color_buffer[i]); + } + free(terminal_buffer); + free(color_buffer); + free(attr_buffer); + free(bg_color_buffer); + + terminal_buffer = saved_terminal; + color_buffer = saved_colors; + attr_buffer = saved_attrs; + bg_color_buffer = saved_colors; + saved_terminal = NULL; + cursor_x = saved_cursor_x; + cursor_y = saved_cursor_y; + using_alternate = 0; + needs_refresh = 1; + draw_terminal(display, window); + } + break; } } @@ -830,18 +752,24 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, return; } - while (*idx < max_len && buf[*idx] != 'm' && buf[*idx] != 'H' && - buf[*idx] != 'A' && buf[*idx] != 'B' && buf[*idx] != 'C' && - buf[*idx] != 'D' && buf[*idx] != 'K' && buf[*idx] != 'J' && - buf[*idx] != 'f' && buf[*idx] != 'r' && buf[*idx] != 's' && - buf[*idx] != 'u' && buf[*idx] != 'h' && buf[*idx] != 'l') { + // Parse parameters + while (*idx < max_len) { + char c = buf[*idx]; + if (c == 'm' || c == 'H' || c == 'A' || c == 'B' || c == 'C' || c == 'D' || + c == 'K' || c == 'J' || c == 'f' || c == 'r' || c == 's' || c == 'u' || + c == 'h' || c == 'l' || c == 'E' || c == 'F' || c == 'G' || c == 'S' || + c == 'T' || c == '@' || c == 'P' || c == 'M' || c == 'L' || c == 'd') { + break; + } + if (num_idx >= sizeof(num_buf) - 1 || param_idx >= sizeof(params) / sizeof(params[0]) - 1) { break; } - if (buf[*idx] >= '0' && buf[*idx] <= '9') { - num_buf[num_idx++] = buf[*idx]; - } else if (buf[*idx] == ';') { + + if (c >= '0' && c <= '9') { + num_buf[num_idx++] = c; + } else if (c == ';') { if (num_buf[0] != '\0') { params[param_idx++] = atoi(num_buf); memset(num_buf, 0, sizeof(num_buf)); @@ -859,18 +787,26 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, case 'H': // Set cursor position case 'f': // Alternative set cursor position if (param_idx >= 2) { - cursor_y = - (params[0] - 1 < 0) - ? 0 - : ((params[0] - 1) >= term_rows ? term_rows - 1 : params[0] - 1); - cursor_x = - (params[1] - 1 < 0) - ? 0 - : ((params[1] - 1) >= term_cols ? term_cols - 1 : params[1] - 1); + cursor_y = params[0] - 1 < 0 ? 0 + : params[0] - 1 >= term_rows ? term_rows - 1 + : params[0] - 1; + cursor_x = params[1] - 1 < 0 ? 0 + : params[1] - 1 >= term_cols ? term_cols - 1 + : params[1] - 1; } else { cursor_x = cursor_y = 0; } break; + case 'd': // Line position absolute + cursor_y = params[0] - 1 < 0 ? 0 + : params[0] - 1 >= term_rows ? term_rows - 1 + : params[0] - 1; + break; + case 'G': // Column position absolute + cursor_x = params[0] - 1 < 0 ? 0 + : params[0] - 1 >= term_cols ? term_cols - 1 + : params[0] - 1; + break; case 'A': // Cursor up cursor_y -= params[0] ? params[0] : 1; if (cursor_y < 0) @@ -891,6 +827,44 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, if (cursor_x < 0) cursor_x = 0; break; + case '@': // Insert blank characters + { + int n = params[0] ? params[0] : 1; + if (n > term_cols - cursor_x) + n = term_cols - cursor_x; + memmove(&terminal_buffer[cursor_y][cursor_x + n], + &terminal_buffer[cursor_y][cursor_x], term_cols - cursor_x - n); + memset(&terminal_buffer[cursor_y][cursor_x], ' ', n); + } break; + case 'P': // Delete characters + { + int n = params[0] ? params[0] : 1; + if (n > term_cols - cursor_x) + n = term_cols - cursor_x; + memmove(&terminal_buffer[cursor_y][cursor_x], + &terminal_buffer[cursor_y][cursor_x + n], term_cols - cursor_x - n); + memset(&terminal_buffer[cursor_y][term_cols - n], ' ', n); + } break; + case 'M': // Delete lines + { + int n = params[0] ? params[0] : 1; + if (cursor_y < term_rows - n) { + memmove(&terminal_buffer[cursor_y], &terminal_buffer[cursor_y + n], + (term_rows - cursor_y - n) * sizeof(char *)); + for (int i = term_rows - n; i < term_rows; i++) + memset(terminal_buffer[i], ' ', term_cols); + } + } break; + case 'L': // Insert lines + { + int n = params[0] ? params[0] : 1; + if (cursor_y < term_rows - n) { + memmove(&terminal_buffer[cursor_y + n], &terminal_buffer[cursor_y], + (term_rows - cursor_y - n) * sizeof(char *)); + for (int i = cursor_y; i < cursor_y + n; i++) + memset(terminal_buffer[i], ' ', term_cols); + } + } break; case 'K': // Clear line for (int i = cursor_x; i < term_cols; i++) { terminal_buffer[cursor_y][i] = ' '; @@ -917,49 +891,45 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, scroll_top = 0; // Entire terminal scroll_bottom = 0; } else if (param_idx == 1) { - scroll_top = (params[0] <= 0) - ? 1 - : (params[0] > term_rows ? term_rows : params[0]); + scroll_top = params[0] <= 0 ? 1 + : params[0] > term_rows ? term_rows + : params[0]; scroll_bottom = 0; } else if (param_idx >= 2) { - scroll_top = (params[0] <= 0) - ? 1 - : (params[0] > term_rows ? term_rows : params[0]); - scroll_bottom = (params[1] <= 0) - ? term_rows - : (params[1] > term_rows ? term_rows : params[1]); - + scroll_top = params[0] <= 0 ? 1 + : params[0] > term_rows ? term_rows + : params[0]; + scroll_bottom = params[1] <= 0 ? term_rows + : params[1] > term_rows ? term_rows + : params[1]; // if top is bigger than bottom, swap values if (scroll_top > scroll_bottom) { int tmp = scroll_top; scroll_top = scroll_bottom; scroll_bottom = tmp; - break; - case 'S': // Scroll up - scroll_region_up(params[0] == 0 ? 1 : params[0]); - needs_refresh = 1; - break; - case 'T': // Scroll down - scroll_region_down(params[0] == 0 ? 1 : params[0]); - needs_refresh = 1; - break; - case 'E': // Cursor next line - cursor_x = 0; - cursor_y += params[0] ? params[0] : 1; - if (cursor_y >= term_rows) { - cursor_y = term_rows - 1; - } - break; - case 'F': // Cursor line before - cursor_x = 0; - cursor_y -= params[0] ? params[0] : 1; - if (cursor_y < 0) { - cursor_y = 0; - } - break; } } break; + case 'S': // Scroll up + scroll_region_up(params[0] ? params[0] : 1); + needs_refresh = 1; + break; + case 'T': // Scroll down + scroll_region_down(params[0] ? params[0] : 1); + needs_refresh = 1; + break; + case 'E': // Cursor next line + cursor_x = 0; + cursor_y += params[0] ? params[0] : 1; + if (cursor_y >= term_rows) + cursor_y = term_rows - 1; + break; + case 'F': // Cursor line before + cursor_x = 0; + cursor_y -= params[0] ? params[0] : 1; + if (cursor_y < 0) + cursor_y = 0; + break; case 'm': // Handling of text for (int i = 0; i < param_idx; i++) { if (params[i] == 0) { // Reset Everything @@ -972,8 +942,6 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, current_attr |= ATTR_DIM; } else if (params[i] == 3) { current_attr |= ATTR_ITALIC; - // } else if (params[i] == 4) { - // current_attr |= ATTR_UNDERLINE; } else if (params[i] == 5) { // Slow blink current_attr |= ATTR_BLINK; } else if (params[i] == 7) { @@ -982,8 +950,6 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, current_attr &= ~ATTR_BOLD; } else if (params[i] == 23) { current_attr &= ~ATTR_ITALIC; - // } else if (params[i] == 24) { - // current_attr &= ~ATTR_UNDERLINE; } else if (params[i] == 25) { current_attr &= ~ATTR_BLINK; } else if (params[i] == 27) { @@ -992,11 +958,9 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, current_color = get_ansi_color(params[i] - 30); } else if (params[i] >= 40 && params[i] <= 47) { // Background colors current_bg_color = get_ansi_color(params[i] - 40); - } else if (params[i] >= 90 && - params[i] <= 97) { // Bright foreground colors + } else if (params[i] >= 90 && params[i] <= 97) { // Bright foreground current_color = get_bright_ansi_color(params[i] - 90); - } else if (params[i] >= 100 && - params[i] <= 107) { // Bright background colors + } else if (params[i] >= 100 && params[i] <= 107) { // Bright background current_bg_color = get_bright_ansi_color(params[i] - 100); } } @@ -1007,73 +971,72 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len, static int master_cb(int fd, void *data, Window window) { if (!terminal_buffer || !color_buffer || !attr_buffer || !bg_color_buffer) return 0; - char buf[4096]; - ssize_t bytes_read; struct { Display *display; Window window; } *ctx = data; - bytes_read = read(fd, buf, sizeof(buf)); - if (bytes_read <= 0 && errno != EAGAIN && errno != EINTR) { + char buf[4096]; + ssize_t n = read(fd, buf, sizeof(buf)); + if (n <= 0 && errno != EAGAIN && errno != EINTR) { destroy_cb(ctx->display, ctx->window); return 0; } - if (bytes_read > 0) { - for (int i = 0; i < bytes_read; i++) { - if (buf[i] == '\033' && i + 1 < bytes_read && buf[i + 1] == '[') { - parse_ansi_code(buf, &i, bytes_read, window); - continue; + if (n <= 0) + return 1; + for (int i = 0; i < n; i++) { + if (buf[i] == '\033' && i + 1 < n && buf[i + 1] == '[') { + parse_ansi_code(buf, &i, n, window); + continue; + } + switch (buf[i]) { + case '\n': + cursor_x = 0; + if (++cursor_y >= term_rows) { + scroll_region_up(1); + cursor_y = term_rows - 1; } - if (buf[i] == '\n') { + needs_refresh = 1; + break; + case '\r': + cursor_x = 0; + break; + case '\b': + if (cursor_x > 0) { + cursor_x--; + needs_refresh = 1; + } else if (cursor_y > 0) { + cursor_y--; + cursor_x = term_cols - 1; + while (cursor_x > 0 && terminal_buffer[cursor_y][cursor_x - 1] == ' ') + cursor_x--; + needs_refresh = 1; + } + break; + default: + if (cursor_y >= term_rows || cursor_x >= term_cols) + break; + terminal_buffer[cursor_y][cursor_x] = buf[i]; + color_buffer[cursor_y][cursor_x] = current_color; + attr_buffer[cursor_y][cursor_x] = current_attr; + bg_color_buffer[cursor_y][cursor_x] = current_bg_color; + needs_refresh = 1; + if (++cursor_x >= term_cols) { cursor_x = 0; - cursor_y++; - if (cursor_y >= term_rows) { - scroll_up(); + if (++cursor_y >= term_rows) { + scroll_region_up(1); cursor_y = term_rows - 1; } - needs_refresh = 1; - } else if (buf[i] == '\r') { - cursor_x = 0; - } else if (buf[i] == '\b') { - if (cursor_x > 0) { - cursor_x--; - needs_refresh = 1; - } else if (cursor_y > 0) { - cursor_y--; - cursor_x = term_cols - 1; - while (cursor_x > 0 && - terminal_buffer[cursor_y][cursor_x - 1] == ' ') { - cursor_x--; - } - needs_refresh = 1; - } - } else { - if (cursor_y < term_rows && cursor_x < term_cols) { - terminal_buffer[cursor_y][cursor_x] = buf[i]; - color_buffer[cursor_y][cursor_x] = current_color; - attr_buffer[cursor_y][cursor_x] = current_attr; - bg_color_buffer[cursor_y][cursor_x] = current_bg_color; - needs_refresh = 1; - cursor_x++; - if (cursor_x >= term_cols) { - cursor_x = 0; - cursor_y++; - if (cursor_y >= term_rows) { - scroll_up(); - cursor_y = term_rows - 1; - } - } - } } + break; } - cursor_visible = 1; - if (needs_refresh) { - check_refresh(ctx->display, ctx->window); - } else { - draw_cursor(ctx->display, ctx->window); - XFlush(ctx->display); - } + } + cursor_visible = 1; + if (needs_refresh) + check_refresh(ctx->display, ctx->window); + else { + draw_cursor(ctx->display, ctx->window); + XFlush(ctx->display); } return 1; }