font: better font baseline detection
[fbpad.git] / term.c
blobceac4a6c41e6a4e450099ae8835733cb78fe67ea
1 #include <ctype.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <poll.h>
5 #include <pty.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "config.h"
12 #include "pad.h"
13 #include "util.h"
14 #include "term.h"
16 #define MODE_CURSOR 0x01
17 #define MODE_WRAP 0x02
18 #define MODE_ORIGIN 0x04
19 #define MODE_AUTOCR 0x08
20 #define MODE_DEFAULT (MODE_CURSOR | MODE_WRAP)
21 #define BIT_SET(i, b, val) ((val) ? ((i) | (b)) : ((i) & ~(b)))
22 #define SQRADDR(r, c) (screen + (r) * pad_cols() + (c))
24 static struct term *term;
25 static struct square *screen;
26 static int row, col;
27 static int fg, bg;
28 static int top, bot;
29 static int mode;
30 static int visible;
32 #define MAXLINES (1 << 13)
33 static int dirty[MAXLINES];
34 static int lazy;
36 static void _term_show(int r, int c, int cursor)
38 struct square *sqr = SQRADDR(r, c);
39 int fgcolor = sqr->c ? sqr->fg : fg;
40 int bgcolor = sqr->c ? sqr->bg : bg;
41 if (cursor && mode & MODE_CURSOR) {
42 int t = fgcolor;
43 fgcolor = bgcolor;
44 bgcolor = t;
46 if (visible)
47 pad_put(sqr->c, r, c, fgcolor, bgcolor);
50 static void _draw_row(int r)
52 int i;
53 pad_blankrow(r, bg);
54 for (i = 0; i < pad_cols(); i++) {
55 struct square *s = SQRADDR(r, i);
56 if (s->c && (s->c != ' ' || s->bg != bg))
57 _term_show(r, i, 0);
61 static void lazy_draw(int sr, int er)
63 int i;
64 if (!visible)
65 return;
66 for (i = sr; i < er; i++) {
67 if (lazy)
68 dirty[i] = 1;
69 else
70 _draw_row(i);
74 static void lazy_drawcols(int r, int sc, int ec)
76 int i;
77 if (!visible)
78 return;
79 if (lazy) {
80 dirty[r] = 1;
81 } else {
82 for (i = sc; i < ec; i++)
83 _term_show(r, i, 0);
87 static void lazy_put(int ch, int r, int c)
89 struct square *sqr = SQRADDR(r, c);
90 sqr->c = ch;
91 sqr->fg = fg;
92 sqr->bg = bg;
93 if (!visible)
94 return;
95 if (lazy)
96 dirty[r] = 1;
97 else
98 _term_show(r, c, 0);
101 static void lazy_cursor(int put)
103 if (!visible)
104 return;
105 if (lazy)
106 dirty[row] = 1;
107 else
108 _term_show(row, col, put);
111 static void lazy_clean()
113 if (visible)
114 memset(dirty, 0, sizeof(*dirty) * MAXLINES);
117 static void lazy_flush()
119 int i;
120 if (!visible)
121 return;
122 _term_show(row, col, 0);
123 for (i = 0; i < pad_rows(); i++)
124 if (dirty[i])
125 _draw_row(i);
126 lazy_clean();
127 _term_show(row, col, 1);
130 static void term_redraw(void)
132 int i;
133 for (i = 0; i < pad_rows(); i++)
134 _draw_row(i);
135 _term_show(row, col, 1);
138 static int origin(void)
140 return mode & MODE_ORIGIN;
143 static void setsize(void)
145 struct winsize size;
146 size.ws_col = pad_cols();
147 size.ws_row = pad_rows();
148 size.ws_xpixel = 0;
149 size.ws_ypixel = 0;
150 ioctl(term->fd, TIOCSWINSZ, &size);
153 #define PTYBUFSIZE (1 << 13)
154 static char ptybuf[PTYBUFSIZE];
155 static int ptylen;
156 static int ptycur;
157 static void waitpty(void)
159 struct pollfd ufds[1];
160 ufds[0].fd = term->fd;
161 ufds[0].events = POLLIN;
162 poll(ufds, 1, -1);
165 static int readpty(void)
167 if (ptycur < ptylen)
168 return ptybuf[ptycur++];
169 if (!term->fd)
170 return -1;
171 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
172 if (ptylen == -1 && errno == EAGAIN) {
173 waitpty();
174 ptylen = read(term->fd, ptybuf, PTYBUFSIZE);
176 if (ptylen > 0) {
177 ptycur = 1;
178 return ptybuf[0];
180 return -1;
183 static void empty_rows(int sr, int er)
185 memset(SQRADDR(sr, 0), 0, (er - sr) * sizeof(*screen) * pad_cols());
188 static void blank_rows(int sr, int er)
190 empty_rows(sr, er);
191 lazy_draw(sr, er);
192 lazy_cursor(1);
195 static void scroll_screen(int sr, int nr, int n)
197 lazy_cursor(0);
198 memmove(SQRADDR(sr + n, 0), SQRADDR(sr, 0),
199 nr * pad_cols() * sizeof(*screen));
200 if (n > 0)
201 empty_rows(sr, sr + n);
202 else
203 empty_rows(sr + nr + n, sr + nr);
204 lazy_draw(MIN(sr, sr + n), MAX(sr + nr, sr + nr + n));
205 lazy_cursor(1);
208 static void insert_lines(int n)
210 int sr = MAX(top, row);
211 int nr = bot - row - n;
212 if (nr > 0)
213 scroll_screen(sr, nr, n);
216 static void delete_lines(int n)
218 int r = MAX(top, row);
219 int sr = r + n;
220 int nr = bot - r - n;
221 if (nr > 0)
222 scroll_screen(sr, nr, -n);
225 static void move_cursor(int r, int c)
227 int t, b;
228 lazy_cursor(0);
229 t = origin() ? top : 0;
230 b = origin() ? bot : pad_rows();
231 row = MAX(t, MIN(r, b - 1));
232 col = MAX(0, MIN(c, pad_cols() - 1));
233 lazy_cursor(1);
236 static void advance(int dr, int dc, int scrl)
238 int r = row + dr;
239 int c = col + dc;
240 if (c >= pad_cols()) {
241 if (scrl && mode & MODE_WRAP) {
242 r++;
243 c = 0;
244 } else {
245 c = pad_cols() - 1;
248 if (r >= bot && scrl) {
249 int n = bot - r - 1;
250 int nr = (bot - top) + n;
251 scroll_screen(top + -n, nr, n);
253 if (r < top && scrl) {
254 int n = top - r;
255 int nr = (bot - top) - n;
256 scroll_screen(top, nr, n);
258 r = MIN(bot - 1, MAX(top, r));
259 move_cursor(r, MAX(0, c));
262 void term_send(int c)
264 unsigned char b = (unsigned char) c;
265 if (term->fd)
266 write(term->fd, &b, 1);
269 static void term_sendstr(char *s)
271 if (term->fd)
272 write(term->fd, s, strlen(s));
275 static void setattr(int m)
277 if (m == 0) {
278 fg = FGCOLOR;
279 bg = BGCOLOR;
281 if (m == 1)
282 fg = fg | 0x08;
283 if (m == 7) {
284 int t = fg;
285 fg = bg;
286 bg = t;
288 if ((m / 10) == 3)
289 fg = m > 37 ? FGCOLOR : m - 30;
290 if ((m / 10) == 4)
291 bg = m > 47 ? BGCOLOR : m - 40;
294 static void kill_chars(int sc, int ec)
296 int i;
297 for (i = sc; i < ec; i++)
298 lazy_put(' ', row, i);
299 lazy_cursor(1);
302 static void move_chars(int sc, int nc, int n)
304 lazy_cursor(0);
305 memmove(SQRADDR(row, sc + n), SQRADDR(row, sc), nc * sizeof(*screen));
306 if (n > 0)
307 memset(SQRADDR(row, sc), 0, n * sizeof(*screen));
308 else
309 memset(SQRADDR(row, pad_cols() + n), 0, -n * sizeof(*screen));
310 lazy_drawcols(row, MIN(sc, sc + n), pad_cols());
311 lazy_cursor(1);
314 static void delete_chars(int n)
316 int sc = col + n;
317 int nc = pad_cols() - sc;
318 move_chars(sc, nc, -n);
321 static void insert_chars(int n)
323 int nc = pad_cols() - col - n;
324 move_chars(col, nc, n);
327 static void term_blank(void)
329 memset(screen, 0, MAXCHARS * sizeof(*screen));
330 if (visible) {
331 pad_blank(bg);
332 lazy_clean();
336 static void ctlseq(void);
337 void term_read(void)
339 ctlseq();
340 lazy = 1;
341 while (ptycur < ptylen)
342 ctlseq();
343 lazy_flush();
344 lazy = 0;
347 void term_exec(char *cmd)
349 memset(term, 0, sizeof(*term));
350 term->cur.bot = term->sav.bot = pad_rows();
351 term->cur.mode = MODE_DEFAULT;
352 term_load(term, visible);
353 if ((term->pid = forkpty(&term->fd, NULL, NULL, NULL)) == -1) {
354 perror("failed to fork");
355 term->fd = 0;
356 return;
358 if (!term->pid) {
359 setenv("TERM", "linux", 1);
360 execlp(cmd, cmd, NULL);
361 exit(1);
363 fcntl(term->fd, F_SETFD, fcntl(term->fd, F_GETFD) | FD_CLOEXEC);
364 fcntl(term->fd, F_SETFL, fcntl(term->fd, F_GETFL) | O_NONBLOCK);
365 setsize();
366 setattr(0);
367 term_blank();
370 static void misc_save(struct term_state *state)
372 state->row = row;
373 state->col = col;
374 state->fg = fg;
375 state->bg = bg;
376 state->top = top;
377 state->bot = bot;
378 state->mode = mode;
381 static void misc_load(struct term_state *state)
383 row = state->row;
384 col = state->col;
385 fg = state->fg;
386 bg = state->bg;
387 top = state->top;
388 bot = state->bot;
389 mode = state->mode;
392 void term_save(struct term *term)
394 visible = 0;
395 misc_save(&term->cur);
398 void term_load(struct term *t, int flags)
400 term = t;
401 misc_load(&term->cur);
402 screen = term->screen;
403 visible = flags;
404 if (flags == TERM_REDRAW) {
405 if (term->fd)
406 term_redraw();
407 else
408 pad_blank(0);
412 void term_end(void)
414 if (term->fd)
415 close(term->fd);
416 term->fd = 0;
417 row = col = 0;
418 fg = 0;
419 bg = 0;
420 term_blank();
423 static void set_region(int t, int b)
425 top = MIN(pad_rows(), MAX(0, t - 1));
426 bot = MIN(pad_rows(), MAX(0, b ? b : pad_rows()));
427 if (origin())
428 move_cursor(top, 0);
431 #include "vt102.c"