source separated to alot of files (don't know if it's better this way, but...)
[k8sterm.git] / src / ttyutils.c
blob01f406169b57524433defe0a52f5ac798b5c4eae
1 static void tsetdirt (int top, int bot) {
2 LIMIT(top, 0, term->row-1);
3 LIMIT(bot, 0, term->row-1);
4 for (int y = top; y <= bot; ++y) markDirty(y, 2);
8 static void tfulldirt (void) {
9 tsetdirt(0, term->row-1);
13 static void tmoveto (int x, int y) {
14 LIMIT(x, 0, term->col-1);
15 LIMIT(y, 0, term->row-1);
16 term->c.state &= ~CURSOR_WRAPNEXT;
17 if (term->c.x != x || term->c.y != y) {
18 term->c.x = x;
19 term->c.y = y;
20 setWantRedraw();
25 static void tclearregion (int x1, int y1, int x2, int y2) {
26 int temp;
28 //fprintf(stderr, "tclearregion: (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
29 if (x1 > x2) { temp = x1; x1 = x2; x2 = temp; }
30 if (y1 > y2) { temp = y1; y1 = y2; y2 = temp; }
31 LIMIT(x1, 0, term->col-1);
32 LIMIT(x2, 0, term->col-1);
33 LIMIT(y1, 0, term->row-1);
34 LIMIT(y2, 0, term->row-1);
35 //fprintf(stderr, " tclearregion: (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
36 for (int y = y1; y <= y2; ++y) {
37 Line l = term->line[y];
39 markDirty(y, (x1 <= 0 && x2 >= term->col-1) ? 2 : 1);
40 for (int x = x1; x <= x2; ++x) {
41 l[x].fg = term->c.attr.fg;
42 l[x].bg = term->c.attr.bg;
43 l[x].state = GLYPH_DIRTY;
44 l[x].attr = ATTR_NULL|(term->c.attr.attr&(ATTR_DEFFG|ATTR_DEFBG));
45 l[x].c[0] = ' ';
46 if (term->sel.bx != -1 && selected(x, y)) selhide();
48 l[term->col-1].state &= ~GLYPH_WRAP;
53 static void tcursor (int mode) {
54 if (mode == CURSOR_SAVE) {
55 term->csaved = term->c;
56 } else if (mode == CURSOR_LOAD) {
57 term->c = term->csaved;
58 tmoveto(term->c.x, term->c.y);
59 setWantRedraw();
64 static void tadjustmaxhistory (int maxh) {
65 if (term != NULL) {
66 LIMIT(maxh, 0, 65535);
67 if (term->maxhistory < maxh) {
68 Line *nl;
69 int newlc = term->linecount+(maxh-term->maxhistory);
71 // add history lines
72 if ((nl = realloc(term->line, sizeof(Line)*newlc)) != NULL) {
73 Glyph g;
75 term->topline = 0;
76 term->line = nl;
77 g.state = GLYPH_DIRTY;
78 g.attr = ATTR_NULL|ATTR_DEFFG|ATTR_DEFBG;
79 g.fg = term->deffg;
80 g.bg = term->defbg;
81 g.c[0] = ' ';
82 g.c[1] = 0;
83 for (int y = term->linecount; y < newlc; ++y) {
84 term->line[y] = calloc(term->col, sizeof(Glyph));
85 for (int x = 0; x < term->col; ++x) term->line[y][x] = g;
87 term->maxhistory = maxh;
88 term->linecount = newlc;
90 } else if (term->maxhistory > maxh) {
91 Line *nl;
93 term->topline = 0;
94 // remove history lines
95 while (term->linecount > term->row+maxh) free(term->line[--term->linecount]);
96 if ((nl = realloc(term->line, sizeof(Line)*term->linecount)) != NULL) term->line = nl;
97 term->maxhistory = maxh;
103 static void tswapscreen (void) {
104 selhide();
105 for (int f = 0; f < term->row; ++f) {
106 Line t = term->line[f];
108 term->line[f] = term->alt[f];
109 term->alt[f] = t;
111 term->mode ^= MODE_ALTSCREEN;
112 tfulldirt();
113 term->justSwapped = 1;
117 //FIXME: works bad with history
118 //FIXME: ugly code
119 static void selscroll (int orig, int n, int tohistory) {
120 int docopy = 0;
122 if (term->sel.bx == -1) return;
124 tfulldirt(); // just in case
125 if (!tohistory) {
126 if (BETWEEN(term->sel.by, orig, term->bot) || BETWEEN(term->sel.ey, orig, term->bot)) {
127 if ((term->sel.by += n) > term->bot || (term->sel.ey += n) < term->top) {
128 selclear(NULL);
129 return;
131 if (term->sel.by < term->top) {
132 term->sel.by = term->top;
133 term->sel.bx = 0;
134 docopy = 1;
136 if (term->sel.ey > term->bot) {
137 term->sel.ey = term->bot;
138 term->sel.ex = term->col;
139 docopy = 1;
141 term->sel.b.x = term->sel.bx;
142 term->sel.b.y = term->sel.by;
143 term->sel.e.x = term->sel.ex;
144 term->sel.e.y = term->sel.ey;
146 } else {
147 // tohistory!=0; always scrolls full screen up (n == -1)
148 //fprintf(stderr, "selscroll to history\n");
149 term->sel.by += n;
150 term->sel.ey += n;
151 //fprintf(stderr, " by=%d; ey=%d; maxhistory=%d\n", term->sel.by, term->sel.ey, term->maxhistory);
152 if (term->sel.ey < 0 && -(term->sel.ey) > term->maxhistory) {
153 // out of screen completely
154 selclear(NULL);
155 return;
157 if (term->sel.by < 0 && -(term->sel.by) > term->maxhistory) {
158 term->sel.by = -term->maxhistory;
159 term->sel.bx = 0;
160 docopy = 1;
162 term->sel.b.x = term->sel.bx;
163 term->sel.b.y = term->sel.by;
164 term->sel.e.x = term->sel.ex;
165 term->sel.e.y = term->sel.ey;
168 if (docopy) selcopy();
172 static void tscrolldown (int orig, int n) {
173 Line temp;
175 LIMIT(n, 0, term->bot-orig+1);
176 if (n < 1) return;
177 selscroll(orig, n, 0);
178 //fprintf(stderr, "tscrolldown(%d, %d)\n", orig, n);
179 tclearregion(0, term->bot-n+1, term->col-1, term->bot);
180 for (int f = term->bot; f >= orig+n; --f) {
181 temp = term->line[f];
182 term->line[f] = term->line[f-n];
183 term->line[f-n] = temp;
184 markDirty(f, 2);
185 markDirty(f-n, 2);
190 static void tscrollup (int orig, int n, int tohistory) {
191 Line temp;
193 if (term == NULL) return;
194 LIMIT(n, 0, term->bot-orig+1);
195 if (n < 1) return;
196 //fprintf(stderr, "tscrollup(%d, %d)\n", orig, n);
197 if (tohistory && !IS_SET(MODE_ALTSCREEN) && term->maxhistory > 0) {
198 Line l = term->line[term->linecount-1];
200 for (int f = term->linecount-1; f > term->row; --f) term->line[f] = term->line[f-1];
201 term->line[term->row] = l;
202 for (int x = 0; x < term->col; ++x) l[x] = term->line[0][x];
203 } else {
204 tohistory = 0;
207 selscroll(orig, -n, tohistory);
208 //tclearregion(0, orig, term->col-1, orig+n-1);
209 for (int f = orig; f <= term->bot-n; ++f) {
210 temp = term->line[f];
211 term->line[f] = term->line[f+n];
212 term->line[f+n] = temp;
213 markDirty(f, 2);
214 markDirty(f+n, 2);
216 tclearregion(0, term->bot-n+1, term->col-1, term->bot);
220 static inline void tsetcharwrap (int y, int wrap) {
221 if (y >= 0 && y < term->row) {
222 if (wrap) term->line[y][term->col-1].state |= GLYPH_WRAP;
223 else term->line[y][term->col-1].state &= ~GLYPH_WRAP;
228 static void tnewline (int first_col) {
229 int y = term->c.y;
231 tsetcharwrap(y, (first_col == 2)); // 2: wrapping
232 if (y == term->bot) tscrollup(term->top, 1, 1); else ++y;
233 tmoveto(first_col ? 0 : term->c.x, y);
237 static void csiparse (void) {
238 const char *p = term->escseq.buf;
240 term->escseq.narg = 0;
241 if (*p == '?') { term->escseq.priv = 1; ++p; }
242 while (p < term->escseq.buf+term->escseq.len) {
243 int n = term->escseq.arg[term->escseq.narg];
245 for (; *p && isdigit(*p); ++p) n = n*10+(p[0]-'0');
246 term->escseq.arg[term->escseq.narg] = n;
248 if (*p == ';' && term->escseq.narg+1 < ESC_ARG_SIZ) {
249 ++term->escseq.narg;
250 ++p;
251 } else {
252 term->escseq.mode = *p;
253 ++term->escseq.narg;
254 break;
260 static void tsetchar (const char *c) {
261 char ub[UTF_SIZ];
262 int rev = 0, gfx = 0;
263 int x = term->c.x, y = term->c.y;
265 if (x < 0 || x >= term->col || y < 0 || y >= term->row) return;
267 if (!term->needConv && unimap != NULL && (unsigned char)c[0] >= 0x80) {
268 uint32 cc;
270 utf8decode(&cc, c);
271 if (cc <= 65535) {
272 ushort uc = unimap[cc];
274 //fprintf(stderr, "unimap: %d [%02X] 0x%04x -> 0x%04x\n", (unsigned char)c[0], cc, uc);
275 if (uc) {
276 if (uc == 127) {
277 // inversed space
278 rev = 1;
279 ub[0] = ' ';
280 } else {
281 if (uc&0x8000) {
282 ub[0] = (uc&0x7f);
283 gfx = 1;
284 } else {
285 utf8encode(ub, uc);
288 c = ub;
292 markDirty(y, 1);
294 term->line[y][x] = term->c.attr;
295 if (rev) term->line[y][x].attr ^= ATTR_REVERSE;
296 if (gfx || (term->mode&term->charset)) {
297 term->line[y][x].attr |= ATTR_GFX;
298 } else {
299 term->line[y][x].attr &= ~ATTR_GFX;
302 term->line[y][x].state = (GLYPH_SET | GLYPH_DIRTY);
303 memcpy(term->line[y][x].c, c, UTF_SIZ);
305 if (IS_GFX(term->line[y][x].attr)) {
306 unsigned char c = (unsigned char)(term->line[y][x].c[0]);
308 if (c > 95 && c < 128) term->line[y][x].c[0] -= 95;
309 else if (c > 127) term->line[y][x].c[0] = ' ';
311 if (term->sel.bx != -1 && selected(x, y)) selhide();
312 //dlogf("tsetchar(%d,%d): [%c] (%d); dirty=%d\n", x, y, c[0], term->wantRedraw, term->dirty[y]);
316 static void tdeletechar (int n) {
317 int src = term->c.x+n;
318 int dst = term->c.x;
319 int size = term->col-src;
321 markDirty(term->c.y, 2);
322 if (src >= term->col) {
323 tclearregion(term->c.x, term->c.y, term->col-1, term->c.y);
324 } else {
325 memmove(&term->line[term->c.y][dst], &term->line[term->c.y][src], size*sizeof(Glyph));
326 tclearregion(term->col-n, term->c.y, term->col-1, term->c.y);
331 static void tinsertblank (int n) {
332 int src = term->c.x;
333 int dst = src+n;
334 int size = term->col-dst;
336 markDirty(term->c.y, 2);
337 if (dst >= term->col) {
338 tclearregion(term->c.x, term->c.y, term->col-1, term->c.y);
339 } else {
340 memmove(&term->line[term->c.y][dst], &term->line[term->c.y][src], size*sizeof(Glyph));
341 tclearregion(src, term->c.y, dst-1, term->c.y);
346 static void tinsertblankline (int n) {
347 if (term->c.y < term->top || term->c.y > term->bot) return;
348 tscrolldown(term->c.y, n);
352 static void tdeleteline (int n) {
353 if (term->c.y < term->top || term->c.y > term->bot) return;
354 tscrollup(term->c.y, n, 0);
358 static void tsetscroll (int t, int b) {
359 int temp;
361 LIMIT(t, 0, term->row-1);
362 LIMIT(b, 0, term->row-1);
363 if (t > b) {
364 temp = t;
365 t = b;
366 b = temp;
368 term->top = t;
369 term->bot = b;
373 static void tunshowhistory (void) {
374 if (term != NULL && term->topline != 0) {
375 term->topline = 0;
376 term->wantRedraw = 1;
377 term->lastDrawTime = 0;
382 static void tsendfocusevent (int focused) {
383 if (term != NULL && IS_SET(MODE_FOCUSEVT)) {
384 ttywritestr("\x1b[");
385 ttywrite(focused?"I":"O", 1);
390 ////////////////////////////////////////////////////////////////////////////////
391 // tty utilities
392 static void tresetmode (void) {
393 term->c.attr.fg = term->deffg;
394 term->c.attr.bg = term->defbg;
395 term->esc = 0;
396 term->top = 0;
397 term->bot = term->row-1;
398 term->mode = MODE_WRAP/* | MODE_MOUSEBTN*/ | MODE_GFX1;
399 term->mousemode = 1000;
400 term->charset = MODE_GFX0;
401 term->c.state = CURSOR_DEFAULT;
402 term->c.attr.attr = ATTR_NULL|ATTR_DEFFG|ATTR_DEFBG;
403 term->c.attr.fg = term->c.attr.bg = 0;
404 tcursor(CURSOR_SAVE);
408 static void treset (void) {
409 Glyph g;
411 term->c = (TCursor){{
412 .attr = ATTR_NULL|ATTR_DEFFG|ATTR_DEFBG,
413 .fg = 0,
414 .bg = 0
415 }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
417 g.state = GLYPH_DIRTY;
418 g.attr = term->c.attr.attr;
419 g.fg = term->c.attr.fg;
420 g.bg = term->c.attr.bg;
421 g.c[0] = ' ';
422 g.c[1] = 0;
424 tresetmode();
425 //tclearregion(0, 0, term->col-1, term->row-1);
426 for (int y = 0; y < term->row; ++y) {
427 markDirty(y, 2);
428 for (int x = 0; x < term->col; ++x) term->alt[y][x] = term->line[y][x] = g;
430 for (int y = term->row; y < term->linecount; ++y) {
431 for (int x = 0; x < term->col; ++x) term->line[y][x] = g;
434 term->topline = 0;
435 tfulldirt();
439 static int tinitialize (int col, int row) {
440 //memset(term, 0, sizeof(Term));
441 //term->needConv = needConversion ? 1 : 0;
442 term->wrbufsize = WBUFSIZ;
443 term->deffg = term->deffg;
444 term->defbg = term->defbg;
445 term->row = row;
446 term->col = col;
447 term->dirty = calloc(term->row, sizeof(*term->dirty));
448 term->maxhistory = opt_maxhistory;
449 term->linecount = term->maxhistory+term->row;
450 term->line = calloc(term->linecount, sizeof(Line));
451 term->alt = calloc(term->row, sizeof(Line));
452 for (int y = 0; y < term->linecount; ++y) term->line[y] = calloc(term->col, sizeof(Glyph));
453 for (int y = 0; y < term->row; ++y) term->alt[y] = calloc(term->col, sizeof(Glyph));
454 /* setup screen */
455 treset();
456 return 1;