Refreshing and No more blinking cursor
Cursor will now be hollow if you're not focused on the window and the refreshing of the terminal makes the cursor not freak out + some visual bugs **should** be fixed. Htop and vim are not going to work still unfortunately.
This commit is contained in:
parent
347ac2948c
commit
a04a1870cc
@ -2,7 +2,7 @@
|
|||||||
What the hell is a cowmonk?
|
What the hell is a cowmonk?
|
||||||
|
|
||||||
## What is cowterm?
|
## What is cowterm?
|
||||||
cowterm is a really simple terminal that is written in pure C, using gtk. I don't recommend anyone seriously using this.
|
cowterm is a really simple terminal that is written in pure C, using Xorg Libraries. I don't recommend anyone seriously using this.
|
||||||
If you wish to, then good luck I guess? Here are some features that are in cowterm:
|
If you wish to, then good luck I guess? Here are some features that are in cowterm:
|
||||||
- You can kill processes in it using Ctrl+C
|
- You can kill processes in it using Ctrl+C
|
||||||
- Yes, this had to be manually implemented
|
- Yes, this had to be manually implemented
|
||||||
@ -30,7 +30,6 @@ Here are some ~~downsides~~ upsides to using cowterm:
|
|||||||
- C compiler (gcc or clang)
|
- C compiler (gcc or clang)
|
||||||
- C libraries
|
- C libraries
|
||||||
- Xorg Libs (xfont, xutil, and xlibs)
|
- Xorg Libs (xfont, xutil, and xlibs)
|
||||||
- GTK 3.0
|
|
||||||
|
|
||||||
### Compilation & Installation
|
### Compilation & Installation
|
||||||
The steps are very simple, nothing like you've never seen before:
|
The steps are very simple, nothing like you've never seen before:
|
||||||
|
13
config.h
13
config.h
@ -1,6 +1,10 @@
|
|||||||
#ifndef CONFIG_H_
|
#ifndef CONFIG_H_
|
||||||
#define CONFIG_H_
|
#define CONFIG_H_
|
||||||
|
|
||||||
|
// 60 Hz refresh rate = 1/60 = 0.0166666... seconds = 16666 microseconds
|
||||||
|
// Change as suited for your monitor
|
||||||
|
#define REFRESH_INTERVAL 16666
|
||||||
|
|
||||||
// Colors are just configured like RBG, if you don't recognize
|
// Colors are just configured like RBG, if you don't recognize
|
||||||
// this color format, search it up and find it out yourself
|
// this color format, search it up and find it out yourself
|
||||||
static const unsigned long int RED = 0xFF0000;
|
static const unsigned long int RED = 0xFF0000;
|
||||||
@ -25,9 +29,12 @@ static const unsigned long int LIGHT_CYAN = 0x80FFFF;
|
|||||||
// "-adobe-courier-medium-r-normal--14-140-75-75-m-90-iso8859-1"
|
// "-adobe-courier-medium-r-normal--14-140-75-75-m-90-iso8859-1"
|
||||||
// "-bitstream-terminal-medium-r-normal--18-140-100-100-c-110-iso8859-1"
|
// "-bitstream-terminal-medium-r-normal--18-140-100-100-c-110-iso8859-1"
|
||||||
// Use 'xlsfonts' command to list available fonts
|
// 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";
|
static const char REGULAR_FONT[] =
|
||||||
static const char BOLD_FONT[] = "-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-1";
|
"-misc-fixed-medium-r-normal--13-120-75-75-c-70-iso8859-1";
|
||||||
static const char ITALICS_FONT[] = "-misc-fixed-medium-o-normal--13-120-75-75-c-70-iso8859-1";
|
static const char BOLD_FONT[] =
|
||||||
|
"-misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-1";
|
||||||
|
static const char ITALICS_FONT[] =
|
||||||
|
"-misc-fixed-medium-o-normal--13-120-75-75-c-70-iso8859-1";
|
||||||
|
|
||||||
// Change the window name to whatever you want lmao
|
// Change the window name to whatever you want lmao
|
||||||
static const char window_name[] = "CowTerm";
|
static const char window_name[] = "CowTerm";
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
PREFIX = /usr/local/
|
PREFIX = /usr/local/
|
||||||
|
|
||||||
# includes and libs
|
# includes and libs
|
||||||
FREETYPELIBS = -lfontconfig -lXft
|
#FREETYPELIBS = -lfontconfig -lXft
|
||||||
FREETYPEINC = /usr/include/freetype2
|
#FREETYPEINC = /usr/include/freetype2
|
||||||
|
|
||||||
INCS = -I/usr/X11R6/include -I${FREETYPEINC}
|
INCS = -I/usr/X11R6/include -I${FREETYPEINC}
|
||||||
LIBS = -L/usr/X11R6/lib -lX11 -lutil ${FREETYPELIBS}
|
LIBS = -L/usr/X11R6/lib -lX11 -lutil ${FREETYPELIBS}
|
||||||
|
131
cowterm.c
131
cowterm.c
@ -22,7 +22,6 @@
|
|||||||
#define MAX_COLS 1000
|
#define MAX_COLS 1000
|
||||||
#define CHAR_WIDTH 8
|
#define CHAR_WIDTH 8
|
||||||
#define CHAR_HEIGHT 16
|
#define CHAR_HEIGHT 16
|
||||||
#define CURSOR_BLINK_INTERVAL 500000 // 500ms in microseconds
|
|
||||||
|
|
||||||
static pid_t child_pid;
|
static pid_t child_pid;
|
||||||
static char **terminal_buffer = NULL;
|
static char **terminal_buffer = NULL;
|
||||||
@ -39,11 +38,14 @@ static GC gc_bold = NULL;
|
|||||||
static Display *display = NULL;
|
static Display *display = NULL;
|
||||||
static int cursor_visible = 1;
|
static int cursor_visible = 1;
|
||||||
static struct timeval last_blink;
|
static struct timeval last_blink;
|
||||||
|
static struct timeval last_refresh;
|
||||||
static Pixmap buffer_pixmap = None;
|
static Pixmap buffer_pixmap = None;
|
||||||
static int master_fd = -1;
|
static int master_fd = -1;
|
||||||
|
static int needs_refresh = 0;
|
||||||
static XFontStruct *regular_font = NULL;
|
static XFontStruct *regular_font = NULL;
|
||||||
static XFontStruct *bold_font = NULL;
|
static XFontStruct *bold_font = NULL;
|
||||||
static XFontStruct *italic_font = NULL;
|
static XFontStruct *italic_font = NULL;
|
||||||
|
static int window_focused = 0;
|
||||||
|
|
||||||
#define ATTR_BOLD 1
|
#define ATTR_BOLD 1
|
||||||
#define ATTR_ITALIC 2
|
#define ATTR_ITALIC 2
|
||||||
@ -67,26 +69,31 @@ static void draw_cursor(Display *display, Window window) {
|
|||||||
// Save original color
|
// Save original color
|
||||||
unsigned long original_color = color_buffer[cursor_y][cursor_x];
|
unsigned long original_color = color_buffer[cursor_y][cursor_x];
|
||||||
|
|
||||||
// Draw inverted cursor background
|
if (!window_focused) {
|
||||||
XSetForeground(display, gc, original_color);
|
XSetForeground(display, gc, original_color);
|
||||||
XFillRectangle(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
XDrawRectangle(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
||||||
cursor_y * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT);
|
cursor_y * CHAR_HEIGHT, CHAR_WIDTH - 1, CHAR_HEIGHT - 1);
|
||||||
|
} else {
|
||||||
|
XSetForeground(display, gc, original_color);
|
||||||
|
XFillRectangle(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
||||||
|
cursor_y * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT);
|
||||||
|
|
||||||
// Draw the character in inverted color
|
if (cursor_x < term_cols && cursor_y < term_rows) {
|
||||||
if (cursor_x < term_cols && cursor_y < term_rows) {
|
char str[2] = {terminal_buffer[cursor_y][cursor_x], '\0'};
|
||||||
char str[2] = {terminal_buffer[cursor_y][cursor_x], '\0'};
|
XSetForeground(display, gc,
|
||||||
XSetForeground(display, gc, XBlackPixel(display, DefaultScreen(display)));
|
XBlackPixel(display, DefaultScreen(display)));
|
||||||
|
|
||||||
XFontStruct *font = regular_font;
|
XFontStruct *font = regular_font;
|
||||||
if (attr_buffer[cursor_y][cursor_x] & ATTR_BOLD) {
|
if (attr_buffer[cursor_y][cursor_x] & ATTR_BOLD) {
|
||||||
font = bold_font;
|
font = bold_font;
|
||||||
} else if (attr_buffer[cursor_y][cursor_x] & ATTR_ITALIC) {
|
} else if (attr_buffer[cursor_y][cursor_x] & ATTR_ITALIC) {
|
||||||
font = italic_font;
|
font = italic_font;
|
||||||
|
}
|
||||||
|
XSetFont(display, gc, font->fid);
|
||||||
|
|
||||||
|
XDrawString(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
||||||
|
(cursor_y + 1) * CHAR_HEIGHT - 2, str, 1);
|
||||||
}
|
}
|
||||||
XSetFont(display, gc, font->fid);
|
|
||||||
|
|
||||||
XDrawString(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
|
||||||
(cursor_y + 1) * CHAR_HEIGHT - 2, str, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,18 +103,10 @@ static void draw_cursor(Display *display, Window window) {
|
|||||||
cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT);
|
cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_cursor_blink(Display *display, Window window) {
|
static void update_cursor_state(Display *display, Window window) {
|
||||||
struct timeval now;
|
if (window_focused) {
|
||||||
gettimeofday(&now, NULL);
|
cursor_visible = 1;
|
||||||
|
return;
|
||||||
long elapsed = (now.tv_sec - last_blink.tv_sec) * 1000000 +
|
|
||||||
(now.tv_usec - last_blink.tv_usec);
|
|
||||||
|
|
||||||
if (elapsed >= CURSOR_BLINK_INTERVAL) {
|
|
||||||
cursor_visible = !cursor_visible;
|
|
||||||
last_blink = now;
|
|
||||||
draw_cursor(display, window);
|
|
||||||
XFlush(display);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +216,7 @@ static void resize_buffers(int new_rows, int new_cols) {
|
|||||||
buffer_pixmap = XCreatePixmap(display, DefaultRootWindow(display),
|
buffer_pixmap = XCreatePixmap(display, DefaultRootWindow(display),
|
||||||
term_cols * CHAR_WIDTH, term_rows * CHAR_HEIGHT,
|
term_cols * CHAR_WIDTH, term_rows * CHAR_HEIGHT,
|
||||||
DefaultDepth(display, DefaultScreen(display)));
|
DefaultDepth(display, DefaultScreen(display)));
|
||||||
|
needs_refresh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_cb(Display *display, Window window) {
|
static void destroy_cb(Display *display, Window window) {
|
||||||
@ -286,12 +286,9 @@ static void draw_terminal(Display *display, Window window) {
|
|||||||
if (!gc) {
|
if (!gc) {
|
||||||
gc = XCreateGC(display, window, 0, NULL);
|
gc = XCreateGC(display, window, 0, NULL);
|
||||||
|
|
||||||
regular_font = XLoadQueryFont(
|
regular_font = XLoadQueryFont(display, REGULAR_FONT);
|
||||||
display, REGULAR_FONT);
|
bold_font = XLoadQueryFont(display, BOLD_FONT);
|
||||||
bold_font = XLoadQueryFont(
|
italic_font = XLoadQueryFont(display, ITALICS_FONT);
|
||||||
display, BOLD_FONT);
|
|
||||||
italic_font = XLoadQueryFont(
|
|
||||||
display, ITALICS_FONT);
|
|
||||||
|
|
||||||
if (!regular_font)
|
if (!regular_font)
|
||||||
regular_font = XLoadQueryFont(display, "fixed");
|
regular_font = XLoadQueryFont(display, "fixed");
|
||||||
@ -325,6 +322,23 @@ static void draw_terminal(Display *display, Window window) {
|
|||||||
|
|
||||||
draw_cursor(display, window);
|
draw_cursor(display, window);
|
||||||
XFlush(display);
|
XFlush(display);
|
||||||
|
needs_refresh = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_refresh(Display *display, Window window) {
|
||||||
|
if (!needs_refresh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
long elapsed = (now.tv_sec - last_refresh.tv_sec) * 1000000 +
|
||||||
|
(now.tv_usec - last_refresh.tv_usec);
|
||||||
|
|
||||||
|
if (elapsed >= REFRESH_INTERVAL) {
|
||||||
|
draw_terminal(display, window);
|
||||||
|
last_refresh = now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_terminal(Display *display, Window window) {
|
static void clear_terminal(Display *display, Window window) {
|
||||||
@ -339,7 +353,7 @@ static void clear_terminal(Display *display, Window window) {
|
|||||||
}
|
}
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
cursor_y = 0;
|
cursor_y = 0;
|
||||||
draw_terminal(display, window);
|
needs_refresh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll the terminal up one line
|
// Scroll the terminal up one line
|
||||||
@ -358,6 +372,7 @@ static void scroll_up(void) {
|
|||||||
color_buffer[term_rows - 1][x] = current_color;
|
color_buffer[term_rows - 1][x] = current_color;
|
||||||
attr_buffer[term_rows - 1][x] = current_attr;
|
attr_buffer[term_rows - 1][x] = current_attr;
|
||||||
}
|
}
|
||||||
|
needs_refresh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles those pesky ANSI color escape codes that terminals use.
|
// Handles those pesky ANSI color escape codes that terminals use.
|
||||||
@ -476,7 +491,7 @@ static int master_cb(int fd, void *data) {
|
|||||||
if (cursor_y >= term_rows) {
|
if (cursor_y >= term_rows) {
|
||||||
scroll_up();
|
scroll_up();
|
||||||
cursor_y = term_rows - 1;
|
cursor_y = term_rows - 1;
|
||||||
draw_terminal(ctx->display, ctx->window);
|
needs_refresh = 1;
|
||||||
}
|
}
|
||||||
} else if (buf[i] == '\r') {
|
} else if (buf[i] == '\r') {
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
@ -484,20 +499,14 @@ static int master_cb(int fd, void *data) {
|
|||||||
if (cursor_x > 0) {
|
if (cursor_x > 0) {
|
||||||
cursor_x--;
|
cursor_x--;
|
||||||
terminal_buffer[cursor_y][cursor_x] = ' ';
|
terminal_buffer[cursor_y][cursor_x] = ' ';
|
||||||
draw_char(ctx->display, buffer_pixmap, cursor_x, cursor_y);
|
needs_refresh = 1;
|
||||||
XCopyArea(ctx->display, buffer_pixmap, ctx->window, gc,
|
|
||||||
cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT, CHAR_WIDTH,
|
|
||||||
CHAR_HEIGHT, cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cursor_y < term_rows && cursor_x < term_cols) {
|
if (cursor_y < term_rows && cursor_x < term_cols) {
|
||||||
terminal_buffer[cursor_y][cursor_x] = buf[i];
|
terminal_buffer[cursor_y][cursor_x] = buf[i];
|
||||||
color_buffer[cursor_y][cursor_x] = current_color;
|
color_buffer[cursor_y][cursor_x] = current_color;
|
||||||
attr_buffer[cursor_y][cursor_x] = current_attr;
|
attr_buffer[cursor_y][cursor_x] = current_attr;
|
||||||
draw_char(ctx->display, buffer_pixmap, cursor_x, cursor_y);
|
needs_refresh = 1;
|
||||||
XCopyArea(ctx->display, buffer_pixmap, ctx->window, gc,
|
|
||||||
cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT, CHAR_WIDTH,
|
|
||||||
CHAR_HEIGHT, cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT);
|
|
||||||
cursor_x++;
|
cursor_x++;
|
||||||
if (cursor_x >= term_cols) {
|
if (cursor_x >= term_cols) {
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
@ -505,15 +514,19 @@ static int master_cb(int fd, void *data) {
|
|||||||
if (cursor_y >= term_rows) {
|
if (cursor_y >= term_rows) {
|
||||||
scroll_up();
|
scroll_up();
|
||||||
cursor_y = term_rows - 1;
|
cursor_y = term_rows - 1;
|
||||||
draw_terminal(ctx->display, ctx->window);
|
needs_refresh = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor_visible = 1;
|
cursor_visible = 1;
|
||||||
draw_cursor(ctx->display, ctx->window);
|
if (needs_refresh) {
|
||||||
XFlush(ctx->display);
|
check_refresh(ctx->display, ctx->window);
|
||||||
|
} else {
|
||||||
|
draw_cursor(ctx->display, ctx->window);
|
||||||
|
XFlush(ctx->display);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -562,6 +575,7 @@ int main(void) {
|
|||||||
term_cols = 80;
|
term_cols = 80;
|
||||||
|
|
||||||
gettimeofday(&last_blink, NULL);
|
gettimeofday(&last_blink, NULL);
|
||||||
|
gettimeofday(&last_refresh, NULL);
|
||||||
|
|
||||||
struct winsize ws = {.ws_row = term_rows,
|
struct winsize ws = {.ws_row = term_rows,
|
||||||
.ws_col = term_cols,
|
.ws_col = term_cols,
|
||||||
@ -626,7 +640,8 @@ int main(void) {
|
|||||||
XSetWMNormalHints(display, window, &hints);
|
XSetWMNormalHints(display, window, &hints);
|
||||||
XStoreName(display, window, window_name);
|
XStoreName(display, window, window_name);
|
||||||
XSelectInput(display, window,
|
XSelectInput(display, window,
|
||||||
KeyPressMask | ExposureMask | StructureNotifyMask);
|
KeyPressMask | ExposureMask | StructureNotifyMask |
|
||||||
|
FocusChangeMask);
|
||||||
XMapWindow(display, window);
|
XMapWindow(display, window);
|
||||||
|
|
||||||
if (openpty(&master, &slave, NULL, NULL, &ws) == -1) {
|
if (openpty(&master, &slave, NULL, NULL, &ws) == -1) {
|
||||||
@ -700,24 +715,34 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FocusIn:
|
||||||
|
window_focused = 1;
|
||||||
|
needs_refresh = 1;
|
||||||
|
break;
|
||||||
|
case FocusOut:
|
||||||
|
window_focused = 0;
|
||||||
|
needs_refresh = 1;
|
||||||
|
break;
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
key_press_cb((XKeyEvent *)&event, &master);
|
key_press_cb((XKeyEvent *)&event, &master);
|
||||||
break;
|
break;
|
||||||
case Expose:
|
case Expose:
|
||||||
draw_terminal(display, window);
|
needs_refresh = 1;
|
||||||
|
check_refresh(display, window);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tv = {0, 100000}; // 100ms timeout for cursor blink
|
struct timeval tv = {0, 1000}; // 1ms timeout for faster refresh
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(master, &fds);
|
FD_SET(master, &fds);
|
||||||
if (select(master + 1, &fds, NULL, NULL, &tv) > 0) {
|
if (select(master + 1, &fds, NULL, NULL, &tv) > 0) {
|
||||||
master_cb(master, &ctx);
|
master_cb(master, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_cursor_blink(display, window);
|
check_refresh(display, window);
|
||||||
|
update_cursor_state(display, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user