X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=a64b84d513ae70b8e29152267ae5896eb464a523;hb=3a095984b053ebb159956368eb3258f51f50e352;hp=b2e5e2228ae46706a963cbe831b1cc9d400dfbb2;hpb=88a8f85a8a6de56d23510cf6e7810d90478085a5;p=st.git diff --git a/st.c b/st.c index b2e5e22..a64b84d 100644 --- a/st.c +++ b/st.c @@ -25,6 +25,9 @@ #include #include #include +#include +#define Glyph Glyph_ +#define Font Font_ #if defined(__linux) #include @@ -107,7 +110,8 @@ enum term_mode { MODE_MOUSEBTN = 32, MODE_MOUSEMOTION = 64, MODE_MOUSE = 32|64, - MODE_REVERSE = 128 + MODE_REVERSE = 128, + MODE_KBDLOCK = 256 }; enum escape_state { @@ -195,9 +199,12 @@ typedef struct { Atom xembed; XIM xim; XIC xic; + XftDraw *xft_draw; + Visual *vis; int scr; - Bool isfixed; /* is fixed geometry? */ + bool isfixed; /* is fixed geometry? */ int fx, fy, fw, fh; /* fixed geometry */ + int tw, th; /* tty width and height */ int w; /* window width */ int h; /* window height */ int ch; /* char height */ @@ -211,7 +218,6 @@ typedef struct { char s[ESC_BUF_SIZ]; } Key; - /* TODO: use better name for vars... */ typedef struct { int mode; @@ -227,17 +233,22 @@ typedef struct { #include "config.h" +/* Font structure */ +typedef struct { + int ascent; + int descent; + short lbearing; + short rbearing; + XFontSet set; + XftFont* xft_set; +} Font; + /* Drawing Context */ typedef struct { ulong col[LEN(colorname) < 256 ? 256 : LEN(colorname)]; + XftColor xft_col[LEN(colorname) < 256 ? 256 : LEN(colorname)]; GC gc; - struct { - int ascent; - int descent; - short lbearing; - short rbearing; - XFontSet set; - } font, bfont, ifont, ibfont; + Font font, bfont, ifont, ibfont; } DC; static void die(const char*, ...); @@ -267,7 +278,7 @@ static void tmoveto(int, int); static void tnew(int, int); static void tnewline(int); static void tputtab(bool); -static void tputc(char*); +static void tputc(char*, int); static void treset(void); static int tresize(int, int); static void tscrollup(int, int); @@ -282,7 +293,7 @@ static void tfulldirt(void); static void ttynew(void); static void ttyread(void); -static void ttyresize(int, int); +static void ttyresize(void); static void ttywrite(const char *, size_t); static void xdraws(char *, Glyph, int, int, int, int); @@ -873,7 +884,7 @@ ttyread(void) { while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) { charsize = utf8decode(ptr, &utf8c); utf8encode(&utf8c, s); - tputc(s); + tputc(s, charsize); ptr += charsize; buflen -= charsize; } @@ -889,13 +900,13 @@ ttywrite(const char *s, size_t n) { } void -ttyresize(int x, int y) { +ttyresize(void) { struct winsize w; w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = xw.w; - w.ws_ypixel = xw.h; + w.ws_xpixel = xw.tw; + w.ws_ypixel = xw.th; if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0) fprintf(stderr, "Couldn't set window size: %s\n", SERRNO); } @@ -930,7 +941,7 @@ tcursor(int mode) { void treset(void) { - unsigned i; + uint i; term.c = (TCursor){{ .mode = ATTR_NULL, .fg = DefaultFG, @@ -942,6 +953,7 @@ treset(void) { term.tabs[i] = 1; term.top = 0, term.bot = term.row - 1; term.mode = MODE_WRAP; + tclearregion(0, 0, term.col-1, term.row-1); } @@ -1082,6 +1094,27 @@ tmoveto(int x, int y) { void tsetchar(char *c) { + /* + * The table is proudly stolen from rxvt. + */ + if(term.c.attr.mode & ATTR_GFX) { + char *vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + if(c[0] >= 0x41 && c[0] <= 0x7e + && vt100_0[c[0] - 0x41]) { + c = vt100_0[c[0] - 0x41]; + } + } + term.dirty[term.c.y] = 1; term.line[term.c.y][term.c.x] = term.c.attr; memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ); @@ -1268,7 +1301,8 @@ tsetmode(bool priv, bool set, int *args, int narg) { for(lim = args + narg; args < lim; ++args) { if(priv) { switch(*args) { - case 1: + break; + case 1: /* DECCKM -- Cursor key */ MODBIT(term.mode, set, MODE_APPKEYPAD); break; case 5: /* DECSCNM -- Reverve video */ @@ -1277,12 +1311,14 @@ tsetmode(bool priv, bool set, int *args, int narg) { if(mode != term.mode) redraw(); break; - case 7: + case 6: /* XXX: DECOM -- Origin */ + break; + case 7: /* DECAWM -- Auto wrap */ MODBIT(term.mode, set, MODE_WRAP); break; - case 20: - MODBIT(term.mode, set, MODE_CRLF); + case 8: /* XXX: DECARM -- Auto repeat */ break; + case 0: /* Error (IGNORED) */ case 12: /* att610 -- Start blinking cursor (IGNORED) */ break; case 25: @@ -1310,6 +1346,12 @@ tsetmode(bool priv, bool set, int *args, int narg) { tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; default: + /* case 2: DECANM -- ANSI/VT52 (NOT SUPPOURTED) */ + /* case 3: DECCOLM -- Column (NOT SUPPORTED) */ + /* case 4: DECSCLM -- Scroll (NOT SUPPORTED) */ + /* case 18: DECPFF -- Printer feed (NOT SUPPORTED) */ + /* case 19: DECPEX -- Printer extent (NOT SUPPORTED) */ + /* case 42: DECNRCM -- National characters (NOT SUPPORTED) */ fprintf(stderr, "erresc: unknown private set/reset mode %d\n", *args); @@ -1317,9 +1359,19 @@ tsetmode(bool priv, bool set, int *args, int narg) { } } else { switch(*args) { - case 4: + case 0: /* Error (IGNORED) */ + break; + case 2: /* KAM -- keyboard action */ + MODBIT(term.mode, set, MODE_KBDLOCK); + break; + case 4: /* IRM -- Insertion-replacement */ MODBIT(term.mode, set, MODE_INSERT); break; + case 12: /* XXX: SRM -- Send/Receive */ + break; + case 20: /* LNM -- Linefeed/new line */ + MODBIT(term.mode, set, MODE_CRLF); + break; default: fprintf(stderr, "erresc: unknown set/reset mode %d\n", @@ -1593,7 +1645,7 @@ strreset(void) { void tputtab(bool forward) { - unsigned x = term.c.x; + uint x = term.c.x; if(forward) { if(x == term.col) @@ -1610,11 +1662,11 @@ tputtab(bool forward) { } void -tputc(char *c) { +tputc(char *c, int len) { char ascii = *c; if(iofd != -1) - write(iofd, c, 1); + write(iofd, c, len); if(term.esc & ESC_START) { if(term.esc & ESC_CSI) { @@ -1645,12 +1697,18 @@ tputc(char *c) { strhandle(); } else if(term.esc & ESC_ALTCHARSET) { switch(ascii) { - case '0': /* Line drawing crap */ + case '0': /* Line drawing set */ term.c.attr.mode |= ATTR_GFX; break; - case 'B': /* Back to regular text */ + case 'B': /* USASCII */ term.c.attr.mode &= ~ATTR_GFX; break; + case 'A': /* UK (IGNORED) */ + case '<': /* multinational charset (IGNORED) */ + case '5': /* Finnish (IGNORED) */ + case 'C': /* Finnish (IGNORED) */ + case 'K': /* German (IGNORED) */ + break; default: fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); } @@ -1669,9 +1727,14 @@ tputc(char *c) { strescseq.type = ascii; term.esc |= ESC_STR; break; - case '(': + case '(': /* set primary charset G0 */ term.esc |= ESC_ALTCHARSET; break; + case ')': /* set secondary charset G1 (IGNORED) */ + case '*': /* set tertiary charset G2 (IGNORED) */ + case '+': /* set quaternary charset G3 (IGNORED) */ + term.esc = 0; + break; case 'D': /* IND -- Linefeed */ if(term.c.y == term.bot) tscrollup(term.top, 1); @@ -1697,6 +1760,7 @@ tputc(char *c) { case 'c': /* RIS -- Reset to inital state */ treset(); term.esc = 0; + xclear(0, 0, xw.w, xw.h); xresettitle(); break; case '=': /* DECPAM -- Application keypad */ @@ -1837,49 +1901,51 @@ tresize(int col, int row) { void xresize(int col, int row) { - xw.w = MAX(1, 2*BORDER + col * xw.cw); - xw.h = MAX(1, 2*BORDER + row * xw.ch); + xw.tw = MAX(1, 2*BORDER + col * xw.cw); + xw.th = MAX(1, 2*BORDER + row * xw.ch); + + XftDrawChange(xw.xft_draw, xw.buf); } void xloadcols(void) { int i, r, g, b; - XColor color; + XRenderColor xft_color = { .alpha = 0 }; ulong white = WhitePixel(xw.dpy, xw.scr); /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */ for(i = 0; i < LEN(colorname); i++) { if(!colorname[i]) continue; - if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) { + if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) { dc.col[i] = white; fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]); } else - dc.col[i] = color.pixel; + dc.col[i] = dc.xft_col[i].pixel; } /* load colors [16-255] ; same colors as xterm */ for(i = 16, 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.dpy, xw.cmap, &color)) { + xft_color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; + xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; + xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) { dc.col[i] = white; fprintf(stderr, "Could not allocate color %d\n", i); } else - dc.col[i] = color.pixel; + dc.col[i] = dc.xft_col[i].pixel; i++; } for(r = 0; r < 24; r++, i++) { - color.red = color.green = color.blue = 0x0808 + 0x0a0a * r; - if(!XAllocColor(xw.dpy, xw.cmap, &color)) { + xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r; + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) { dc.col[i] = white; fprintf(stderr, "Could not allocate color %d\n", i); } else - dc.col[i] = color.pixel; + dc.col[i] = dc.xft_col[i].pixel; } } @@ -1916,58 +1982,25 @@ xhints(void) { XFree(sizeh); } -XFontSet -xinitfont(char *fontstr) { - XFontSet set; - char *def, **missing; - int n; - - missing = NULL; - set = XCreateFontSet(xw.dpy, fontstr, &missing, &n, &def); - if(missing) { - while(n--) - fprintf(stderr, "st: missing fontset: %s\n", missing[n]); - XFreeStringList(missing); - } - return set; -} - void -xgetfontinfo(XFontSet set, int *ascent, int *descent, short *lbearing, short *rbearing) { - XFontStruct **xfonts; - char **font_names; - int i, n; +xinitfont(Font *f, char *fontstr) { + f->xft_set = XftFontOpenName(xw.dpy, xw.scr, fontstr); - *ascent = *descent = *lbearing = *rbearing = 0; - n = XFontsOfFontSet(set, &xfonts, &font_names); - for(i = 0; i < n; i++) { - *ascent = MAX(*ascent, (*xfonts)->ascent); - *descent = MAX(*descent, (*xfonts)->descent); - *lbearing = MAX(*lbearing, (*xfonts)->min_bounds.lbearing); - *rbearing = MAX(*rbearing, (*xfonts)->max_bounds.rbearing); - xfonts++; - } + if(!f->xft_set) + die("st: can't open font %s.\n", fontstr); + + f->ascent = f->xft_set->ascent; + f->descent = f->xft_set->descent; + f->lbearing = 0; + f->rbearing = f->xft_set->max_advance_width; } void initfonts(char *fontstr, char *bfontstr, char *ifontstr, char *ibfontstr) { - if((dc.font.set = xinitfont(fontstr)) == NULL) - die("Can't load font %s\n", fontstr); - if((dc.bfont.set = xinitfont(bfontstr)) == NULL) - die("Can't load bfont %s\n", bfontstr); - if((dc.ifont.set = xinitfont(ifontstr)) == NULL) - die("Can't load ifont %s\n", ifontstr); - if((dc.ibfont.set = xinitfont(ibfontstr)) == NULL) - die("Can't load ibfont %s\n", ibfontstr); - - xgetfontinfo(dc.font.set, &dc.font.ascent, &dc.font.descent, - &dc.font.lbearing, &dc.font.rbearing); - xgetfontinfo(dc.bfont.set, &dc.bfont.ascent, &dc.bfont.descent, - &dc.bfont.lbearing, &dc.bfont.rbearing); - xgetfontinfo(dc.ifont.set, &dc.ifont.ascent, &dc.ifont.descent, - &dc.ifont.lbearing, &dc.ifont.rbearing); - xgetfontinfo(dc.ibfont.set, &dc.ibfont.ascent, &dc.ibfont.descent, - &dc.ibfont.lbearing, &dc.ibfont.rbearing); + xinitfont(&dc.font, fontstr); + xinitfont(&dc.bfont, bfontstr); + xinitfont(&dc.ifont, ifontstr); + xinitfont(&dc.ibfont, ibfontstr); } void @@ -1980,6 +2013,7 @@ xinit(void) { if(!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ initfonts(FONT, BOLDFONT, ITALICFONT, ITALICBOLDFONT); @@ -2022,14 +2056,19 @@ xinit(void) { parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr); xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy, xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, - XDefaultVisual(xw.dpy, xw.scr), + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask | CWColormap, &attrs); + + /* double buffering */ if(!XdbeQueryExtension(xw.dpy, &major, &minor)) die("Xdbe extension is not present\n"); xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied); + /* Xft rendering context */ + xw.xft_draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + /* input methods */ xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing @@ -2057,8 +2096,8 @@ void xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { int fg = base.fg, bg = base.bg, temp; int winx = BORDER+x*xw.cw, winy = BORDER+y*xw.ch + dc.font.ascent, width = charlen*xw.cw; - XFontSet fontset = dc.font.set; - int i; + Font *font = &dc.font; + XGlyphInfo extents; /* only switch default fg/bg if term is in RV mode */ if(IS_SET(MODE_REVERSE)) { @@ -2073,28 +2112,21 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(base.mode & ATTR_BOLD) { fg += 8; - fontset = dc.bfont.set; + font = &dc.bfont; } if(base.mode & ATTR_ITALIC) - fontset = dc.ifont.set; + font = &dc.ifont; if(base.mode & (ATTR_ITALIC|ATTR_ITALIC)) - fontset = dc.ibfont.set; + font = &dc.ibfont; XSetBackground(xw.dpy, dc.gc, dc.col[bg]); XSetForeground(xw.dpy, dc.gc, dc.col[fg]); - if(base.mode & ATTR_GFX) { - for(i = 0; i < bytelen; i++) { - char c = gfx[(uint)s[i] % 256]; - if(c) - s[i] = c; - else if(s[i] > 0x5f) - s[i] -= 0x5f; - } - } - - XmbDrawImageString(xw.dpy, xw.buf, fontset, dc.gc, winx, winy, s, bytelen); + XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents); + width = extents.xOff; + XftDrawRect(xw.xft_draw, &dc.xft_col[bg], winx, winy - font->ascent, width, xw.ch); + XftDrawStringUtf8(xw.xft_draw, &dc.xft_col[fg], font->xft_set, winx, winy, (FcChar8 *)s, bytelen); if(base.mode & ATTR_UNDERLINE) XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1); @@ -2142,6 +2174,8 @@ xresettitle(void) { void redraw(void) { struct timespec tv = {0, REDRAW_TIMEOUT * 1000}; + + xclear(0, 0, xw.w, xw.h); tfulldirt(); draw(); XSync(xw.dpy, False); /* necessary for a good tput flash */ @@ -2265,6 +2299,8 @@ kpress(XEvent *ev) { int shift; Status status; + if (IS_SET(MODE_KBDLOCK)) + return; meta = e->state & Mod1Mask; shift = e->state & ShiftMask; len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status); @@ -2331,9 +2367,11 @@ resize(XEvent *e) { row = (xw.h - 2*BORDER) / xw.ch; if(col == term.col && row == term.row) return; + + xclear(0, 0, xw.w, xw.h); tresize(col, row); xresize(col, row); - ttyresize(col, row); + ttyresize(); } void @@ -2388,7 +2426,7 @@ run(void) { int main(int argc, char *argv[]) { int i, bitm, xr, yr; - unsigned int wr, hr; + uint wr, hr; xw.fw = xw.fh = xw.fx = xw.fy = 0; xw.isfixed = False;