term: clear the screen when nothing to show
[fbpad.git] / fbpad.c
blob9e111018a396e7decc8bac5a2e29861a63a4f971
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)
16 #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL)
19 static struct term terms[TAGS * 2];
20 static int cterm; /* current tag */
21 static int lterm; /* last tag */
22 static int exitit;
24 static int readchar(void)
26 char b;
27 if (read(STDIN_FILENO, &b, 1) > 0)
28 return (int) b;
29 return -1;
32 static void showterm(int n)
34 if (lterm % TAGS != cterm % TAGS)
35 lterm = cterm;
36 term_save(&terms[cterm]);
37 cterm = n;
38 term_load(&terms[cterm], TERM_REDRAW);
41 static struct term *mainterm(void)
43 if (terms[cterm].fd)
44 return &terms[cterm];
45 return NULL;
48 static void directkey(void)
50 int c = readchar();
51 static int pending = 0;
52 if (pending) {
53 char *tags = "xnlhtrv-";
54 if (strchr(tags, c))
55 showterm(strchr(tags, c) - tags);
56 pending = 0;
57 return;
59 if (c == ESC) {
60 switch ((c = readchar())) {
61 case 'c':
62 if (!mainterm())
63 term_exec(SHELL);
64 return;
65 case 'j':
66 case 'k':
67 showterm((cterm + TAGS) % ARRAY_SIZE(terms));
68 return;
69 case 'o':
70 showterm(lterm);
71 return;
72 case ';':
73 pending = 1;
74 return;
75 case CTRLKEY('q'):
76 exitit = 1;
77 return;
78 default:
79 if (mainterm())
80 term_send(ESC);
83 if (c != -1)
84 if (mainterm())
85 term_send(c);
88 static int find_by_fd(int fd)
90 int i;
91 for (i = 0; i < ARRAY_SIZE(terms); i++)
92 if (terms[i].fd == fd)
93 return i;
94 return -1;
97 static int fill_ufds(struct pollfd *ufds)
99 int n = 1;
100 int i;
101 ufds[0].fd = STDIN_FILENO;
102 ufds[0].events = POLLIN;
103 for (i = 0; i < ARRAY_SIZE(terms); i++) {
104 if (terms[i].fd) {
105 ufds[n].fd = terms[i].fd;
106 ufds[n].events = POLLIN;
107 n++;
110 return n;
113 static void temp_switch(int termid)
115 if (termid != cterm) {
116 term_save(&terms[cterm]);
117 term_load(&terms[termid], TERM_HIDDEN);
121 static void switch_back(int termid)
123 if (termid != cterm) {
124 term_save(&terms[termid]);
125 term_load(&terms[cterm], TERM_VISIBLE);
129 static void check_ufds(struct pollfd *ufds, int n)
131 int i;
132 for (i = 1; i < n; i++) {
133 int idx = find_by_fd(ufds[i].fd);
134 if (ufds[i].revents & BADPOLLFLAGS) {
135 temp_switch(idx);
136 term_end();
137 switch_back(idx);
139 if (ufds[i].revents & POLLIN) {
140 temp_switch(idx);
141 term_read();
142 switch_back(idx);
147 static void mainloop(void)
149 struct pollfd ufds[ARRAY_SIZE(terms) + 1];
150 struct termios oldtermios, termios;
151 int rv;
152 int n;
153 tcgetattr(STDIN_FILENO, &termios);
154 oldtermios = termios;
155 cfmakeraw(&termios);
156 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
157 memset(ufds, 0, sizeof(ufds));
158 term_load(&terms[cterm], TERM_REDRAW);
159 n = fill_ufds(ufds);
160 while (!exitit) {
161 rv = poll(ufds, n, 1000);
162 if (rv == -1 && errno != EINTR)
163 break;
164 if (ufds[0].revents & BADPOLLFLAGS)
165 break;
166 if (ufds[0].revents & POLLIN)
167 directkey();
168 check_ufds(ufds, n);
169 n = fill_ufds(ufds);
171 tcsetattr(STDIN_FILENO, 0, &oldtermios);
174 static void signalreceived(int n)
176 if (exitit)
177 return;
178 switch (n) {
179 case SIGUSR1:
180 term_save(&terms[cterm]);
181 ioctl(STDIN_FILENO, VT_RELDISP, 1);
182 break;
183 case SIGUSR2:
184 pad_shown();
185 term_load(&terms[cterm], TERM_REDRAW);
186 break;
190 static void setupsignals(void)
192 struct vt_mode vtm;
193 vtm.mode = VT_PROCESS;
194 vtm.waitv = 0;
195 vtm.relsig = SIGUSR1;
196 vtm.acqsig = SIGUSR2;
197 vtm.frsig = 0;
198 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
200 signal(SIGUSR1, signalreceived);
201 signal(SIGUSR2, signalreceived);
204 int main(void)
206 char *hide = "\x1b[?25l";
207 char *clear = "\x1b[2J\x1b[H";
208 char *show = "\x1b[?25h";
209 write(STDIN_FILENO, clear, strlen(clear));
210 write(STDIN_FILENO, hide, strlen(hide));
211 pad_init();
212 setupsignals();
213 fcntl(STDIN_FILENO, F_SETFL,
214 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
215 mainloop();
216 pad_free();
217 write(STDIN_FILENO, show, strlen(show));
218 return 0;