X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=9ca032f5a34a221787ca53235fc5021e9ffd2cb0;hb=6db6980e27bdde6f2d444dd3cdd7a46985fa84fc;hp=db5e04f401c8f24953d0cd4bbadc4b40d915db08;hpb=2f5ebe0a4d71aea0bb3aa0e500765a402e4a96f4;p=st.git diff --git a/st.c b/st.c old mode 100755 new mode 100644 index db5e04f..9ca032f --- a/st.c +++ b/st.c @@ -20,7 +20,13 @@ #include #include -#define TNAME "xterm" +#if defined(LINUX) + #include +#elif defined(OPENBSD) + #include +#elif defined(FREEBSD) + #include +#endif /* Arbitrary sizes */ #define ESC_TITLE_SIZ 256 @@ -36,10 +42,12 @@ #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) +#define IS_SET(flag) (term.mode & (flag)) /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */ enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 }; -enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, CURSOR_SAVE, CURSOR_LOAD }; +enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, + CURSOR_SAVE, CURSOR_LOAD }; enum { GLYPH_SET=1, GLYPH_DIRTY=2 }; enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 }; enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 }; @@ -106,16 +114,16 @@ typedef struct { char s[ESC_BUF_SIZ]; } Key; -#include "config.h" - /* Drawing Context */ typedef struct { - unsigned long col[LEN(colorname)]; + unsigned long col[256]; XFontStruct* font; XFontStruct* bfont; GC gc; } DC; +#include "config.h" + static void die(const char *errstr, ...); static void draw(int); static void execsh(void); @@ -129,7 +137,6 @@ static void csireset(void); static void tclearregion(int, int, int, int); static void tcursor(int); -static void tmovecursor(int); static void tdeletechar(int); static void tdeleteline(int); static void tinsertblank(int); @@ -137,6 +144,7 @@ static void tinsertblankline(int); static void tmoveto(int, int); static void tnew(int, int); static void tnewline(void); +static void tputtab(void); static void tputc(char); static void tputs(char*, int); static void treset(void); @@ -153,10 +161,13 @@ static void ttyread(void); static void ttyresize(int, int); static void ttywrite(const char *, size_t); -static unsigned long xgetcol(const char *); +static void xbell(void); +static void xdraws(char *, Glyph, int, int, int); +static void xhints(void); static void xclear(int, int, int, int); static void xcursor(int); static void xinit(void); +static void xloadcols(void); static void expose(XEvent *); static char* kmap(KeySym); @@ -239,19 +250,12 @@ sigchld(int a) { void ttynew(void) { int m, s; - char *pts; - - if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0) - die("openpt failed: %s\n", SERRNO); - if(grantpt(m) < 0) - die("grandpt failed: %s\n", SERRNO); - if(unlockpt(m) < 0) - die("unlockpt failed: %s\n", SERRNO); - if(!(pts = ptsname(m))) - die("ptsname failed: %s\n", SERRNO); - if((s = open(pts, O_RDWR | O_NOCTTY)) < 0) - die("Couldn't open slave: %s\n", SERRNO); - fcntl(s, F_SETFL, O_NDELAY); + + /* seems to work fine on linux, openbsd and freebsd */ + struct winsize w = {term.row, term.col, 0, 0}; + if(openpty(&m, &s, NULL, NULL, &w) < 0) + die("openpty failed: %s\n", SERRNO); + switch(pid = fork()) { case -1: die("fork failed\n"); @@ -262,7 +266,9 @@ ttynew(void) { dup2(s, STDOUT_FILENO); dup2(s, STDERR_FILENO); if(ioctl(s, TIOCSCTTY, NULL) < 0) - die("ioctl TTIOCSTTY failed: %s\n", SERRNO); + die("ioctl TIOCSCTTY failed: %s\n", SERRNO); + close(s); + close(m); execsh(); break; default: @@ -331,7 +337,8 @@ treset(void) { } void -tnew(int col, int row) { /* screen size */ +tnew(int col, int row) { + /* screen size */ term.row = row, term.col = col; term.top = 0, term.bot = term.row - 1; /* mode */ @@ -431,37 +438,6 @@ tmoveto(int x, int y) { term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y; } -void -tmovecursor(int dir) { - int xf = term.c.x, yf = term.c.y; - - switch(dir) { - case CURSOR_UP: - yf--; - break; - case CURSOR_DOWN: - yf++; - break; - case CURSOR_LEFT: - xf--; - if(term.mode & MODE_WRAP && xf < 0) { - xf = term.col-1, yf--; - if(yf < term.top) - yf = term.top, xf = 0; - } - break; - case CURSOR_RIGHT: - xf++; - if(term.mode & MODE_WRAP && xf >= term.col) { - xf = 0, yf++; - if(yf > term.bot) - yf = term.bot, tscroll(); - } - break; - } - tmoveto(xf, yf); -} - void tsetchar(char c) { term.line[term.c.y][term.c.x] = term.c.attr; @@ -498,21 +474,21 @@ tdeletechar(int n) { return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(term.col-size, term.c.y, term.col-1, term.c.y); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); } void tinsertblank(int n) { int src = term.c.x; int dst = src + n; - int size = term.col - n - src; + int size = term.col - dst; if(dst >= term.col) { tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst, term.c.y); + tclearregion(src, term.c.y, dst - 1, term.c.y); } void @@ -592,19 +568,45 @@ tsetattr(int *attr, int l) { case 27: term.c.attr.mode &= ~ATTR_REVERSE; break; + case 38: + if (i + 2 < l && attr[i + 1] == 5) { + i += 2; + if (BETWEEN(attr[i], 0, 255)) + term.c.attr.fg = attr[i]; + else + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[i]); + } + else + fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); + break; case 39: term.c.attr.fg = DefaultFG; break; + case 48: + if (i + 2 < l && attr[i + 1] == 5) { + i += 2; + if (BETWEEN(attr[i], 0, 255)) + term.c.attr.bg = attr[i]; + else + fprintf(stderr, "erresc: bad bgcolor %d\n", attr[i]); + } + else + fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); + break; case 49: - term.c.attr.fg = DefaultBG; + term.c.attr.bg = DefaultBG; break; default: if(BETWEEN(attr[i], 30, 37)) term.c.attr.fg = attr[i] - 30; else if(BETWEEN(attr[i], 40, 47)) term.c.attr.bg = attr[i] - 40; + else if(BETWEEN(attr[i], 90, 97)) + term.c.attr.fg = attr[i] - 90 + 8; + else if(BETWEEN(attr[i], 100, 107)) + term.c.attr.fg = attr[i] - 100 + 8; else - fprintf(stderr, "erresc: gfx attr %d unkown\n", attr[i]); + fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[i]); break; } } @@ -837,12 +839,7 @@ csireset(void) { void tputtab(void) { int space = TAB - term.c.x % TAB; - - if(term.c.x + space >= term.col) - space--; - - for(; space > 0; space--) - tmovecursor(CURSOR_RIGHT); + tmoveto(term.c.x + space, term.c.y); } void @@ -879,7 +876,7 @@ tputc(char c) { printf("esc unhandled charset: ESC ( %c\n", c); } term.esc = 0; - } else { + } else { switch(c) { case '[': term.esc |= ESC_CSI; @@ -948,7 +945,7 @@ tputc(char c) { tputtab(); break; case '\b': - tmovecursor(CURSOR_LEFT); + tmoveto(term.c.x-1, term.c.y); break; case '\r': tmoveto(0, term.c.y); @@ -965,14 +962,17 @@ tputc(char c) { break; default: tsetchar(c); - tmovecursor(CURSOR_RIGHT); + if(term.c.x+1 < term.col) { + tmoveto(term.c.x+1, term.c.y); + } else if(IS_SET(MODE_WRAP)) + tnewline(); break; } } } void -tputs(char *s, int len) { +tputs(char *s, int len) { for(; len > 0; len--) tputc(*s++); } @@ -980,23 +980,28 @@ tputs(char *s, int len) { void tresize(int col, int row) { int i; - Line *line; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); if(col < 1 || row < 1) return; - /* alloc */ - line = calloc(row, sizeof(Line)); - for(i = 0 ; i < row; i++) - line[i] = calloc(col, sizeof(Glyph)); - /* copy */ - for(i = 0 ; i < minrow; i++) - memcpy(line[i], term.line[i], mincol * sizeof(Glyph)); - /* free */ - for(i = 0; i < term.row; i++) + + /* free uneeded rows */ + for(i = row; i < term.row; i++) free(term.line[i]); - free(term.line); + + /* resize to new height */ + term.line = realloc(term.line, row * sizeof(Line)); + + /* resize each row to new width, zero-pad if needed */ + for(i = 0; i < minrow; i++) { + term.line[i] = realloc(term.line[i], col * sizeof(Glyph)); + memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph)); + } + + /* allocate any new rows */ + for(/* i == minrow */; i < row; i++) + term.line[i] = calloc(col, sizeof(Glyph)); LIMIT(term.c.x, 0, col-1); LIMIT(term.c.y, 0, row-1); @@ -1004,53 +1009,79 @@ tresize(int col, int row) { LIMIT(term.bot, 0, row-1); term.bot = row-1; - term.line = line; term.col = col, term.row = row; } -unsigned long -xgetcol(const char *s) { +void +xloadcols(void) { + int i, r, g, b; XColor color; Colormap cmap = DefaultColormap(xw.dis, xw.scr); + unsigned long white = WhitePixel(xw.dis, xw.scr); + + for(i = 0; i < 16; i++) { + if (!XAllocNamedColor(xw.dis, cmap, colorname[i], &color, &color)) { + dc.col[i] = white; + fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]); + } else + dc.col[i] = color.pixel; + } - if(!XAllocNamedColor(xw.dis, cmap, s, &color, &color)) { - color.pixel = WhitePixel(xw.dis, xw.scr); - fprintf(stderr, "Could not allocate color '%s'\n", s); + /* same colors as xterm */ + for(r = 0; r < 6; r++) + for(g = 0; g < 6; g++) + for(b = 0; b < 6; b++) { + color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; + color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; + color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; + if (!XAllocColor(xw.dis, cmap, &color)) { + dc.col[i] = white; + fprintf(stderr, "Could not allocate color %d\n", i); + } else + dc.col[i] = color.pixel; + i++; + } + + for(r = 0; r < 24; r++, i++) { + color.red = color.green = color.blue = 0x0808 + 0x0a0a * r; + if (!XAllocColor(xw.dis, cmap, &color)) { + dc.col[i] = white; + fprintf(stderr, "Could not allocate color %d\n", i); + } else + dc.col[i] = color.pixel; } - return color.pixel; } void xclear(int x1, int y1, int x2, int y2) { XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]); XFillRectangle(xw.dis, xw.buf, dc.gc, - x1 * xw.cw, y1 * xw.ch, - (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch); + x1 * xw.cw, y1 * xw.ch, + (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch); } void xhints(void) { - XClassHint chint = {TNAME, TNAME}; - XWMHints wmhint = {.flags = InputHint, .input = 1}; - XSizeHints shint = { - .flags = PSize | PResizeInc, - .height = xw.h, /* XXX: doesn't seem to work, see run() */ + XClassHint class = {TNAME, TNAME}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints size = { + .flags = PSize | PResizeInc | PBaseSize, + .height = xw.h, .width = xw.w, .height_inc = xw.ch, .width_inc = xw.cw, + .base_height = 2*BORDER, + .base_width = 2*BORDER, }; - XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &shint, &wmhint, &chint); + XSetWMProperties(xw.dis, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class); } void xinit(void) { - int i; - - xw.dis = XOpenDisplay(NULL); - xw.scr = XDefaultScreen(xw.dis); - if(!xw.dis) + if(!(xw.dis = XOpenDisplay(NULL))) die("Can't open display\n"); + xw.scr = XDefaultScreen(xw.dis); /* font */ if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT))) @@ -1061,8 +1092,7 @@ xinit(void) { xw.ch = dc.font->ascent + dc.font->descent; /* colors */ - for(i = 0; i < LEN(colorname); i++) - dc.col[i] = xgetcol(colorname[i]); + xloadcols(); term.c.attr.fg = DefaultFG; term.c.attr.bg = DefaultBG; @@ -1071,7 +1101,7 @@ xinit(void) { xw.h = term.row * xw.ch + 2*BORDER; xw.w = term.col * xw.cw + 2*BORDER; xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0, - xw.w, xw.h, 0, + xw.w, xw.h, 0, dc.col[DefaultBG], dc.col[DefaultBG]); xw.bufw = xw.w - 2*BORDER; @@ -1081,7 +1111,7 @@ xinit(void) { dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL); XMapWindow(xw.dis, xw.win); xhints(); - XStoreName(xw.dis, xw.win, TNAME); + XStoreName(xw.dis, xw.win, "st"); XSync(xw.dis, 0); } @@ -1101,9 +1131,9 @@ xdraws(char *s, Glyph base, int x, int y, int len) { if(base.mode & ATTR_GFX) for(i = 0; i < len; i++) - s[i] = gfx[s[i]]; + s[i] = gfx[(int)s[i]]; - XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid); + XSetFont(xw.dis, dc.gc, base.mode & ATTR_BOLD ? dc.bfont->fid : dc.font->fid); XDrawImageString(xw.dis, xw.buf, dc.gc, winx, winy, s, len); if(base.mode & ATTR_UNDERLINE) @@ -1121,7 +1151,7 @@ xcursor(int mode) { if(term.line[term.c.y][term.c.x].state & GLYPH_SET) g.c = term.line[term.c.y][term.c.x].c; - + /* remove the old cursor */ if(term.line[oldy][oldx].state & GLYPH_SET) xdraws(&term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1); @@ -1135,7 +1165,6 @@ xcursor(int mode) { } } - #ifdef DEBUG /* basic drawing routines */ void @@ -1148,7 +1177,7 @@ xdrawc(int x, int y, Glyph g) { } void -draw_(int dummy) { +draw(int dummy) { int x, y; xclear(0, 0, term.col-1, term.row-1); @@ -1162,14 +1191,17 @@ draw_(int dummy) { XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER); XFlush(xw.dis); } -#endif +#else +/* optimized drawing routine */ void draw(int redraw_all) { int i, x, y, ox; Glyph base, new; char buf[DRAW_BUF_SIZ]; + XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]); + XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h); for(y = 0; y < term.row; y++) { base = term.line[y][0]; i = ox = 0; @@ -1192,6 +1224,8 @@ draw(int redraw_all) { XFlush(xw.dis); } +#endif + void expose(XEvent *ev) { draw(SCREEN_REDRAW); @@ -1220,7 +1254,7 @@ kpress(XEvent *ev) { shift = e->state & ShiftMask; len = XLookupString(e, buf, sizeof(buf), &ksym, NULL); - if(customkey = kmap(ksym)) + if((customkey = kmap(ksym))) ttywrite(customkey, strlen(customkey)); else if(len > 0) { buf[sizeof(buf)-1] = '\0'; @@ -1233,7 +1267,7 @@ kpress(XEvent *ev) { case XK_Down: case XK_Left: case XK_Right: - sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]); + sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]); ttywrite(buf, 3); break; case XK_Insert: @@ -1300,7 +1334,7 @@ run(void) { int main(int argc, char *argv[]) { if(argc == 2 && !strncmp("-v", argv[1], 3)) - die("st-" VERSION ", © 2009 st engineers\n"); + die("st-" VERSION ", (c) 2010 st engineers\n"); else if(argc != 1) die("usage: st [-v]\n"); setlocale(LC_CTYPE, "");