config: move fbval_t typedef from draw.h
[fbpad.git] / term.c
blob0c7fee290ea66b61f76257521fb885da40baabe8
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <pty.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include "config.h"
10 #include "pad.h"
11 #include "util.h"
12 #include "term.h"
14 #define MODE_NOCURSOR 0x01
15 #define MODE_NOWRAP 0x02
16 #define MODE_ORIGIN 0x04
17 #define MODE_NOAUTOCR 0x08
18 #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b)))
19 #define SQRADDR(r, c) (&screen[(r) * pad_cols() + (c)])
21 static struct term *term;
22 static struct square *screen;
23 static int row, col;
24 static int fg, bg;
25 static int top, bot;
26 static int mode;
27 static int visible;
29 #define MAXLINES (1 << 13)
30 static int dirty[MAXLINES];
31 static int lazy;
33 static void _term_show(int r, int c, int cursor)
35 struct square *sqr = SQRADDR(r, c);
36 int fgcolor = sqr->c ? sqr->fg : fg;
37 int bgcolor = sqr->c ? sqr->bg : bg;
38 if (cursor && !(mode & MODE_NOCURSOR)) {
39 int t = fgcolor;
40 fgcolor = bgcolor;
41 bgcolor = t;
43 if (visible)
44 pad_put(sqr->c, r, c, fgcolor, bgcolor);
47 static void _draw_row(int r)
49 int i;
50 for (i = 0; i < pad_cols(); i++)
51 _term_show(r, i, 0);
54 static void lazy_draw(int sr, int er)
56 int i;
57 if (!visible)
58 return;
59 for (i = sr; i < er; i++) {
60 if (lazy)
61 dirty[i] = 1;
62 else
63 _draw_row(i);
67 static void lazy_drawcols(int r, int sc, int ec)
69 int i;
70 if (!visible)
71 return;
72 if (lazy) {
73 dirty[r] = 1;
74 } else {
75 for (i = sc; i < ec; i++)
76 _term_show(r, i, 0);
80 static void lazy_put(int ch, int r, int c)
82 struct square *sqr = SQRADDR(r, c);
83 sqr->c = ch;
84 sqr->fg = fg;
85 sqr->bg = bg;
86 if (!visible)
87 return;
88 if (lazy)
89 dirty[r] = 1;
90 else
91 _term_show(r, c, 0);
94 static void lazy_cursor(int put)
96 if (!visible)
97 return;
98 if (lazy)
99 dirty[row] = 1;
100 else
101 _term_show(row, col, put);
104 static void lazy_clean()
106 if (visible)
107 memset(dirty, 0, sizeof(*dirty) * MAXLINES);
110 static void lazy_flush()
112 int i;
113 if (!visible)
114 return;
115 _term_show(row, col, 0);
116 for (i = 0; i < pad_rows(); i++)
117 if (dirty[i])
118 _draw_row(i);
119 lazy_clean();
120 _term_show(row, col, 1);
123 static int origin(void)
125 return mode & MODE_ORIGIN;
128 static void setsize(void)
130 struct winsize size;
131 size.ws_col = pad_cols();
132 size.ws_row = pad_rows();
133 size.ws_xpixel = 0;
134 size.ws_ypixel = 0;
135 ioctl(term->fd, TIOCSWINSZ, &size);
138 #define PTYBUFSIZE (1 << 13)
139 static char ptybuf[PTYBUFSIZE];
140 static int ptylen;
141 static int ptycur;
142 static int readpty(void)
144 if (ptycur < ptylen)
145 return ptybuf[ptycur++];
146 if ((ptylen = read(term->fd, ptybuf, PTYBUFSIZE)) > 0) {
147 ptycur = 1;
148 return ptybuf[0];
150 return -1;
153 static void empty_rows(int sr, int er)
155 memset(SQRADDR(sr, 0), 0, (er - sr) * sizeof(*screen) * pad_cols());
158 static void blank_rows(int sr, int er)
160 empty_rows(sr, er);
161 lazy_draw(sr, er);
162 lazy_cursor(1);
165 static void scroll_screen(int sr, int nr, int n)
167 lazy_cursor(0);
168 memmove(SQRADDR(sr + n, 0), SQRADDR(sr, 0),
169 nr * pad_cols() * sizeof(*screen));
170 if (n > 0)
171 empty_rows(sr, sr + n);
172 else
173 empty_rows(sr + nr + n, sr + nr);
174 lazy_draw(MIN(sr, sr + n), MAX(sr + nr, sr + nr + n));
175 lazy_cursor(1);
178 static void insert_lines(int n)
180 int sr = MAX(top, row);
181 int nr = bot - row - n;
182 if (nr > 0)
183 scroll_screen(sr, nr, n);
186 static void delete_lines(int n)
188 int r = MAX(top, row);
189 int sr = r + n;
190 int nr = bot - r - n;
191 if (nr > 0)
192 scroll_screen(sr, nr, -n);
195 static void move_cursor(int r, int c)
197 int t, b;
198 lazy_cursor(0);
199 t = origin() ? top : 0;
200 b = origin() ? bot : pad_rows();
201 row = MAX(t, MIN(r, b - 1));
202 col = MAX(0, MIN(c, pad_cols() - 1));
203 lazy_cursor(1);
206 static void advance(int dr, int dc, int scrl)
208 int r = row + dr;
209 int c = col + dc;
210 if (c >= pad_cols()) {
211 if (!scrl || (mode & MODE_NOWRAP)) {
212 c = pad_cols() - 1;
213 } else {
214 r++;
215 c = 0;
218 if (r >= bot && scrl) {
219 int n = bot - r - 1;
220 int nr = (bot - top) + n;
221 scroll_screen(top + -n, nr, n);
223 if (r < top && scrl) {
224 int n = top - r;
225 int nr = (bot - top) - n;
226 scroll_screen(top, nr, n);
228 r = MIN(bot - 1, MAX(top, r));
229 move_cursor(r, MAX(0, c));
232 void term_send(int c)
234 unsigned char b = (unsigned char) c;
235 if (term->fd)
236 write(term->fd, &b, 1);
239 void term_sendstr(char *s)
241 if (term->fd)
242 write(term->fd, s, strlen(s));
245 static void setmode(int m)
247 if (m == 0) {
248 fg = FGCOLOR;
249 bg = BGCOLOR;
251 if (m == 1)
252 fg = fg | 0x08;
253 if (m == 7) {
254 int t = fg;
255 fg = bg;
256 bg = t;
258 if (m >= 30 && m <= 37)
259 fg = m - 30;
260 if (m >= 40 && m <= 47)
261 bg = m - 40;
264 static void kill_chars(int sc, int ec)
266 int i;
267 for (i = sc; i < ec; i++)
268 lazy_put(' ', row, i);
269 lazy_cursor(1);
272 static void move_chars(int sc, int nc, int n)
274 lazy_cursor(0);
275 memmove(SQRADDR(row, sc + n), SQRADDR(row, sc),
276 nc * sizeof(*screen));
277 if (n > 0)
278 memset(SQRADDR(row, sc), 0, n * sizeof(*screen));
279 else
280 memset(SQRADDR(row, pad_rows() + n), 0, -n * sizeof(*screen));
281 lazy_drawcols(row, MIN(sc, sc + n), pad_cols());
282 lazy_cursor(1);
285 static void delete_chars(int n)
287 move_chars(col + n, pad_cols(), -n);
290 static void insert_chars(int n)
292 int nc = pad_cols() - col - n;
293 move_chars(col, nc, n);
296 static void term_blank(void)
298 memset(screen, 0, MAXCHARS * sizeof(*screen));
299 if (visible) {
300 pad_blank(bg);
301 lazy_clean();
305 static void ctlseq(void);
306 void term_read(void)
308 ctlseq();
309 lazy = 1;
310 while (ptycur < ptylen)
311 ctlseq();
312 lazy_flush();
313 lazy = 0;
316 void term_exec(char *cmd)
318 bot = pad_rows();
319 if ((term->pid = forkpty(&term->fd, NULL, NULL, NULL)) == -1) {
320 perror("failed to fork");
321 term->fd = 0;
322 return;
324 if (!term->pid) {
325 setenv("TERM", "linux", 1);
326 execlp(cmd, cmd, NULL);
327 exit(1);
329 fcntl(term->fd, F_SETFD, fcntl(term->fd, F_GETFD) | FD_CLOEXEC);
330 fcntl(term->fd, F_SETFL, fcntl(term->fd, F_GETFL) | O_NONBLOCK);
331 setsize();
332 setmode(0);
333 term_blank();
336 static void misc_save(struct term_state *state)
338 state->row = row;
339 state->col = col;
340 state->fg = fg;
341 state->bg = bg;
342 state->top = top;
343 state->bot = bot;
344 state->mode = mode;
347 static void misc_load(struct term_state *state)
349 row = state->row;
350 col = state->col;
351 fg = state->fg;
352 bg = state->bg;
353 top = state->top;
354 bot = state->bot;
355 mode = state->mode;
358 void term_save(struct term *term)
360 visible = 0;
361 misc_save(&term->cur);
364 void term_load(struct term *t, int flags)
366 term = t;
367 misc_load(&term->cur);
368 screen = term->screen;
369 visible = flags;
370 if (term->fd && flags == TERM_REDRAW) {
371 lazy_draw(0, pad_rows());
372 lazy_cursor(1);
374 if (!term->fd && flags)
375 pad_blank(0);
378 void term_end(void)
380 term->fd = 0;
381 row = col = 0;
382 fg = 0;
383 bg = 0;
384 term_blank();
387 void set_region(int t, int b)
389 top = MIN(pad_rows(), MAX(0, t - 1));
390 bot = MIN(pad_rows(), MAX(0, b ? b : pad_rows()));
391 if (origin())
392 move_cursor(top, 0);
395 #include "vt102.c"