diff options
Diffstat (limited to 'st.c')
| -rw-r--r-- | st.c | 167 |
1 files changed, 88 insertions, 79 deletions
| @@ -1,4 +1,4 @@ | |||
| 1 | /* See LICENSE for licence details. */ | 1 | /* See LICENSE for licence details. */ |
| 2 | #include "st.h" | 2 | #include "st.h" |
| 3 | 3 | ||
| 4 | /* Globals */ | 4 | /* Globals */ |
| @@ -27,11 +27,10 @@ execsh(void) { | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | void | 29 | void |
| 30 | xbell(void) { /* visual bell */ | 30 | xbell(void) { /* visual bell */ |
| 31 | XRectangle r = { 0, 0, xw.w, xw.h }; | 31 | XRectangle r = { 0, 0, xw.w, xw.h }; |
| 32 | XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); | 32 | XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); |
| 33 | XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); | 33 | XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); |
| 34 | XFlush(xw.dis); | ||
| 35 | usleep(30000); | 34 | usleep(30000); |
| 36 | draw(SCredraw); | 35 | draw(SCredraw); |
| 37 | } | 36 | } |
| @@ -127,7 +126,7 @@ escfinal(char c) { | |||
| 127 | } | 126 | } |
| 128 | else if(BETWEEN(c, 0x40, 0x7E)) | 127 | else if(BETWEEN(c, 0x40, 0x7E)) |
| 129 | return 1; | 128 | return 1; |
| 130 | return 0; | 129 | return 0; |
| 131 | } | 130 | } |
| 132 | 131 | ||
| 133 | void | 132 | void |
| @@ -168,7 +167,7 @@ tscroll(void) { | |||
| 168 | term.line[i] = term.line[i+1]; | 167 | term.line[i] = term.line[i+1]; |
| 169 | memset(temp, 0, sizeof(Glyph) * term.col); | 168 | memset(temp, 0, sizeof(Glyph) * term.col); |
| 170 | term.line[term.bot] = temp; | 169 | term.line[term.bot] = temp; |
| 171 | xscroll(); | 170 | xscroll(); |
| 172 | } | 171 | } |
| 173 | 172 | ||
| 174 | void | 173 | void |
| @@ -372,13 +371,13 @@ tsetattr(int *attr, int l) { | |||
| 372 | term.c.attr.bg = DefaultBG; | 371 | term.c.attr.bg = DefaultBG; |
| 373 | break; | 372 | break; |
| 374 | case 1: | 373 | case 1: |
| 375 | term.c.attr.mode |= ATbold; | 374 | term.c.attr.mode |= ATbold; |
| 376 | break; | 375 | break; |
| 377 | case 4: | 376 | case 4: |
| 378 | term.c.attr.mode |= ATunderline; | 377 | term.c.attr.mode |= ATunderline; |
| 379 | break; | 378 | break; |
| 380 | case 7: | 379 | case 7: |
| 381 | term.c.attr.mode |= ATreverse; | 380 | term.c.attr.mode |= ATreverse; |
| 382 | break; | 381 | break; |
| 383 | case 8: | 382 | case 8: |
| 384 | term.c.hidden = CShide; | 383 | term.c.hidden = CShide; |
| @@ -390,7 +389,7 @@ tsetattr(int *attr, int l) { | |||
| 390 | term.c.attr.mode &= ~ATunderline; | 389 | term.c.attr.mode &= ~ATunderline; |
| 391 | break; | 390 | break; |
| 392 | case 27: | 391 | case 27: |
| 393 | term.c.attr.mode &= ~ATreverse; | 392 | term.c.attr.mode &= ~ATreverse; |
| 394 | break; | 393 | break; |
| 395 | case 39: | 394 | case 39: |
| 396 | term.c.attr.fg = DefaultFG; | 395 | term.c.attr.fg = DefaultFG; |
| @@ -420,7 +419,7 @@ tsetscroll(int t, int b) { | |||
| 420 | b = temp; | 419 | b = temp; |
| 421 | } | 420 | } |
| 422 | term.top = t; | 421 | term.top = t; |
| 423 | term.bot = b; | 422 | term.bot = b; |
| 424 | } | 423 | } |
| 425 | 424 | ||
| 426 | 425 | ||
| @@ -481,7 +480,7 @@ eschandle(void) { | |||
| 481 | break; | 480 | break; |
| 482 | case 2: /* all */ | 481 | case 2: /* all */ |
| 483 | tclearregion(0, 0, term.col-1, term.row-1); | 482 | tclearregion(0, 0, term.col-1, term.row-1); |
| 484 | break; | 483 | break; |
| 485 | } | 484 | } |
| 486 | break; | 485 | break; |
| 487 | case 'K': /* Clear line */ | 486 | case 'K': /* Clear line */ |
| @@ -501,6 +500,10 @@ eschandle(void) { | |||
| 501 | DEFAULT(escseq.arg[0], 1); | 500 | DEFAULT(escseq.arg[0], 1); |
| 502 | tinsertblankline(escseq.arg[0]); | 501 | tinsertblankline(escseq.arg[0]); |
| 503 | break; | 502 | break; |
| 503 | case 'l': | ||
| 504 | if(escseq.priv && escseq.arg[0] == 25) | ||
| 505 | term.c.hidden = 1; | ||
| 506 | break; | ||
| 504 | case 'M': /* Delete <n> lines */ | 507 | case 'M': /* Delete <n> lines */ |
| 505 | DEFAULT(escseq.arg[0], 1); | 508 | DEFAULT(escseq.arg[0], 1); |
| 506 | tdeleteline(escseq.arg[0]); | 509 | tdeleteline(escseq.arg[0]); |
| @@ -514,6 +517,8 @@ eschandle(void) { | |||
| 514 | tmoveto(term.c.x, escseq.arg[0]-1); | 517 | tmoveto(term.c.x, escseq.arg[0]-1); |
| 515 | break; | 518 | break; |
| 516 | case 'h': /* Set terminal mode */ | 519 | case 'h': /* Set terminal mode */ |
| 520 | if(escseq.priv && escseq.arg[0] == 25) | ||
| 521 | term.c.hidden = 0; | ||
| 517 | break; | 522 | break; |
| 518 | case 'm': /* Terminal attribute (color) */ | 523 | case 'm': /* Terminal attribute (color) */ |
| 519 | tsetattr(escseq.arg, escseq.narg); | 524 | tsetattr(escseq.arg, escseq.narg); |
| @@ -542,15 +547,15 @@ void | |||
| 542 | escdump(void) { | 547 | escdump(void) { |
| 543 | int i; | 548 | int i; |
| 544 | puts("------"); | 549 | puts("------"); |
| 545 | printf("rawbuf : %s\n", escseq.buf); | 550 | printf("rawbuf : %s\n", escseq.buf); |
| 546 | printf("prechar : %c\n", escseq.pre); | 551 | printf("prechar : %c\n", escseq.pre); |
| 547 | printf("private : %c\n", escseq.priv ? '?' : ' '); | 552 | printf("private : %c\n", escseq.priv ? '?' : ' '); |
| 548 | printf("narg : %d\n", escseq.narg); | 553 | printf("narg : %d\n", escseq.narg); |
| 549 | if(escseq.narg) { | 554 | if(escseq.narg) { |
| 550 | for(i = 0; i < escseq.narg; i++) | 555 | for(i = 0; i < escseq.narg; i++) |
| 551 | printf("\targ %d = %d\n", i, escseq.arg[i]); | 556 | printf("\targ %d = %d\n", i, escseq.arg[i]); |
| 552 | } | 557 | } |
| 553 | printf("mode : %c\n", escseq.mode); | 558 | printf("mode : %c\n", escseq.mode); |
| 554 | } | 559 | } |
| 555 | 560 | ||
| 556 | void | 561 | void |
| @@ -560,20 +565,21 @@ escreset(void) { | |||
| 560 | 565 | ||
| 561 | void | 566 | void |
| 562 | tputtab(void) { | 567 | tputtab(void) { |
| 563 | int space = TAB - term.c.x % TAB; | 568 | int space = TAB - term.c.x % TAB; |
| 564 | 569 | ||
| 565 | if(term.c.x + space >= term.col) | 570 | if(term.c.x + space >= term.col) |
| 566 | space--; | 571 | space--; |
| 567 | 572 | ||
| 568 | for(; space > 0; space--) | 573 | for(; space > 0; space--) |
| 569 | tcursor(CSright); | 574 | tcursor(CSright); |
| 570 | } | 575 | } |
| 571 | 576 | ||
| 572 | void | 577 | void |
| 573 | tputc(char c) { | 578 | tputc(char c) { |
| 574 | static int inesc = 0; | 579 | static int inesc = 0; |
| 575 | 580 | #if 0 | |
| 576 | //dump(c); | 581 | dump(c); |
| 582 | #endif | ||
| 577 | /* start of escseq */ | 583 | /* start of escseq */ |
| 578 | if(c == '\033') | 584 | if(c == '\033') |
| 579 | escreset(), inesc = 1; | 585 | escreset(), inesc = 1; |
| @@ -585,9 +591,9 @@ tputc(char c) { | |||
| 585 | tsetchar(c); | 591 | tsetchar(c); |
| 586 | tcursor(CSright); | 592 | tcursor(CSright); |
| 587 | break; | 593 | break; |
| 588 | case '\t': | 594 | case '\t': |
| 589 | tputtab(); | 595 | tputtab(); |
| 590 | break; | 596 | break; |
| 591 | case '\b': | 597 | case '\b': |
| 592 | tcursor(CSleft); | 598 | tcursor(CSleft); |
| 593 | break; | 599 | break; |
| @@ -636,24 +642,24 @@ tresize(int col, int row) { | |||
| 636 | 642 | ||
| 637 | if(col < 1 || row < 1) | 643 | if(col < 1 || row < 1) |
| 638 | return; | 644 | return; |
| 639 | /* alloc */ | 645 | /* alloc */ |
| 640 | line = calloc(row, sizeof(Line)); | 646 | line = calloc(row, sizeof(Line)); |
| 641 | for(i = 0 ; i < row; i++) | 647 | for(i = 0 ; i < row; i++) |
| 642 | line[i] = calloc(col, sizeof(Glyph)); | 648 | line[i] = calloc(col, sizeof(Glyph)); |
| 643 | /* copy */ | 649 | /* copy */ |
| 644 | for(i = 0 ; i < minrow; i++) | 650 | for(i = 0 ; i < minrow; i++) |
| 645 | memcpy(line[i], term.line[i], mincol * sizeof(Glyph)); | 651 | memcpy(line[i], term.line[i], mincol * sizeof(Glyph)); |
| 646 | /* free */ | 652 | /* free */ |
| 647 | for(i = 0; i < term.row; i++) | 653 | for(i = 0; i < term.row; i++) |
| 648 | free(term.line[i]); | 654 | free(term.line[i]); |
| 649 | free(term.line); | 655 | free(term.line); |
| 650 | 656 | ||
| 651 | LIMIT(term.c.x, 0, col-1); | 657 | LIMIT(term.c.x, 0, col-1); |
| 652 | LIMIT(term.c.y, 0, row-1); | 658 | LIMIT(term.c.y, 0, row-1); |
| 653 | LIMIT(term.top, 0, row-1); | 659 | LIMIT(term.top, 0, row-1); |
| 654 | LIMIT(term.bot, 0, row-1); | 660 | LIMIT(term.bot, 0, row-1); |
| 655 | 661 | ||
| 656 | term.bot = row-1; | 662 | term.bot = row-1; |
| 657 | term.line = line; | 663 | term.line = line; |
| 658 | term.col = col, term.row = row; | 664 | term.col = col, term.row = row; |
| 659 | } | 665 | } |
| @@ -706,12 +712,12 @@ xinit(void) { | |||
| 706 | 712 | ||
| 707 | xw.dis = XOpenDisplay(NULL); | 713 | xw.dis = XOpenDisplay(NULL); |
| 708 | xw.scr = XDefaultScreen(xw.dis); | 714 | xw.scr = XDefaultScreen(xw.dis); |
| 709 | if(!xw.dis) | 715 | if(!xw.dis) |
| 710 | die("can not open display"); | 716 | die("can not open display"); |
| 711 | 717 | ||
| 712 | /* font */ | 718 | /* font */ |
| 713 | if(!(dc.font = XLoadQueryFont(xw.dis, FONT))) | 719 | if(!(dc.font = XLoadQueryFont(xw.dis, FONT))) |
| 714 | die("can not find font " FONT); | 720 | die("can not find font " FONT); |
| 715 | 721 | ||
| 716 | xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing; | 722 | xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing; |
| 717 | xw.ch = dc.font->ascent + dc.font->descent + LINESPACE; | 723 | xw.ch = dc.font->ascent + dc.font->descent + LINESPACE; |
| @@ -724,7 +730,7 @@ xinit(void) { | |||
| 724 | term.c.attr.bg = DefaultBG; | 730 | term.c.attr.bg = DefaultBG; |
| 725 | term.c.attr.mode = ATnone; | 731 | term.c.attr.mode = ATnone; |
| 726 | /* windows */ | 732 | /* windows */ |
| 727 | xw.h = term.row * xw.ch; | 733 | xw.h = term.row * xw.ch; |
| 728 | xw.w = term.col * xw.cw; | 734 | xw.w = term.col * xw.cw; |
| 729 | /* XXX: this BORDER is useless after the first resize, handle it in xdraws() */ | 735 | /* XXX: this BORDER is useless after the first resize, handle it in xdraws() */ |
| 730 | xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0, | 736 | xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0, |
| @@ -746,7 +752,6 @@ xinit(void) { | |||
| 746 | XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint); | 752 | XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmhint, &chint); |
| 747 | XStoreName(xw.dis, xw.win, TNAME); | 753 | XStoreName(xw.dis, xw.win, TNAME); |
| 748 | XSync(xw.dis, 0); | 754 | XSync(xw.dis, 0); |
| 749 | |||
| 750 | } | 755 | } |
| 751 | 756 | ||
| 752 | void | 757 | void |
| @@ -765,7 +770,7 @@ xdrawc(int x, int y, Glyph g) { | |||
| 765 | /* string */ | 770 | /* string */ |
| 766 | XSetForeground(xw.dis, dc.gc, xfg); | 771 | XSetForeground(xw.dis, dc.gc, xfg); |
| 767 | XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1); | 772 | XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1); |
| 768 | if(g.mode & ATbold) /* XXX: bold hack (draw again at x+1) */ | 773 | if(g.mode & ATbold) /* XXX: bold hack (draw again at x+1) */ |
| 769 | XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent, &(g.c), 1); | 774 | XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent, &(g.c), 1); |
| 770 | /* underline */ | 775 | /* underline */ |
| 771 | if(g.mode & ATunderline) { | 776 | if(g.mode & ATunderline) { |
| @@ -779,10 +784,10 @@ xcursor(int mode) { | |||
| 779 | static int oldx = 0; | 784 | static int oldx = 0; |
| 780 | static int oldy = 0; | 785 | static int oldy = 0; |
| 781 | Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0}; | 786 | Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0}; |
| 782 | 787 | ||
| 783 | LIMIT(oldx, 0, term.col-1); | 788 | LIMIT(oldx, 0, term.col-1); |
| 784 | LIMIT(oldy, 0, term.row-1); | 789 | LIMIT(oldy, 0, term.row-1); |
| 785 | 790 | ||
| 786 | if(term.line[term.c.y][term.c.x].state & CRset) | 791 | if(term.line[term.c.y][term.c.x].state & CRset) |
| 787 | g.c = term.line[term.c.y][term.c.x].c; | 792 | g.c = term.line[term.c.y][term.c.x].c; |
| 788 | /* remove the old cursor */ | 793 | /* remove the old cursor */ |
| @@ -825,7 +830,7 @@ kpress(XKeyEvent *e) { | |||
| 825 | int meta; | 830 | int meta; |
| 826 | int shift; | 831 | int shift; |
| 827 | 832 | ||
| 828 | meta = e->state & Mod4Mask; | 833 | meta = e->state & Mod1Mask; |
| 829 | shift = e->state & ShiftMask; | 834 | shift = e->state & ShiftMask; |
| 830 | len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); | 835 | len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); |
| 831 | if(len > 0) { | 836 | if(len > 0) { |
| @@ -836,11 +841,9 @@ kpress(XKeyEvent *e) { | |||
| 836 | return; | 841 | return; |
| 837 | } | 842 | } |
| 838 | switch(ksym) { | 843 | switch(ksym) { |
| 839 | #ifdef DEBUG1 | ||
| 840 | default: | 844 | default: |
| 841 | printf("errkey: %d\n", (int)ksym); | 845 | fprintf(stderr, "errkey: %d\n", (int)ksym); |
| 842 | break; | 846 | break; |
| 843 | #endif | ||
| 844 | case XK_Up: | 847 | case XK_Up: |
| 845 | case XK_Down: | 848 | case XK_Down: |
| 846 | case XK_Left: | 849 | case XK_Left: |
| @@ -849,13 +852,14 @@ kpress(XKeyEvent *e) { | |||
| 849 | ttywrite(buf, 3); | 852 | ttywrite(buf, 3); |
| 850 | break; | 853 | break; |
| 851 | case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break; | 854 | case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break; |
| 852 | case XK_Home: ttywrite( KEYHOME, sizeof( KEYHOME)-1); break; | 855 | case XK_Home: ttywrite(KEYHOME, sizeof(KEYHOME)-1); break; |
| 853 | case XK_End: ttywrite( KEYEND, sizeof( KEYEND)-1); break; | 856 | case XK_End: ttywrite(KEYEND, sizeof(KEYEND) -1); break; |
| 854 | case XK_Prior: ttywrite( KEYPREV, sizeof( KEYPREV)-1); break; | 857 | case XK_Prior: ttywrite(KEYPREV, sizeof(KEYPREV)-1); break; |
| 855 | case XK_Next: ttywrite( KEYNEXT, sizeof( KEYNEXT)-1); break; | 858 | case XK_Next: ttywrite(KEYNEXT, sizeof(KEYNEXT)-1); break; |
| 856 | case XK_Insert: | 859 | case XK_Insert: |
| 857 | /* XXX: paste X clipboard */ | 860 | /* XXX: paste X clipboard */ |
| 858 | if(shift); | 861 | if(shift) |
| 862 | ; | ||
| 859 | break; | 863 | break; |
| 860 | } | 864 | } |
| 861 | } | 865 | } |
| @@ -865,7 +869,7 @@ resize(XEvent *e) { | |||
| 865 | int col, row; | 869 | int col, row; |
| 866 | col = e->xconfigure.width / xw.cw; | 870 | col = e->xconfigure.width / xw.cw; |
| 867 | row = e->xconfigure.height / xw.ch; | 871 | row = e->xconfigure.height / xw.ch; |
| 868 | 872 | ||
| 869 | if(term.col != col || term.row != row) { | 873 | if(term.col != col || term.row != row) { |
| 870 | tresize(col, row); | 874 | tresize(col, row); |
| 871 | ttyresize(col, row); | 875 | ttyresize(col, row); |
| @@ -881,37 +885,42 @@ run(void) { | |||
| 881 | int ret; | 885 | int ret; |
| 882 | XEvent ev; | 886 | XEvent ev; |
| 883 | fd_set rfd; | 887 | fd_set rfd; |
| 884 | struct timeval tv = {0, 10000}; | 888 | int xfd = XConnectionNumber(xw.dis); |
| 885 | 889 | ||
| 886 | running = 1; | 890 | running = 1; |
| 887 | XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask); | 891 | XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask); |
| 888 | XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize bug in wmii */ | 892 | XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize bug in wmii */ |
| 893 | |||
| 889 | while(running) { | 894 | while(running) { |
| 890 | while(XPending(xw.dis)) { | ||
| 891 | XNextEvent(xw.dis, &ev); | ||
| 892 | switch (ev.type) { | ||
| 893 | default: | ||
| 894 | break; | ||
| 895 | case KeyPress: | ||
| 896 | kpress(&ev.xkey); | ||
| 897 | break; | ||
| 898 | case Expose: | ||
| 899 | draw(SCredraw); | ||
| 900 | break; | ||
| 901 | case ConfigureNotify: | ||
| 902 | resize(&ev); | ||
| 903 | break; | ||
| 904 | } | ||
| 905 | } | ||
| 906 | FD_ZERO(&rfd); | 895 | FD_ZERO(&rfd); |
| 907 | FD_SET(cmdfd, &rfd); | 896 | FD_SET(cmdfd, &rfd); |
| 908 | ret = select(cmdfd+1, &rfd, NULL, NULL, &tv); | 897 | FD_SET(xfd, &rfd); |
| 898 | XFlush(xw.dis); | ||
| 899 | ret = select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL); | ||
| 900 | |||
| 909 | if(ret < 0) { | 901 | if(ret < 0) { |
| 910 | fprintf(stderr, "select: %m\n"); | 902 | fprintf(stderr, "select: %m\n"); |
| 911 | running = 0; | 903 | running = 0; |
| 912 | } | 904 | } |
| 913 | if(!ret) | 905 | |
| 914 | continue; | 906 | if(FD_ISSET(xfd, &rfd)) { |
| 907 | while(XPending(xw.dis)) { | ||
| 908 | XNextEvent(xw.dis, &ev); | ||
| 909 | switch (ev.type) { | ||
| 910 | default: | ||
| 911 | break; | ||
| 912 | case KeyPress: | ||
| 913 | kpress(&ev.xkey); | ||
| 914 | break; | ||
| 915 | case Expose: | ||
| 916 | draw(SCredraw); | ||
| 917 | break; | ||
| 918 | case ConfigureNotify: | ||
| 919 | resize(&ev); | ||
| 920 | break; | ||
| 921 | } | ||
| 922 | } | ||
| 923 | } | ||
| 915 | if(FD_ISSET(cmdfd, &rfd)) { | 924 | if(FD_ISSET(cmdfd, &rfd)) { |
| 916 | ttyread(); | 925 | ttyread(); |
| 917 | draw(SCupdate); | 926 | draw(SCupdate); |
| @@ -926,9 +935,9 @@ main(int argc, char *argv[]) { | |||
| 926 | else if(argc != 1) | 935 | else if(argc != 1) |
| 927 | die("usage: st [-v]\n"); | 936 | die("usage: st [-v]\n"); |
| 928 | setlocale(LC_CTYPE, ""); | 937 | setlocale(LC_CTYPE, ""); |
| 929 | tnew(80, 24); | 938 | tnew(80, 24); |
| 930 | ttynew(); | 939 | ttynew(); |
| 931 | xinit(); | 940 | xinit(); |
| 932 | run(); | 941 | run(); |
| 933 | return 0; | 942 | return 0; |
| 934 | } | 943 | } |
