fbpad: re-register signals in signalreceived()
[fbpad.git] / fbpad.c
bloba146458e6da426510360571e0e53e788b2b9d8a3
1 /*
2 * fbpad - a small framebuffer virtual terminal
4 * Copyright (C) 2009-2011 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under GNU GPL version 2.
7 */
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <poll.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <sys/ioctl.h>
15 #include <sys/wait.h>
16 #include <termios.h>
17 #include <unistd.h>
18 #include <linux/vt.h>
19 #include "config.h"
20 #include "pad.h"
21 #include "term.h"
22 #include "util.h"
24 #define CTRLKEY(x) ((x) - 96)
25 #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL)
26 #define NTAGS sizeof(tags)
27 #define NTERMS (NTAGS * 2)
29 static char tags[] = TAGS;
30 static struct term terms[NTERMS];
31 static int tops[NTAGS]; /* top terms of tags */
32 static int ctag; /* current tag */
33 static int ltag; /* the 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 int cterm(void)
47 return tops[ctag] * NTAGS + ctag;
50 static void showterm(int n)
52 if (cterm() == n)
53 return;
54 if (ctag != n % NTAGS)
55 ltag = ctag;
56 term_save(&terms[cterm()]);
57 ctag = n % NTAGS;
58 tops[ctag] = n / NTAGS;
59 term_load(&terms[n], hidden ? TERM_HIDDEN : TERM_REDRAW);
62 static void showtag(int n)
64 showterm(tops[n] * NTAGS + n);
67 static struct term *mainterm(void)
69 if (terms[cterm()].fd)
70 return &terms[cterm()];
71 return NULL;
74 static void exec_cmd(char *file)
76 if (!mainterm())
77 term_exec(file);
80 static int altterm(int n)
82 return n < NTAGS ? n + NTAGS : n - NTAGS;
85 static void nextterm(void)
87 int n = (cterm() + 1) % NTERMS;
88 while (n != cterm()) {
89 if (terms[n].fd) {
90 showterm(n);
91 break;
93 n = (n + 1) % NTERMS;
97 static void showtags(void)
99 int colors[] = {15, 4, 2};
100 int c = 0;
101 int r = pad_rows() - 1;
102 int i;
103 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
104 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
105 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
106 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
107 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
108 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
109 for (i = 0; i < NTAGS; i++) {
110 int nt = 0;
111 if (terms[i].fd)
112 nt++;
113 if (terms[altterm(i)].fd)
114 nt++;
115 pad_put(i == ctag ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
116 pad_put(tags[i], r, c++, colors[nt], 7);
117 pad_put(i == ctag ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
121 static void directkey(void)
123 int c = readchar();
124 if (c == ESC) {
125 switch ((c = readchar())) {
126 case 'c':
127 exec_cmd(SHELL);
128 return;
129 case 'm':
130 exec_cmd(MAIL);
131 return;
132 case 'e':
133 exec_cmd(EDITOR);
134 return;
135 case 'j':
136 case 'k':
137 showterm(altterm(cterm()));
138 return;
139 case 'o':
140 showtag(ltag);
141 return;
142 case 'p':
143 showtags();
144 return;
145 case '\t':
146 nextterm();
147 return;
148 case CTRLKEY('q'):
149 exitit = 1;
150 return;
151 case 's':
152 term_screenshot();
153 return;
154 default:
155 if (strchr(tags, c)) {
156 showtag(strchr(tags, c) - tags);
157 return;
159 if (mainterm())
160 term_send(ESC);
163 if (c != -1 && mainterm())
164 term_send(c);
167 static void temp_switch(int termid)
169 if (termid != cterm()) {
170 term_save(&terms[cterm()]);
171 term_load(&terms[termid], TERM_HIDDEN);
175 static void switch_back(int termid)
177 if (termid != cterm()) {
178 term_save(&terms[termid]);
179 term_load(&terms[cterm()], hidden ? TERM_HIDDEN : TERM_VISIBLE);
183 static int poll_all(void)
185 struct pollfd ufds[NTERMS + 1];
186 int term_idx[NTERMS + 1];
187 int i;
188 int n = 1;
189 ufds[0].fd = STDIN_FILENO;
190 ufds[0].events = POLLIN;
191 for (i = 0; i < NTERMS; i++) {
192 if (terms[i].fd) {
193 ufds[n].fd = terms[i].fd;
194 ufds[n].events = POLLIN;
195 term_idx[n++] = i;
198 if (poll(ufds, n, 1000) < 1)
199 return 0;
200 if (ufds[0].revents & BADPOLLFLAGS)
201 return 1;
202 if (ufds[0].revents & POLLIN)
203 directkey();
204 for (i = 1; i < n; i++) {
205 temp_switch(term_idx[i]);
206 if (ufds[i].revents & POLLIN)
207 term_read();
208 if (ufds[i].revents & BADPOLLFLAGS)
209 term_end();
210 switch_back(term_idx[i]);
212 return 0;
215 static void mainloop(void)
217 struct termios oldtermios, termios;
218 tcgetattr(STDIN_FILENO, &termios);
219 oldtermios = termios;
220 cfmakeraw(&termios);
221 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
222 term_load(&terms[cterm()], TERM_REDRAW);
223 while (!exitit)
224 if (poll_all())
225 break;
226 tcsetattr(STDIN_FILENO, 0, &oldtermios);
229 static void signalreceived(int n);
230 static int signalregister(void)
232 signal(SIGUSR1, signalreceived);
233 signal(SIGUSR2, signalreceived);
234 signal(SIGCHLD, signalreceived);
237 static void signalreceived(int n)
239 if (exitit)
240 return;
241 /* racy, new signals may arrive before re-registeration */
242 signalregister();
243 switch (n) {
244 case SIGUSR1:
245 hidden = 1;
246 term_save(&terms[cterm()]);
247 term_load(&terms[cterm()], TERM_HIDDEN);
248 ioctl(STDIN_FILENO, VT_RELDISP, 1);
249 break;
250 case SIGUSR2:
251 hidden = 0;
252 pad_shown();
253 term_save(&terms[cterm()]);
254 term_load(&terms[cterm()], TERM_REDRAW);
255 break;
256 case SIGCHLD:
257 while (waitpid(-1, NULL, WNOHANG) > 0)
259 break;
263 static void setupsignals(void)
265 struct vt_mode vtm;
266 vtm.mode = VT_PROCESS;
267 vtm.waitv = 0;
268 vtm.relsig = SIGUSR1;
269 vtm.acqsig = SIGUSR2;
270 vtm.frsig = 0;
271 signalregister();
272 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
275 int main(void)
277 char *hide = "\x1b[?25l";
278 char *clear = "\x1b[2J\x1b[H";
279 char *show = "\x1b[?25h";
280 write(STDOUT_FILENO, clear, strlen(clear));
281 write(STDIN_FILENO, hide, strlen(hide));
282 if (pad_init())
283 goto failed;
284 setupsignals();
285 fcntl(STDIN_FILENO, F_SETFL,
286 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
287 mainloop();
288 pad_free();
289 failed:
290 write(STDIN_FILENO, show, strlen(show));
291 return 0;