X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=37bec706e27fdb2dc81c4061c1636888c53ccc2a;hp=96d45bf4ae82f351489ec2814a5becaa0ba3afbc;hb=315b7ee9ce13603339104cab0402d7d6c10e92b8;hpb=210dda9570095443bac887c2bfcd75f2bcc23780 diff --git a/st.c b/st.c index 96d45bf..37bec70 100644 --- a/st.c +++ b/st.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -132,10 +133,21 @@ enum term_mode { MODE_FOCUS = 65536, MODE_MOUSEX10 = 131072, MODE_MOUSEMANY = 262144, + MODE_BRCKTPASTE = 524288, MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ |MODE_MOUSEMANY, }; +enum charset { + CS_GRAPHIC0, + CS_GRAPHIC1, + CS_UK, + CS_USA, + CS_MULTI, + CS_GER, + CS_FIN +}; + enum escape_state { ESC_START = 1, ESC_CSI = 2, @@ -169,8 +181,8 @@ typedef unsigned short ushort; typedef struct { char c[UTF_SIZ]; /* character code */ ushort mode; /* attribute flags */ - ulong fg; /* foreground */ - ulong bg; /* background */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ } Glyph; typedef Glyph *Line; @@ -215,6 +227,9 @@ typedef struct { int bot; /* bottom scroll limit */ int mode; /* terminal mode flags */ int esc; /* escape state flags */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ bool numlock; /* lock numbers in keyboard */ bool *tabs; } Term; @@ -225,7 +240,7 @@ typedef struct { Colourmap cmap; Window win; Drawable buf; - Atom xembed, wmdeletewin; + Atom xembed, wmdeletewin, netwmname, netwmpid; XIM xim; XIC xic; Draw draw; @@ -242,15 +257,15 @@ typedef struct { } XWindow; typedef struct { - int b; + uint b; uint mask; - char s[ESC_BUF_SIZ]; + char *s; } Mousekey; typedef struct { KeySym k; uint mask; - char s[ESC_BUF_SIZ]; + char *s; /* three valued logic variables: 0 indifferent, 1 on, -1 off */ signed char appkey; /* application keypad */ signed char appcursor; /* application cursor */ @@ -365,11 +380,14 @@ static void tsetdirtattr(int); static void tsetmode(bool, bool, int *, int); static void tfulldirt(void); static void techo(char *, int); -static long tdefcolor(int *, int *, int); +static int32_t tdefcolor(int *, int *, int); +static void tselcs(void); +static void tdeftran(char); static inline bool match(uint, uint); static void ttynew(void); static void ttyread(void); static void ttyresize(void); +static void ttysend(char *, size_t); static void ttywrite(const char *, size_t); static void xdraws(char *, Glyph, int, int, int, int); @@ -380,7 +398,7 @@ static void xinit(void); static void xloadcols(void); static int xsetcolorname(int, const char *); static int xloadfont(Font *, FcPattern *); -static void xloadfonts(char *, int); +static void xloadfonts(char *, double); static int xloadfontset(Font *); static void xsettitle(char *); static void xresettitle(void); @@ -460,7 +478,7 @@ static char *opt_font = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ static char *usedfont = NULL; -static int usedfontsize = 0; +static double usedfontsize = 0; /* Font Ring Cache */ enum { @@ -823,18 +841,23 @@ mousereport(XEvent *e) { button = oldbutton + 32; ox = x; oy = y; - } else if(!IS_SET(MODE_MOUSESGR) - && (e->xbutton.type == ButtonRelease - || button == AnyButton)) { - button = 3; } else { - button -= Button1; - if(button >= 3) - button += 64 - 3; + if(!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { + button = 3; + } else { + button -= Button1; + if(button >= 3) + button += 64 - 3; + } if(e->xbutton.type == ButtonPress) { oldbutton = button; ox = x; oy = y; + } else if(e->xbutton.type == ButtonRelease) { + oldbutton = 3; + /* MODE_MOUSEX10: no button release reporting */ + if(IS_SET(MODE_MOUSEX10)) + return; } } @@ -851,8 +874,7 @@ mousereport(XEvent *e) { e->xbutton.type == ButtonRelease ? 'm' : 'M'); } else if(x < 223 && y < 223) { len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - IS_SET(MODE_MOUSEX10)? button-1 : 32+button, - 32+x+1, 32+y+1); + 32+button, 32+x+1, 32+y+1); } else { return; } @@ -873,9 +895,7 @@ bpress(XEvent *e) { for(mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) { if(e->xbutton.button == mk->b && match(mk->mask, e->xbutton.state)) { - ttywrite(mk->s, strlen(mk->s)); - if(IS_SET(MODE_ECHO)) - techo(mk->s, strlen(mk->s)); + ttysend(mk->s, strlen(mk->s)); return; } } @@ -933,11 +953,12 @@ selcopy(void) { /* append every set & selected glyph to the selection */ for(y = sel.nb.y; y < sel.ne.y + 1; y++) { gp = &term.line[y][0]; - last = gp + term.col; + last = &gp[term.col-1]; - while(--last >= gp && !(selected(last - gp, y) && \ - strcmp(last->c, " ") != 0)) - /* nothing */; + while(last >= gp && !(selected(last - gp, y) && + strcmp(last->c, " ") != 0)) { + --last; + } for(x = 0; gp <= last; x++, ++gp) { if(!selected(x, y) || (gp->mode & ATTR_WDUMMY)) @@ -957,7 +978,7 @@ selcopy(void) { * st. * FIXME: Fix the computer world. */ - if(y < sel.ne.y && !((gp-1)->mode & ATTR_WRAP)) + if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP)) *ptr++ = '\n'; /* @@ -1009,7 +1030,11 @@ selnotify(XEvent *e) { *repl++ = '\r'; } - ttywrite((const char *)data, nitems * format / 8); + if(IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[200~", 6); + ttysend((char *)data, nitems * format / 8); + if(IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[201~", 6); XFree(data); /* number of 32-bit chunks returned */ ofs += nitems * format / 32; @@ -1276,6 +1301,13 @@ ttywrite(const char *s, size_t n) { } void +ttysend(char *s, size_t n) { + ttywrite(s, n); + if(IS_SET(MODE_ECHO)) + techo(s, n); +} + +void ttyresize(void) { struct winsize w; @@ -1333,13 +1365,14 @@ tfulldirt(void) { void tcursor(int mode) { - static TCursor c; + static TCursor c[2]; + bool alt = IS_SET(MODE_ALTSCREEN); if(mode == CURSOR_SAVE) { - c = term.c; + c[alt] = term.c; } else if(mode == CURSOR_LOAD) { - term.c = c; - tmoveto(c.x, c.y); + term.c = c[alt]; + tmoveto(c[alt].x, c[alt].y); } } @@ -1359,6 +1392,8 @@ treset(void) { term.top = 0; term.bot = term.row - 1; term.mode = MODE_WRAP; + memset(term.trantbl, sizeof(term.trantbl), CS_USA); + term.charset = 0; tclearregion(0, 0, term.col-1, term.row-1); tmoveto(0, 0); @@ -1633,9 +1668,9 @@ tdeleteline(int n) { tscrollup(term.c.y, n); } -long +int32_t tdefcolor(int *attr, int *npar, int l) { - long idx = -1; + int32_t idx = -1; uint r, g, b; switch (attr[*npar + 1]) { @@ -1684,7 +1719,7 @@ tdefcolor(int *attr, int *npar, int l) { void tsetattr(int *attr, int l) { int i; - long idx; + int32_t idx; for(i = 0; i < l; i++) { switch(attr[i]) { @@ -1845,12 +1880,12 @@ tsetmode(bool priv, bool set, int *args, int narg) { case 1034: MODBIT(term.mode, set, MODE_8BIT); break; - case 1049: /* = 1047 and 1048 */ - case 47: + case 1049: /* swap screen & set/restore cursor as xterm */ + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + case 47: /* swap screen */ case 1047: if (!allowaltscreen) break; - alt = IS_SET(MODE_ALTSCREEN); if(alt) { tclearregion(0, 0, term.col-1, @@ -1864,6 +1899,9 @@ tsetmode(bool priv, bool set, int *args, int narg) { case 1048: tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; + case 2004: /* 2004: bracketed paste mode */ + MODBIT(term.mode, set, MODE_BRCKTPASTE); + break; /* Not implemented mouse modes. See comments there. */ case 1001: /* mouse highlight mode; can hang the terminal by design when implemented. */ @@ -1907,6 +1945,9 @@ tsetmode(bool priv, bool set, int *args, int narg) { void csihandle(void) { + char buf[40]; + int len; + switch(csiescseq.mode) { default: unknown: @@ -2055,6 +2096,13 @@ csihandle(void) { case 'm': /* SGR -- Terminal attribute (color) */ tsetattr(csiescseq.arg, csiescseq.narg); break; + case 'n': /* DSR – Device Status Report (cursor position) */ + if (csiescseq.arg[0] == 6) { + len = snprintf(buf, sizeof(buf),"\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len); + break; + } case 'r': /* DECSTBM -- Set Scrolling Region */ if(csiescseq.priv) { goto unknown; @@ -2105,20 +2153,21 @@ csireset(void) { void strhandle(void) { char *p = NULL; - int i, j, narg; + int j, narg, par; strparse(); narg = strescseq.narg; + par = atoi(strescseq.args[0]); switch(strescseq.type) { case ']': /* OSC -- Operating System Command */ - switch(i = atoi(strescseq.args[0])) { + switch(par) { case 0: case 1: case 2: if(narg > 1) xsettitle(strescseq.args[1]); - break; + return; case 4: /* color set */ if(narg < 3) break; @@ -2135,25 +2184,20 @@ strhandle(void) { */ redraw(0); } - break; - default: - fprintf(stderr, "erresc: unknown str "); - strdump(); - break; + return; } break; case 'k': /* old title set compatibility */ xsettitle(strescseq.args[0]); - break; + return; case 'P': /* DSC -- Device Control String */ case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ - default: - fprintf(stderr, "erresc: unknown str "); - strdump(); - /* die(""); */ - break; + return; } + + fprintf(stderr, "erresc: unknown str "); + strdump(); } void @@ -2237,6 +2281,33 @@ techo(char *buf, int len) { } void +tdeftran(char ascii) { + char c, (*bp)[2]; + static char tbl[][2] = { + {'0', CS_GRAPHIC0}, {'1', CS_GRAPHIC1}, {'A', CS_UK}, + {'B', CS_USA}, {'<', CS_MULTI}, {'K', CS_GER}, + {'5', CS_FIN}, {'C', CS_FIN}, + {0, 0} + }; + + for (bp = &tbl[0]; (c = (*bp)[0]) && c != ascii; ++bp) + /* nothing */; + + if (c == 0) + fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); + else + term.trantbl[term.icharset] = (*bp)[1]; +} + +void +tselcs(void) { + if (term.trantbl[term.charset] == CS_GRAPHIC0) + term.c.attr.mode |= ATTR_GFX; + else + term.c.attr.mode &= ~ATTR_GFX; +} + +void tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; @@ -2320,19 +2391,20 @@ tputc(char *c, int len) { case '\a': /* BEL */ if(!(xw.state & WIN_FOCUSED)) xseturgency(1); + if (bellvolume) + XBell(xw.dpy, bellvolume); return; case '\033': /* ESC */ csireset(); term.esc = ESC_START; return; case '\016': /* SO */ + term.charset = 0; + tselcs(); + return; case '\017': /* SI */ - /* - * Different charsets are hard to handle. Applications - * should use the right alt charset escapes for the - * only reason they still exist: line drawing. The - * rest is incompatible history st should not support. - */ + term.charset = 1; + tselcs(); return; case '\032': /* SUB */ case '\030': /* CAN */ @@ -2360,22 +2432,8 @@ tputc(char *c, int len) { if(ascii == '\\') strhandle(); } else if(term.esc & ESC_ALTCHARSET) { - switch(ascii) { - case '0': /* Line drawing set */ - term.c.attr.mode |= ATTR_GFX; - break; - 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); - } + tdeftran(ascii); + tselcs(); term.esc = 0; } else if(term.esc & ESC_TEST) { if(ascii == '8') { /* DEC screen alignment test. */ @@ -2406,13 +2464,12 @@ tputc(char *c, int len) { term.esc |= ESC_STR; break; case '(': /* set primary charset G0 */ + case ')': /* set secondary charset G1 */ + case '*': /* set tertiary charset G2 */ + case '+': /* set quaternary charset G3 */ + term.icharset = ascii - '('; 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); @@ -2766,9 +2823,9 @@ xloadfont(Font *f, FcPattern *pattern) { } void -xloadfonts(char *fontstr, int fontsize) { +xloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; - FcResult result; + FcResult r_sz, r_psz; double fontval; if(fontstr[0] == '-') { @@ -2782,12 +2839,16 @@ xloadfonts(char *fontstr, int fontsize) { if(fontsize > 0) { FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); usedfontsize = fontsize; } else { - result = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval); - if(result == FcResultMatch) { - usedfontsize = (int)fontval; + r_psz = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval); + r_sz = FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval); + if(r_psz == FcResultMatch) { + usedfontsize = fontval; + } else if(r_sz == FcResultMatch) { + usedfontsize = -1; } else { /* * Default font size is 12, if none given. This is to @@ -2804,6 +2865,12 @@ xloadfonts(char *fontstr, int fontsize) { 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); + usedfontsize = fontval; + } + /* Setting character width and height. */ xw.cw = CEIL(dc.font.width * cwscale); xw.ch = CEIL(dc.font.height * chscale); @@ -2873,6 +2940,7 @@ xinit(void) { Cursor cursor; Window parent; int sw, sh; + pid_t thispid = getpid(); if(!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); @@ -2964,8 +3032,13 @@ xinit(void) { xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&thispid, 1); + xresettitle(); XMapWindow(xw.dpy, xw.win); xhints(); @@ -3007,6 +3080,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { base.fg = defaultunderline; } if(IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; colfg.red = TRUERED(base.fg); colfg.green = TRUEGREEN(base.fg); colfg.blue = TRUEBLUE(base.fg); @@ -3017,6 +3091,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } if(IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; colbg.green = TRUEGREEN(base.bg); colbg.red = TRUERED(base.bg); colbg.blue = TRUEBLUE(base.bg); @@ -3296,6 +3371,7 @@ xsettitle(char *p) { Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); XFree(prop.value); } @@ -3442,15 +3518,7 @@ focus(XEvent *ev) { static inline bool match(uint mask, uint state) { - state &= ~ignoremod; - - if(mask == XK_NO_MOD && state) - return false; - if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state) - return false; - if(mask == XK_ANY_MOD) - return true; - return state == mask; + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); } void @@ -3480,25 +3548,16 @@ kmap(KeySym k, uint state) { if(!match(kp->mask, state)) continue; - if(kp->appkey > 0) { - if(!IS_SET(MODE_APPKEYPAD)) - continue; - if(term.numlock && kp->appkey == 2) - continue; - } else if(kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) { + if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if(term.numlock && kp->appkey == 2) continue; - } - if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) || - (kp->appcursor > 0 - && !IS_SET(MODE_APPCURSOR))) { + if(IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) continue; - } - if((kp->crlf < 0 && IS_SET(MODE_CRLF)) || - (kp->crlf > 0 && !IS_SET(MODE_CRLF))) { + if(IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0) continue; - } return kp->s; } @@ -3510,8 +3569,8 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; - char xstr[31], buf[32], *customkey, *cp = buf; - int len, ret; + char buf[32], *customkey; + int len; long c; Status status; Shortcut *bp; @@ -3519,8 +3578,7 @@ kpress(XEvent *ev) { if(IS_SET(MODE_KBDLOCK)) return; - len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status); - e->state &= ~Mod2Mask; + len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); /* 1. shortcuts */ for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if(ksym == bp->keysym && match(bp->mod, e->state)) { @@ -3531,33 +3589,26 @@ kpress(XEvent *ev) { /* 2. custom keys from config.h */ if((customkey = kmap(ksym, e->state))) { - len = strlen(customkey); - memcpy(buf, customkey, len); - /* 3. hardcoded (overrides X lookup) */ - } else { - if(len == 0) - return; + ttysend(customkey, strlen(customkey)); + return; + } - if(len == 1 && e->state & Mod1Mask) { - if(IS_SET(MODE_8BIT)) { - if(*xstr < 0177) { - c = *xstr | 0x80; - ret = utf8encode(&c, cp); - cp += ret; - len = 0; - } - } else { - *cp++ = '\033'; + /* 3. composed string from input method */ + if(len == 0) + return; + if(len == 1 && e->state & Mod1Mask) { + if(IS_SET(MODE_8BIT)) { + if(*buf < 0177) { + c = *buf | 0x80; + len = utf8encode(&c, buf); } + } else { + buf[1] = buf[0]; + buf[0] = '\033'; + len = 2; } - - memcpy(cp, xstr, len); - len = cp - buf + len; } - - ttywrite(buf, len); - if(IS_SET(MODE_ECHO)) - techo(buf, len); + ttysend(buf, len); } @@ -3625,16 +3676,18 @@ run(void) { } } + ttynew(); if(!xw.isfixed) cresize(w, h); else cresize(xw.fw, xw.fh); - ttynew(); gettimeofday(&lastblink, NULL); gettimeofday(&last, NULL); for(xev = actionfps;;) { + long deltatime; + FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); @@ -3668,8 +3721,9 @@ run(void) { gettimeofday(&lastblink, NULL); dodraw = 1; } - if(TIMEDIFF(now, last) \ - > (xev? (1000/xfps) : (1000/actionfps))) { + deltatime = TIMEDIFF(now, last); + if(deltatime > (xev? (1000/xfps) : (1000/actionfps)) + || deltatime < 0) { dodraw = 1; last = now; }