term: use three arrays instead of square struct
[fbpad.git] / fbpad.c
blobff63ca094ff8ee6bf0fb8f9588d8ecc5de892157
1 /*
2 * fbpad - A small linux framebuffer virtual terminal
4 * Copyright (C) 2009 Ali Gholami Rudi
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, as published by the
8 * Free Software Foundation.
9 */
10 #include <ctype.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <poll.h>
14 #include <pty.h>
15 #include <signal.h>
16 #include <string.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include <linux/vt.h>
20 #include <locale.h>
21 #include "config.h"
22 #include "pad.h"
23 #include "term.h"
24 #include "util.h"
26 #define CTRLKEY(x) ((x) - 96)
27 #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL)
28 #define NTAGS sizeof(tags)
30 static char tags[] = TAGS;
31 static struct term terms[NTAGS * 2];
32 static int cterm; /* current tag */
33 static int lterm; /* last tag */
34 static int exitit;
35 static int hidden;
37 static int readchar(void)
39 char b;
40 if (read(STDIN_FILENO, &b, 1) > 0)
41 return (int) b;
42 return -1;
45 static void showterm(int n)
47 if (cterm % NTAGS != n % NTAGS)
48 lterm = cterm;
49 term_save(&terms[cterm]);
50 cterm = n;
51 term_load(&terms[cterm], hidden ? TERM_HIDDEN : TERM_REDRAW);
54 static struct term *mainterm(void)
56 if (terms[cterm].fd)
57 return &terms[cterm];
58 return NULL;
61 static void exec_cmd(char *file)
63 if (!mainterm())
64 term_exec(file);
67 static int altterm(int n)
69 return n < NTAGS ? n + NTAGS : n - NTAGS;
72 static void nextterm(void)
74 int n = (cterm + 1) % ARRAY_SIZE(terms);
75 while (n != cterm) {
76 if (terms[n].fd) {
77 showterm(n);
78 break;
80 n = (n + 1) % ARRAY_SIZE(terms);
84 static void showterms(void)
86 int colors[] = {FGCOLOR, 4, 2, 5};
87 int c = 0;
88 int r = pad_rows() - 1;
89 int i;
90 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
91 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
92 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
93 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
94 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
95 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
96 for (i = 0; i < NTAGS; i++) {
97 int nt = 0;
98 int shown = i == cterm || altterm(i) == cterm;
99 if (terms[i].fd)
100 nt = 1;
101 if (terms[altterm(i)].fd)
102 nt = nt ? 2 : 3;
103 pad_put(shown ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
104 pad_put(tags[i], r, c++, colors[nt], 7);
105 pad_put(shown ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
109 static void directkey(void)
111 int c = readchar();
112 if (c == ESC) {
113 switch ((c = readchar())) {
114 case 'c':
115 exec_cmd(SHELL);
116 return;
117 case 'm':
118 exec_cmd(MAIL);
119 return;
120 case 'e':
121 exec_cmd(EDITOR);
122 return;
123 case 'j':
124 case 'k':
125 showterm(altterm(cterm));
126 return;
127 case 'o':
128 showterm(lterm);
129 return;
130 case 'p':
131 showterms();
132 return;
133 case '\t':
134 nextterm();
135 return;
136 case CTRLKEY('q'):
137 exitit = 1;
138 return;
139 case 's':
140 term_screenshot();
141 return;
142 default:
143 if (strchr(tags, c)) {
144 showterm(strchr(tags, c) - tags);
145 return;
147 if (mainterm())
148 term_send(ESC);
151 if (c != -1 && mainterm())
152 term_send(c);
155 static int find_by_fd(int fd)
157 int i;
158 for (i = 0; i < ARRAY_SIZE(terms); i++)
159 if (terms[i].fd == fd)
160 return i;
161 return -1;
164 static int fill_ufds(struct pollfd *ufds)
166 int n = 1;
167 int i;
168 ufds[0].fd = STDIN_FILENO;
169 ufds[0].events = POLLIN;
170 for (i = 0; i < ARRAY_SIZE(terms); i++) {
171 if (terms[i].fd) {
172 ufds[n].fd = terms[i].fd;
173 ufds[n].events = POLLIN;
174 n++;
177 return n;
180 static void temp_switch(int termid)
182 if (termid != cterm) {
183 term_save(&terms[cterm]);
184 term_load(&terms[termid], TERM_HIDDEN);
188 static void switch_back(int termid)
190 if (termid != cterm) {
191 term_save(&terms[termid]);
192 term_load(&terms[cterm], hidden ? TERM_HIDDEN : TERM_VISIBLE);
196 static void check_ufds(struct pollfd *ufds, int n)
198 int i;
199 for (i = 1; i < n; i++) {
200 int idx = find_by_fd(ufds[i].fd);
201 if (ufds[i].revents & BADPOLLFLAGS) {
202 temp_switch(idx);
203 term_end();
204 switch_back(idx);
205 } else if (ufds[i].revents & POLLIN) {
206 temp_switch(idx);
207 term_read();
208 switch_back(idx);
213 static void mainloop(void)
215 struct pollfd ufds[ARRAY_SIZE(terms) + 1];
216 struct termios oldtermios, termios;
217 int rv;
218 int n;
219 tcgetattr(STDIN_FILENO, &termios);
220 oldtermios = termios;
221 cfmakeraw(&termios);
222 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
223 memset(ufds, 0, sizeof(ufds));
224 term_load(&terms[cterm], TERM_REDRAW);
225 n = fill_ufds(ufds);
226 while (!exitit) {
227 rv = poll(ufds, n, 1000);
228 if (rv == -1 && errno != EINTR)
229 break;
230 if (ufds[0].revents & BADPOLLFLAGS)
231 break;
232 if (ufds[0].revents & POLLIN)
233 directkey();
234 check_ufds(ufds, n);
235 n = fill_ufds(ufds);
237 tcsetattr(STDIN_FILENO, 0, &oldtermios);
240 static void signalreceived(int n)
242 if (exitit)
243 return;
244 switch (n) {
245 case SIGUSR1:
246 hidden = 1;
247 term_save(&terms[cterm]);
248 term_load(&terms[cterm], TERM_HIDDEN);
249 ioctl(STDIN_FILENO, VT_RELDISP, 1);
250 break;
251 case SIGUSR2:
252 hidden = 0;
253 pad_shown();
254 term_save(&terms[cterm]);
255 term_load(&terms[cterm], TERM_REDRAW);
256 break;
257 case SIGCHLD:
258 while (waitpid(-1, 0, WNOHANG) > 0)
260 break;
264 static void setupsignals(void)
266 struct vt_mode vtm;
267 vtm.mode = VT_PROCESS;
268 vtm.waitv = 0;
269 vtm.relsig = SIGUSR1;
270 vtm.acqsig = SIGUSR2;
271 vtm.frsig = 0;
272 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
274 signal(SIGUSR1, signalreceived);
275 signal(SIGUSR2, signalreceived);
276 signal(SIGCHLD, signalreceived);
279 int main(void)
281 char *hide = "\x1b[?25l";
282 char *clear = "\x1b[2J\x1b[H";
283 char *show = "\x1b[?25h";
284 setlocale(LC_ALL, "");
285 write(STDIN_FILENO, clear, strlen(clear));
286 write(STDIN_FILENO, hide, strlen(hide));
287 pad_init();
288 setupsignals();
289 fcntl(STDIN_FILENO, F_SETFL,
290 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
291 mainloop();
292 pad_free();
293 write(STDIN_FILENO, show, strlen(show));
294 return 0;