X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=031272ff41a7c468414c02442f9abe3234553794;hb=fa9a4599720703932d1c4f16b9aeee1f91f96263;hp=0db3d58716d3b5203ee4f14b1559c63b3fa2585c;hpb=dc33d1d66e89ee974cc6d7cfa2efb693ce67aa86;p=st.git diff --git a/st.c b/st.c index 0db3d58..031272f 100644 --- a/st.c +++ b/st.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -65,8 +66,10 @@ char *argv0; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) #define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) @@ -85,6 +88,8 @@ char *argv0; #define TRUEGREEN(x) (((x) & 0xff00)) #define TRUEBLUE(x) (((x) & 0xff) << 8) +/* constants */ +#define ISO14755CMD "dmenu -w %lu -p codepoint: xbutton.state & forceselmod)) { mousereport(e); return; } - for (mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) { - if (e->xbutton.button == mk->b - && match(mk->mask, e->xbutton.state)) { - ttysend(mk->s, strlen(mk->s)); + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (e->xbutton.button == ms->b + && match(ms->mask, e->xbutton.state)) { + ttysend(ms->s, strlen(ms->s)); return; } } @@ -1002,7 +1017,10 @@ getsel(void) /* append every set & selected glyph to the selection */ for (y = sel.nb.y; y <= sel.ne.y; y++) { - linelen = tlinelen(y); + if ((linelen = tlinelen(y)) == 0) { + *ptr++ = '\n'; + continue; + } if (sel.type == SEL_RECTANGULAR) { gp = &term.line[y][sel.nb.x]; @@ -1130,10 +1148,10 @@ selnotify(XEvent *e) *repl++ = '\r'; } - if (IS_SET(MODE_BRCKTPASTE)) + if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) ttywrite("\033[200~", 6); ttysend((char *)data, nitems * format / 8); - if (IS_SET(MODE_BRCKTPASTE)) + if (IS_SET(MODE_BRCKTPASTE) && rem == 0) ttywrite("\033[201~", 6); XFree(data); /* number of 32-bit chunks returned */ @@ -1144,8 +1162,7 @@ selnotify(XEvent *e) * Deleting the property again tells the selection owner to send the * next data chunk in the property. */ - if (e->type == PropertyNotify) - XDeleteProperty(xw.dpy, xw.win, (int)property); + XDeleteProperty(xw.dpy, xw.win, (int)property); } void @@ -1397,9 +1414,9 @@ stty(void) if ((n = strlen(s)) > siz-1) die("stty parameter length too long\n"); *q++ = ' '; - q = memcpy(q, s, n); + memcpy(q, s, n); q += n; - siz-= n + 1; + siz -= n + 1; } *q = '\0'; if (system(cmd) != 0) @@ -1425,8 +1442,7 @@ ttynew(void) if (opt_line) { if ((cmdfd = open(opt_line, O_RDWR)) < 0) die("open line failed: %s\n", strerror(errno)); - close(0); - dup(cmdfd); + dup2(cmdfd, 0); stty(); return; } @@ -1459,7 +1475,7 @@ ttynew(void) } } -void +size_t ttyread(void) { static char buf[BUFSIZ]; @@ -1473,25 +1489,39 @@ ttyread(void) if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) die("Couldn't read from shell: %s\n", strerror(errno)); - /* process every complete utf8 char */ buflen += ret; ptr = buf; - while ((charsize = utf8decode(ptr, &unicodep, buflen))) { - tputc(unicodep); - ptr += charsize; - buflen -= charsize; - } + for (;;) { + if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + /* process a complete utf8 char */ + charsize = utf8decode(ptr, &unicodep, buflen); + if (charsize == 0) + break; + tputc(unicodep); + ptr += charsize; + buflen -= charsize; + + } else { + if (buflen <= 0) + break; + tputc(*ptr++ & 0xFF); + buflen--; + } + } /* keep any uncomplete utf8 char for the next call */ - memmove(buf, ptr, buflen); + if (buflen > 0) + memmove(buf, ptr, buflen); + + return ret; } void ttywrite(const char *s, size_t n) { - fd_set wfd; - struct timespec tv; + fd_set wfd, rfd; ssize_t r; + size_t lim = 256; /* * Remember that we are using a pty, which might be a modem line. @@ -1501,37 +1531,32 @@ ttywrite(const char *s, size_t n) */ while (n > 0) { FD_ZERO(&wfd); + FD_ZERO(&rfd); FD_SET(cmdfd, &wfd); - tv.tv_sec = 0; - tv.tv_nsec = 0; + FD_SET(cmdfd, &rfd); /* Check if we can write. */ - if (pselect(cmdfd+1, NULL, &wfd, NULL, &tv, NULL) < 0) { + if (pselect(cmdfd+1, &rfd, &wfd, NULL, NULL, NULL) < 0) { if (errno == EINTR) continue; die("select failed: %s\n", strerror(errno)); } - if(!FD_ISSET(cmdfd, &wfd)) { - /* No, then free some buffer space. */ - ttyread(); - } else { + if (FD_ISSET(cmdfd, &wfd)) { /* - * Only write 256 bytes at maximum. This seems to be a - * reasonable value for a serial line. Bigger values - * might clog the I/O. + * Only write the bytes written by ttywrite() or the + * default of 256. This seems to be a reasonable value + * for a serial line. Bigger values might clog the I/O. */ - r = write(cmdfd, s, (n < 256)? n : 256); - if (r < 0) { - die("write error on tty: %s\n", - strerror(errno)); - } + if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0) + goto write_error; if (r < n) { /* * We weren't able to write out everything. * This means the buffer is getting full * again. Empty it. */ - ttyread(); + if (n < lim) + lim = ttyread(); n -= r; s += r; } else { @@ -1539,22 +1564,39 @@ ttywrite(const char *s, size_t n) break; } } + if (FD_ISSET(cmdfd, &rfd)) + lim = ttyread(); } + return; + +write_error: + die("write error on tty: %s\n", strerror(errno)); } void ttysend(char *s, size_t n) { int len; + char *t, *lim; Rune u; ttywrite(s, n); - if (IS_SET(MODE_ECHO)) - while ((len = utf8decode(s, &u, n)) > 0) { - techo(u); - n -= len; - s += len; + if (!IS_SET(MODE_ECHO)) + return; + + lim = &s[n]; + for (t = s; t < lim; t += len) { + if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + len = utf8decode(t, &u, n); + } else { + u = *t & 0xFF; + len = 1; } + if (len <= 0) + break; + techo(u); + n -= len; + } } void @@ -1648,7 +1690,7 @@ treset(void) term.tabs[i] = 1; term.top = 0; term.bot = term.row - 1; - term.mode = MODE_WRAP; + term.mode = MODE_WRAP|MODE_UTF8; memset(term.trantbl, CS_USA, sizeof(term.trantbl)); term.charset = 0; @@ -2428,15 +2470,15 @@ csihandle(void) break; case ' ': switch (csiescseq.mode[1]) { - case 'q': /* DECSCUSR -- Set Cursor Style */ - DEFAULT(csiescseq.arg[0], 1); - if (!BETWEEN(csiescseq.arg[0], 0, 6)) { - goto unknown; - } - xw.cursor = csiescseq.arg[0]; - break; - default: + case 'q': /* DECSCUSR -- Set Cursor Style */ + DEFAULT(csiescseq.arg[0], 1); + if (!BETWEEN(csiescseq.arg[0], 0, 6)) { goto unknown; + } + xw.cursor = csiescseq.arg[0]; + break; + default: + goto unknown; } break; } @@ -2448,22 +2490,22 @@ csidump(void) int i; uint c; - printf("ESC["); + fprintf(stderr, "ESC["); for (i = 0; i < csiescseq.len; i++) { c = csiescseq.buf[i] & 0xff; if (isprint(c)) { - putchar(c); + putc(c, stderr); } else if (c == '\n') { - printf("(\\n)"); + fprintf(stderr, "(\\n)"); } else if (c == '\r') { - printf("(\\r)"); + fprintf(stderr, "(\\r)"); } else if (c == 0x1b) { - printf("(\\e)"); + fprintf(stderr, "(\\e)"); } else { - printf("(%02x)", c); + fprintf(stderr, "(%02x)", c); } } - putchar('\n'); + putc('\n', stderr); } void @@ -2514,6 +2556,7 @@ strhandle(void) xsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ + term.mode |= ESC_DCS; case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ return; @@ -2551,24 +2594,25 @@ strdump(void) int i; uint c; - printf("ESC%c", strescseq.type); + fprintf(stderr, "ESC%c", strescseq.type); for (i = 0; i < strescseq.len; i++) { c = strescseq.buf[i] & 0xff; if (c == '\0') { + putc('\n', stderr); return; } else if (isprint(c)) { - putchar(c); + putc(c, stderr); } else if (c == '\n') { - printf("(\\n)"); + fprintf(stderr, "(\\n)"); } else if (c == '\r') { - printf("(\\r)"); + fprintf(stderr, "(\\r)"); } else if (c == 0x1b) { - printf("(\\e)"); + fprintf(stderr, "(\\e)"); } else { - printf("(%02x)", c); + fprintf(stderr, "(%02x)", c); } } - printf("ESC\\\n"); + fprintf(stderr, "ESC\\\n"); } void @@ -2577,6 +2621,13 @@ strreset(void) memset(&strescseq, 0, sizeof(strescseq)); } +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + void tprinter(char *s, size_t len) { @@ -2588,6 +2639,30 @@ tprinter(char *s, size_t len) } } +void +iso14755(const Arg *arg) +{ + char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)]; + FILE *p; + char *us, *e, codepoint[9], uc[UTF_SIZ]; + unsigned long utf32; + + snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win); + if (!(p = popen(cmd, "r"))) + return; + + us = fgets(codepoint, sizeof(codepoint), p); + pclose(p); + + if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) + return; + if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || + (*e != '\n' && *e != '\0')) + return; + + ttysend(uc, utf8encode(utf32, uc)); +} + void toggleprinter(const Arg *arg) { @@ -2674,6 +2749,15 @@ techo(Rune u) tputc(u); } +void +tdefutf8(char ascii) +{ + if (ascii == 'G') + term.mode |= MODE_UTF8; + else if (ascii == '@') + term.mode &= ~MODE_UTF8; +} + void tdeftran(char ascii) { @@ -2704,9 +2788,12 @@ tdectest(char c) void tstrsequence(uchar c) { + strreset(); + switch (c) { case 0x90: /* DCS -- Device Control String */ c = 'P'; + term.esc |= ESC_DCS; break; case 0x9f: /* APC -- Application Program Command */ c = '_'; @@ -2718,7 +2805,6 @@ tstrsequence(uchar c) c = ']'; break; } - strreset(); strescseq.type = c; term.esc |= ESC_STR; } @@ -2773,18 +2859,37 @@ tcontrolcode(uchar ascii) case '\023': /* XOFF (IGNORED) */ case 0177: /* DEL (IGNORED) */ return; + case 0x80: /* TODO: PAD */ + case 0x81: /* TODO: HOP */ + case 0x82: /* TODO: BPH */ + case 0x83: /* TODO: NBH */ case 0x84: /* TODO: IND */ break; case 0x85: /* NEL -- Next line */ tnewline(1); /* always go to first col */ break; + case 0x86: /* TODO: SSA */ + case 0x87: /* TODO: ESA */ + break; case 0x88: /* HTS -- Horizontal tab stop */ term.tabs[term.c.x] = 1; break; + case 0x89: /* TODO: HTJ */ + case 0x8a: /* TODO: VTS */ + case 0x8b: /* TODO: PLD */ + case 0x8c: /* TODO: PLU */ case 0x8d: /* TODO: RI */ case 0x8e: /* TODO: SS2 */ case 0x8f: /* TODO: SS3 */ + case 0x91: /* TODO: PU1 */ + case 0x92: /* TODO: PU2 */ + case 0x93: /* TODO: STS */ + case 0x94: /* TODO: CCH */ + case 0x95: /* TODO: MW */ + case 0x96: /* TODO: SPA */ + case 0x97: /* TODO: EPA */ case 0x98: /* TODO: SOS */ + case 0x99: /* TODO: SGCI */ break; case 0x9a: /* DECID -- Identify Terminal */ ttywrite(vtiden, sizeof(vtiden) - 1); @@ -2793,9 +2898,9 @@ tcontrolcode(uchar ascii) case 0x9c: /* TODO: ST */ break; case 0x90: /* DCS -- Device Control String */ - case 0x9f: /* APC -- Application Program Command */ - case 0x9e: /* PM -- Privacy Message */ case 0x9d: /* OSC -- Operating System Command */ + case 0x9e: /* PM -- Privacy Message */ + case 0x9f: /* APC -- Application Program Command */ tstrsequence(ascii); return; } @@ -2817,6 +2922,9 @@ eschandle(uchar ascii) case '#': term.esc |= ESC_TEST; return 0; + case '%': + term.esc |= ESC_UTF8; + return 0; case 'P': /* DCS -- Device Control String */ case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ @@ -2895,15 +3003,20 @@ tputc(Rune u) int width, len; Glyph *gp; - len = utf8encode(u, c); - if ((width = wcwidth(u)) == -1) { - memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ - width = 1; + control = ISCONTROL(u); + if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { + c[0] = u; + width = len = 1; + } else { + len = utf8encode(u, c); + if (!control && (width = wcwidth(u)) == -1) { + memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ + width = 1; + } } if (IS_SET(MODE_PRINT)) tprinter(c, len); - control = ISCONTROL(u); /* * STR sequence must be checked before anything else @@ -2914,30 +3027,47 @@ tputc(Rune u) if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) { - term.esc &= ~(ESC_START|ESC_STR); + term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); + if (IS_SET(MODE_SIXEL)) { + /* TODO: render sixel */; + term.mode &= ~MODE_SIXEL; + return; + } term.esc |= ESC_STR_END; - } else if (strescseq.len + len < sizeof(strescseq.buf) - 1) { - memmove(&strescseq.buf[strescseq.len], c, len); - strescseq.len += len; + goto check_control_code; + } + + + if (IS_SET(MODE_SIXEL)) { + /* TODO: implement sixel mode */ return; - } else { - /* - * Here is a bug in terminals. If the user never sends - * some code to stop the str or esc command, then st - * will stop responding. But this is better than - * silently failing with unknown characters. At least - * then users will report back. - * - * In the case users ever get fixed, here is the code: - */ - /* - * term.esc = 0; - * strhandle(); - */ + } + if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') + term.mode |= MODE_SIXEL; + + if (strescseq.len+len >= sizeof(strescseq.buf)-1) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * will stop responding. But this is better than + * silently failing with unknown characters. At least + * then users will report back. + * + * In the case users ever get fixed, here is the code: + */ + /* + * term.esc = 0; + * strhandle(); + */ return; } + + memmove(&strescseq.buf[strescseq.len], c, len); + strescseq.len += len; + return; } +check_control_code: /* * Actions of control codes must be performed as soon they arrive * because they can be embedded inside a control sequence, and @@ -2960,6 +3090,8 @@ tputc(Rune u) csihandle(); } return; + } else if (term.esc & ESC_UTF8) { + tdefutf8(u); } else if (term.esc & ESC_ALTCHARSET) { tdeftran(u); } else if (term.esc & ESC_TEST) { @@ -3178,17 +3310,6 @@ xsetcolorname(int x, const char *name) return 0; } -void -xtermclear(int col1, int row1, int col2, int row2) -{ - XftDrawRect(xw.draw, - &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], - borderpx + col1 * xw.cw, - borderpx + row1 * xw.ch, - (col2-col1+1) * xw.cw, - (row2-row1+1) * xw.ch); -} - /* * Absolute coordinates. */ @@ -3203,7 +3324,8 @@ xclear(int x1, int y1, int x2, int y2) void xhints(void) { - XClassHint class = {opt_class ? opt_class : termname, termname}; + XClassHint class = {opt_name ? opt_name : termname, + opt_class ? opt_class : termname}; XWMHints wm = {.flags = InputHint, .input = 1}; XSizeHints *sizeh = NULL; @@ -3251,20 +3373,64 @@ xgeommasktogravity(int mask) int xloadfont(Font *f, FcPattern *pattern) { + FcPattern *configured; FcPattern *match; FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; - match = FcFontMatch(NULL, pattern, &result); - if (!match) + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) return 1; + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); FcPatternDestroy(match); return 1; } + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("st: font slant does not match\n", stderr); + } + } + + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("st: font weight does not match\n", stderr); + } + } + + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); + f->set = NULL; - f->pattern = FcPatternDuplicate(pattern); + f->pattern = configured; f->ascent = f->match->ascent; f->descent = f->match->descent; @@ -3272,7 +3438,7 @@ xloadfont(Font *f, FcPattern *pattern) f->rbearing = f->match->max_advance_width; f->height = f->ascent + f->descent; - f->width = f->lbearing + f->rbearing; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); return 0; } @@ -3316,15 +3482,15 @@ xloadfonts(char *fontstr, double fontsize) defaultfontsize = usedfontsize; } - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - if (xloadfont(&dc.font, pattern)) die("st: can't open font %s\n", fontstr); if (usedfontsize < 0) { FcPatternGetDouble(dc.font.match->pattern, FC_PIXEL_SIZE, 0, &fontval); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); + if (xloadfont(&dc.font, pattern)) + die("st: can't open font %s\n", fontstr); usedfontsize = fontval; if (fontsize == 0) defaultfontsize = fontval; @@ -3389,6 +3555,7 @@ xzoomabs(const Arg *arg) xunloadfonts(); xloadfonts(usedfont, arg->f); cresize(0, 0); + ttyresize(); redraw(); xhints(); } @@ -3411,6 +3578,7 @@ xinit(void) Cursor cursor; Window parent; pid_t thispid = getpid(); + XColor xmousefg, xmousebg; if (!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); @@ -3434,7 +3602,7 @@ xinit(void) if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2; if (xw.gm & YNegative) - xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2; + xw.t += DisplayHeight(xw.dpy, xw.scr) - xw.h - 2; /* Events */ xw.attrs.background_pixel = dc.col[defaultbg].pixel; @@ -3483,11 +3651,22 @@ xinit(void) die("XCreateIC failed. Could not obtain input method.\n"); /* white cursor, black outline */ - cursor = XCreateFontCursor(xw.dpy, XC_xterm); + cursor = XCreateFontCursor(xw.dpy, mouseshape); XDefineCursor(xw.dpy, xw.win, cursor); - XRecolorCursor(xw.dpy, cursor, - &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff}, - &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000}); + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } + + XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); @@ -3628,7 +3807,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x specs[numspecs].font = frc[f].font; specs[numspecs].glyph = glyphidx; specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)(winy + frc[f].font->ascent); + specs[numspecs].y = (short)yp; xp += runewidth; numspecs++; } @@ -3646,14 +3825,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i XRenderColor colfg, colbg; XRectangle r; - /* Determine foreground and background colors based on mode. */ - if (base.fg == defaultfg) { - if (base.mode & ATTR_ITALIC) - base.fg = defaultitalic; - else if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) - base.fg = defaultitalic; - else if (base.mode & ATTR_UNDERLINE) - base.fg = defaultunderline; + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = defaultattr; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = defaultattr; } if (IS_TRUECOL(base.fg)) { @@ -3775,6 +3953,7 @@ xdrawglyph(Glyph g, int x, int y) { int numspecs; XftGlyphFontSpec spec; + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); xdrawglyphfontspecs(&spec, g, numspecs, x, y); } @@ -3784,7 +3963,9 @@ xdrawcursor(void) { static int oldx = 0, oldy = 0; int curx; - Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}; + Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; + int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); + Color drawcol; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -3797,10 +3978,36 @@ xdrawcursor(void) if (term.line[term.c.y][curx].mode & ATTR_WDUMMY) curx--; + /* remove the old cursor */ + og = term.line[oldy][oldx]; + if (ena_sel && selected(oldx, oldy)) + og.mode ^= ATTR_REVERSE; + xdrawglyph(og, oldx, oldy); + g.u = term.line[term.c.y][term.c.x].u; - /* remove the old cursor */ - xdrawglyph(term.line[oldy][oldx], oldx, oldy); + /* + * Select the right color for the right mode. + */ + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.bg = defaultfg; + if (ena_sel && selected(term.c.x, term.c.y)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } + } else { + if (ena_sel && selected(term.c.x, term.c.y)) { + drawcol = dc.col[defaultrcs]; + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + drawcol = dc.col[defaultcs]; + } + } if (IS_SET(MODE_HIDE)) return; @@ -3808,47 +4015,44 @@ xdrawcursor(void) /* draw the new one */ if (xw.state & WIN_FOCUSED) { switch (xw.cursor) { - case 0: /* Blinking Block */ - case 1: /* Blinking Block (Default) */ - case 2: /* Steady Block */ - if (IS_SET(MODE_REVERSE)) { - g.mode |= ATTR_REVERSE; - g.fg = defaultcs; - g.bg = defaultfg; - } - - g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE; - xdrawglyph(g, term.c.x, term.c.y); - break; - case 3: /* Blinking Underline */ - case 4: /* Steady Underline */ - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + curx * xw.cw, - borderpx + (term.c.y + 1) * xw.ch - cursorthickness, - xw.cw, cursorthickness); - break; - case 5: /* Blinking bar */ - case 6: /* Steady bar */ - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + curx * xw.cw, - borderpx + term.c.y * xw.ch, - cursorthickness, xw.ch); - break; + case 7: /* st extension: snowman */ + utf8decode("☃", &g.u, UTF_SIZ); + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ + g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE; + xdrawglyph(g, term.c.x, term.c.y); + break; + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * xw.cw, + borderpx + (term.c.y + 1) * xw.ch - \ + cursorthickness, + xw.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * xw.cw, + borderpx + term.c.y * xw.ch, + cursorthickness, xw.ch); + break; } } else { - XftDrawRect(xw.draw, &dc.col[defaultcs], + XftDrawRect(xw.draw, &drawcol, borderpx + curx * xw.cw, borderpx + term.c.y * xw.ch, xw.cw - 1, 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], + XftDrawRect(xw.draw, &drawcol, borderpx + curx * xw.cw, borderpx + term.c.y * xw.ch, 1, xw.ch - 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], + XftDrawRect(xw.draw, &drawcol, borderpx + (curx + 1) * xw.cw - 1, borderpx + term.c.y * xw.ch, 1, xw.ch - 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], + XftDrawRect(xw.draw, &drawcol, borderpx + curx * xw.cw, borderpx + (term.c.y + 1) * xw.ch - 1, xw.cw, 1); @@ -3898,7 +4102,7 @@ drawregion(int x1, int y1, int x2, int y2) { int i, x, y, ox, numspecs; Glyph base, new; - XftGlyphFontSpec* specs; + XftGlyphFontSpec *specs; int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); if (!(xw.state & WIN_VISIBLE)) @@ -3908,7 +4112,6 @@ drawregion(int x1, int y1, int x2, int y2) if (!term.dirty[y]) continue; - xtermclear(0, y, term.col, y); term.dirty[y] = 0; specs = term.specbuf; @@ -4134,7 +4337,6 @@ cresize(int width, int height) tresize(col, row); xresize(col, row); - ttyresize(); } void @@ -4144,6 +4346,7 @@ resize(XEvent *e) return; cresize(e->xconfigure.width, e->xconfigure.height); + ttyresize(); } void @@ -4172,8 +4375,9 @@ run(void) } } while (ev.type != MapNotify); - ttynew(); cresize(w, h); + ttynew(); + ttyresize(); clock_gettime(CLOCK_MONOTONIC, &last); lastblink = last; @@ -4257,14 +4461,14 @@ run(void) void usage(void) { - die("%s " VERSION " (c) 2010-2015 st engineers\n" - "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n" - " [-i] [-t title] [-T title] [-w windowid] [-e command ...]" - " [command ...]\n" - " st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n" - " [-i] [-t title] [-T title] [-w windowid] [-l line]" - " [stty_args ...]\n", - argv0); + die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" + " %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); } int @@ -4274,7 +4478,7 @@ main(int argc, char *argv[]) xw.l = xw.t = 0; xw.isfixed = False; - xw.cursor = 0; + xw.cursor = cursorshape; ARGBEGIN { case 'a': @@ -4303,6 +4507,9 @@ main(int argc, char *argv[]) case 'l': opt_line = EARGF(usage()); break; + case 'n': + opt_name = EARGF(usage()); + break; case 't': case 'T': opt_title = EARGF(usage()); @@ -4311,6 +4518,8 @@ main(int argc, char *argv[]) opt_embed = EARGF(usage()); break; case 'v': + die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0); + break; default: usage(); } ARGEND;