term: pass term size to forkpty()
[fbpad.git] / fbpad.c
blob204027dd606880691acc992da9162caf02d57021
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 tops[NTAGS]; /* top terms of tags */
33 static int ctag; /* current tag */
34 static int ltag; /* the last tag */
35 static int exitit;
36 static int hidden;
38 static int readchar(void)
40 char b;
41 if (read(STDIN_FILENO, &b, 1) > 0)
42 return (int) b;
43 return -1;
46 static int cterm(void)
48 return tops[ctag] * NTAGS + ctag;
51 static void showterm(int n)
53 if (cterm() == n)
54 return;
55 if (ctag != n % NTAGS)
56 ltag = ctag;
57 term_save(&terms[cterm()]);
58 ctag = n % NTAGS;
59 tops[ctag] = n / NTAGS;
60 term_load(&terms[n], hidden ? TERM_HIDDEN : TERM_REDRAW);
63 static void showtag(int n)
65 showterm(tops[n] * NTAGS + n);
68 static struct term *mainterm(void)
70 if (terms[cterm()].fd)
71 return &terms[cterm()];
72 return NULL;
75 static void exec_cmd(char *file)
77 if (!mainterm())
78 term_exec(file);
81 static int altterm(int n)
83 return n < NTAGS ? n + NTAGS : n - NTAGS;
86 static void nextterm(void)
88 int n = (cterm() + 1) % ARRAY_SIZE(terms);
89 while (n != cterm()) {
90 if (terms[n].fd) {
91 showterm(n);
92 break;
94 n = (n + 1) % ARRAY_SIZE(terms);
98 static void showtags(void)
100 int colors[] = {15, 4, 2};
101 int c = 0;
102 int r = pad_rows() - 1;
103 int i;
104 pad_put('T', r, c++, FGCOLOR, BGCOLOR);
105 pad_put('A', r, c++, FGCOLOR, BGCOLOR);
106 pad_put('G', r, c++, FGCOLOR, BGCOLOR);
107 pad_put('S', r, c++, FGCOLOR, BGCOLOR);
108 pad_put(':', r, c++, FGCOLOR, BGCOLOR);
109 pad_put(' ', r, c++, FGCOLOR, BGCOLOR);
110 for (i = 0; i < NTAGS; i++) {
111 int nt = 0;
112 if (terms[i].fd)
113 nt++;
114 if (terms[altterm(i)].fd)
115 nt++;
116 pad_put(i == ctag ? '(' : ' ', r, c++, FGCOLOR, BGCOLOR);
117 pad_put(tags[i], r, c++, colors[nt], 7);
118 pad_put(i == ctag ? ')' : ' ', r, c++, FGCOLOR, BGCOLOR);
122 static void directkey(void)
124 int c = readchar();
125 if (c == ESC) {
126 switch ((c = readchar())) {
127 case 'c':
128 exec_cmd(SHELL);
129 return;
130 case 'm':
131 exec_cmd(MAIL);
132 return;
133 case 'e':
134 exec_cmd(EDITOR);
135 return;
136 case 'j':
137 case 'k':
138 showterm(altterm(cterm()));
139 return;
140 case 'o':
141 showtag(ltag);
142 return;
143 case 'p':
144 showtags();
145 return;
146 case '\t':
147 nextterm();
148 return;
149 case CTRLKEY('q'):
150 exitit = 1;
151 return;
152 case 's':
153 term_screenshot();
154 return;
155 default:
156 if (strchr(tags, c)) {
157 showtag(strchr(tags, c) - tags);
158 return;
160 if (mainterm())
161 term_send(ESC);
164 if (c != -1 && mainterm())
165 term_send(c);
168 static int find_by_fd(int fd)
170 int i;
171 for (i = 0; i < ARRAY_SIZE(terms); i++)
172 if (terms[i].fd == fd)
173 return i;
174 return -1;
177 static int fill_ufds(struct pollfd *ufds)
179 int n = 1;
180 int i;
181 ufds[0].fd = STDIN_FILENO;
182 ufds[0].events = POLLIN;
183 for (i = 0; i < ARRAY_SIZE(terms); i++) {
184 if (terms[i].fd) {
185 ufds[n].fd = terms[i].fd;
186 ufds[n].events = POLLIN;
187 n++;
190 return n;
193 static void temp_switch(int termid)
195 if (termid != cterm()) {
196 term_save(&terms[cterm()]);
197 term_load(&terms[termid], TERM_HIDDEN);
201 static void switch_back(int termid)
203 if (termid != cterm()) {
204 term_save(&terms[termid]);
205 term_load(&terms[cterm()], hidden ? TERM_HIDDEN : TERM_VISIBLE);
209 static void check_ufds(struct pollfd *ufds, int n)
211 int i;
212 for (i = 1; i < n; i++) {
213 int idx = find_by_fd(ufds[i].fd);
214 if (ufds[i].revents & BADPOLLFLAGS) {
215 temp_switch(idx);
216 term_end();
217 switch_back(idx);
218 } else if (ufds[i].revents & POLLIN) {
219 temp_switch(idx);
220 term_read();
221 switch_back(idx);
226 static void mainloop(void)
228 struct pollfd ufds[ARRAY_SIZE(terms) + 1];
229 struct termios oldtermios, termios;
230 int rv;
231 int n;
232 tcgetattr(STDIN_FILENO, &termios);
233 oldtermios = termios;
234 cfmakeraw(&termios);
235 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
236 memset(ufds, 0, sizeof(ufds));
237 term_load(&terms[cterm()], TERM_REDRAW);
238 n = fill_ufds(ufds);
239 while (!exitit) {
240 rv = poll(ufds, n, 1000);
241 if (rv == -1 && errno != EINTR)
242 break;
243 if (ufds[0].revents & BADPOLLFLAGS)
244 break;
245 if (ufds[0].revents & POLLIN)
246 directkey();
247 check_ufds(ufds, n);
248 n = fill_ufds(ufds);
250 tcsetattr(STDIN_FILENO, 0, &oldtermios);
253 static void signalreceived(int n)
255 if (exitit)
256 return;
257 switch (n) {
258 case SIGUSR1:
259 hidden = 1;
260 term_save(&terms[cterm()]);
261 term_load(&terms[cterm()], TERM_HIDDEN);
262 ioctl(STDIN_FILENO, VT_RELDISP, 1);
263 break;
264 case SIGUSR2:
265 hidden = 0;
266 pad_shown();
267 term_save(&terms[cterm()]);
268 term_load(&terms[cterm()], TERM_REDRAW);
269 break;
270 case SIGCHLD:
271 while (waitpid(-1, 0, WNOHANG) > 0)
273 break;
277 static void setupsignals(void)
279 struct vt_mode vtm;
280 vtm.mode = VT_PROCESS;
281 vtm.waitv = 0;
282 vtm.relsig = SIGUSR1;
283 vtm.acqsig = SIGUSR2;
284 vtm.frsig = 0;
285 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
287 signal(SIGUSR1, signalreceived);
288 signal(SIGUSR2, signalreceived);
289 signal(SIGCHLD, signalreceived);
292 int main(void)
294 char *hide = "\x1b[?25l";
295 char *clear = "\x1b[2J\x1b[H";
296 char *show = "\x1b[?25h";
297 setlocale(LC_ALL, "");
298 write(STDOUT_FILENO, clear, strlen(clear));
299 write(STDIN_FILENO, hide, strlen(hide));
300 pad_init();
301 setupsignals();
302 fcntl(STDIN_FILENO, F_SETFL,
303 fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
304 mainloop();
305 pad_free();
306 write(STDIN_FILENO, show, strlen(show));
307 return 0;