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)
This commit is contained in:
parent
dc7562af52
commit
60505314a4
589
cowterm.c
589
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)));
|
||||
|
||||
if (needs_refresh) {
|
||||
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;
|
||||
}
|
||||
|
||||
// Only draw the changed parts of the terminal to the buffer
|
||||
if (needs_refresh) {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
// 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],
|
||||
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[y], temp_attr_buffer[y + 1],
|
||||
term_cols * sizeof(int));
|
||||
memcpy(bg_color_buffer[y], temp_bg_color_buffer[y + 1],
|
||||
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));
|
||||
}
|
||||
|
||||
// Clear the bottom line
|
||||
memset(terminal_buffer[end], ' ', term_cols);
|
||||
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[end][x] = current_color;
|
||||
attr_buffer[end][x] = current_attr;
|
||||
bg_color_buffer[end][x] = current_bg_color;
|
||||
}
|
||||
color_buffer[i][x] = current_color;
|
||||
attr_buffer[i][x] = current_attr;
|
||||
bg_color_buffer[i][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,36 +568,57 @@ 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') {
|
||||
|
||||
if (!num_buf[0])
|
||||
return;
|
||||
|
||||
int code = atoi(num_buf);
|
||||
if (buf[*idx] == 'h' || buf[*idx] == 'l') {
|
||||
if (buf[*idx] != 'h' && buf[*idx] != 'l')
|
||||
return;
|
||||
|
||||
switch (code) {
|
||||
case 1047: // Alternate screen buffer
|
||||
case 1047: // Alt buffer
|
||||
if (buf[*idx] == 'h') {
|
||||
if (!saved_terminal) {
|
||||
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, sizeof(char));
|
||||
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]);
|
||||
@ -727,6 +630,7 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
|
||||
free(color_buffer);
|
||||
free(attr_buffer);
|
||||
free(bg_color_buffer);
|
||||
|
||||
terminal_buffer = saved_terminal;
|
||||
color_buffer = saved_colors;
|
||||
attr_buffer = saved_attrs;
|
||||
@ -737,6 +641,7 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
|
||||
draw_terminal(display, window);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1048: // Save/restore cursor
|
||||
if (buf[*idx] == 'h') {
|
||||
saved_cursor_x = cursor_x;
|
||||
@ -746,29 +651,47 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
|
||||
cursor_y = saved_cursor_y;
|
||||
}
|
||||
break;
|
||||
case 1049: // Combined alternate buffer + cursor
|
||||
|
||||
case 1049: // Alt buffer + cursor
|
||||
if (buf[*idx] == 'h') {
|
||||
saved_cursor_x = cursor_x;
|
||||
saved_cursor_y = cursor_y;
|
||||
if (!saved_terminal) {
|
||||
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, sizeof(char));
|
||||
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]);
|
||||
@ -780,6 +703,7 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
|
||||
free(color_buffer);
|
||||
free(attr_buffer);
|
||||
free(bg_color_buffer);
|
||||
|
||||
terminal_buffer = saved_terminal;
|
||||
color_buffer = saved_colors;
|
||||
attr_buffer = saved_attrs;
|
||||
@ -793,8 +717,6 @@ static void handle_alternate_buffer(const char *buf, int *idx, int max_len,
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long get_ansi_color(int index) {
|
||||
@ -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,48 +891,44 @@ 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]);
|
||||
scroll_region_up(params[0] ? params[0] : 1);
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 'T': // Scroll down
|
||||
scroll_region_down(params[0] == 0 ? 1 : params[0]);
|
||||
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) {
|
||||
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) {
|
||||
if (cursor_y < 0)
|
||||
cursor_y = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'm': // Handling of text
|
||||
for (int i = 0; i < param_idx; i++) {
|
||||
@ -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,74 +971,73 @@ 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);
|
||||
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;
|
||||
}
|
||||
if (buf[i] == '\n') {
|
||||
switch (buf[i]) {
|
||||
case '\n':
|
||||
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') {
|
||||
break;
|
||||
case '\r':
|
||||
cursor_x = 0;
|
||||
} else if (buf[i] == '\b') {
|
||||
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] == ' ') {
|
||||
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) {
|
||||
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;
|
||||
cursor_x++;
|
||||
if (cursor_x >= term_cols) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cursor_visible = 1;
|
||||
if (needs_refresh) {
|
||||
if (needs_refresh)
|
||||
check_refresh(ctx->display, ctx->window);
|
||||
} else {
|
||||
else {
|
||||
draw_cursor(ctx->display, ctx->window);
|
||||
XFlush(ctx->display);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user