fbpad: switch to the first font for tag summary
[fbpad.git] / fbpad.c
blob8ae7633838bdd36af3a0a7694294df856a6b25a3
1 /*
2 * fbpad - a small framebuffer virtual terminal
4 * Copyright (C) 2009-2012 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the modified BSD license.
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"
23 #include "scrsnap.h"
24 #include "draw.h"
26 #define CTRLKEY(x) ((x) - 96)
27 #define BADPOLLFLAGS (POLLHUP | POLLERR | POLLNVAL)
28 #define NTAGS (sizeof(tags) - 1)
29 #define NTERMS (NTAGS * 2)
30 #define TERMOPEN(i) (terms[i].fd)
31 #define TERMSNAP(i) (strchr(TAGS_SAVED, tags[(i) % NTAGS]))
33 static char tags[] = TAGS;
34 static struct term terms[NTERMS];
35 static int tops[NTAGS]; /* top terms of tags */
36 static int ctag; /* current tag */
37 static int ltag; /* the last tag */
38 static int fonts[NTERMS]; /* term fonts */
39 static int setfont; /* the next character is font */
40 static int exitit;
41 static int hidden;
43 static int readchar(void)
45 char b;
46 if (read(STDIN_FILENO, &b, 1) > 0)
47 return (int) b;
48 return -1;
51 static int cterm(void)
53 return tops[ctag] * NTAGS + ctag;
56 static void term_switch(int oidx, int nidx, int show, int save, int load)
58 int flags = show ? (load ? TERM_REDRAW : TERM_VISIBLE) : TERM_HIDDEN;
59 if (save && TERMOPEN(oidx) && TERMSNAP(oidx))
60 scr_snap(&terms[oidx]);
61 term_save(&terms[oidx]);
62 if (show && load && TERMOPEN(nidx) && TERMSNAP(nidx))
63 flags = scr_load(&terms[nidx]) ? TERM_REDRAW : TERM_VISIBLE;
64 if (show)
65 pad_font(fonts[nidx]);
66 term_load(&terms[nidx], flags);
69 static void showterm(int n)
71 if (cterm() == n)
72 return;
73 if (ctag != n % NTAGS)
74 ltag = ctag;
75 term_switch(cterm(), n, !hidden, !hidden, !hidden);
76 ctag = n % NTAGS;
77 tops[ctag] = n / NTAGS;
80 static void showtag(int n)
82 showterm(tops[n] * NTAGS + n);
85 static struct term *mainterm(void)
87 if (TERMOPEN(cterm()))
88 return &terms[cterm()];
89 return NULL;
92 static void exec_cmd(char *file)
94 if (!mainterm())
95 term_exec(file);
98 static int altterm(int n)
100 return n < NTAGS ? n + NTAGS : n - NTAGS;
103 static void nextterm(void)
105 int n = (cterm() + 1) % NTERMS;
106 while (n != cterm()) {
107 if (TERMOPEN(n)) {
108 showterm(n);
109 break;
111 n = (n + 1) % NTERMS;
115 static void showtags(void)
117 int colors[] = {15, 4, 2};
118 int c = 0;
119 int r = pad_rows() - 1;
120 int i;
121 pad_font(0);
122 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
123 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
124 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
125 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
126 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
127 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
128 for (i = 0; i < NTAGS; i++) {
129 int nt = 0;
130 if (TERMOPEN(i))
131 nt++;
132 if (TERMOPEN(altterm(i)))
133 nt++;
134 pad_put(i == ctag ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
135 if (TERMSNAP(i))
136 pad_put(tags[i], r, c++, !nt ? BGCOLOR : colors[nt], 15);
137 else
138 pad_put(tags[i], r, c++, colors[nt], BGCOLOR);
139 pad_put(i == ctag ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
141 pad_font(fonts[cterm()]);
144 static void directkey(void)
146 int c = readchar();
147 if (setfont && c != -1) {
148 setfont = 0;
149 if (c != ESC && isdigit(c)) {
150 fonts[cterm()] = c - '0';
151 term_switch(cterm(), cterm(), 1, 0, 1);
153 return;
155 if (c == ESC) {
156 switch ((c = readchar())) {
157 case 'c':
158 exec_cmd(SHELL);
159 return;
160 case 'm':
161 exec_cmd(MAIL);
162 return;
163 case 'e':
164 exec_cmd(EDITOR);
165 return;
166 case 'j':
167 case 'k':
168 showterm(altterm(cterm()));
169 return;
170 case 'o':
171 showtag(ltag);
172 return;
173 case 'p':
174 showtags();
175 return;
176 case '\t':
177 nextterm();
178 return;
179 case CTRLKEY('q'):
180 exitit = 1;
181 return;
182 case 's':
183 term_screenshot();
184 return;
185 case 'y':
186 term_switch(cterm(), cterm(), 1, 0, 1);
187 return;
188 case 'f':
189 setfont = 1;
190 return;
191 default:
192 if (strchr(tags, c)) {
193 showtag(strchr(tags, c) - tags);
194 return;
196 if (mainterm())
197 term_send(ESC);
200 if (c != -1 && mainterm())
201 term_send(c);
204 static void temp_switch(int termid)
206 if (termid != cterm())
207 term_switch(cterm(), termid, 0, 0, 0);
210 static void switch_back(int termid)
212 if (termid != cterm())
213 term_switch(termid, cterm(), 1, 0, 0);
216 static int poll_all(void)
218 struct pollfd ufds[NTERMS + 1];
219 int term_idx[NTERMS + 1];
220 int i;
221 int n = 1;
222 ufds[0].fd = STDIN_FILENO;
223 ufds[0].events = POLLIN;
224 for (i = 0; i < NTERMS; i++) {
225 if (TERMOPEN(i)) {
226 ufds[n].fd = terms[i].fd;
227 ufds[n].events = POLLIN;
228 term_idx[n++] = i;
231 if (poll(ufds, n, 1000) < 1)
232 return 0;
233 if (ufds[0].revents & BADPOLLFLAGS)
234 return 1;
235 if (ufds[0].revents & POLLIN)
236 directkey();
237 for (i = 1; i < n; i++) {
238 temp_switch(term_idx[i]);
239 if (ufds[i].revents & POLLIN)
240 term_read();
241 if (ufds[i].revents & BADPOLLFLAGS) {
242 scr_free(&terms[cterm()]);
243 term_end();
245 switch_back(term_idx[i]);
247 return 0;
250 static void mainloop(void)
252 struct termios oldtermios, termios;
253 tcgetattr(STDIN_FILENO, &termios);
254 oldtermios = termios;
255 cfmakeraw(&termios);
256 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
257 term_load(&terms[cterm()], TERM_REDRAW);
258 while (!exitit)
259 if (poll_all())
260 break;
261 tcsetattr(STDIN_FILENO, 0, &oldtermios);
264 static void signalreceived(int n);
265 static void signalregister(void)
267 signal(SIGUSR1, signalreceived);
268 signal(SIGUSR2, signalreceived);
269 signal(SIGCHLD, signalreceived);
272 static void signalreceived(int n)
274 if (exitit)
275 return;
276 /* racy, new signals may arrive before re-registeration */
277 signalregister();
278 switch (n) {
279 case SIGUSR1:
280 hidden = 1;
281 term_switch(cterm(), cterm(), 0, 1, 0);
282 ioctl(STDIN_FILENO, VT_RELDISP, 1);
283 break;
284 case SIGUSR2:
285 hidden = 0;
286 fb_cmap();
287 term_switch(cterm(), cterm(), 1, 0, 1);
288 break;
289 case SIGCHLD:
290 while (waitpid(-1, NULL, WNOHANG) > 0)
292 break;
296 static void setupsignals(void)
298 struct vt_mode vtm;
299 vtm.mode = VT_PROCESS;
300 vtm.waitv = 0;
301 vtm.relsig = SIGUSR1;
302 vtm.acqsig = SIGUSR2;
303 vtm.frsig = 0;
304 signalregister();
305 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
308 int main(void)
310 char *hide = "\x1b[?25l";
311 char *clear = "\x1b[2J\x1b[H";
312 char *show = "\x1b[?25h";
313 write(STDOUT_FILENO, clear, strlen(clear));
314 write(STDIN_FILENO, hide, strlen(hide));
315 if (pad_init())
316 goto failed;
317 setupsignals();
318 fcntl(STDIN_FILENO, F_SETFL,
319 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
320 mainloop();
321 pad_free();
322 failed:
323 write(STDIN_FILENO, show, strlen(show));
324 return 0;