fbpad: put all poll() stuff in poll_all()
[fbpad.git] / fbpad.c
blob4c62a012d072827e75374ccf76b0be08800bd315
1 /*
2 * fbpad - A small linux framebuffer virtual terminal
4 * Copyright (C) 2009-2010 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/ioctl.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20 #include <linux/vt.h>
21 #include <locale.h>
22 #include "config.h"
23 #include "pad.h"
24 #include "term.h"
25 #include "util.h"
27 #define CTRLKEY(x) ((x) - 96)
28 #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL)
29 #define NTAGS sizeof(tags)
30 #define NTERMS (NTAGS * 2)
32 static char tags[] = TAGS;
33 static struct term terms[NTERMS];
34 static int tops[NTAGS]; /* top terms of tags */
35 static int ctag; /* current tag */
36 static int ltag; /* the last tag */
37 static int exitit;
38 static int hidden;
40 static int readchar(void)
42 char b;
43 if (read(STDIN_FILENO, &b, 1) > 0)
44 return (int) b;
45 return -1;
48 static int cterm(void)
50 return tops[ctag] * NTAGS + ctag;
53 static void showterm(int n)
55 if (cterm() == n)
56 return;
57 if (ctag != n % NTAGS)
58 ltag = ctag;
59 term_save(&terms[cterm()]);
60 ctag = n % NTAGS;
61 tops[ctag] = n / NTAGS;
62 term_load(&terms[n], hidden ? TERM_HIDDEN : TERM_REDRAW);
65 static void showtag(int n)
67 showterm(tops[n] * NTAGS + n);
70 static struct term *mainterm(void)
72 if (terms[cterm()].fd)
73 return &terms[cterm()];
74 return NULL;
77 static void exec_cmd(char *file)
79 if (!mainterm())
80 term_exec(file);
83 static int altterm(int n)
85 return n < NTAGS ? n + NTAGS : n - NTAGS;
88 static void nextterm(void)
90 int n = (cterm() + 1) % NTERMS;
91 while (n != cterm()) {
92 if (terms[n].fd) {
93 showterm(n);
94 break;
96 n = (n + 1) % NTERMS;
100 static void showtags(void)
102 int colors[] = {15, 4, 2};
103 int c = 0;
104 int r = pad_rows() - 1;
105 int i;
106 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
107 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
108 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
109 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
110 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
111 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
112 for (i = 0; i < NTAGS; i++) {
113 int nt = 0;
114 if (terms[i].fd)
115 nt++;
116 if (terms[altterm(i)].fd)
117 nt++;
118 pad_put(i == ctag ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
119 pad_put(tags[i], r, c++, colors[nt], 7);
120 pad_put(i == ctag ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
124 static void directkey(void)
126 int c = readchar();
127 if (c == ESC) {
128 switch ((c = readchar())) {
129 case 'c':
130 exec_cmd(SHELL);
131 return;
132 case 'm':
133 exec_cmd(MAIL);
134 return;
135 case 'e':
136 exec_cmd(EDITOR);
137 return;
138 case 'j':
139 case 'k':
140 showterm(altterm(cterm()));
141 return;
142 case 'o':
143 showtag(ltag);
144 return;
145 case 'p':
146 showtags();
147 return;
148 case '\t':
149 nextterm();
150 return;
151 case CTRLKEY('q'):
152 exitit = 1;
153 return;
154 case 's':
155 term_screenshot();
156 return;
157 default:
158 if (strchr(tags, c)) {
159 showtag(strchr(tags, c) - tags);
160 return;
162 if (mainterm())
163 term_send(ESC);
166 if (c != -1 && mainterm())
167 term_send(c);
170 static void temp_switch(int termid)
172 if (termid != cterm()) {
173 term_save(&terms[cterm()]);
174 term_load(&terms[termid], TERM_HIDDEN);
178 static void switch_back(int termid)
180 if (termid != cterm()) {
181 term_save(&terms[termid]);
182 term_load(&terms[cterm()], hidden ? TERM_HIDDEN : TERM_VISIBLE);
186 static int poll_all(void)
188 struct pollfd ufds[NTERMS + 1];
189 int term_idx[NTERMS + 1];
190 int i;
191 int n = 1;
192 ufds[0].fd = STDIN_FILENO;
193 ufds[0].events = POLLIN;
194 for (i = 0; i < NTERMS; i++) {
195 if (terms[i].fd) {
196 ufds[n].fd = terms[i].fd;
197 ufds[n].events = POLLIN;
198 term_idx[n++] = i;
201 if (poll(ufds, n, 1000) < 1)
202 return 0;
203 if (ufds[0].revents & BADPOLLFLAGS)
204 return 1;
205 if (ufds[0].revents & POLLIN)
206 directkey();
207 for (i = 1; i < n; i++) {
208 temp_switch(term_idx[i]);
209 if (ufds[i].revents & POLLIN)
210 term_read();
211 if (ufds[i].revents & BADPOLLFLAGS)
212 term_end();
213 switch_back(term_idx[i]);
215 return 0;
218 static void mainloop(void)
220 struct termios oldtermios, termios;
221 tcgetattr(STDIN_FILENO, &termios);
222 oldtermios = termios;
223 cfmakeraw(&termios);
224 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
225 term_load(&terms[cterm()], TERM_REDRAW);
226 while (!exitit)
227 if (poll_all())
228 break;
229 tcsetattr(STDIN_FILENO, 0, &oldtermios);
232 static void signalreceived(int n)
234 if (exitit)
235 return;
236 switch (n) {
237 case SIGUSR1:
238 hidden = 1;
239 term_save(&terms[cterm()]);
240 term_load(&terms[cterm()], TERM_HIDDEN);
241 ioctl(STDIN_FILENO, VT_RELDISP, 1);
242 break;
243 case SIGUSR2:
244 hidden = 0;
245 pad_shown();
246 term_save(&terms[cterm()]);
247 term_load(&terms[cterm()], TERM_REDRAW);
248 break;
249 case SIGCHLD:
250 while (waitpid(-1, 0, WNOHANG) > 0)
252 break;
256 static void setupsignals(void)
258 struct vt_mode vtm;
259 vtm.mode = VT_PROCESS;
260 vtm.waitv = 0;
261 vtm.relsig = SIGUSR1;
262 vtm.acqsig = SIGUSR2;
263 vtm.frsig = 0;
264 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
266 signal(SIGUSR1, signalreceived);
267 signal(SIGUSR2, signalreceived);
268 signal(SIGCHLD, signalreceived);
271 int main(void)
273 char *hide = "\x1b[?25l";
274 char *clear = "\x1b[2J\x1b[H";
275 char *show = "\x1b[?25h";
276 setlocale(LC_ALL, "");
277 write(STDOUT_FILENO, clear, strlen(clear));
278 write(STDIN_FILENO, hide, strlen(hide));
279 pad_init();
280 setupsignals();
281 fcntl(STDIN_FILENO, F_SETFL,
282 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
283 mainloop();
284 pad_free();
285 write(STDIN_FILENO, show, strlen(show));
286 return 0;