moved code from header to source files
This commit is contained in:
165
src/unix.c
Executable file
165
src/unix.c
Executable file
@@ -0,0 +1,165 @@
|
||||
#include "tim.h"
|
||||
|
||||
#ifdef TIM_UNIX
|
||||
|
||||
i64 tim_time_usec(void) {
|
||||
struct timespec ts = {0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
void tim_write_str(cstr s, i32 size) {
|
||||
ssize_t _ = write(STDOUT_FILENO, s, size);
|
||||
(void)_; // remove unused-result warning
|
||||
}
|
||||
|
||||
void signal_handler(i32 signal) {
|
||||
// signals are written into a fifo pipe and read by event loop
|
||||
ssize_t _ = write(tim.signal_pipe[1], &signal, sizeof(signal));
|
||||
(void)_; // remove unused-result warning
|
||||
}
|
||||
|
||||
void tim_update_screen_size(void) {
|
||||
struct winsize ws = {0};
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != 0) {
|
||||
printf("ERROR: can't get console buffer size\n");
|
||||
exit(1);
|
||||
}
|
||||
i32 w = ws.ws_col;
|
||||
i32 h = ws.ws_row;
|
||||
tim.resized = (u32)(w * h) <= TIM_MAX_CELLS && (w != tim.w || h != tim.h);
|
||||
if (tim.resized) {
|
||||
tim.w = tim.scopes[0].w = w;
|
||||
tim.h = tim.scopes[0].h = h;
|
||||
}
|
||||
}
|
||||
|
||||
void tim_init_terminal(void) {
|
||||
tcgetattr(STDOUT_FILENO, &tim.attr); // store attributes
|
||||
struct termios attr = tim.attr; //
|
||||
cfmakeraw(&attr); // configure raw mode
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &attr); // set new attributes
|
||||
tim_write_str(S("\33[?2004l")); // reset bracketed paste mode
|
||||
tim_write_str(S("\33[?1049h")); // use alternate buffer
|
||||
tim_write_str(S("\33[?25l")); // hide cursor
|
||||
tim_write_str(S("\33[?1000h")); // enable mouse
|
||||
tim_write_str(S("\33[?1002h")); // enable button events
|
||||
tim_write_str(S("\33[?1006h")); // use mouse sgr protocol
|
||||
tim_update_screen_size(); // get terminal size
|
||||
i32 err = pipe(tim.signal_pipe); // create signal pipe
|
||||
if (!err) { //
|
||||
signal(SIGWINCH, signal_handler); // terminal size changed
|
||||
}
|
||||
}
|
||||
|
||||
void tim_reset_terminal(void) {
|
||||
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tim.attr); // restore attributes
|
||||
tim_write_str(S("\33[?1000l")); // disable mouse
|
||||
tim_write_str(S("\33[?1002l")); // disable mouse
|
||||
tim_write_str(S("\33[m")); // reset colors
|
||||
tim_write_str(S("\33[?25h")); // show cursor
|
||||
tim_write_str(S("\33[?1049l")); // exit alternate buffer
|
||||
}
|
||||
|
||||
// parse input stored in e->s
|
||||
bool parse_input(event* restrict e, i32 n) {
|
||||
char* s = e->s;
|
||||
|
||||
if (n == 1 || s[0] != 27) {
|
||||
// regular key press
|
||||
e->type = TimEvent_Key;
|
||||
e->key = s[0] == 127 ? TimKey_Backspace : tim_utf8_to_i32(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (n >= 9 && !memcmp(s, S("\33[<"))) {
|
||||
// sgr mouse sequence
|
||||
e->type = TimEvent_Mouse;
|
||||
i32 btn = strtol(s + 3, &s, 10);
|
||||
e->x = strtol(s + 1, &s, 10) - 1;
|
||||
e->y = strtol(s + 1, &s, 10) - 1;
|
||||
if (btn == 0 && s[0] == 'M') {
|
||||
// left button pressed
|
||||
e->key = TimKey_MouseButtonLeft;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct {char s[4]; i32 k;} key_table[] = {
|
||||
{"[A" , TimKey_Up}, //
|
||||
{"[B" , TimKey_Down}, //
|
||||
{"[C" , TimKey_Right}, //
|
||||
{"[D" , TimKey_Left}, //
|
||||
{"[2~", TimKey_Insert}, //
|
||||
{"[4h", TimKey_Insert}, // st
|
||||
{"[3~", TimKey_Delete}, //
|
||||
{"[P" , TimKey_Delete}, // st
|
||||
{"[H" , TimKey_Home}, //
|
||||
{"[1~", TimKey_Home}, // rxvt, lxterm, putty, tmux, screen
|
||||
{"[7~", TimKey_Home}, // rxvt
|
||||
{"[F" , TimKey_End}, //
|
||||
{"[4~", TimKey_End}, // rxvt, lxterm, putty, tmux, screen, st
|
||||
{"[8~", TimKey_End}, // rxvt
|
||||
{"[5~", TimKey_PageUp}, //
|
||||
{"[6~", TimKey_PageDown}, //
|
||||
};
|
||||
|
||||
if ((n == 3 || n == 4) && s[0] == 27) {
|
||||
// key sequence
|
||||
for (i32 i = 0; i < (i32)ARRAY_SIZE(key_table); i++) {
|
||||
if (!memcmp(s + 1, key_table[i].s, n - 1)) {
|
||||
e->type = TimEvent_Key;
|
||||
e->key = key_table[i].k;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void tim_read_event(i32 timeout_ms) {
|
||||
event* e = &tim.event;
|
||||
|
||||
struct pollfd pfd[2] = {
|
||||
{.fd = tim.signal_pipe[0], .events = POLLIN},
|
||||
{.fd = STDIN_FILENO, .events = POLLIN},
|
||||
};
|
||||
|
||||
while (true) {
|
||||
memset(e, 0, sizeof(*e));
|
||||
|
||||
i32 r = poll(pfd, 2, timeout_ms > 0 ? timeout_ms : -1);
|
||||
if (r < 0) {
|
||||
// poll error, EINTR or EAGAIN
|
||||
continue;
|
||||
} else if (r == 0) {
|
||||
// poll timeout
|
||||
e->type = TimEvent_Draw;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
// received signal
|
||||
i32 sig = 0;
|
||||
i32 n = read(tim.signal_pipe[0], &sig, sizeof(sig));
|
||||
if (n > 0 && sig == SIGWINCH) {
|
||||
// screen size changed
|
||||
e->type = TimEvent_Draw;
|
||||
tim_update_screen_size();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pfd[1].revents & POLLIN) {
|
||||
// received input
|
||||
i32 n = read(STDIN_FILENO, e->s, sizeof(e->s) - 1);
|
||||
if (parse_input(e, n)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
#endif // TIM_UNIX
|
||||
Reference in New Issue
Block a user