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 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:
|
||||
- You can kill processes in it using Ctrl+C
|
||||
- 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 libraries
|
||||
- Xorg Libs (xfont, xutil, and xlibs)
|
||||
- GTK 3.0
|
||||
|
||||
### Compilation & Installation
|
||||
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_
|
||||
#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
|
||||
// this color format, search it up and find it out yourself
|
||||
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"
|
||||
// "-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";
|
||||
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";
|
||||
static const char REGULAR_FONT[] =
|
||||
"-misc-fixed-medium-r-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
|
||||
static const char window_name[] = "CowTerm";
|
||||
|
@ -4,8 +4,8 @@
|
||||
PREFIX = /usr/local/
|
||||
|
||||
# includes and libs
|
||||
FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
#FREETYPELIBS = -lfontconfig -lXft
|
||||
#FREETYPEINC = /usr/include/freetype2
|
||||
|
||||
INCS = -I/usr/X11R6/include -I${FREETYPEINC}
|
||||
LIBS = -L/usr/X11R6/lib -lX11 -lutil ${FREETYPELIBS}
|
||||
|
99
cowterm.c
99
cowterm.c
@ -22,7 +22,6 @@
|
||||
#define MAX_COLS 1000
|
||||
#define CHAR_WIDTH 8
|
||||
#define CHAR_HEIGHT 16
|
||||
#define CURSOR_BLINK_INTERVAL 500000 // 500ms in microseconds
|
||||
|
||||
static pid_t child_pid;
|
||||
static char **terminal_buffer = NULL;
|
||||
@ -39,11 +38,14 @@ static GC gc_bold = NULL;
|
||||
static Display *display = NULL;
|
||||
static int cursor_visible = 1;
|
||||
static struct timeval last_blink;
|
||||
static struct timeval last_refresh;
|
||||
static Pixmap buffer_pixmap = None;
|
||||
static int master_fd = -1;
|
||||
static int needs_refresh = 0;
|
||||
static XFontStruct *regular_font = NULL;
|
||||
static XFontStruct *bold_font = NULL;
|
||||
static XFontStruct *italic_font = NULL;
|
||||
static int window_focused = 0;
|
||||
|
||||
#define ATTR_BOLD 1
|
||||
#define ATTR_ITALIC 2
|
||||
@ -67,15 +69,19 @@ static void draw_cursor(Display *display, Window window) {
|
||||
// Save original color
|
||||
unsigned long original_color = color_buffer[cursor_y][cursor_x];
|
||||
|
||||
// Draw inverted cursor background
|
||||
if (!window_focused) {
|
||||
XSetForeground(display, gc, original_color);
|
||||
XDrawRectangle(display, buffer_pixmap, gc, cursor_x * CHAR_WIDTH,
|
||||
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) {
|
||||
char str[2] = {terminal_buffer[cursor_y][cursor_x], '\0'};
|
||||
XSetForeground(display, gc, XBlackPixel(display, DefaultScreen(display)));
|
||||
XSetForeground(display, gc,
|
||||
XBlackPixel(display, DefaultScreen(display)));
|
||||
|
||||
XFontStruct *font = regular_font;
|
||||
if (attr_buffer[cursor_y][cursor_x] & ATTR_BOLD) {
|
||||
@ -89,6 +95,7 @@ static void draw_cursor(Display *display, Window window) {
|
||||
(cursor_y + 1) * CHAR_HEIGHT - 2, str, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the relevant area to the window
|
||||
XCopyArea(display, buffer_pixmap, window, gc, cursor_x * CHAR_WIDTH,
|
||||
@ -96,18 +103,10 @@ static void draw_cursor(Display *display, Window window) {
|
||||
cursor_x * CHAR_WIDTH, cursor_y * CHAR_HEIGHT);
|
||||
}
|
||||
|
||||
static void update_cursor_blink(Display *display, Window window) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
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);
|
||||
static void update_cursor_state(Display *display, Window window) {
|
||||
if (window_focused) {
|
||||
cursor_visible = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,6 +216,7 @@ static void resize_buffers(int new_rows, int new_cols) {
|
||||
buffer_pixmap = XCreatePixmap(display, DefaultRootWindow(display),
|
||||
term_cols * CHAR_WIDTH, term_rows * CHAR_HEIGHT,
|
||||
DefaultDepth(display, DefaultScreen(display)));
|
||||
needs_refresh = 1;
|
||||
}
|
||||
|
||||
static void destroy_cb(Display *display, Window window) {
|
||||
@ -286,12 +286,9 @@ 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);
|
||||
regular_font = XLoadQueryFont(display, REGULAR_FONT);
|
||||
bold_font = XLoadQueryFont(display, BOLD_FONT);
|
||||
italic_font = XLoadQueryFont(display, ITALICS_FONT);
|
||||
|
||||
if (!regular_font)
|
||||
regular_font = XLoadQueryFont(display, "fixed");
|
||||
@ -325,6 +322,23 @@ static void draw_terminal(Display *display, Window window) {
|
||||
|
||||
draw_cursor(display, window);
|
||||
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) {
|
||||
@ -339,7 +353,7 @@ static void clear_terminal(Display *display, Window window) {
|
||||
}
|
||||
cursor_x = 0;
|
||||
cursor_y = 0;
|
||||
draw_terminal(display, window);
|
||||
needs_refresh = 1;
|
||||
}
|
||||
|
||||
// Scroll the terminal up one line
|
||||
@ -358,6 +372,7 @@ static void scroll_up(void) {
|
||||
color_buffer[term_rows - 1][x] = current_color;
|
||||
attr_buffer[term_rows - 1][x] = current_attr;
|
||||
}
|
||||
needs_refresh = 1;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
scroll_up();
|
||||
cursor_y = term_rows - 1;
|
||||
draw_terminal(ctx->display, ctx->window);
|
||||
needs_refresh = 1;
|
||||
}
|
||||
} else if (buf[i] == '\r') {
|
||||
cursor_x = 0;
|
||||
@ -484,20 +499,14 @@ static int master_cb(int fd, void *data) {
|
||||
if (cursor_x > 0) {
|
||||
cursor_x--;
|
||||
terminal_buffer[cursor_y][cursor_x] = ' ';
|
||||
draw_char(ctx->display, buffer_pixmap, cursor_x, cursor_y);
|
||||
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);
|
||||
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;
|
||||
draw_char(ctx->display, buffer_pixmap, cursor_x, cursor_y);
|
||||
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);
|
||||
needs_refresh = 1;
|
||||
cursor_x++;
|
||||
if (cursor_x >= term_cols) {
|
||||
cursor_x = 0;
|
||||
@ -505,16 +514,20 @@ static int master_cb(int fd, void *data) {
|
||||
if (cursor_y >= term_rows) {
|
||||
scroll_up();
|
||||
cursor_y = term_rows - 1;
|
||||
draw_terminal(ctx->display, ctx->window);
|
||||
needs_refresh = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor_visible = 1;
|
||||
if (needs_refresh) {
|
||||
check_refresh(ctx->display, ctx->window);
|
||||
} else {
|
||||
draw_cursor(ctx->display, ctx->window);
|
||||
XFlush(ctx->display);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -562,6 +575,7 @@ int main(void) {
|
||||
term_cols = 80;
|
||||
|
||||
gettimeofday(&last_blink, NULL);
|
||||
gettimeofday(&last_refresh, NULL);
|
||||
|
||||
struct winsize ws = {.ws_row = term_rows,
|
||||
.ws_col = term_cols,
|
||||
@ -626,7 +640,8 @@ int main(void) {
|
||||
XSetWMNormalHints(display, window, &hints);
|
||||
XStoreName(display, window, window_name);
|
||||
XSelectInput(display, window,
|
||||
KeyPressMask | ExposureMask | StructureNotifyMask);
|
||||
KeyPressMask | ExposureMask | StructureNotifyMask |
|
||||
FocusChangeMask);
|
||||
XMapWindow(display, window);
|
||||
|
||||
if (openpty(&master, &slave, NULL, NULL, &ws) == -1) {
|
||||
@ -700,24 +715,34 @@ int main(void) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FocusIn:
|
||||
window_focused = 1;
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case FocusOut:
|
||||
window_focused = 0;
|
||||
needs_refresh = 1;
|
||||
break;
|
||||
case KeyPress:
|
||||
key_press_cb((XKeyEvent *)&event, &master);
|
||||
break;
|
||||
case Expose:
|
||||
draw_terminal(display, window);
|
||||
needs_refresh = 1;
|
||||
check_refresh(display, window);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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_SET(master, &fds);
|
||||
if (select(master + 1, &fds, NULL, NULL, &tv) > 0) {
|
||||
master_cb(master, &ctx);
|
||||
}
|
||||
|
||||
update_cursor_blink(display, window);
|
||||
check_refresh(display, window);
|
||||
update_cursor_state(display, window);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user