aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h5
-rw-r--r--st.c318
2 files changed, 178 insertions, 145 deletions
diff --git a/config.h b/config.h
index 0e04ab1..a7fc58c 100644
--- a/config.h
+++ b/config.h
@@ -31,10 +31,6 @@ static Key key[] = {
31 { XK_End, "\033[4~" }, 31 { XK_End, "\033[4~" },
32 { XK_Prior, "\033[5~" }, 32 { XK_Prior, "\033[5~" },
33 { XK_Next, "\033[6~" }, 33 { XK_Next, "\033[6~" },
34 { XK_Left, "\033[D" },
35 { XK_Right, "\033[C" },
36 { XK_Up, "\033[A" },
37 { XK_Down, "\033[B" },
38}; 34};
39 35
40static char gfx[] = { 36static char gfx[] = {
@@ -70,4 +66,5 @@ static char gfx[] = {
70 ['l'] = '+', 66 ['l'] = '+',
71 ['k'] = '+', 67 ['k'] = '+',
72 ['x'] = '|', 68 ['x'] = '|',
69 [255] = 0,
73}; 70};
diff --git a/st.c b/st.c
index ca5fb5d..fcb3d65 100644
--- a/st.c
+++ b/st.c
@@ -23,10 +23,10 @@
23#define TNAME "xterm" 23#define TNAME "xterm"
24 24
25/* Arbitrary sizes */ 25/* Arbitrary sizes */
26#define TITLESIZ 256 26#define ESC_TITLE_SIZ 256
27#define ESCSIZ 256 27#define ESC_BUF_SIZ 256
28#define ESCARGSIZ 16 28#define ESC_ARG_SIZ 16
29#define MAXDRAWBUF 1024 29#define DRAW_BUF_SIZ 1024
30 30
31#define SERRNO strerror(errno) 31#define SERRNO strerror(errno)
32#define MIN(a, b) ((a) < (b) ? (a) : (b)) 32#define MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -38,21 +38,19 @@
38#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) 38#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
39 39
40/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */ 40/* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */
41enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4, ATgfx=8 }; 41enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 };
42enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSsave, CSload }; 42enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, CURSOR_SAVE, CURSOR_LOAD };
43enum { CRset=1, CRupdate=2 }; 43enum { GLYPH_SET=1, GLYPH_DIRTY=2 };
44enum { TMwrap=1, TMinsert=2 }; 44enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 };
45enum { ESCin=1, ESCcsi=2, ESCosc=4, ESCtitle=8, ESCcharset=16 }; 45enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 };
46enum { SCupdate, SCredraw }; 46enum { SCREEN_UPDATE, SCREEN_REDRAW };
47
48typedef int Color;
49 47
50typedef struct { 48typedef struct {
51 char c; /* character code */ 49 char c; /* character code */
52 char mode; /* attribute flags */ 50 char mode; /* attribute flags */
53 Color fg; /* foreground */ 51 int fg; /* foreground */
54 Color bg; /* background */ 52 int bg; /* background */
55 char state; /* state flag */ 53 char state; /* state flags */
56} Glyph; 54} Glyph;
57 55
58typedef Glyph* Line; 56typedef Glyph* Line;
@@ -67,11 +65,11 @@ typedef struct {
67/* CSI Escape sequence structs */ 65/* CSI Escape sequence structs */
68/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */ 66/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
69typedef struct { 67typedef struct {
70 char buf[ESCSIZ]; /* raw string */ 68 char buf[ESC_BUF_SIZ]; /* raw string */
71 int len; /* raw string length */ 69 int len; /* raw string length */
72 char priv; 70 char priv;
73 int arg[ESCARGSIZ]; 71 int arg[ESC_ARG_SIZ];
74 int narg; /* nb of args */ 72 int narg; /* nb of args */
75 char mode; 73 char mode;
76} CSIEscape; 74} CSIEscape;
77 75
@@ -83,9 +81,9 @@ typedef struct {
83 TCursor c; /* cursor */ 81 TCursor c; /* cursor */
84 int top; /* top scroll limit */ 82 int top; /* top scroll limit */
85 int bot; /* bottom scroll limit */ 83 int bot; /* bottom scroll limit */
86 int mode; /* terminal mode */ 84 int mode; /* terminal mode flags */
87 int esc; 85 int esc; /* escape state flags */
88 char title[TITLESIZ]; 86 char title[ESC_TITLE_SIZ];
89 int titlelen; 87 int titlelen;
90} Term; 88} Term;
91 89
@@ -102,7 +100,7 @@ typedef struct {
102 100
103typedef struct { 101typedef struct {
104 KeySym k; 102 KeySym k;
105 char s[ESCSIZ]; 103 char s[ESC_BUF_SIZ];
106} Key; 104} Key;
107 105
108#include "config.h" 106#include "config.h"
@@ -126,8 +124,8 @@ static void csiparse(void);
126static void csireset(void); 124static void csireset(void);
127 125
128static void tclearregion(int, int, int, int); 126static void tclearregion(int, int, int, int);
129static void tcpos(int);
130static void tcursor(int); 127static void tcursor(int);
128static void tmovecursor(int);
131static void tdeletechar(int); 129static void tdeletechar(int);
132static void tdeleteline(int); 130static void tdeleteline(int);
133static void tinsertblank(int); 131static void tinsertblank(int);
@@ -187,7 +185,7 @@ tdump(void) {
187 putchar('#'); 185 putchar('#');
188 else { 186 else {
189 c = term.line[row][col]; 187 c = term.line[row][col];
190 putchar(c.state & CRset ? c.c : '.'); 188 putchar(c.state & GLYPH_SET ? c.c : '.');
191 } 189 }
192 } 190 }
193 putchar('\n'); 191 putchar('\n');
@@ -218,7 +216,7 @@ xbell(void) { /* visual bell */
218 XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); 216 XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
219 XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); 217 XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
220 /* usleep(30000); */ 218 /* usleep(30000); */
221 draw(SCredraw); 219 draw(SCREEN_REDRAW);
222} 220}
223 221
224void 222void
@@ -281,13 +279,10 @@ ttyread(void) {
281 char buf[BUFSIZ] = {0}; 279 char buf[BUFSIZ] = {0};
282 int ret; 280 int ret;
283 281
284 switch(ret = read(cmdfd, buf, BUFSIZ)) { 282 if((ret = read(cmdfd, buf, BUFSIZ)) < 0)
285 case -1:
286 die("Couldn't read from shell: %s\n", SERRNO); 283 die("Couldn't read from shell: %s\n", SERRNO);
287 break; 284 else
288 default:
289 tputs(buf, ret); 285 tputs(buf, ret);
290 }
291} 286}
292 287
293void 288void
@@ -308,14 +303,13 @@ ttyresize(int x, int y) {
308} 303}
309 304
310void 305void
311tcpos(int mode) { 306tcursor(int mode) {
312 static int x = 0; 307 static TCursor c;
313 static int y = 0; 308
314 309 if(mode == CURSOR_SAVE)
315 if(mode == CSsave) 310 c = term.c;
316 x = term.c.x, y = term.c.y; 311 else if(mode == CURSOR_LOAD)
317 else if(mode == CSload) 312 term.c = c, tmoveto(c.x, c.y);
318 tmoveto(x, y);
319} 313}
320 314
321void 315void
@@ -323,9 +317,9 @@ tnew(int col, int row) { /* screen size */
323 term.row = row, term.col = col; 317 term.row = row, term.col = col;
324 term.top = 0, term.bot = term.row - 1; 318 term.top = 0, term.bot = term.row - 1;
325 /* mode */ 319 /* mode */
326 term.mode = TMwrap; 320 term.mode = MODE_WRAP;
327 /* cursor */ 321 /* cursor */
328 term.c.attr.mode = ATnone; 322 term.c.attr.mode = ATTR_NULL;
329 term.c.attr.fg = DefaultFG; 323 term.c.attr.fg = DefaultFG;
330 term.c.attr.bg = DefaultBG; 324 term.c.attr.bg = DefaultBG;
331 term.c.x = term.c.y = 0; 325 term.c.x = term.c.y = 0;
@@ -370,7 +364,7 @@ csiparse(void) {
370 escseq.arg[escseq.narg] *= 10; 364 escseq.arg[escseq.narg] *= 10;
371 escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */; 365 escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
372 } 366 }
373 if(*p == ';' && escseq.narg+1 < ESCARGSIZ) 367 if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ)
374 escseq.narg++, p++; 368 escseq.narg++, p++;
375 else { 369 else {
376 escseq.mode = *p; 370 escseq.mode = *p;
@@ -387,27 +381,27 @@ tmoveto(int x, int y) {
387} 381}
388 382
389void 383void
390tcursor(int dir) { 384tmovecursor(int dir) {
391 int xf = term.c.x, yf = term.c.y; 385 int xf = term.c.x, yf = term.c.y;
392 386
393 switch(dir) { 387 switch(dir) {
394 case CSup: 388 case CURSOR_UP:
395 yf--; 389 yf--;
396 break; 390 break;
397 case CSdown: 391 case CURSOR_DOWN:
398 yf++; 392 yf++;
399 break; 393 break;
400 case CSleft: 394 case CURSOR_LEFT:
401 xf--; 395 xf--;
402 if(term.mode & TMwrap && xf < 0) { 396 if(term.mode & MODE_WRAP && xf < 0) {
403 xf = term.col-1, yf--; 397 xf = term.col-1, yf--;
404 if(yf < term.top) 398 if(yf < term.top)
405 yf = term.top, xf = 0; 399 yf = term.top, xf = 0;
406 } 400 }
407 break; 401 break;
408 case CSright: 402 case CURSOR_RIGHT:
409 xf++; 403 xf++;
410 if(term.mode & TMwrap && xf >= term.col) { 404 if(term.mode & MODE_WRAP && xf >= term.col) {
411 xf = 0, yf++; 405 xf = 0, yf++;
412 if(yf > term.bot) 406 if(yf > term.bot)
413 yf = term.bot, tscroll(); 407 yf = term.bot, tscroll();
@@ -421,7 +415,7 @@ void
421tsetchar(char c) { 415tsetchar(char c) {
422 term.line[term.c.y][term.c.x] = term.c.attr; 416 term.line[term.c.y][term.c.x] = term.c.attr;
423 term.line[term.c.y][term.c.x].c = c; 417 term.line[term.c.y][term.c.x].c = c;
424 term.line[term.c.y][term.c.x].state |= CRset | CRupdate; 418 term.line[term.c.y][term.c.x].state |= GLYPH_SET | GLYPH_DIRTY;
425} 419}
426 420
427void 421void
@@ -477,7 +471,7 @@ tsetlinestate(int n, int state) {
477} 471}
478 472
479void 473void
480tinsertblankline (int n) { 474tinsertblankline(int n) {
481 int i; 475 int i;
482 Line blank; 476 Line blank;
483 int bot = term.bot; 477 int bot = term.bot;
@@ -497,8 +491,8 @@ tinsertblankline (int n) {
497 term.line[i-n] = blank; 491 term.line[i-n] = blank;
498 /* blank it */ 492 /* blank it */
499 memset(blank, 0, term.col * sizeof(Glyph)); 493 memset(blank, 0, term.col * sizeof(Glyph));
500 tsetlinestate(i, CRupdate); 494 tsetlinestate(i, GLYPH_DIRTY);
501 tsetlinestate(i-n, CRupdate); 495 tsetlinestate(i-n, GLYPH_DIRTY);
502 } 496 }
503} 497}
504 498
@@ -523,8 +517,8 @@ tdeleteline(int n) {
523 term.line[i+n] = blank; 517 term.line[i+n] = blank;
524 /* blank it */ 518 /* blank it */
525 memset(blank, 0, term.col * sizeof(Glyph)); 519 memset(blank, 0, term.col * sizeof(Glyph));
526 tsetlinestate(i, CRupdate); 520 tsetlinestate(i, GLYPH_DIRTY);
527 tsetlinestate(i-n, CRupdate); 521 tsetlinestate(i-n, GLYPH_DIRTY);
528 } 522 }
529} 523}
530 524
@@ -535,30 +529,30 @@ tsetattr(int *attr, int l) {
535 for(i = 0; i < l; i++) { 529 for(i = 0; i < l; i++) {
536 switch(attr[i]) { 530 switch(attr[i]) {
537 case 0: 531 case 0:
538 term.c.attr.mode &= ~(ATreverse | ATunderline | ATbold); 532 term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD);
539 term.c.attr.fg = DefaultFG; 533 term.c.attr.fg = DefaultFG;
540 term.c.attr.bg = DefaultBG; 534 term.c.attr.bg = DefaultBG;
541 break; 535 break;
542 case 1: 536 case 1:
543 term.c.attr.mode |= ATbold; 537 term.c.attr.mode |= ATTR_BOLD;
544 break; 538 break;
545 case 4: 539 case 4:
546 term.c.attr.mode |= ATunderline; 540 term.c.attr.mode |= ATTR_UNDERLINE;
547 break; 541 break;
548 case 7: 542 case 7:
549 term.c.attr.mode |= ATreverse; 543 term.c.attr.mode |= ATTR_REVERSE;
550 break; 544 break;
551 case 8: 545 case 8:
552 term.c.hidden = CShide; 546 term.c.hidden = CURSOR_HIDE;
553 break; 547 break;
554 case 22: 548 case 22:
555 term.c.attr.mode &= ~ATbold; 549 term.c.attr.mode &= ~ATTR_BOLD;
556 break; 550 break;
557 case 24: 551 case 24:
558 term.c.attr.mode &= ~ATunderline; 552 term.c.attr.mode &= ~ATTR_UNDERLINE;
559 break; 553 break;
560 case 27: 554 case 27:
561 term.c.attr.mode &= ~ATreverse; 555 term.c.attr.mode &= ~ATTR_REVERSE;
562 break; 556 break;
563 case 39: 557 case 39:
564 term.c.attr.fg = DefaultFG; 558 term.c.attr.fg = DefaultFG;
@@ -593,57 +587,56 @@ tsetscroll(int t, int b) {
593 587
594void 588void
595csihandle(void) { 589csihandle(void) {
596 if(escseq.priv)
597 csidump();
598 switch(escseq.mode) { 590 switch(escseq.mode) {
599 unknown:
600 default: 591 default:
601 fprintf(stderr, "erresc: unknown sequence\n"); 592 unknown:
593 printf("erresc: unknown sequence -- ");
602 csidump(); 594 csidump();
603 /* die(""); */ 595 /* die(""); */
604 break; 596 break;
605 case '@': /* Insert <n> blank char */ 597 case '@': /* ICH -- Insert <n> blank char */
606 DEFAULT(escseq.arg[0], 1); 598 DEFAULT(escseq.arg[0], 1);
607 tinsertblank(escseq.arg[0]); 599 tinsertblank(escseq.arg[0]);
608 break; 600 break;
609 case 'A': /* Cursor <n> Up */ 601 case 'A': /* CUU -- Cursor <n> Up */
610 case 'e': 602 case 'e':
611 DEFAULT(escseq.arg[0], 1); 603 DEFAULT(escseq.arg[0], 1);
612 tmoveto(term.c.x, term.c.y-escseq.arg[0]); 604 tmoveto(term.c.x, term.c.y-escseq.arg[0]);
613 break; 605 break;
614 case 'B': /* Cursor <n> Down */ 606 case 'B': /* CUD -- Cursor <n> Down */
615 DEFAULT(escseq.arg[0], 1); 607 DEFAULT(escseq.arg[0], 1);
616 tmoveto(term.c.x, term.c.y+escseq.arg[0]); 608 tmoveto(term.c.x, term.c.y+escseq.arg[0]);
617 break; 609 break;
618 case 'C': /* Cursor <n> Forward */ 610 case 'C': /* CUF -- Cursor <n> Forward */
619 case 'a': 611 case 'a':
620 DEFAULT(escseq.arg[0], 1); 612 DEFAULT(escseq.arg[0], 1);
621 tmoveto(term.c.x+escseq.arg[0], term.c.y); 613 tmoveto(term.c.x+escseq.arg[0], term.c.y);
622 break; 614 break;
623 case 'D': /* Cursor <n> Backward */ 615 case 'D': /* CUB -- Cursor <n> Backward */
624 DEFAULT(escseq.arg[0], 1); 616 DEFAULT(escseq.arg[0], 1);
625 tmoveto(term.c.x-escseq.arg[0], term.c.y); 617 tmoveto(term.c.x-escseq.arg[0], term.c.y);
626 break; 618 break;
627 case 'E': /* Cursor <n> Down and first col */ 619 case 'E': /* CNL -- Cursor <n> Down and first col */
628 DEFAULT(escseq.arg[0], 1); 620 DEFAULT(escseq.arg[0], 1);
629 tmoveto(0, term.c.y+escseq.arg[0]); 621 tmoveto(0, term.c.y+escseq.arg[0]);
630 break; 622 break;
631 case 'F': /* Cursor <n> Up and first col */ 623 case 'F': /* CPL -- Cursor <n> Up and first col */
632 DEFAULT(escseq.arg[0], 1); 624 DEFAULT(escseq.arg[0], 1);
633 tmoveto(0, term.c.y-escseq.arg[0]); 625 tmoveto(0, term.c.y-escseq.arg[0]);
634 break; 626 break;
635 case 'G': /* Move to <col> */ 627 case 'G': /* CHA -- Move to <col> */
636 case '`': 628 case '`': /* XXX: HPA -- same? */
637 DEFAULT(escseq.arg[0], 1); 629 DEFAULT(escseq.arg[0], 1);
638 tmoveto(escseq.arg[0]-1, term.c.y); 630 tmoveto(escseq.arg[0]-1, term.c.y);
639 break; 631 break;
640 case 'H': /* Move to <row> <col> */ 632 case 'H': /* CUP -- Move to <row> <col> */
641 case 'f': 633 case 'f': /* XXX: HVP -- same? */
642 DEFAULT(escseq.arg[0], 1); 634 DEFAULT(escseq.arg[0], 1);
643 DEFAULT(escseq.arg[1], 1); 635 DEFAULT(escseq.arg[1], 1);
644 tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); 636 tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
645 break; 637 break;
646 case 'J': /* Clear screen */ 638 /* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */
639 case 'J': /* ED -- Clear screen */
647 switch(escseq.arg[0]) { 640 switch(escseq.arg[0]) {
648 case 0: /* below */ 641 case 0: /* below */
649 tclearregion(term.c.x, term.c.y, term.col-1, term.row-1); 642 tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
@@ -653,10 +646,13 @@ csihandle(void) {
653 break; 646 break;
654 case 2: /* all */ 647 case 2: /* all */
655 tclearregion(0, 0, term.col-1, term.row-1); 648 tclearregion(0, 0, term.col-1, term.row-1);
656 break; 649 break;
650 case 3: /* XXX: erase saved lines (xterm) */
651 default:
652 goto unknown;
657 } 653 }
658 break; 654 break;
659 case 'K': /* Clear line */ 655 case 'K': /* EL -- Clear line */
660 switch(escseq.arg[0]) { 656 switch(escseq.arg[0]) {
661 case 0: /* right */ 657 case 0: /* right */
662 tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); 658 tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -669,54 +665,77 @@ csihandle(void) {
669 break; 665 break;
670 } 666 }
671 break; 667 break;
672 case 'S': 668 case 'S': /* XXX: SU -- Scroll <n> line up (faked) */
673 case 'L': /* Insert <n> blank lines */ 669 case 'L': /* IL -- Insert <n> blank lines */
674 DEFAULT(escseq.arg[0], 1); 670 DEFAULT(escseq.arg[0], 1);
675 tinsertblankline(escseq.arg[0]); 671 tinsertblankline(escseq.arg[0]);
676 break; 672 break;
677 case 'l': 673 case 'l': /* RM -- Reset Mode */
678 if(escseq.priv) { 674 if(escseq.priv) {
679 switch(escseq.arg[0]) { 675 switch(escseq.arg[0]) {
676 case 1:
677 term.mode &= ~MODE_APPKEYPAD;
678 break;
680 case 7: 679 case 7:
681 term.mode &= ~TMwrap; 680 term.mode &= ~MODE_WRAP;
681 break;
682 case 12: /* att610 -- Stop blinking cursor (IGNORED) */
682 break; 683 break;
683 case 25: 684 case 25:
684 term.c.hidden = 1; 685 term.c.hidden = 1;
685 break; 686 break;
687 case 1048: /* XXX: no alt. screen to erase/save */
688 case 1049:
689 tcursor(CURSOR_LOAD);
690 tclearregion(0, 0, term.col-1, term.row-1);
691 break;
692 default:
693 goto unknown;
686 } 694 }
687 } 695 } else goto unknown;
688 break; 696 break;
689 case 'M': /* Delete <n> lines */ 697 case 'M': /* DL -- Delete <n> lines */
690 DEFAULT(escseq.arg[0], 1); 698 DEFAULT(escseq.arg[0], 1);
691 tdeleteline(escseq.arg[0]); 699 tdeleteline(escseq.arg[0]);
692 break; 700 break;
693 case 'X': 701 case 'X': /* ECH -- Erase <n> char XXX: same? */
694 case 'P': /* Delete <n> char */ 702 case 'P': /* DCH -- Delete <n> char */
695 DEFAULT(escseq.arg[0], 1); 703 DEFAULT(escseq.arg[0], 1);
696 tdeletechar(escseq.arg[0]); 704 tdeletechar(escseq.arg[0]);
697 break; 705 break;
698 case 'd': /* Move to <row> */ 706 /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
707 case 'd': /* VPA -- Move to <row> */
699 DEFAULT(escseq.arg[0], 1); 708 DEFAULT(escseq.arg[0], 1);
700 tmoveto(term.c.x, escseq.arg[0]-1); 709 tmoveto(term.c.x, escseq.arg[0]-1);
701 break; 710 break;
702 case 'h': /* Set terminal mode */ 711 case 'h': /* SM -- Set terminal mode */
703 if(escseq.priv) 712 if(escseq.priv) {
704 switch(escseq.arg[0]) { 713 switch(escseq.arg[0]) {
714 case 1:
715 term.mode |= MODE_APPKEYPAD;
716 break;
705 case 7: 717 case 7:
706 term.mode |= TMwrap; 718 term.mode |= MODE_WRAP;
719 break;
720 case 12: /* att610 -- Start blinking cursor (IGNORED) */
707 break; 721 break;
708 case 25: 722 case 25:
709 term.c.hidden = 0; 723 term.c.hidden = 0;
710 break; 724 break;
711 case 1034: 725 case 1048:
712 /* XXX: Interpret "meta" key, sets eighth bit. */ 726 case 1049: /* XXX: no alt. screen to erase/save */
727 tcursor(CURSOR_SAVE);
728 tclearregion(0, 0, term.col-1, term.row-1);
713 break; 729 break;
730 default:
731 goto unknown;
714 } 732 }
733 } else goto unknown;
715 break; 734 break;
716 case 'm': /* Terminal attribute (color) */ 735 case 'm': /* SGR -- Terminal attribute (color) */
717 tsetattr(escseq.arg, escseq.narg); 736 tsetattr(escseq.arg, escseq.narg);
718 break; 737 break;
719 case 'r': 738 case 'r': /* DECSTBM -- Set Scrolling Region */
720 if(escseq.priv) 739 if(escseq.priv)
721 goto unknown; 740 goto unknown;
722 else { 741 else {
@@ -725,11 +744,11 @@ csihandle(void) {
725 tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); 744 tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
726 } 745 }
727 break; 746 break;
728 case 's': /* Save cursor position */ 747 case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
729 tcpos(CSsave); 748 tcursor(CURSOR_SAVE);
730 break; 749 break;
731 case 'u': /* Load cursor position */ 750 case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
732 tcpos(CSload); 751 tcursor(CURSOR_LOAD);
733 break; 752 break;
734 } 753 }
735} 754}
@@ -759,70 +778,82 @@ tputtab(void) {
759 space--; 778 space--;
760 779
761 for(; space > 0; space--) 780 for(; space > 0; space--)
762 tcursor(CSright); 781 tmovecursor(CURSOR_RIGHT);
763} 782}
764 783
765void 784void
766tputc(char c) { 785tputc(char c) {
767#if 0 786 /* dump(c); */
768 dump(c); 787 if(term.esc & ESC_START) {
769#endif 788 if(term.esc & ESC_CSI) {
770 if(term.esc & ESCin) {
771 if(term.esc & ESCcsi) {
772 escseq.buf[escseq.len++] = c; 789 escseq.buf[escseq.len++] = c;
773 if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) { 790 if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
774 term.esc = 0; 791 term.esc = 0;
775 csiparse(), csihandle(); 792 csiparse(), csihandle();
776 } 793 }
777 } else if (term.esc & ESCosc) { 794 } else if(term.esc & ESC_OSC) {
778 if(c == ';') { 795 if(c == ';') {
779 term.titlelen = 0; 796 term.titlelen = 0;
780 term.esc = ESCin | ESCtitle; 797 term.esc = ESC_START | ESC_TITLE;
781 } 798 }
782 } else if(term.esc & ESCtitle) { 799 } else if(term.esc & ESC_TITLE) {
783 if(c == '\a' || term.titlelen+1 >= TITLESIZ) { 800 if(c == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
784 term.esc = 0; 801 term.esc = 0;
785 term.title[term.titlelen] = '\0'; 802 term.title[term.titlelen] = '\0';
786 XStoreName(xw.dis, xw.win, term.title); 803 XStoreName(xw.dis, xw.win, term.title);
787 } else { 804 } else {
788 term.title[term.titlelen++] = c; 805 term.title[term.titlelen++] = c;
789 } 806 }
790 } else if(term.esc & ESCcharset) { 807 } else if(term.esc & ESC_ALTCHARSET) {
791 printf("ESC ( %c\n", c);
792 switch(c) { 808 switch(c) {
793 case '0': /* Line drawing crap */ 809 case '0': /* Line drawing crap */
794 term.c.attr.mode |= ATgfx; 810 term.c.attr.mode |= ATTR_GFX;
795 break; 811 break;
796 case 'B': /* Back to regular text */ 812 case 'B': /* Back to regular text */
797 term.c.attr.mode &= ~ATgfx; 813 term.c.attr.mode &= ~ATTR_GFX;
798 break; 814 break;
815 default:
816 printf("esc unhandled charset: ESC ( %c\n", c);
799 } 817 }
800 term.esc = 0; 818 term.esc = 0;
801 } else { 819 } else {
802 switch(c) { 820 switch(c) {
803 case '[': 821 case '[':
804 term.esc |= ESCcsi; 822 term.esc |= ESC_CSI;
805 break; 823 break;
806 case ']': 824 case ']':
807 term.esc |= ESCosc; 825 term.esc |= ESC_OSC;
808 break; 826 break;
809 case '(': 827 case '(':
810 term.esc |= ESCcharset; 828 term.esc |= ESC_ALTCHARSET;
811 break; 829 break;
812 case 'A': 830 case 'A':
813 tmoveto(term.c.x, term.c.y-1); 831 tmoveto(term.c.x, term.c.y-1);
832 term.esc = 0;
814 break; 833 break;
815 case 'B': 834 case 'B':
816 tmoveto(term.c.x, term.c.y+1); 835 tmoveto(term.c.x, term.c.y+1);
836 term.esc = 0;
817 break; 837 break;
818 case 'C': 838 case 'C':
819 tmoveto(term.c.x+1, term.c.y); 839 tmoveto(term.c.x+1, term.c.y);
840 term.esc = 0;
820 break; 841 break;
821 case 'D': 842 case 'D':
822 tmoveto(term.c.x-1, term.c.y); 843 tmoveto(term.c.x-1, term.c.y);
844 term.esc = 0;
845 break;
846 case '=': /* DECPAM */
847 term.mode |= MODE_APPKEYPAD;
848 term.esc = 0;
849 break;
850 case '>': /* DECPNM */
851 term.mode &= ~MODE_APPKEYPAD;
852 term.esc = 0;
823 break; 853 break;
824 default: 854 default:
825 fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.'); 855 fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.');
856 term.esc = 0;
826 } 857 }
827 } 858 }
828 } else { 859 } else {
@@ -831,7 +862,7 @@ tputc(char c) {
831 tputtab(); 862 tputtab();
832 break; 863 break;
833 case '\b': 864 case '\b':
834 tcursor(CSleft); 865 tmovecursor(CURSOR_LEFT);
835 break; 866 break;
836 case '\r': 867 case '\r':
837 tmoveto(0, term.c.y); 868 tmoveto(0, term.c.y);
@@ -844,11 +875,11 @@ tputc(char c) {
844 break; 875 break;
845 case '\033': 876 case '\033':
846 csireset(); 877 csireset();
847 term.esc = ESCin; 878 term.esc = ESC_START;
848 break; 879 break;
849 default: 880 default:
850 tsetchar(c); 881 tsetchar(c);
851 tcursor(CSright); 882 tmovecursor(CURSOR_RIGHT);
852 break; 883 break;
853 } 884 }
854 } 885 }
@@ -917,7 +948,7 @@ xscroll(void) {
917 int dsty = term.top * xw.ch; 948 int dsty = term.top * xw.ch;
918 int height = (term.bot-term.top) * xw.ch; 949 int height = (term.bot-term.top) * xw.ch;
919 950
920 xcursor(CShide); 951 xcursor(CURSOR_HIDE);
921 XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty); 952 XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty);
922 xclear(0, term.bot, term.col-1, term.bot); 953 xclear(0, term.bot, term.col-1, term.bot);
923} 954}
@@ -950,7 +981,7 @@ xinit(void) {
950 981
951 term.c.attr.fg = DefaultFG; 982 term.c.attr.fg = DefaultFG;
952 term.c.attr.bg = DefaultBG; 983 term.c.attr.bg = DefaultBG;
953 term.c.attr.mode = ATnone; 984 term.c.attr.mode = ATTR_NULL;
954 /* windows */ 985 /* windows */
955 xw.h = term.row * xw.ch; 986 xw.h = term.row * xw.ch;
956 xw.w = term.col * xw.cw; 987 xw.w = term.col * xw.cw;
@@ -977,12 +1008,12 @@ xinit(void) {
977} 1008}
978 1009
979void 1010void
980xdraws (char *s, Glyph base, int x, int y, int len) { 1011xdraws(char *s, Glyph base, int x, int y, int len) {
981 unsigned long xfg, xbg; 1012 unsigned long xfg, xbg;
982 int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw; 1013 int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw;
983 int i; 1014 int i;
984 1015
985 if(base.mode & ATreverse) 1016 if(base.mode & ATTR_REVERSE)
986 xfg = dc.col[base.bg], xbg = dc.col[base.fg]; 1017 xfg = dc.col[base.bg], xbg = dc.col[base.fg];
987 else 1018 else
988 xfg = dc.col[base.fg], xbg = dc.col[base.bg]; 1019 xfg = dc.col[base.fg], xbg = dc.col[base.bg];
@@ -990,15 +1021,13 @@ xdraws (char *s, Glyph base, int x, int y, int len) {
990 XSetBackground(xw.dis, dc.gc, xbg); 1021 XSetBackground(xw.dis, dc.gc, xbg);
991 XSetForeground(xw.dis, dc.gc, xfg); 1022 XSetForeground(xw.dis, dc.gc, xfg);
992 1023
993 if(base.mode & ATgfx) { 1024 if(base.mode & ATTR_GFX)
994
995 for(i = 0; i < len; i++) 1025 for(i = 0; i < len; i++)
996 s[i] = gfx[s[i]]; 1026 s[i] = gfx[s[i]];
997 }
998 1027
999 XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len); 1028 XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len);
1000 1029
1001 if(base.mode & ATunderline) 1030 if(base.mode & ATTR_UNDERLINE)
1002 XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1); 1031 XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1);
1003} 1032}
1004 1033
@@ -1008,7 +1037,7 @@ xdrawc(int x, int y, Glyph g) {
1008 unsigned long xfg, xbg; 1037 unsigned long xfg, xbg;
1009 1038
1010 /* reverse video */ 1039 /* reverse video */
1011 if(g.mode & ATreverse) 1040 if(g.mode & ATTR_REVERSE)
1012 xfg = dc.col[g.bg], xbg = dc.col[g.fg]; 1041 xfg = dc.col[g.bg], xbg = dc.col[g.fg];
1013 else 1042 else
1014 xfg = dc.col[g.fg], xbg = dc.col[g.bg]; 1043 xfg = dc.col[g.fg], xbg = dc.col[g.bg];
@@ -1022,20 +1051,20 @@ void
1022xcursor(int mode) { 1051xcursor(int mode) {
1023 static int oldx = 0; 1052 static int oldx = 0;
1024 static int oldy = 0; 1053 static int oldy = 0;
1025 Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0}; 1054 Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0};
1026 1055
1027 LIMIT(oldx, 0, term.col-1); 1056 LIMIT(oldx, 0, term.col-1);
1028 LIMIT(oldy, 0, term.row-1); 1057 LIMIT(oldy, 0, term.row-1);
1029 1058
1030 if(term.line[term.c.y][term.c.x].state & CRset) 1059 if(term.line[term.c.y][term.c.x].state & GLYPH_SET)
1031 g.c = term.line[term.c.y][term.c.x].c; 1060 g.c = term.line[term.c.y][term.c.x].c;
1032 /* remove the old cursor */ 1061 /* remove the old cursor */
1033 if(term.line[oldy][oldx].state & CRset) 1062 if(term.line[oldy][oldx].state & GLYPH_SET)
1034 xdrawc(oldx, oldy, term.line[oldy][oldx]); 1063 xdrawc(oldx, oldy, term.line[oldy][oldx]);
1035 else 1064 else
1036 xclear(oldx, oldy, oldx, oldy); 1065 xclear(oldx, oldy, oldx, oldy);
1037 /* draw the new one */ 1066 /* draw the new one */
1038 if(mode == CSdraw) { 1067 if(mode == CURSOR_DRAW) {
1039 xdrawc(term.c.x, term.c.y, g); 1068 xdrawc(term.c.x, term.c.y, g);
1040 oldx = term.c.x, oldy = term.c.y; 1069 oldx = term.c.x, oldy = term.c.y;
1041 } 1070 }
@@ -1045,14 +1074,14 @@ void
1045draw(int redraw_all) { 1074draw(int redraw_all) {
1046 int i, x, y, ox; 1075 int i, x, y, ox;
1047 Glyph base, new; 1076 Glyph base, new;
1048 char buf[MAXDRAWBUF]; 1077 char buf[DRAW_BUF_SIZ];
1049 1078
1050 for(y = 0; y < term.row; y++) { 1079 for(y = 0; y < term.row; y++) {
1051 base = term.line[y][0]; 1080 base = term.line[y][0];
1052 i = ox = 0; 1081 i = ox = 0;
1053 for(x = 0; x < term.col; x++) { 1082 for(x = 0; x < term.col; x++) {
1054 new = term.line[y][x]; 1083 new = term.line[y][x];
1055 if(!ATTRCMP(base, new) && i < MAXDRAWBUF) 1084 if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ)
1056 buf[i++] = new.c; 1085 buf[i++] = new.c;
1057 else { 1086 else {
1058 xdraws(buf, base, ox, y, i); 1087 xdraws(buf, base, ox, y, i);
@@ -1065,12 +1094,12 @@ draw(int redraw_all) {
1065 xdraws(buf, base, ox, y, i); 1094 xdraws(buf, base, ox, y, i);
1066 } 1095 }
1067 if(!term.c.hidden) 1096 if(!term.c.hidden)
1068 xcursor(CSdraw); 1097 xcursor(CURSOR_DRAW);
1069} 1098}
1070 1099
1071void 1100void
1072expose(XEvent *ev) { 1101expose(XEvent *ev) {
1073 draw(SCredraw); 1102 draw(SCREEN_REDRAW);
1074} 1103}
1075 1104
1076char* 1105char*
@@ -1105,6 +1134,13 @@ kpress(XEvent *ev) {
1105 ttywrite(buf, len); 1134 ttywrite(buf, len);
1106 } else 1135 } else
1107 switch(ksym) { 1136 switch(ksym) {
1137 case XK_Up:
1138 case XK_Down:
1139 case XK_Left:
1140 case XK_Right:
1141 sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]);
1142 ttywrite(buf, 3);
1143 break;
1108 case XK_Insert: 1144 case XK_Insert:
1109 if(shift) 1145 if(shift)
1110 /* XXX: paste X clipboard */; 1146 /* XXX: paste X clipboard */;
@@ -1126,7 +1162,7 @@ resize(XEvent *e) {
1126 ttyresize(col, row); 1162 ttyresize(col, row);
1127 xw.w = e->xconfigure.width; 1163 xw.w = e->xconfigure.width;
1128 xw.h = e->xconfigure.height; 1164 xw.h = e->xconfigure.height;
1129 draw(SCredraw); 1165 draw(SCREEN_REDRAW);
1130 } 1166 }
1131} 1167}
1132 1168
@@ -1151,7 +1187,7 @@ run(void) {
1151 } 1187 }
1152 if(FD_ISSET(cmdfd, &rfd)) { 1188 if(FD_ISSET(cmdfd, &rfd)) {
1153 ttyread(); 1189 ttyread();
1154 draw(SCupdate); 1190 draw(SCREEN_UPDATE);
1155 } 1191 }
1156 while(XPending(xw.dis)) { 1192 while(XPending(xw.dis)) {
1157 XNextEvent(xw.dis, &ev); 1193 XNextEvent(xw.dis, &ev);