add tmessage application
This commit is contained in:
parent
b3d186ee92
commit
bf5bfc71da
4
Makefile
4
Makefile
|
@ -44,7 +44,7 @@ sh:
|
|||
check:
|
||||
shellcheck sh/*
|
||||
|
||||
mkc: c/scream c/timer c/boid c/anaconda c/colors c/xgetnewwindow
|
||||
mkc: c/scream c/timer c/boid c/anaconda c/colors c/xgetnewwindow c/tmessage
|
||||
|
||||
c/boid:
|
||||
cc c/boid.c -o c/boid -lm -lX11
|
||||
|
@ -62,6 +62,7 @@ c:
|
|||
cp -f c/anaconda $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f c/colors $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f c/xgetnewwindow $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f c/tmessage $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
clean:
|
||||
rm -f c/scream
|
||||
|
@ -70,3 +71,4 @@ clean:
|
|||
rm -f c/anaconda
|
||||
rm -f c/simplestatus
|
||||
rm -f c/xgetnewwindow
|
||||
rm -f c/tmessage
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <ctype.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ESC_CLEAR "\033[2J"
|
||||
#define ESC_CUSHOME "\033[H"
|
||||
#define ESC_NEWLINE "\033[E\033[1C"
|
||||
|
||||
const char MSG_OK[] = "(O)k";
|
||||
const char MSG_CANCEL[] = "(C)ancel";
|
||||
|
||||
typedef struct winsize ws;
|
||||
|
||||
int lines, cols;
|
||||
char *message;
|
||||
size_t message_len;
|
||||
|
||||
struct termios original_termios;
|
||||
|
||||
void render(char *message, int message_len, int lines, int cols);
|
||||
|
||||
void rawmode_start() {
|
||||
tcgetattr(STDIN_FILENO, &original_termios);
|
||||
struct termios raw = original_termios;
|
||||
raw.c_lflag &= ~(ECHO | ICANON);
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
|
||||
}
|
||||
|
||||
void rawmode_stop() {
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original_termios);
|
||||
printf("\n\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
ws *getWinSize(void) {
|
||||
/* we're only going to use these values once per invocation,
|
||||
* so it's fine that it's static. */
|
||||
static ws w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
return &w;
|
||||
}
|
||||
|
||||
void handler(int signal, siginfo_t *info, void *context) {
|
||||
ws *w = getWinSize();
|
||||
lines = w->ws_row;
|
||||
cols = w->ws_col;
|
||||
|
||||
render(message, message_len, lines, cols);
|
||||
return;
|
||||
}
|
||||
|
||||
void termhandler(int signal, siginfo_t *info, void *context) {
|
||||
rawmode_stop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int calculate_number_of_lines(int length, int cols) {
|
||||
/* cols - 1 accounts for right padding */
|
||||
return length / (cols - 1) + 1;
|
||||
}
|
||||
|
||||
void go_to_initial_message_printing_pos(void) {
|
||||
printf(ESC_CUSHOME "\033[1B\033[1C");
|
||||
}
|
||||
|
||||
void print_message(char *message, int messagelen, int cols) {
|
||||
int linecount = calculate_number_of_lines(messagelen, cols);
|
||||
int adjcols = cols - 2;
|
||||
int offset = 1;
|
||||
for(int character = 0; character < messagelen; character++) {
|
||||
if(character == adjcols * offset) {
|
||||
printf(ESC_NEWLINE);
|
||||
offset++;
|
||||
}
|
||||
putchar(message[character]);
|
||||
}
|
||||
}
|
||||
|
||||
void render(char *message, int messagelen, int lines, int cols) {
|
||||
int cancel_length = sizeof(MSG_CANCEL) / sizeof(MSG_CANCEL[0]);
|
||||
|
||||
/* print the stuff */
|
||||
printf(ESC_CLEAR "" ESC_CUSHOME);
|
||||
go_to_initial_message_printing_pos();
|
||||
print_message(message, message_len, cols);
|
||||
|
||||
printf(ESC_NEWLINE);
|
||||
printf(ESC_NEWLINE);
|
||||
printf("%s", MSG_OK);
|
||||
printf("\033[1D\033[%iC\033[%iD%s", cols, cancel_length, MSG_CANCEL);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int cancel_length = strlen(MSG_CANCEL);
|
||||
char c;
|
||||
struct sigaction resizeaction = {};
|
||||
struct sigaction termaction = {};
|
||||
ws *w;
|
||||
|
||||
/* check if we have a message */
|
||||
if(argc > 1) {
|
||||
message = argv[1]; /* second argument's a message */
|
||||
message_len = strlen(message);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* setup sigaction handlers */
|
||||
resizeaction.sa_sigaction = &handler;
|
||||
if(sigaction(SIGWINCH, &resizeaction, NULL) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
termaction.sa_sigaction = &termhandler;
|
||||
if(sigaction(SIGTERM, &termaction, NULL) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
rawmode_start();
|
||||
|
||||
/* get window properties */
|
||||
w = getWinSize();
|
||||
lines = w->ws_row;
|
||||
cols = w->ws_col;
|
||||
|
||||
render(message, message_len, lines, cols);
|
||||
|
||||
for(;;) {
|
||||
read(STDIN_FILENO, &c, 1);
|
||||
if(c == 'o') {
|
||||
return 2;
|
||||
rawmode_stop();
|
||||
} else if(c == 'c') {
|
||||
return 3;
|
||||
rawmode_stop();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue