term: make term switching faster
[fbpad.git] / fbpad.c
blobe5c0e47223986c74b83773b42f689d55804e0cb4
1 #include <errno.h>
2 #include <poll.h>
3 #include <pty.h>
4 #include <signal.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <linux/vt.h>
8 #include <fcntl.h>
9 #include "pad.h"
10 #include "term.h"
11 #include "util.h"
13 #define SHELL "/bin/bash"
14 #define TAGS 8
15 #define CTRLKEY(x) ((x) - 96)
17 static struct term terms[TAGS * 2];
18 static int cterm; /* current tag */
19 static int lterm; /* last tag */
20 static int exitit;
22 static int readchar(void)
24 char b;
25 if (read(STDIN_FILENO, &b, 1) > 0)
26 return (int) b;
27 return -1;
30 static void showterm(int n)
32 if (lterm % TAGS != cterm % TAGS)
33 lterm = cterm;
34 term_save(&terms[cterm]);
35 cterm = n;
36 term_load(&terms[cterm]);
39 static struct term *mainterm(void)
41 if (terms[cterm].fd)
42 return &terms[cterm];
43 return NULL;
46 static void directkey(void)
48 int c = readchar();
49 static int pending = 0;
50 if (pending) {
51 char *tags = "xnlhtrv-";
52 if (strchr(tags, c))
53 showterm(strchr(tags, c) - tags);
54 pending = 0;
55 return;
57 if (c == ESC) {
58 switch ((c = readchar())) {
59 case 'c':
60 if (!mainterm())
61 term_exec(SHELL);
62 return;
63 case 'j':
64 case 'k':
65 showterm((cterm + TAGS) % ARRAY_SIZE(terms));
66 return;
67 case 'o':
68 showterm(lterm);
69 return;
70 case ';':
71 pending = 1;
72 return;
73 case CTRLKEY('q'):
74 exitit = 1;
75 return;
76 default:
77 if (mainterm())
78 term_send(ESC);
81 if (c != -1)
82 if (mainterm())
83 term_send(c);
86 static void mainloop(void)
88 struct pollfd ufds[2];
89 int rv;
90 struct termios oldtermios, termios;
91 long badflags = POLLHUP | POLLERR | POLLNVAL;
92 tcgetattr(STDIN_FILENO, &termios);
93 oldtermios = termios;
94 cfmakeraw(&termios);
95 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
96 memset(ufds, 0, sizeof(ufds));
97 term_load(&terms[cterm]);
98 ufds[0].fd = STDIN_FILENO;
99 ufds[0].events = POLLIN;
100 ufds[1].fd = terms[cterm].fd;
101 ufds[1].events = POLLIN;
102 while (!exitit) {
103 rv = poll(ufds, mainterm() ? 2 : 1, 1000);
104 if (rv == -1 && errno != EINTR)
105 break;
106 if (ufds[0].revents & badflags)
107 break;
108 if (mainterm() && ufds[1].revents & badflags)
109 term_end();
110 if (mainterm() && ufds[1].revents & POLLIN)
111 term_read();
112 if (ufds[0].revents & POLLIN)
113 directkey();
114 ufds[1].fd = terms[cterm].fd;
116 tcsetattr(STDIN_FILENO, 0, &oldtermios);
119 static void signalreceived(int n)
121 if (exitit)
122 return;
123 switch (n) {
124 case SIGUSR1:
125 term_save(&terms[cterm]);
126 ioctl(STDIN_FILENO, VT_RELDISP, 1);
127 break;
128 case SIGUSR2:
129 pad_shown();
130 term_load(&terms[cterm]);
131 break;
135 static void setupsignals(void)
137 struct vt_mode vtm;
138 vtm.mode = VT_PROCESS;
139 vtm.waitv = 0;
140 vtm.relsig = SIGUSR1;
141 vtm.acqsig = SIGUSR2;
142 vtm.frsig = 0;
143 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
145 signal(SIGUSR1, signalreceived);
146 signal(SIGUSR2, signalreceived);
149 int main(void)
151 char *hide = "\x1b[?25l";
152 char *clear = "\x1b[2J\x1b[H";
153 char *show = "\x1b[?25h";
154 write(STDIN_FILENO, clear, strlen(clear));
155 write(STDIN_FILENO, hide, strlen(hide));
156 pad_init();
157 pad_blank(0);
158 setupsignals();
159 fcntl(STDIN_FILENO, F_SETFL,
160 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
161 mainloop();
162 pad_free();
163 write(STDIN_FILENO, show, strlen(show));
164 return 0;