draw: fix framebuffer mmap() size
[fbpad.git] / fbpad.c
blob8653cf973d7e0343a4a5de0b3c6738f4b118c708
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/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)
31 static char tags[] = TAGS;
32 static struct term terms[NTAGS * 2];
33 static int tops[NTAGS]; /* top terms of tags */
34 static int ctag; /* current tag */
35 static int ltag; /* the last tag */
36 static int exitit;
37 static int hidden;
39 static int readchar(void)
41 char b;
42 if (read(STDIN_FILENO, &b, 1) > 0)
43 return (int) b;
44 return -1;
47 static int cterm(void)
49 return tops[ctag] * NTAGS + ctag;
52 static void showterm(int n)
54 if (cterm() == n)
55 return;
56 if (ctag != n % NTAGS)
57 ltag = ctag;
58 term_save(&terms[cterm()]);
59 ctag = n % NTAGS;
60 tops[ctag] = n / NTAGS;
61 term_load(&terms[n], hidden ? TERM_HIDDEN : TERM_REDRAW);
64 static void showtag(int n)
66 showterm(tops[n] * NTAGS + n);
69 static struct term *mainterm(void)
71 if (terms[cterm()].fd)
72 return &terms[cterm()];
73 return NULL;
76 static void exec_cmd(char *file)
78 if (!mainterm())
79 term_exec(file);
82 static int altterm(int n)
84 return n < NTAGS ? n + NTAGS : n - NTAGS;
87 static void nextterm(void)
89 int n = (cterm() + 1) % ARRAY_SIZE(terms);
90 while (n != cterm()) {
91 if (terms[n].fd) {
92 showterm(n);
93 break;
95 n = (n + 1) % ARRAY_SIZE(terms);
99 static void showtags(void)
101 int colors[] = {15, 4, 2};
102 int c = 0;
103 int r = pad_rows() - 1;
104 int i;
105 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
106 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
107 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
108 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
109 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
110 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
111 for (i = 0; i < NTAGS; i++) {
112 int nt = 0;
113 if (terms[i].fd)
114 nt++;
115 if (terms[altterm(i)].fd)
116 nt++;
117 pad_put(i == ctag ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
118 pad_put(tags[i], r, c++, colors[nt], 7);
119 pad_put(i == ctag ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
123 static void directkey(void)
125 int c = readchar();
126 if (c == ESC) {
127 switch ((c = readchar())) {
128 case 'c':
129 exec_cmd(SHELL);
130 return;
131 case 'm':
132 exec_cmd(MAIL);
133 return;
134 case 'e':
135 exec_cmd(EDITOR);
136 return;
137 case 'j':
138 case 'k':
139 showterm(altterm(cterm()));
140 return;
141 case 'o':
142 showtag(ltag);
143 return;
144 case 'p':
145 showtags();
146 return;
147 case '\t':
148 nextterm();
149 return;
150 case CTRLKEY('q'):
151 exitit = 1;
152 return;
153 case 's':
154 term_screenshot();
155 return;
156 default:
157 if (strchr(tags, c)) {
158 showtag(strchr(tags, c) - tags);
159 return;
161 if (mainterm())
162 term_send(ESC);
165 if (c != -1 && mainterm())
166 term_send(c);
169 static int find_by_fd(int fd)
171 int i;
172 for (i = 0; i < ARRAY_SIZE(terms); i++)
173 if (terms[i].fd == fd)
174 return i;
175 return -1;
178 static int fill_ufds(struct pollfd *ufds)
180 int n = 1;
181 int i;
182 ufds[0].fd = STDIN_FILENO;
183 ufds[0].events = POLLIN;
184 for (i = 0; i < ARRAY_SIZE(terms); i++) {
185 if (terms[i].fd) {
186 ufds[n].fd = terms[i].fd;
187 ufds[n].events = POLLIN;
188 n++;
191 return n;
194 static void temp_switch(int termid)
196 if (termid != cterm()) {
197 term_save(&terms[cterm()]);
198 term_load(&terms[termid], TERM_HIDDEN);
202 static void switch_back(int termid)
204 if (termid != cterm()) {
205 term_save(&terms[termid]);
206 term_load(&terms[cterm()], hidden ? TERM_HIDDEN : TERM_VISIBLE);
210 static void check_ufds(struct pollfd *ufds, int n)
212 int i;
213 for (i = 1; i < n; i++) {
214 int idx = find_by_fd(ufds[i].fd);
215 if (ufds[i].revents & BADPOLLFLAGS) {
216 temp_switch(idx);
217 term_end();
218 switch_back(idx);
219 } else if (ufds[i].revents & POLLIN) {
220 temp_switch(idx);
221 term_read();
222 switch_back(idx);
227 static void mainloop(void)
229 struct pollfd ufds[ARRAY_SIZE(terms) + 1];
230 struct termios oldtermios, termios;
231 int rv;
232 int n;
233 tcgetattr(STDIN_FILENO, &termios);
234 oldtermios = termios;
235 cfmakeraw(&termios);
236 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
237 memset(ufds, 0, sizeof(ufds));
238 term_load(&terms[cterm()], TERM_REDRAW);
239 n = fill_ufds(ufds);
240 while (!exitit) {
241 rv = poll(ufds, n, 1000);
242 if (rv == -1 && errno != EINTR)
243 break;
244 if (ufds[0].revents & BADPOLLFLAGS)
245 break;
246 if (ufds[0].revents & POLLIN)
247 directkey();
248 check_ufds(ufds, n);
249 n = fill_ufds(ufds);
251 tcsetattr(STDIN_FILENO, 0, &oldtermios);
254 static void signalreceived(int n)
256 if (exitit)
257 return;
258 switch (n) {
259 case SIGUSR1:
260 hidden = 1;
261 term_save(&terms[cterm()]);
262 term_load(&terms[cterm()], TERM_HIDDEN);
263 ioctl(STDIN_FILENO, VT_RELDISP, 1);
264 break;
265 case SIGUSR2:
266 hidden = 0;
267 pad_shown();
268 term_save(&terms[cterm()]);
269 term_load(&terms[cterm()], TERM_REDRAW);
270 break;
271 case SIGCHLD:
272 while (waitpid(-1, 0, WNOHANG) > 0)
274 break;
278 static void setupsignals(void)
280 struct vt_mode vtm;
281 vtm.mode = VT_PROCESS;
282 vtm.waitv = 0;
283 vtm.relsig = SIGUSR1;
284 vtm.acqsig = SIGUSR2;
285 vtm.frsig = 0;
286 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
288 signal(SIGUSR1, signalreceived);
289 signal(SIGUSR2, signalreceived);
290 signal(SIGCHLD, signalreceived);
293 int main(void)
295 char *hide = "\x1b[?25l";
296 char *clear = "\x1b[2J\x1b[H";
297 char *show = "\x1b[?25h";
298 setlocale(LC_ALL, "");
299 write(STDOUT_FILENO, clear, strlen(clear));
300 write(STDIN_FILENO, hide, strlen(hide));
301 pad_init();
302 setupsignals();
303 fcntl(STDIN_FILENO, F_SETFL,
304 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
305 mainloop();
306 pad_free();
307 write(STDIN_FILENO, show, strlen(show));
308 return 0;