X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=8ca310c92ebedb20d5f31f922d9e3f50c0d96733;hb=753fe862b14c7dd4b0449ab2c3bf22ecbb10030e;hp=c48132a738e9c479166d2ec96a07bf5c15ac7ac7;hpb=d2937b05aed9cee8d6651cd806d31682a853c773;p=st.git diff --git a/st.c b/st.c index c48132a..8ca310c 100644 --- a/st.c +++ b/st.c @@ -1,4 +1,4 @@ -/* See LICENSE for licence details. */ +/* See LICENSE for license details. */ #include #include #include @@ -158,8 +158,7 @@ enum escape_state { enum window_state { WIN_VISIBLE = 1, - WIN_REDRAW = 2, - WIN_FOCUSED = 4 + WIN_FOCUSED = 2 }; enum selection_type { @@ -352,6 +351,7 @@ static void draw(void); static void redraw(void); static void drawregion(int, int, int, int); static void execsh(void); +static void stty(void); static void sigchld(int); static void run(void); @@ -423,7 +423,7 @@ static void xsettitle(char *); static void xresettitle(void); static void xsetpointermotion(int); static void xseturgency(int); -static void xsetsel(char *); +static void xsetsel(char *, Time); static void xtermclear(int, int, int, int); static void xunloadfont(Font *); static void xunloadfonts(void); @@ -449,7 +449,7 @@ static void selinit(void); static void selnormalize(void); static inline bool selected(int, int); static char *getsel(void); -static void selcopy(void); +static void selcopy(Time); static void selscroll(int, int); static void selsnap(int, int *, int *, int); static int x2col(int); @@ -459,7 +459,7 @@ static void mousereport(XEvent *); static size_t utf8decode(char *, long *, size_t); static long utf8decodebyte(char, size_t *); -static size_t utf8encode(long, char *, size_t); +static size_t utf8encode(long, char *); static char utf8encodebyte(long, size_t); static size_t utf8len(char *); static size_t utf8validate(long *, size_t); @@ -508,6 +508,7 @@ static char *opt_title = NULL; static char *opt_embed = NULL; static char *opt_class = NULL; static char *opt_font = NULL; +static char *opt_line = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ static char *usedfont = NULL; @@ -609,11 +610,11 @@ utf8decodebyte(char c, size_t *i) { } size_t -utf8encode(long u, char *c, size_t clen) { +utf8encode(long u, char *c) { size_t len, i; len = utf8validate(&u, 0); - if(clen < len) + if(len > UTF_SIZ) return 0; for(i = len - 1; i != 0; --i) { c[i] = utf8encodebyte(u, 0); @@ -671,7 +672,8 @@ y2row(int y) { return LIMIT(y, 0, term.row-1); } -int tlinelen(int y) { +int +tlinelen(int y) { int i = term.col; if(term.line[y][i - 1].mode & ATTR_WRAP) @@ -944,7 +946,7 @@ getsel(void) { ptr = str = xmalloc(bufsize); /* append every set & selected glyph to the selection */ - for(y = sel.nb.y; y < sel.ne.y + 1; y++) { + for(y = sel.nb.y; y <= sel.ne.y; y++) { linelen = tlinelen(y); if(sel.type == SEL_RECTANGULAR) { @@ -984,8 +986,8 @@ getsel(void) { } void -selcopy(void) { - xsetsel(getsel()); +selcopy(Time t) { + xsetsel(getsel(), t); } void @@ -997,7 +999,7 @@ selnotify(XEvent *e) { XSelectionEvent *xsev; ofs = 0; - xsev = (XSelectionEvent *)e; + xsev = &e->xselection; if (xsev->property == None) return; do { @@ -1083,6 +1085,9 @@ selrequest(XEvent *e) { xev.selection = xsre->selection; xev.target = xsre->target; xev.time = xsre->time; + if (xsre->property == None) + xsre->property = xsre->target; + /* reject */ xev.property = None; @@ -1125,11 +1130,13 @@ selrequest(XEvent *e) { } void -xsetsel(char *str) { +xsetsel(char *str, Time t) { free(sel.primary); sel.primary = str; - XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime); + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(0); } void @@ -1146,7 +1153,7 @@ brelease(XEvent *e) { selclear(NULL); } else { getbuttoninfo(e); - selcopy(); + selcopy(e->xbutton.time); } sel.mode = 0; tsetdirt(sel.nb.y, sel.ne.y); @@ -1248,11 +1255,56 @@ sigchld(int a) { exit(EXIT_SUCCESS); } + +void +stty(void) +{ + char cmd[_POSIX_ARG_MAX], **p, *q, *s; + size_t n, siz; + + if((n = strlen(stty_args)) > sizeof(cmd)-1) + die("incorrect stty parameters\n"); + memcpy(cmd, stty_args, n); + q = cmd + n; + siz = sizeof(cmd) - n; + for(p = opt_cmd; p && (s = *p); ++p) { + if((n = strlen(s)) > siz-1) + die("stty parameter length too long\n"); + *q++ = ' '; + q = memcpy(q, s, n); + q += n; + siz-= n + 1; + } + *q = '\0'; + if (system(cmd) != 0) + perror("Couldn't call stty"); +} + void ttynew(void) { int m, s; struct winsize w = {term.row, term.col, 0, 0}; + if(opt_io) { + term.mode |= MODE_PRINT; + iofd = (!strcmp(opt_io, "-")) ? + STDOUT_FILENO : + open(opt_io, O_WRONLY | O_CREAT, 0666); + if(iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + opt_io, strerror(errno)); + } + } + + if (opt_line) { + if((cmdfd = open(opt_line, O_RDWR)) < 0) + die("open line failed: %s\n", strerror(errno)); + close(STDIN_FILENO); + dup(cmdfd); + stty(); + return; + } + /* seems to work fine on linux, openbsd and freebsd */ if(openpty(&m, &s, NULL, NULL, &w) < 0) die("openpty failed: %s\n", strerror(errno)); @@ -1262,6 +1314,7 @@ ttynew(void) { die("fork failed\n"); break; case 0: + close(iofd); setsid(); /* create a new process group */ dup2(s, STDIN_FILENO); dup2(s, STDOUT_FILENO); @@ -1276,16 +1329,6 @@ ttynew(void) { close(s); cmdfd = m; signal(SIGCHLD, sigchld); - if(opt_io) { - term.mode |= MODE_PRINT; - iofd = (!strcmp(opt_io, "-")) ? - STDOUT_FILENO : - open(opt_io, O_WRONLY | O_CREAT, 0666); - if(iofd < 0) { - fprintf(stderr, "Error opening %s:%s\n", - opt_io, strerror(errno)); - } - } break; } } @@ -1308,7 +1351,7 @@ ttyread(void) { buflen += ret; ptr = buf; while((charsize = utf8decode(ptr, &unicodep, buflen))) { - utf8encode(unicodep, s, UTF_SIZ); + utf8encode(unicodep, s); tputc(s, charsize); ptr += charsize; buflen -= charsize; @@ -1416,7 +1459,7 @@ treset(void) { term.top = 0; term.bot = term.row - 1; term.mode = MODE_WRAP; - memset(term.trantbl, sizeof(term.trantbl), CS_USA); + memset(term.trantbl, CS_USA, sizeof(term.trantbl)); term.charset = 0; for(i = 0; i < 2; i++) { @@ -1571,11 +1614,9 @@ tmoveto(int x, int y) { miny = 0; maxy = term.row - 1; } - LIMIT(x, 0, term.col-1); - LIMIT(y, miny, maxy); term.c.state &= ~CURSOR_WRAPNEXT; - term.c.x = x; - term.c.y = y; + term.c.x = LIMIT(x, 0, term.col-1); + term.c.y = LIMIT(y, miny, maxy); } void @@ -2228,8 +2269,7 @@ strhandle(void) { term.esc &= ~(ESC_STR_END|ESC_STR); strparse(); - narg = strescseq.narg; - par = atoi(strescseq.args[0]); + par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; switch(strescseq.type) { case ']': /* OSC -- Operating System Command */ @@ -2392,7 +2432,7 @@ tputtab(int n) { for(--x; x > 0 && !term.tabs[x]; --x) /* nothing */ ; } - tmoveto(x, term.c.y); + term.c.x = LIMIT(x, 0, term.col-1); } void @@ -2446,26 +2486,23 @@ tdectest(char c) { void tstrsequence(uchar c) { - if (c & 0x80) { - switch (c) { - case 0x90: /* DCS -- Device Control String */ - c = 'P'; - break; - case 0x9f: /* APC -- Application Program Command */ - c = '_'; - break; - case 0x9e: /* PM -- Privacy Message */ - c = '^'; - break; - case 0x9d: /* OSC -- Operating System Command */ - c = ']'; - break; - } + switch (c) { + case 0x90: /* DCS -- Device Control String */ + c = 'P'; + break; + case 0x9f: /* APC -- Application Program Command */ + c = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; } strreset(); strescseq.type = c; term.esc |= ESC_STR; - return; } void @@ -2547,7 +2584,6 @@ tcontrolcode(uchar ascii) { } /* only CAN, SUB, \a and C1 chars interrupt a sequence */ term.esc &= ~(ESC_STR_END|ESC_STR); - return; } /* @@ -2769,7 +2805,6 @@ tresize(int col, int row) { int i; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); - int slide = term.c.y - row + 1; bool *bp; TCursor c; @@ -2779,20 +2814,19 @@ tresize(int col, int row) { return; } - /* free unneeded rows */ - i = 0; - if(slide > 0) { - /* - * slide screen to keep cursor where we expect it - - * tscrollup would work here, but we can optimize to - * memmove because we're freeing the earlier lines - */ - for(/* i = 0 */; i < slide; i++) { - free(term.line[i]); - free(term.alt[i]); - } - memmove(term.line, term.line + slide, row * sizeof(Line)); - memmove(term.alt, term.alt + slide, row * sizeof(Line)); + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to + * memmove because we're freeing the earlier lines + */ + for(i = 0; i <= term.c.y - row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + /* ensure that both src and dst are not NULL */ + if (i > 0) { + memmove(term.line, term.line + i, row * sizeof(Line)); + memmove(term.alt, term.alt + i, row * sizeof(Line)); } for(i += row; i < term.row; i++) { free(term.line[i]); @@ -2864,82 +2898,58 @@ sixd_to_16bit(int x) { return x == 0 ? 0 : 0x3737 + 0x2828 * x; } +bool +xloadcolor(int i, const char *name, Color *ncolor) { + XRenderColor color = { .alpha = 0xffff }; + + if(!name) { + if(BETWEEN(i, 16, 255)) { /* 256 color */ + if(i < 6*6*6+16) { /* same colors as xterm */ + color.red = sixd_to_16bit( ((i-16)/36)%6 ); + color.green = sixd_to_16bit( ((i-16)/6) %6 ); + color.blue = sixd_to_16bit( ((i-16)/1) %6 ); + } else { /* greyscale */ + color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); + color.green = color.blue = color.red; + } + return XftColorAllocValue(xw.dpy, xw.vis, + xw.cmap, &color, ncolor); + } else + name = colorname[i]; + } + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + void xloadcols(void) { int i; - XRenderColor color = { .alpha = 0xffff }; static bool loaded; Color *cp; if(loaded) { - for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp) + for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp) XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); } - /* load colors [0-15] and [256-LEN(colorname)] (config.h) */ - for(i = 0; i < LEN(colorname); i++) { - if(!colorname[i]) - continue; - if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) { - die("Could not allocate color '%s'\n", colorname[i]); + for(i = 0; i < LEN(dc.col); i++) + if(!xloadcolor(i, NULL, &dc.col[i])) { + if(colorname[i]) + die("Could not allocate color '%s'\n", colorname[i]); + else + die("Could not allocate color %d\n", i); } - } - - /* load colors [16-231] ; same colors as xterm */ - for(i = 16; i < 6*6*6+16; i++) { - color.red = sixd_to_16bit( ((i-16)/36)%6 ); - color.green = sixd_to_16bit( ((i-16)/6) %6 ); - color.blue = sixd_to_16bit( ((i-16)/1) %6 ); - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) - die("Could not allocate color %d\n", i); - } - - /* load colors [232-255] ; grayscale */ - for(; i < 256; i++) { - color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16)); - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) - die("Could not allocate color %d\n", i); - } loaded = true; } int xsetcolorname(int x, const char *name) { - XRenderColor color = { .alpha = 0xffff }; Color ncolor; - if(!BETWEEN(x, 0, LEN(colorname))) + if(!BETWEEN(x, 0, LEN(dc.col))) return 1; - if(!name) { - if(BETWEEN(x, 16, 16 + 215)) { /* 256 color */ - color.red = sixd_to_16bit( ((x-16)/36)%6 ); - color.green = sixd_to_16bit( ((x-16)/6) %6 ); - color.blue = sixd_to_16bit( ((x-16)/1) %6 ); - if(!XftColorAllocValue(xw.dpy, xw.vis, - xw.cmap, &color, &ncolor)) { - return 1; - } - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; - return 0; - } else if(BETWEEN(x, 16 + 216, 255)) { /* greyscale */ - color.red = color.green = color.blue = \ - 0x0808 + 0x0a0a * (x - (16 + 216)); - if(!XftColorAllocValue(xw.dpy, xw.vis, - xw.cmap, &color, &ncolor)) { - return 1; - } - - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; - return 0; - } else { /* system colors */ - name = colorname[x]; - } - } - if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor)) + if(!xloadcolor(x, name, &ncolor)) return 1; XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); @@ -3662,7 +3672,6 @@ drawregion(int x1, int y1, int x2, int y2) { Glyph base, new; char buf[DRAW_BUF_SIZ]; bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - long unicodep; if(!(xw.state & WIN_VISIBLE)) return; @@ -3691,7 +3700,7 @@ drawregion(int x1, int y1, int x2, int y2) { base = new; } - sl = utf8decode(new.c, &unicodep, UTF_SIZ); + sl = utf8len(new.c); memcpy(buf+ib, new.c, sl); ib += sl; ic += (new.mode & ATTR_WIDE)? 2 : 1; @@ -3704,12 +3713,6 @@ drawregion(int x1, int y1, int x2, int y2) { void expose(XEvent *ev) { - XExposeEvent *e = &ev->xexpose; - - if(xw.state & WIN_REDRAW) { - if(!e->count) - xw.state &= ~WIN_REDRAW; - } redraw(); } @@ -3717,12 +3720,7 @@ void visibility(XEvent *ev) { XVisibilityEvent *e = &ev->xvisibility; - if(e->state == VisibilityFullyObscured) { - xw.state &= ~WIN_VISIBLE; - } else if(!(xw.state & WIN_VISIBLE)) { - /* need a full redraw for next Expose, not just a buf copy */ - xw.state |= WIN_VISIBLE | WIN_REDRAW; - } + MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE); } void @@ -3850,7 +3848,7 @@ kpress(XEvent *ev) { if(IS_SET(MODE_8BIT)) { if(*buf < 0177) { c = *buf | 0x80; - len = utf8encode(c, buf, UTF_SIZ); + len = utf8encode(c, buf); } } else { buf[1] = buf[0]; @@ -3955,7 +3953,7 @@ run(void) { clock_gettime(CLOCK_MONOTONIC, &now); drawtimeout.tv_sec = 0; - drawtimeout.tv_nsec = (1000/xfps) * 1E6; + drawtimeout.tv_nsec = (1000 * 1E6)/ xfps; tv = &drawtimeout; dodraw = 0; @@ -3966,8 +3964,7 @@ run(void) { dodraw = 1; } deltatime = TIMEDIFF(now, last); - if(deltatime > (xev? (1000/xfps) : (1000/actionfps)) - || deltatime < 0) { + if(deltatime > 1000 / (xev ? xfps : actionfps)) { dodraw = 1; last = now; } @@ -4010,14 +4007,16 @@ run(void) { void usage(void) { - die("%s " VERSION " (c) 2010-2015 st engineers\n" \ + 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] [-w windowid] [-e command ...]\n", argv0); + " [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n" + " st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n" + " [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n", + argv0); } int main(int argc, char *argv[]) { - char *titles; uint cols = 80, rows = 24; xw.l = xw.t = 0; @@ -4032,14 +4031,8 @@ main(int argc, char *argv[]) { opt_class = EARGF(usage()); break; case 'e': - /* eat all remaining arguments */ - if(argc > 1) { - opt_cmd = &argv[1]; - if(argv[1] != NULL && opt_title == NULL) { - titles = xstrdup(argv[1]); - opt_title = basename(titles); - } - } + if(argc > 1) + --argc, ++argv; goto run; case 'f': opt_font = EARGF(usage()); @@ -4054,6 +4047,9 @@ main(int argc, char *argv[]) { case 'o': opt_io = EARGF(usage()); break; + case 'l': + opt_line = EARGF(usage()); + break; case 't': opt_title = EARGF(usage()); break; @@ -4066,6 +4062,12 @@ main(int argc, char *argv[]) { } ARGEND; run: + if(argc > 0) { + /* eat all remaining arguments */ + opt_cmd = argv; + if(!opt_title && !opt_line) + opt_title = basename(xstrdup(argv[0])); + } setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); tnew(MAX(cols, 1), MAX(rows, 1));