Ali Gholami Rudi <aliqr...@gmail.com> wrote: > Ammar James <lone.no...@gmail.com> wrote: > >> Fbpad is a small framebuffer virtual terminal that uses libfreetype to > >> render truetype fonts. It manages many terminals through tags. The tag > >> management is intentionally minimal and simple. A tag is represented > >> with a single letter (or digit if you prefer) and each tag has a main > >> and an alt terminal. Something like dwm monocle layout where each tag > >> can hold at most two windows (that was how I used dwm on a laptop > >> screen). If someone prefers tiled windows, he can run dvtm inside > > > > You might be interested in dvtm. > > Why? What I needed was a terminal with truetype fonts on linux > framebuffer, I'm not sure how dvtm can help. The tag management of > fbpad is very minimal and was an afterthought; "fbpad is a framebuffer
If someone prefers separating terminal management, from terminal emulation, this patch changes fbpad to handle only one terminal; it executes the given command and exits as soon as the command exits. Ali config.h | 5 -- fbpad.c | 200 ++++++++------------------------------------------------------ term.c | 103 +++++++++++++++----------------- term.h | 28 +-------- vt102.c | 4 +- 5 files changed, 76 insertions(+), 264 deletions(-) diff --git a/config.h b/config.h index 62545c2..c48422d 100644 --- a/config.h +++ b/config.h @@ -1,8 +1,3 @@ -#define TAGS "xnlhtrv-" -#define SHELL "/bin/bash" -#define MAIL "mutt" -#define EDITOR "vim" - #define FONTFACE "/usr/lib/X11/fonts/TTF/DejaVuSansMono.ttf" #define FONTSIZE 10 #define DPI 196 diff --git a/fbpad.c b/fbpad.c index 3c2bd77..6e8caa8 100644 --- a/fbpad.c +++ b/fbpad.c @@ -13,6 +13,7 @@ #include <poll.h> #include <pty.h> #include <signal.h> +#include <stdio.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> @@ -27,12 +28,7 @@ #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL) #define NTAGS sizeof(tags) -static char tags[] = TAGS; -static struct term terms[NTAGS * 2]; -static int cterm; /* current tag */ -static int lterm; /* last tag */ static int exitit; -static int hidden; static int readchar(void) { @@ -42,194 +38,45 @@ static int readchar(void) return -1; } -static void showterm(int n) -{ - if (cterm % NTAGS != n % NTAGS) - lterm = cterm; - term_save(&terms[cterm]); - cterm = n; - term_load(&terms[cterm], hidden ? TERM_HIDDEN : TERM_REDRAW); -} - -static struct term *mainterm(void) -{ - if (terms[cterm].fd) - return &terms[cterm]; - return NULL; -} - -static void exec_cmd(char *file) -{ - if (!mainterm()) - term_exec(file); -} - -static int altterm(int n) -{ - return n < NTAGS ? n + NTAGS : n - NTAGS; -} - -static void nextterm(void) -{ - int n = (cterm + 1) % ARRAY_SIZE(terms); - while (n != cterm) { - if (terms[n].fd) { - showterm(n); - break; - } - n = (n + 1) % ARRAY_SIZE(terms); - } -} - -static void showterms(void) -{ - int colors[] = {FGCOLOR, 4, 2, 5}; - int c = 0; - int r = pad_rows() - 1; - int i; - pad_put('T', r, c++, FGCOLOR, BGCOLOR); - pad_put('A', r, c++, FGCOLOR, BGCOLOR); - pad_put('G', r, c++, FGCOLOR, BGCOLOR); - pad_put('S', r, c++, FGCOLOR, BGCOLOR); - pad_put(':', r, c++, FGCOLOR, BGCOLOR); - pad_put(' ', r, c++, FGCOLOR, BGCOLOR); - for (i = 0; i < NTAGS; i++) { - int nt = 0; - int shown = i == cterm || altterm(i) == cterm; - if (terms[i].fd) - nt = 1; - if (terms[altterm(i)].fd) - nt = nt ? 2 : 3; - pad_put(shown ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR); - pad_put(tags[i], r, c++, colors[nt], 7); - pad_put(shown ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR); - } -} - static void directkey(void) { - int c = readchar(); - if (c == ESC) { - switch ((c = readchar())) { - case 'c': - exec_cmd(SHELL); - return; - case 'm': - exec_cmd(MAIL); - return; - case 'e': - exec_cmd(EDITOR); - return; - case 'j': - case 'k': - showterm(altterm(cterm)); - return; - case 'o': - showterm(lterm); - return; - case 'p': - showterms(); - return; - case '\t': - nextterm(); - return; - case CTRLKEY('q'): - exitit = 1; - return; - default: - if (strchr(tags, c)) { - showterm(strchr(tags, c) - tags); - return; - } - if (mainterm()) - term_send(ESC); - } - } - if (c != -1 && mainterm()) - term_send(c); -} - -static int find_by_fd(int fd) -{ - int i; - for (i = 0; i < ARRAY_SIZE(terms); i++) - if (terms[i].fd == fd) - return i; - return -1; + term_send(readchar()); } -static int fill_ufds(struct pollfd *ufds) +static void fill_ufds(struct pollfd *ufds) { - int n = 1; - int i; ufds[0].fd = STDIN_FILENO; ufds[0].events = POLLIN; - for (i = 0; i < ARRAY_SIZE(terms); i++) { - if (terms[i].fd) { - ufds[n].fd = terms[i].fd; - ufds[n].events = POLLIN; - n++; - } - } - return n; + ufds[1].fd = term_fd(); + ufds[1].events = POLLIN; } -static void temp_switch(int termid) +static void check_ufds(struct pollfd *ufds) { - if (termid != cterm) { - term_save(&terms[cterm]); - term_load(&terms[termid], TERM_HIDDEN); - } -} - -static void switch_back(int termid) -{ - if (termid != cterm) { - term_save(&terms[termid]); - term_load(&terms[cterm], hidden ? TERM_HIDDEN : TERM_VISIBLE); - } -} - -static void check_ufds(struct pollfd *ufds, int n) -{ - int i; - for (i = 1; i < n; i++) { - int idx = find_by_fd(ufds[i].fd); - if (ufds[i].revents & BADPOLLFLAGS) { - temp_switch(idx); - term_end(); - switch_back(idx); - } else if (ufds[i].revents & POLLIN) { - temp_switch(idx); - term_read(); - switch_back(idx); - } - } + if (ufds[0].revents & BADPOLLFLAGS || ufds[1].revents & BADPOLLFLAGS) + exitit = 1; + if (ufds[0].revents & POLLIN) + directkey(); + if (ufds[1].revents & POLLIN) + term_read(); } static void mainloop(void) { - struct pollfd ufds[ARRAY_SIZE(terms) + 1]; + struct pollfd ufds[2]; struct termios oldtermios, termios; int rv; - int n; tcgetattr(STDIN_FILENO, &termios); oldtermios = termios; cfmakeraw(&termios); tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios); memset(ufds, 0, sizeof(ufds)); - term_load(&terms[cterm], TERM_REDRAW); - n = fill_ufds(ufds); + fill_ufds(ufds); while (!exitit) { - rv = poll(ufds, n, 1000); + rv = poll(ufds, 2, 1000); if (rv == -1 && errno != EINTR) break; - if (ufds[0].revents & BADPOLLFLAGS) - break; - if (ufds[0].revents & POLLIN) - directkey(); - check_ufds(ufds, n); - n = fill_ufds(ufds); + check_ufds(ufds); } tcsetattr(STDIN_FILENO, 0, &oldtermios); } @@ -240,16 +87,12 @@ static void signalreceived(int n) return; switch (n) { case SIGUSR1: - hidden = 1; - term_save(&terms[cterm]); - term_load(&terms[cterm], TERM_HIDDEN); + term_hide(); ioctl(STDIN_FILENO, VT_RELDISP, 1); break; case SIGUSR2: - hidden = 0; pad_shown(); - term_save(&terms[cterm]); - term_load(&terms[cterm], TERM_REDRAW); + term_show(); break; case SIGCHLD: waitpid(-1, 0, WNOHANG); @@ -272,11 +115,15 @@ static void setupsignals(void) signal(SIGCHLD, signalreceived); } -int main(void) +int main(int argc, char *argv[]) { char *hide = "\x1b[?25l"; char *clear = "\x1b[2J\x1b[H"; char *show = "\x1b[?25h"; + if (argc < 2) { + printf("Usage: %s program\n", argv[0]); + return 0; + } setlocale(LC_ALL, ""); write(STDIN_FILENO, clear, strlen(clear)); write(STDIN_FILENO, hide, strlen(hide)); @@ -284,6 +131,7 @@ int main(void) setupsignals(); fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); + term_exec(argv[1]); mainloop(); pad_free(); write(STDIN_FILENO, show, strlen(show)); diff --git a/term.c b/term.c index f7bfe06..11b7385 100644 --- a/term.c +++ b/term.c @@ -25,12 +25,22 @@ #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b))) #define SQRADDR(r, c) (screen + (r) * pad_cols() + (c)) -static struct term *term; -static struct square *screen; static int row, col; static int fg, bg; static int top, bot; static unsigned int mode; +static pid_t pid; +static struct term_state { + int row, col; + int fg, bg; + unsigned int mode; +} sav; +static int fd; +static struct square { + int c; + short fg; + short bg; +} screen[MAXCHARS]; static int visible; #define MAXLINES (1 << 13) @@ -142,14 +152,6 @@ static void lazy_flush() _term_show(row, col, 1); } -static void term_redraw(void) -{ - int i; - for (i = 0; i < pad_rows(); i++) - _draw_row(i); - _term_show(row, col, 1); -} - static int origin(void) { return mode & MODE_ORIGIN; @@ -162,7 +164,7 @@ static void setsize(void) size.ws_row = pad_rows(); size.ws_xpixel = 0; size.ws_ypixel = 0; - ioctl(term->fd, TIOCSWINSZ, &size); + ioctl(fd, TIOCSWINSZ, &size); } #define PTYBUFSIZE (1 << 13) @@ -172,7 +174,7 @@ static int ptycur; static void waitpty(void) { struct pollfd ufds[1]; - ufds[0].fd = term->fd; + ufds[0].fd = fd; ufds[0].events = POLLIN; poll(ufds, 1, -1); } @@ -181,12 +183,12 @@ static int readpty(void) { if (ptycur < ptylen) return ptybuf[ptycur++]; - if (!term->fd) + if (!fd) return -1; - ptylen = read(term->fd, ptybuf, PTYBUFSIZE); + ptylen = read(fd, ptybuf, PTYBUFSIZE); if (ptylen == -1 && errno == EAGAIN) { waitpty(); - ptylen = read(term->fd, ptybuf, PTYBUFSIZE); + ptylen = read(fd, ptybuf, PTYBUFSIZE); } if (ptylen > 0) { ptycur = 1; @@ -277,14 +279,14 @@ static void advance(int dr, int dc, int scrl) void term_send(int c) { unsigned char b = (unsigned char) c; - if (term->fd) - write(term->fd, &b, 1); + if (fd) + write(fd, &b, 1); } static void term_sendstr(char *s) { - if (term->fd) - write(term->fd, s, strlen(s)); + if (fd) + write(fd, s, strlen(s)); } static void setattr(int m) @@ -370,22 +372,22 @@ void term_read(void) void term_exec(char *cmd) { - memset(term, 0, sizeof(*term)); - term->bot = pad_rows(); - term->cur.mode = term->sav.mode = MODE_DEFAULT; - term_load(term, visible); - if ((term->pid = forkpty(&term->fd, NULL, NULL, NULL)) == -1) { + bot = pad_rows(); + visible = 1; + mode = MODE_DEFAULT; + sav.mode = MODE_DEFAULT; + if ((pid = forkpty(&fd, NULL, NULL, NULL)) == -1) { perror("failed to fork"); - term->fd = 0; + fd = 0; return; } - if (!term->pid) { + if (!pid) { setenv("TERM", "linux", 1); execlp(cmd, cmd, NULL); exit(1); } - fcntl(term->fd, F_SETFD, fcntl(term->fd, F_GETFD) | FD_CLOEXEC); - fcntl(term->fd, F_SETFL, fcntl(term->fd, F_GETFL) | O_NONBLOCK); + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); setsize(); setattr(0); term_blank(); @@ -409,36 +411,10 @@ static void misc_load(struct term_state *state) mode = state->mode; } -void term_save(struct term *term) -{ - visible = 0; - misc_save(&term->cur); - term->top = top; - term->bot = bot; -} - -void term_load(struct term *t, int flags) -{ - term = t; - misc_load(&term->cur); - screen = term->screen; - visible = flags; - top = term->top; - bot = term->bot; - if (flags == TERM_REDRAW) { - if (term->fd) - term_redraw(); - else - pad_blank(0); - } -} - void term_end(void) { - if (term->fd) - close(term->fd); - memset(term, 0, sizeof(*term)); - term_load(term, visible ? TERM_REDRAW : TERM_HIDDEN); + if (fd) + close(fd); } static void set_region(int t, int b) @@ -449,4 +425,19 @@ static void set_region(int t, int b) move_cursor(top, 0); } +int term_fd(void) +{ + return fd; +} + +void term_hide(void) +{ + visible = 0; +} + +void term_show(void) +{ + visible = 1; +} + #include "vt102.c" diff --git a/term.h b/term.h index 4b73c68..7e23e24 100644 --- a/term.h +++ b/term.h @@ -1,31 +1,9 @@ #define ESC 27 -struct term_state { - int row, col; - int fg, bg; - unsigned int mode; -}; - -struct term { - int fd; - int pid; - int top, bot; - struct term_state cur, sav; - struct square { - int c; - short fg; - short bg; - } screen[MAXCHARS]; -}; - -#define TERM_HIDDEN 0 -#define TERM_VISIBLE 1 -#define TERM_REDRAW 2 - -void term_load(struct term *term, int visible); -void term_save(struct term *term); - void term_read(void); void term_send(int c); void term_exec(char *cmd); void term_end(void); +int term_fd(void); +void term_hide(void); +void term_show(void); diff --git a/vt102.c b/vt102.c index c505c65..fcee560 100644 --- a/vt102.c +++ b/vt102.c @@ -97,10 +97,10 @@ static void escseq(void) escseq_g3(); break; case '7': /* DECSC save state (position, charset, attributes) */ - misc_save(&term->sav); + misc_save(&sav); break; case '8': /* DECRC restore most recently saved state */ - misc_load(&term->sav); + misc_load(&sav); break; case 'M': /* RI reverse line feed */ advance(-1, 0, 1);