diff --git a/src/gui/widget/yaft/.gitignore b/src/gui/widget/yaft/.gitignore deleted file mode 100644 index 7f0f0146e..000000000 --- a/src/gui/widget/yaft/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.bk -yaft -yaftx -glyph.h -mkfont -mkfont_bdf diff --git a/src/gui/widget/yaft/Makefile.am b/src/gui/widget/yaft/Makefile.am new file mode 100644 index 000000000..9cee5d14b --- /dev/null +++ b/src/gui/widget/yaft/Makefile.am @@ -0,0 +1,42 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions -D__STDC_FORMAT_MACROS + +AM_CPPFLAGS += \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/libconfigfile \ + @SIGC_CFLAGS@ \ + @FREETYPE_CFLAGS@ \ + @LUA_CFLAGS@ \ + @HWLIB_CFLAGS@ + +noinst_LIBRARIES = libneutrino_gui_terminal.a + +HDR = glyph.h yaft.h conf.h color.h parse.h terminal.h util.h \ + ctrlseq/esc.h ctrlseq/csi.h ctrlseq/osc.h ctrlseq/dcs.h \ + fb/common.h fb/linux.h fb/freebsd.h fb/netbsd.h fb/openbsd.h \ + x/x.h + +libneutrino_gui_terminal_a_SOURCES = \ + yaft_class.cpp + +# glyph.h \ +# yaft.h \ +# conf.h \ +# color.h \ +# parse.h \ +# terminal.h \ +# util.h \ +# ctrlseq/esc.h \ +# ctrlseq/csi.h \ +# ctrlseq/osc.h \ +# ctrlseq/dcs.h \ +# fb/common.h \ +# fb/linux.h \ +# fb/freebsd.h \ +# fb/netbsd.h \ +# fb/openbsd.h \ +# x/x.h diff --git a/src/gui/widget/yaft/makefile b/src/gui/widget/yaft/makefile.off similarity index 100% rename from src/gui/widget/yaft/makefile rename to src/gui/widget/yaft/makefile.off diff --git a/src/gui/widget/yaft/yaft_class.cpp b/src/gui/widget/yaft/yaft_class.cpp new file mode 100644 index 000000000..4ece9209f --- /dev/null +++ b/src/gui/widget/yaft/yaft_class.cpp @@ -0,0 +1,239 @@ +/* See LICENSE for licence details. */ +/* yaft.c: include main function */ +#include "yaft.h" +#include "conf.h" +#include "util.h" +#include "fb/common.h" +#include "terminal.h" +#include "ctrlseq/esc.h" +#include "ctrlseq/csi.h" +#include "ctrlseq/osc.h" +#include "ctrlseq/dcs.h" +#include "parse.h" + +void sig_handler(int signo) +{ + sigset_t sigset; + /* global */ + extern volatile sig_atomic_t vt_active; + extern volatile sig_atomic_t child_alive; + extern volatile sig_atomic_t need_redraw; + + logging(DEBUG, "caught signal! no:%d\n", signo); + + if (signo == SIGCHLD) { + child_alive = false; + wait(NULL); + } else if (signo == SIGUSR1) { /* vt activate */ + vt_active = true; + need_redraw = true; + ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); + } else if (signo == SIGUSR2) { /* vt deactivate */ + vt_active = false; + ioctl(STDIN_FILENO, VT_RELDISP, 1); + + if (BACKGROUND_DRAW) { /* update passive cursor */ + need_redraw = true; + } else { /* sleep until next vt switching */ + sigfillset(&sigset); + sigdelset(&sigset, SIGUSR1); + sigsuspend(&sigset); + } + } +} + +void set_rawmode(int fd, struct termios *save_tm) +{ + struct termios tm; + + tm = *save_tm; + tm.c_iflag = tm.c_oflag = 0; + tm.c_cflag &= ~CSIZE; + tm.c_cflag |= CS8; + tm.c_lflag &= ~(ECHO | ISIG | ICANON); + tm.c_cc[VMIN] = 1; /* min data size (byte) */ + tm.c_cc[VTIME] = 0; /* time out */ + etcsetattr(fd, TCSAFLUSH, &tm); +} + +bool tty_init(struct termios *termios_orig) +{ + struct sigaction sigact; + + memset(&sigact, 0, sizeof(struct sigaction)); + sigact.sa_handler = sig_handler; + sigact.sa_flags = SA_RESTART; + esigaction(SIGCHLD, &sigact, NULL); + + if (VT_CONTROL) { + esigaction(SIGUSR1, &sigact, NULL); + esigaction(SIGUSR2, &sigact, NULL); + + struct vt_mode vtm; + vtm.mode = VT_PROCESS; + vtm.waitv = 0; + vtm.acqsig = SIGUSR1; + vtm.relsig = SIGUSR2; + vtm.frsig = 0; + + if (ioctl(STDIN_FILENO, VT_SETMODE, &vtm)) + logging(WARN, "ioctl: VT_SETMODE failed (maybe here is not console)\n"); + + if (FORCE_TEXT_MODE == false) { + if (ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS)) + logging(WARN, "ioctl: KDSETMODE failed (maybe here is not console)\n"); + } + } + + etcgetattr(STDIN_FILENO, termios_orig); + set_rawmode(STDIN_FILENO, termios_orig); + ewrite(STDIN_FILENO, "\033[?25l", 6); /* make cusor invisible */ + + return true; +} + +void tty_die(struct termios *termios_orig) +{ + /* no error handling */ + struct sigaction sigact; + struct vt_mode vtm; + + memset(&sigact, 0, sizeof(struct sigaction)); + sigact.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sigact, NULL); + + if (VT_CONTROL) { + sigaction(SIGUSR1, &sigact, NULL); + sigaction(SIGUSR2, &sigact, NULL); + + vtm.mode = VT_AUTO; + vtm.waitv = 0; + vtm.relsig = vtm.acqsig = vtm.frsig = 0; + + ioctl(STDIN_FILENO, VT_SETMODE, &vtm); + + if (FORCE_TEXT_MODE == false) + ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT); + } + + tcsetattr(STDIN_FILENO, TCSAFLUSH, termios_orig); + fflush(stdout); + ewrite(STDIN_FILENO, "\033[?25h", 6); /* make cursor visible */ +} + +bool fork_and_exec(int *master, int lines, int cols) +{ + extern const char *shell_cmd; /* defined in conf.h */ + char *shell_env; + pid_t pid; + struct winsize ws = {.ws_row = lines, .ws_col = cols, + /* XXX: this variables are UNUSED (man tty_ioctl), + but useful for calculating terminal cell size */ + .ws_ypixel = CELL_HEIGHT * lines, .ws_xpixel = CELL_WIDTH * cols}; + + pid = eforkpty(master, NULL, NULL, &ws); + if (pid < 0) + return false; + else if (pid == 0) { /* child */ + esetenv("TERM", term_name, 1); + if ((shell_env = getenv("SHELL")) != NULL) + eexecl(shell_env); + else + eexecl(shell_cmd); + /* never reach here */ + exit(EXIT_FAILURE); + } + return true; +} + +int check_fds(fd_set *fds, struct timeval *tv, int input, int master) +{ + FD_ZERO(fds); + FD_SET(input, fds); + FD_SET(master, fds); + tv->tv_sec = 0; + tv->tv_usec = SELECT_TIMEOUT; + return eselect(master + 1, fds, NULL, NULL, tv); +} + +int main() +{ + uint8_t buf[BUFSIZE]; + ssize_t size; + fd_set fds; + struct timeval tv; + struct framebuffer_t fb; + struct terminal_t term; + /* global */ + extern volatile sig_atomic_t need_redraw; + extern volatile sig_atomic_t child_alive; + extern struct termios termios_orig; + + /* init */ + if (setlocale(LC_ALL, "") == NULL) /* for wcwidth() */ + logging(WARN, "setlocale falied\n"); + + if (!fb_init(&fb)) { + logging(FATAL, "framebuffer initialize failed\n"); + goto fb_init_failed; + } + + if (!term_init(&term, fb.info.width, fb.info.height)) { + logging(FATAL, "terminal initialize failed\n"); + goto term_init_failed; + } + + if (!tty_init(&termios_orig)) { + logging(FATAL, "tty initialize failed\n"); + goto tty_init_failed; + } + + /* fork and exec shell */ + if (!fork_and_exec(&term.fd, term.lines, term.cols)) { + logging(FATAL, "forkpty failed\n"); + goto tty_init_failed; + } + child_alive = true; + + /* main loop */ + while (child_alive) { + if (need_redraw) { + need_redraw = false; + cmap_update(fb.fd, fb.cmap); /* after VT switching, need to restore cmap (in 8bpp mode) */ + redraw(&term); + refresh(&fb, &term); + } + + if (check_fds(&fds, &tv, STDIN_FILENO, term.fd) == -1) + continue; + + if (FD_ISSET(STDIN_FILENO, &fds)) { + if ((size = read(STDIN_FILENO, buf, BUFSIZE)) > 0) + ewrite(term.fd, buf, size); + } + if (FD_ISSET(term.fd, &fds)) { + if ((size = read(term.fd, buf, BUFSIZE)) > 0) { + if (VERBOSE) + ewrite(STDOUT_FILENO, buf, size); + parse(&term, buf, size); + if (LAZY_DRAW && size == BUFSIZE) + continue; /* maybe more data arrives soon */ + refresh(&fb, &term); + } + } + } + + /* normal exit */ + tty_die(&termios_orig); + term_die(&term); + fb_die(&fb); + return EXIT_SUCCESS; + + /* error exit */ +tty_init_failed: + term_die(&term); +term_init_failed: + fb_die(&fb); +fb_init_failed: + return EXIT_FAILURE; +}