Unicode support!
Took a lot of debugging...
This commit is contained in:
parent
63522a14fc
commit
14296c3b6b
6
config.h
6
config.h
@ -33,11 +33,11 @@ static const unsigned long int LIGHT_CYAN = 0x80FFFF;
|
||||
// "-bitstream-terminal-medium-r-normal--18-140-100-100-c-110-iso8859-1"
|
||||
// Use 'xlsfonts' command to list available fonts
|
||||
static const char REGULAR_FONT[] =
|
||||
"-misc-fixed-medium-r-normal--13-120-75-75-c-70-iso8859-1";
|
||||
"-misc-fixed-medium-r-normal--13-120-75-75-c-70-iso10646-1";
|
||||
static const char BOLD_FONT[] =
|
||||
"-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-1";
|
||||
"-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso10646-1";
|
||||
static const char ITALICS_FONT[] =
|
||||
"-misc-fixed-medium-o-normal--13-120-75-75-c-70-iso8859-1";
|
||||
"-misc-fixed-medium-o-normal--13-120-75-75-c-70-iso10646-1";
|
||||
|
||||
// Change the window name to whatever you want lmao
|
||||
static const char window_name[] = "CowTerm";
|
||||
|
139
cowterm.c
139
cowterm.c
@ -4,6 +4,7 @@
|
||||
#include <X11/keysym.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <pty.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@ -15,6 +16,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@ -26,7 +28,7 @@
|
||||
|
||||
// General window/terminal stuff
|
||||
static pid_t child_pid;
|
||||
static char **terminal_buffer = NULL;
|
||||
static wchar_t **terminal_buffer = NULL;
|
||||
static unsigned long **color_buffer = NULL;
|
||||
static int **attr_buffer = NULL;
|
||||
static int term_rows;
|
||||
@ -58,7 +60,7 @@ static unsigned long current_bg_color;
|
||||
static unsigned long **bg_color_buffer = NULL;
|
||||
|
||||
// Alternatives to handle the ANSI escape codes
|
||||
static char **saved_terminal = NULL;
|
||||
static wchar_t **saved_terminal = NULL;
|
||||
static unsigned long **saved_colors = NULL;
|
||||
static int **saved_attrs = NULL;
|
||||
static int saved_cursor_x = 0;
|
||||
@ -155,12 +157,12 @@ static void resize_buffers(int new_rows, int new_cols) {
|
||||
if (new_cols < 1)
|
||||
new_cols = 1;
|
||||
|
||||
size_t row_size = ((new_cols * sizeof(char) + 15) & ~15);
|
||||
size_t row_size = ((new_cols * sizeof(wchar_t) + 15) & ~15);
|
||||
size_t color_row_size = ((new_cols * sizeof(unsigned long) + 15) & ~15);
|
||||
size_t attr_row_size = ((new_cols * sizeof(int) + 15) & ~15);
|
||||
size_t bg_color_row_size = ((new_cols * sizeof(unsigned long) + 15) & ~15);
|
||||
|
||||
char **new_term_buffer = malloc(new_rows * sizeof(char *));
|
||||
wchar_t **new_term_buffer = malloc(new_rows * sizeof(char *));
|
||||
unsigned long **new_color_buffer = malloc(new_rows * sizeof(unsigned long *));
|
||||
int **new_attr_buffer = malloc(new_rows * sizeof(int *));
|
||||
unsigned long **new_bg_color_buffer =
|
||||
@ -198,23 +200,22 @@ static void resize_buffers(int new_rows, int new_cols) {
|
||||
if (i < term_rows && i < new_rows && terminal_buffer && color_buffer &&
|
||||
attr_buffer && bg_color_buffer) {
|
||||
int copy_cols = (new_cols < term_cols) ? new_cols : term_cols;
|
||||
memcpy(new_term_buffer[i], terminal_buffer[i], copy_cols * sizeof(char));
|
||||
memcpy(new_term_buffer[i], terminal_buffer[i],
|
||||
copy_cols * sizeof(wchar_t));
|
||||
memcpy(new_color_buffer[i], color_buffer[i],
|
||||
copy_cols * sizeof(unsigned long));
|
||||
memcpy(new_attr_buffer[i], attr_buffer[i], copy_cols * sizeof(int));
|
||||
memcpy(new_bg_color_buffer[i], bg_color_buffer[i],
|
||||
copy_cols * sizeof(unsigned long));
|
||||
if (new_cols > term_cols) {
|
||||
memset(new_term_buffer[i] + term_cols, ' ', new_cols - term_cols);
|
||||
for (int x = term_cols; x < new_cols; x++) {
|
||||
new_term_buffer[i][x] = L' ';
|
||||
new_color_buffer[i][x] = current_color;
|
||||
new_attr_buffer[i][x] = current_attr;
|
||||
new_bg_color_buffer[i][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memset(new_term_buffer[i], ' ', new_cols);
|
||||
for (int x = 0; x < new_cols; x++) {
|
||||
new_term_buffer[i][x] = L' ';
|
||||
new_color_buffer[i][x] = current_color;
|
||||
new_attr_buffer[i][x] = current_attr;
|
||||
new_bg_color_buffer[i][x] = current_bg_color;
|
||||
@ -223,16 +224,32 @@ static void resize_buffers(int new_rows, int new_cols) {
|
||||
}
|
||||
|
||||
// Free old buffers after successful allocation
|
||||
if (terminal_buffer && color_buffer && attr_buffer && bg_color_buffer) {
|
||||
if (terminal_buffer) {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
if (terminal_buffer[i])
|
||||
free(terminal_buffer[i]);
|
||||
free(color_buffer[i]);
|
||||
free(attr_buffer[i]);
|
||||
free(bg_color_buffer[i]);
|
||||
}
|
||||
free(terminal_buffer);
|
||||
}
|
||||
if (color_buffer) {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
if (color_buffer[i])
|
||||
free(color_buffer[i]);
|
||||
}
|
||||
free(color_buffer);
|
||||
}
|
||||
if (attr_buffer) {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
if (attr_buffer[i])
|
||||
free(attr_buffer[i]);
|
||||
}
|
||||
free(attr_buffer);
|
||||
}
|
||||
if (bg_color_buffer) {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
if (bg_color_buffer[i])
|
||||
free(bg_color_buffer[i]);
|
||||
}
|
||||
free(bg_color_buffer);
|
||||
}
|
||||
|
||||
@ -305,9 +322,14 @@ static void draw_char(Display *display, Drawable d, int x, int y) {
|
||||
if (x < 0 || x >= term_cols || y < 0 || y >= term_rows)
|
||||
return;
|
||||
|
||||
char c = terminal_buffer[y][x];
|
||||
if (c < 32 || c > 126) // Only allow printable ASCII characters
|
||||
return;
|
||||
wchar_t c = terminal_buffer[y][x];
|
||||
char utf8_buf[8] = {0};
|
||||
if (c == 0 || c == L' ') {
|
||||
utf8_buf[0] = ' ';
|
||||
} else {
|
||||
wchar_t wstr[2] = {c, 0};
|
||||
wcstombs(utf8_buf, wstr, sizeof(utf8_buf));
|
||||
}
|
||||
|
||||
unsigned long fg = color_buffer[y][x];
|
||||
unsigned long bg = bg_color_buffer[y][x];
|
||||
@ -333,7 +355,6 @@ static void draw_char(Display *display, Drawable d, int x, int y) {
|
||||
|
||||
XSetForeground(display, gc, fg);
|
||||
|
||||
char str[2] = {c, '\0'};
|
||||
XFontStruct *font = regular_font;
|
||||
|
||||
if (attr & ATTR_BOLD)
|
||||
@ -342,8 +363,8 @@ static void draw_char(Display *display, Drawable d, int x, int y) {
|
||||
font = italic_font;
|
||||
|
||||
XSetFont(display, gc, font->fid);
|
||||
XDrawString(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 4, str,
|
||||
1);
|
||||
XDrawString(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 4,
|
||||
utf8_buf, strlen(utf8_buf));
|
||||
|
||||
if (attr & ATTR_UNDERLINE) {
|
||||
XDrawLine(display, d, gc, x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 1,
|
||||
@ -415,7 +436,8 @@ static void scroll_region_up(int amount) {
|
||||
return;
|
||||
|
||||
for (int i = start; i <= end - amount; i++) {
|
||||
memcpy(terminal_buffer[i], terminal_buffer[i + amount], term_cols);
|
||||
memcpy(terminal_buffer[i], terminal_buffer[i + amount],
|
||||
term_cols * sizeof(wchar_t));
|
||||
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));
|
||||
@ -424,8 +446,8 @@ static void scroll_region_up(int amount) {
|
||||
}
|
||||
|
||||
for (int i = end - amount + 1; i <= end; i++) {
|
||||
memset(terminal_buffer[i], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[i][x] = L' ';
|
||||
color_buffer[i][x] = current_color;
|
||||
attr_buffer[i][x] = current_attr;
|
||||
bg_color_buffer[i][x] = current_bg_color;
|
||||
@ -441,7 +463,7 @@ static void scroll_region_down(int amount) {
|
||||
if (end >= term_rows)
|
||||
end = term_rows - 1;
|
||||
|
||||
char **tbuf = malloc(term_rows * sizeof(char *));
|
||||
wchar_t **tbuf = malloc(term_rows * sizeof(wchar_t *));
|
||||
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 *));
|
||||
@ -452,7 +474,7 @@ static void scroll_region_down(int amount) {
|
||||
}
|
||||
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
tbuf[i] = malloc(term_cols);
|
||||
tbuf[i] = malloc(term_cols * sizeof(wchar_t));
|
||||
cbuf[i] = malloc(term_cols * sizeof(unsigned long));
|
||||
abuf[i] = malloc(term_cols * sizeof(int));
|
||||
bbuf[i] = malloc(term_cols * sizeof(unsigned long));
|
||||
@ -465,21 +487,21 @@ static void scroll_region_down(int amount) {
|
||||
|
||||
if (scroll_top == 0 && scroll_bottom == 0) {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
memcpy(tbuf[i], terminal_buffer[i], term_cols);
|
||||
memcpy(tbuf[i], terminal_buffer[i], term_cols * sizeof(wchar_t));
|
||||
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++) {
|
||||
for (int y = term_rows - 1; y > 0; y--) {
|
||||
memcpy(terminal_buffer[y], tbuf[y - 1], term_cols);
|
||||
memcpy(terminal_buffer[y], tbuf[y - 1], term_cols * sizeof(wchar_t));
|
||||
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));
|
||||
}
|
||||
memset(terminal_buffer[0], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[0][x] = L' ';
|
||||
color_buffer[0][x] = current_color;
|
||||
attr_buffer[0][x] = current_attr;
|
||||
bg_color_buffer[0][x] = current_bg_color;
|
||||
@ -487,21 +509,21 @@ static void scroll_region_down(int amount) {
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
memcpy(tbuf[i], terminal_buffer[i], term_cols);
|
||||
memcpy(tbuf[i], terminal_buffer[i], term_cols * sizeof(wchar_t));
|
||||
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++) {
|
||||
for (int y = end; y > start; y--) {
|
||||
memcpy(terminal_buffer[y], tbuf[y - 1], term_cols);
|
||||
memcpy(terminal_buffer[y], tbuf[y - 1], term_cols * sizeof(wchar_t));
|
||||
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));
|
||||
}
|
||||
memset(terminal_buffer[start], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[start][x] = L' ';
|
||||
color_buffer[start][x] = current_color;
|
||||
attr_buffer[start][x] = current_attr;
|
||||
bg_color_buffer[start][x] = current_bg_color;
|
||||
@ -936,7 +958,7 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
switch (params[0]) {
|
||||
case 0: // Clear from cursor to end of line
|
||||
for (int x = cursor_x; x < term_cols; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
terminal_buffer[cursor_y][x] = L' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
@ -944,15 +966,15 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
break;
|
||||
case 1: // Clear from cursor to beginning of line
|
||||
for (int x = 0; x <= cursor_x; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
terminal_buffer[cursor_y][x] = L' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
break;
|
||||
case 2: // Clear entire line
|
||||
memset(terminal_buffer[cursor_y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[cursor_y][x] = L' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
@ -960,46 +982,45 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
break;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
draw_terminal(display, window);
|
||||
break;
|
||||
case 'J': // Clear screen
|
||||
switch (params[0]) {
|
||||
case 0: // Clear from cursor to end of screen
|
||||
// Clear current line from cursor
|
||||
for (int x = cursor_x; x < term_cols; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
terminal_buffer[cursor_y][x] = L' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
// Clear all lines below cursor
|
||||
for (int y = cursor_y + 1; y < term_rows; y++) {
|
||||
memset(terminal_buffer[y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[y][x] = L' ';
|
||||
color_buffer[y][x] = current_color;
|
||||
attr_buffer[y][x] = current_attr;
|
||||
bg_color_buffer[y][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 1: // Clear from cursor to beginning of screen
|
||||
// Clear current line up to cursor
|
||||
for (int x = 0; x <= cursor_x; x++) {
|
||||
terminal_buffer[cursor_y][x] = ' ';
|
||||
terminal_buffer[cursor_y][x] = L' ';
|
||||
color_buffer[cursor_y][x] = current_color;
|
||||
attr_buffer[cursor_y][x] = current_attr;
|
||||
bg_color_buffer[cursor_y][x] = current_bg_color;
|
||||
}
|
||||
// Clear all lines above cursor
|
||||
for (int y = 0; y < cursor_y; y++) {
|
||||
memset(terminal_buffer[y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[y][x] = L' ';
|
||||
color_buffer[y][x] = current_color;
|
||||
attr_buffer[y][x] = current_attr;
|
||||
bg_color_buffer[y][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case 2: // Clear entire screen
|
||||
case 3: // Clear entire screen and scrollback (treat same as 2)
|
||||
@ -1007,16 +1028,19 @@ static void parse_ansi_code(const char *buf, int *idx, int max_len,
|
||||
current_bg_color = XBlackPixel(display, DefaultScreen(display));
|
||||
current_attr = 0;
|
||||
for (int y = 0; y < term_rows; y++) {
|
||||
memset(terminal_buffer[y], ' ', term_cols);
|
||||
for (int x = 0; x < term_cols; x++) {
|
||||
terminal_buffer[y][x] = L' ';
|
||||
color_buffer[y][x] = current_color;
|
||||
attr_buffer[y][x] = current_attr;
|
||||
bg_color_buffer[y][x] = current_bg_color;
|
||||
}
|
||||
}
|
||||
needs_refresh = 1;
|
||||
cursor_x = 0;
|
||||
cursor_y = 0;
|
||||
break;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
draw_terminal(display, window);
|
||||
break;
|
||||
case 'r': // Set scrolling region
|
||||
if (param_idx == 0) {
|
||||
@ -1194,7 +1218,7 @@ static int master_cb(int fd, void *data, Window window) {
|
||||
continue;
|
||||
}
|
||||
if ((buf[i] >= 32 && buf[i] <= 126) || buf[i] == '\n' || buf[i] == '\r' ||
|
||||
buf[i] == '\b' || buf[i] == '\t') {
|
||||
buf[i] == '\b' || buf[i] == '\t' || (buf[i] & 0x80)) {
|
||||
switch (buf[i]) {
|
||||
case '\n':
|
||||
cursor_x = 0;
|
||||
@ -1239,6 +1263,27 @@ static int master_cb(int fd, void *data, Window window) {
|
||||
cursor_y = term_rows - 1;
|
||||
}
|
||||
}
|
||||
} else if (buf[i] & 0x80) { // UTF-8
|
||||
mbstate_t ps;
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
wchar_t wc;
|
||||
size_t len = mbrtowc(&wc, buf + i, n - i, &ps);
|
||||
|
||||
if (len != (size_t)-1 && len != (size_t)-2 && len != 0) {
|
||||
terminal_buffer[cursor_y][cursor_x] = wc;
|
||||
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;
|
||||
if (++cursor_y >= term_rows) {
|
||||
scroll_region_up(1);
|
||||
cursor_y = term_rows - 1;
|
||||
}
|
||||
}
|
||||
i += len - 1; // -1 because loop will increment i
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1331,19 +1376,24 @@ int main(void) {
|
||||
gettimeofday(&last_blink, 0);
|
||||
gettimeofday(&last_refresh, 0);
|
||||
|
||||
if (!(terminal_buffer = calloc(term_rows, sizeof(char *))) ||
|
||||
if (!(terminal_buffer = calloc(term_rows, sizeof(wchar_t *))) ||
|
||||
!(color_buffer = calloc(term_rows, sizeof(unsigned long *))) ||
|
||||
!(attr_buffer = calloc(term_rows, sizeof(int *))) ||
|
||||
!(bg_color_buffer = calloc(term_rows, sizeof(unsigned long *))))
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < term_rows; i++) {
|
||||
if (!(terminal_buffer[i] = calloc(term_cols, sizeof(char))) ||
|
||||
if (!(terminal_buffer[i] = calloc(term_cols, sizeof(wchar_t))) ||
|
||||
!(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))))
|
||||
return 1;
|
||||
memset(terminal_buffer[i], ' ', term_cols);
|
||||
for (int j = 0; j < term_cols; j++) {
|
||||
terminal_buffer[i][j] = L' ';
|
||||
color_buffer[i][j] = current_color;
|
||||
attr_buffer[i][j] = current_attr;
|
||||
bg_color_buffer[i][j] = current_bg_color;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(display = XOpenDisplay(0)))
|
||||
@ -1402,6 +1452,7 @@ int main(void) {
|
||||
if (slave > 2)
|
||||
close(slave);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
char *sh = getenv("SHELL");
|
||||
#if COLOR_256_SUPPORT
|
||||
setenv("TERM", "xterm-256color", 1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user