X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=4a505b528fb562e3487402bbd77675852062cbc2;hp=45bc89d179e561ab7ecc317f08cdd8a33caad122;hb=d945d7093d1822bf249e2e38ce97e5b37f695fdb;hpb=ec3268961d1dc4072f6caa6f97db5436da2ff411 diff --git a/st.c b/st.c index 45bc89d..4a505b5 100644 --- a/st.c +++ b/st.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -62,15 +63,13 @@ char *argv0; #define XK_NO_MOD 0 #define XK_SWITCH_MOD (1<<13) -#define REDRAW_TIMEOUT (80*1000) /* 80 ms */ - /* macros */ #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 DEFAULT(a, b) (a) = (a) ? (a) : (b) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) -#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f)) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) @@ -84,23 +83,23 @@ char *argv0; #define TRUERED(x) (((x) & 0xff0000) >> 8) #define TRUEGREEN(x) (((x) & 0xff00)) #define TRUEBLUE(x) (((x) & 0xff) << 8) +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ + + histsize + 1) % histsize] : term.line[(y) - term.scr]) -#define VT102ID "\033[?6c" - enum glyph_attribute { ATTR_NULL = 0, - ATTR_BOLD = 1, - ATTR_FAINT = 2, - ATTR_ITALIC = 4, - ATTR_UNDERLINE = 8, - ATTR_BLINK = 16, - ATTR_REVERSE = 32, - ATTR_INVISIBLE = 64, - ATTR_STRUCK = 128, - ATTR_WRAP = 256, - ATTR_WIDE = 512, - ATTR_WDUMMY = 1024, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, }; enum cursor_movement { @@ -115,27 +114,27 @@ enum cursor_state { }; enum term_mode { - MODE_WRAP = 1, - MODE_INSERT = 2, - MODE_APPKEYPAD = 4, - MODE_ALTSCREEN = 8, - MODE_CRLF = 16, - MODE_MOUSEBTN = 32, - MODE_MOUSEMOTION = 64, - MODE_REVERSE = 128, - MODE_KBDLOCK = 256, - MODE_HIDE = 512, - MODE_ECHO = 1024, - MODE_APPCURSOR = 2048, - MODE_MOUSESGR = 4096, - MODE_8BIT = 8192, - MODE_BLINK = 16384, - MODE_FBLINK = 32768, - MODE_FOCUS = 65536, - MODE_MOUSEX10 = 131072, - MODE_MOUSEMANY = 262144, - MODE_BRCKTPASTE = 524288, - MODE_PRINT = 1048576, + MODE_WRAP = 1 << 0, + MODE_INSERT = 1 << 1, + MODE_APPKEYPAD = 1 << 2, + MODE_ALTSCREEN = 1 << 3, + MODE_CRLF = 1 << 4, + MODE_MOUSEBTN = 1 << 5, + MODE_MOUSEMOTION = 1 << 6, + MODE_REVERSE = 1 << 7, + MODE_KBDLOCK = 1 << 8, + MODE_HIDE = 1 << 9, + MODE_ECHO = 1 << 10, + MODE_APPCURSOR = 1 << 11, + MODE_MOUSESGR = 1 << 12, + MODE_8BIT = 1 << 13, + MODE_BLINK = 1 << 14, + MODE_FBLINK = 1 << 15, + MODE_FOCUS = 1 << 16, + MODE_MOUSEX10 = 1 << 17, + MODE_MOUSEMANY = 1 << 18, + MODE_BRCKTPASTE = 1 << 19, + MODE_PRINT = 1 << 20, MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ |MODE_MOUSEMANY, }; @@ -200,14 +199,14 @@ typedef struct { } TCursor; /* CSI Escape sequence structs */ -/* ESC '[' [[ [] [;]] ] */ +/* ESC '[' [[ [] [;]] []] */ typedef struct { char buf[ESC_BUF_SIZ]; /* raw string */ int len; /* raw string length */ char priv; int arg[ESC_ARG_SIZ]; int narg; /* nb of args */ - char mode; + char mode[2]; } CSIEscape; /* STR Escape sequence structs */ @@ -226,6 +225,9 @@ typedef struct { int col; /* nb col */ Line *line; /* screen */ Line *alt; /* alternate screen */ + Line *hist; /* history buffer */ + int histi; /* history index */ + int scr; /* scroll back */ bool *dirty; /* dirtyness of lines */ TCursor c; /* cursor */ int top; /* top scroll limit */ @@ -260,6 +262,7 @@ typedef struct { int ch; /* char height */ int cw; /* char width */ char state; /* focus, redraw, visible */ + int cursor; /* cursor style */ } XWindow; typedef struct { @@ -293,7 +296,7 @@ typedef struct { int x, y; } nb, ne, ob, oe; - char *clip; + char *primary, *clipboard; Atom xtarget; bool alt; struct timespec tclick1; @@ -315,10 +318,15 @@ typedef struct { } Shortcut; /* function definitions used in config.h */ +static void clipcopy(const Arg *); static void clippaste(const Arg *); +static void kscrolldown(const Arg *); +static void kscrollup(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); static void xzoom(const Arg *); +static void xzoomabs(const Arg *); +static void xzoomreset(const Arg *); static void printsel(const Arg *); static void printscreen(const Arg *) ; static void toggleprinter(const Arg *); @@ -348,7 +356,7 @@ typedef struct { static void die(const char *, ...); static void draw(void); -static void redraw(int); +static void redraw(void); static void drawregion(int, int, int, int); static void execsh(void); static void sigchld(int); @@ -358,6 +366,7 @@ static void csidump(void); static void csihandle(void); static void csiparse(void); static void csireset(void); +static int eschandle(uchar ascii); static void strdump(void); static void strhandle(void); static void strparse(void); @@ -382,9 +391,9 @@ static void tnewline(int); static void tputtab(int); static void tputc(char *, int); static void treset(void); -static int tresize(int, int); -static void tscrollup(int, int); -static void tscrolldown(int, int); +static void tresize(int, int); +static void tscrollup(int, int, bool); +static void tscrolldown(int, int, bool); static void tsetattr(int *, int); static void tsetchar(char *, Glyph *, int, int); static void tsetscroll(int, int); @@ -479,7 +488,11 @@ static void (*handler[LASTEvent])(XEvent *) = { [MotionNotify] = bmotion, [ButtonPress] = bpress, [ButtonRelease] = brelease, - [SelectionClear] = selclear, +/* + * Uncomment if you want the selection to disappear when you select something + * different in another window. + */ +/* [SelectionClear] = selclear, */ [SelectionNotify] = selnotify, [SelectionRequest] = selrequest, }; @@ -504,6 +517,7 @@ static int oldbutton = 3; /* button event on startup: 3 = release */ static char *usedfont = NULL; static double usedfontsize = 0; +static double defaultfontsize = 0; static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; @@ -521,6 +535,7 @@ enum { typedef struct { XftFont *font; int flags; + long unicodep; } Fontcache; /* Fontcache is an array now. A new font will be appended to the array. */ @@ -634,11 +649,13 @@ utf8validate(long *u, size_t i) { static void selinit(void) { - memset(&sel.tclick1, 0, sizeof(sel.tclick1)); - memset(&sel.tclick2, 0, sizeof(sel.tclick2)); + clock_gettime(CLOCK_MONOTONIC, &sel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &sel.tclick2); sel.mode = 0; + sel.snap = 0; sel.ob.x = -1; - sel.clip = NULL; + sel.primary = NULL; + sel.clipboard = NULL; sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); if(sel.xtarget == None) sel.xtarget = XA_STRING; @@ -663,7 +680,10 @@ y2row(int y) { static int tlinelen(int y) { int i = term.col; - while (i > 0 && term.line[y][i - 1].c[0] == ' ') + if(TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + + while(i > 0 && TLINE(y)[i - 1].c[0] == ' ') --i; return i; @@ -683,6 +703,9 @@ selnormalize(void) { sel.nb.y = MIN(sel.ob.y, sel.oe.y); sel.ne.y = MAX(sel.ob.y, sel.oe.y); + selsnap(sel.snap, &sel.nb.x, &sel.nb.y, -1); + selsnap(sel.snap, &sel.ne.x, &sel.ne.y, +1); + /* expand selection over line breaks */ if (sel.type == SEL_RECTANGULAR) return; @@ -707,7 +730,8 @@ selected(int x, int y) { void selsnap(int mode, int *x, int *y, int direction) { int newx, newy, xt, yt; - Glyph *gp; + bool delim, prevdelim; + Glyph *gp, *prevgp; switch(mode) { case SNAP_WORD: @@ -715,6 +739,8 @@ selsnap(int mode, int *x, int *y, int direction) { * Snap around if the word wraps around at the end or * beginning of a line. */ + prevgp = &TLINE(*y)[*x]; + prevdelim = strchr(worddelimiters, prevgp->c[0]) != NULL; for(;;) { newx = *x + direction; newy = *y; @@ -728,19 +754,23 @@ selsnap(int mode, int *x, int *y, int direction) { yt = *y, xt = *x; else yt = newy, xt = newx; - if(!(term.line[yt][xt].mode & ATTR_WRAP)) + if(!(TLINE(yt)[xt].mode & ATTR_WRAP)) break; } if (newx >= tlinelen(newy)) break; - gp = &term.line[newy][newx]; - if (!(gp->mode & ATTR_WDUMMY) && strchr(worddelimiters, gp->c[0])) + gp = &TLINE(newy)[newx]; + delim = strchr(worddelimiters, gp->c[0]) != NULL; + if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->c[0] != prevgp->c[0]))) break; *x = newx; *y = newy; + prevgp = gp; + prevdelim = delim; } break; case SNAP_LINE: @@ -752,14 +782,14 @@ selsnap(int mode, int *x, int *y, int direction) { *x = (direction < 0) ? 0 : term.col - 1; if(direction < 0 && *y > 0) { for(; *y > 0; *y += direction) { - if(!(term.line[*y-1][term.col-1].mode + if(!(TLINE(*y-1)[term.col-1].mode & ATTR_WRAP)) { break; } } } else if(direction > 0 && *y < term.row-1) { for(; *y < term.row; *y += direction) { - if(!(term.line[*y][term.col-1].mode + if(!(TLINE(*y)[term.col-1].mode & ATTR_WRAP)) { break; } @@ -778,15 +808,6 @@ getbuttoninfo(XEvent *e) { sel.oe.x = x2col(e->xbutton.x); sel.oe.y = y2row(e->xbutton.y); - - if(sel.ob.y < sel.oe.y - || (sel.ob.y == sel.oe.y && sel.ob.x < sel.oe.x)) { - selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1); - selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1); - } else { - selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1); - selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1); - } selnormalize(); sel.type = SEL_REGULAR; @@ -800,66 +821,67 @@ getbuttoninfo(XEvent *e) { void mousereport(XEvent *e) { - int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), - button = e->xbutton.button, state = e->xbutton.state, - len; - char buf[40]; - static int ox, oy; - - /* from urxvt */ - if(e->xbutton.type == MotionNotify) { - if(x == ox && y == oy) - return; - if(!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) - return; - /* MOUSE_MOTION: no reporting if no button is pressed */ - if(IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) - return; - - button = oldbutton + 32; - ox = x; - oy = y; - } else { - 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; - if (button == 64 || button == 65) - return; - } - } - - if(!IS_SET(MODE_MOUSEX10)) { - button += (state & ShiftMask ? 4 : 0) - + (state & Mod4Mask ? 8 : 0) - + (state & ControlMask ? 16 : 0); - } - - len = 0; - if(IS_SET(MODE_MOUSESGR)) { - len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, - e->xbutton.type == ButtonRelease ? 'm' : 'M'); - } else if(x < 223 && y < 223) { - len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - 32+button, 32+x+1, 32+y+1); - } else { - return; - } - - ttywrite(buf, len); + return; // jason +// int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), +// button = e->xbutton.button, state = e->xbutton.state, +// len; +// char buf[40]; +// static int ox, oy; +// +// /* from urxvt */ +// if(e->xbutton.type == MotionNotify) { +// if(x == ox && y == oy) +// return; +// if(!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) +// return; +// /* MOUSE_MOTION: no reporting if no button is pressed */ +// if(IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) +// return; +// +// button = oldbutton + 32; +// ox = x; +// oy = y; +// } else { +// 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; +// if (button == 64 || button == 65) +// return; +// } +// } +// +// if(!IS_SET(MODE_MOUSEX10)) { +// button += (state & ShiftMask ? 4 : 0) +// + (state & Mod4Mask ? 8 : 0) +// + (state & ControlMask ? 16 : 0); +// } +// +// len = 0; +// if(IS_SET(MODE_MOUSESGR)) { +// len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", +// button, x+1, y+1, +// e->xbutton.type == ButtonRelease ? 'm' : 'M'); +// } else if(x < 223 && y < 223) { +// len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", +// 32+button, 32+x+1, 32+y+1); +// } else { +// return; +// } +// +// ttywrite(buf, len); } void @@ -901,8 +923,6 @@ bpress(XEvent *e) { } else { sel.snap = 0; } - selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1); - selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1); selnormalize(); /* @@ -935,13 +955,15 @@ getsel(void) { linelen = tlinelen(y); if(sel.type == SEL_RECTANGULAR) { - gp = &term.line[y][sel.nb.x]; + gp = &TLINE(y)[sel.nb.x]; lastx = sel.ne.x; } else { - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } - last = &term.line[y][MIN(lastx, linelen-1)]; + last = &TLINE(y)[MIN(lastx, linelen-1)]; + while(last >= gp && last->c[0] == ' ') + --last; for( ; gp <= last; ++gp) { if(gp->mode & ATTR_WDUMMY) @@ -961,7 +983,7 @@ getsel(void) { * st. * FIXME: Fix the computer world. */ - if(sel.ne.y > y || lastx >= linelen) + if((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) *ptr++ = '\n'; } *ptr = 0; @@ -979,12 +1001,17 @@ selnotify(XEvent *e) { int format; uchar *data, *last, *repl; Atom type; + XSelectionEvent *xsev; ofs = 0; + xsev = (XSelectionEvent *)e; + if (xsev->property == None) + return; do { - if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4, - False, AnyPropertyType, &type, &format, - &nitems, &rem, &data)) { + if(XGetWindowProperty(xw.dpy, xw.win, xsev->property, ofs, + BUFSIZ/4, False, AnyPropertyType, + &type, &format, &nitems, &rem, + &data)) { fprintf(stderr, "Clipboard allocation failed\n"); return; } @@ -1020,11 +1047,25 @@ selpaste(const Arg *dummy) { } void +clipcopy(const Arg *dummy) { + Atom clipboard; + + if(sel.clipboard != NULL) + free(sel.clipboard); + + if(sel.primary != NULL) { + sel.clipboard = xstrdup(sel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } +} + +void clippaste(const Arg *dummy) { Atom clipboard; clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY, + XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard, xw.win, CurrentTime); } @@ -1040,7 +1081,8 @@ void selrequest(XEvent *e) { XSelectionRequestEvent *xsre; XSelectionEvent xev; - Atom xa_targets, string; + Atom xa_targets, string, clipboard; + char *seltext; xsre = (XSelectionRequestEvent *) e; xev.type = SelectionNotify; @@ -1059,11 +1101,29 @@ selrequest(XEvent *e) { XA_ATOM, 32, PropModeReplace, (uchar *) &string, 1); xev.property = xsre->property; - } else if(xsre->target == sel.xtarget && sel.clip != NULL) { - XChangeProperty(xsre->display, xsre->requestor, xsre->property, - xsre->target, 8, PropModeReplace, - (uchar *) sel.clip, strlen(sel.clip)); - xev.property = xsre->property; + } else if(xsre->target == sel.xtarget || xsre->target == XA_STRING) { + /* + * xith XA_STRING non ascii characters may be incorrect in the + * requestor. It is not our problem, use utf8. + */ + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + if(xsre->selection == XA_PRIMARY) { + seltext = sel.primary; + } else if(xsre->selection == clipboard) { + seltext = sel.clipboard; + } else { + fprintf(stderr, + "Unhandled clipboard selection 0x%lx\n", + xsre->selection); + return; + } + if(seltext != NULL) { + XChangeProperty(xsre->display, xsre->requestor, + xsre->property, xsre->target, + 8, PropModeReplace, + (uchar *)seltext, strlen(seltext)); + xev.property = xsre->property; + } } /* all done, send a notification to the listener */ @@ -1073,16 +1133,10 @@ selrequest(XEvent *e) { void xsetsel(char *str) { - /* register the selection for both the clipboard and the primary */ - Atom clipboard; - - free(sel.clip); - sel.clip = str; + free(sel.primary); + sel.primary = str; XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime); - - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); } void @@ -1141,23 +1195,40 @@ die(const char *errstr, ...) { void execsh(void) { - char **args; - char *envshell = getenv("SHELL"); - const struct passwd *pass = getpwuid(getuid()); + char **args, *sh, *prog; + const struct passwd *pw; char buf[sizeof(long) * 8 + 1]; - unsetenv("COLUMNS"); - unsetenv("LINES"); - unsetenv("TERMCAP"); + errno = 0; + if((pw = getpwuid(getuid())) == NULL) { + if(errno) + die("getpwuid:%s\n", strerror(errno)); + else + die("who are you?\n"); + } - if(pass) { - setenv("LOGNAME", pass->pw_name, 1); - setenv("USER", pass->pw_name, 1); - setenv("SHELL", pass->pw_shell, 0); - setenv("HOME", pass->pw_dir, 0); + if (!(sh = getenv("SHELL"))) { + sh = (pw->pw_shell[0]) ? pw->pw_shell : shell; } + if(opt_cmd) + prog = opt_cmd[0]; + else if(utmp) + prog = utmp; + else + prog = sh; + args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL}; + snprintf(buf, sizeof(buf), "%lu", xw.win); + + unsetenv("COLUMNS"); + unsetenv("LINES"); + unsetenv("TERMCAP"); + setenv("LOGNAME", pw->pw_name, 1); + setenv("USER", pw->pw_name, 1); + setenv("SHELL", sh, 1); + setenv("HOME", pw->pw_dir, 1); + setenv("TERM", termname, 1); setenv("WINDOWID", buf, 1); signal(SIGCHLD, SIG_DFL); @@ -1167,11 +1238,8 @@ execsh(void) { signal(SIGTERM, SIG_DFL); signal(SIGALRM, SIG_DFL); - DEFAULT(envshell, shell); - setenv("TERM", termname, 1); - args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL}; - execvp(args[0], args); - exit(EXIT_FAILURE); + execvp(prog, args); + _exit(EXIT_FAILURE); } void @@ -1255,10 +1323,15 @@ ttyread(void) { /* keep any uncomplete utf8 char for the next call */ memmove(buf, ptr, buflen); + if(term.scr > 0 && term.scr < histsize-1) term.scr++; } void ttywrite(const char *s, size_t n) { + Arg arg = (Arg){ .i = term.scr }; + + kscrolldown(&arg); + if(xwrite(cmdfd, s, n) == -1) die("write error on tty: %s\n", strerror(errno)); } @@ -1358,9 +1431,12 @@ treset(void) { memset(term.trantbl, sizeof(term.trantbl), CS_USA); term.charset = 0; - tclearregion(0, 0, term.col-1, term.row-1); - tmoveto(0, 0); - tcursor(CURSOR_SAVE); + for(i = 0; i < 2; i++) { + tmoveto(0, 0); + tcursor(CURSOR_SAVE); + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } } void @@ -1383,13 +1459,51 @@ tswapscreen(void) { } void -tscrolldown(int orig, int n) { +kscrolldown(const Arg* a) { + int n = a->i; + + if(n < 0) + n = term.row + n; + + if(n > term.scr) + n = term.scr; + + if(term.scr > 0) { + term.scr -= n; + selscroll(0, -n); + tfulldirt(); + } +} + +void +kscrollup(const Arg* a) { + int n = a->i; + + if(n < 0) + n = term.row + n; + + if(term.scr <= histsize - n) { + term.scr += n; + selscroll(0, n); + tfulldirt(); + } +} + +void +tscrolldown(int orig, int n, bool copyhist) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); tsetdirt(orig, term.bot-n); + if(copyhist) { + term.histi = (term.histi - 1 + histsize) % histsize; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[term.bot]; + term.line[term.bot] = temp; + } + tclearregion(0, term.bot-n+1, term.col-1, term.bot); for(i = term.bot; i >= orig+n; i--) { @@ -1402,12 +1516,19 @@ tscrolldown(int orig, int n) { } void -tscrollup(int orig, int n) { +tscrollup(int orig, int n, bool copyhist) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); + if(copyhist) { + term.histi = (term.histi + 1) % histsize; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[orig]; + term.line[orig] = temp; + } + tclearregion(0, orig, term.col-1, orig+n-1); tsetdirt(orig+n, term.bot); @@ -1454,7 +1575,7 @@ tnewline(int first_col) { int y = term.c.y; if(y == term.bot) { - tscrollup(term.top, 1); + tscrollup(term.top, 1, true); } else { y++; } @@ -1486,7 +1607,8 @@ csiparse(void) { break; p++; } - csiescseq.mode = *p; + csiescseq.mode[0] = *p++; + csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0'; } /* for absolute user moves, when decom is set */ @@ -1553,6 +1675,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) { void tclearregion(int x1, int y1, int x2, int y2) { int x, y, temp; + Glyph *gp; if(x1 > x2) temp = x1, x1 = x2, x2 = temp; @@ -1567,10 +1690,13 @@ tclearregion(int x1, int y1, int x2, int y2) { for(y = y1; y <= y2; y++) { term.dirty[y] = 1; for(x = x1; x <= x2; x++) { + gp = &term.line[y][x]; if(selected(x, y)) selclear(NULL); - term.line[y][x] = term.c.attr; - memcpy(term.line[y][x].c, " ", 2); + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + gp->mode = 0; + memcpy(gp->c, " ", 2); } } } @@ -1610,13 +1736,13 @@ tinsertblank(int n) { void tinsertblankline(int n) { if(BETWEEN(term.c.y, term.top, term.bot)) - tscrolldown(term.c.y, n); + tscrolldown(term.c.y, n, false); } void tdeleteline(int n) { if(BETWEEN(term.c.y, term.top, term.bot)) - tscrollup(term.c.y, n); + tscrollup(term.c.y, n, false); } int32_t @@ -1798,7 +1924,7 @@ tsetmode(bool priv, bool set, int *args, int narg) { mode = term.mode; MODBIT(term.mode, set, MODE_REVERSE); if(mode != term.mode) - redraw(REDRAW_TIMEOUT); + redraw(); break; case 6: /* DECOM -- Origin */ MODBIT(term.c.state, set, CURSOR_ORIGIN); @@ -1920,7 +2046,7 @@ csihandle(void) { char buf[40]; int len; - switch(csiescseq.mode) { + switch(csiescseq.mode[0]) { default: unknown: fprintf(stderr, "erresc: unknown csi "); @@ -1961,7 +2087,7 @@ csihandle(void) { break; case 'c': /* DA -- Device Attributes */ if(csiescseq.arg[0] == 0) - ttywrite(VT102ID, sizeof(VT102ID) - 1); + ttywrite(vtiden, sizeof(vtiden) - 1); break; case 'C': /* CUF -- Cursor Forward */ case 'a': /* HPR -- Cursor Forward */ @@ -2045,11 +2171,11 @@ csihandle(void) { break; case 'S': /* SU -- Scroll line up */ DEFAULT(csiescseq.arg[0], 1); - tscrollup(term.top, csiescseq.arg[0]); + tscrollup(term.top, csiescseq.arg[0], false); break; case 'T': /* SD -- Scroll line down */ DEFAULT(csiescseq.arg[0], 1); - tscrolldown(term.top, csiescseq.arg[0]); + tscrolldown(term.top, csiescseq.arg[0], false); break; case 'L': /* IL -- Insert blank lines */ DEFAULT(csiescseq.arg[0], 1); @@ -2108,6 +2234,19 @@ csihandle(void) { case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ tcursor(CURSOR_LOAD); 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: + goto unknown; + } + break; } } @@ -2172,7 +2311,7 @@ strhandle(void) { * TODO if defaultbg color is changed, borders * are dirty */ - redraw(0); + redraw(); } return; } @@ -2192,12 +2331,23 @@ strhandle(void) { void strparse(void) { + int c; char *p = strescseq.buf; strescseq.narg = 0; strescseq.buf[strescseq.len] = '\0'; - while(p && strescseq.narg < STR_ARG_SIZ) - strescseq.args[strescseq.narg++] = strsep(&p, ";"); + + if(*p == '\0') + return; + + while(strescseq.narg < STR_ARG_SIZ) { + strescseq.args[strescseq.narg++] = p; + while((c = *p) != ';' && c != '\0') + ++p; + if(c == '\0') + return; + *p++ = '\0'; + } } void @@ -2307,13 +2457,13 @@ techo(char *buf, int len) { for(; len > 0; buf++, len--) { char c = *buf; - if(ISCONTROL(c)) { /* control code */ + if(ISCONTROL((uchar) c)) { /* control code */ if(c & 0x80) { c &= 0x7f; tputc("^", 1); tputc("[", 1); } else if(c != '\n' && c != '\r' && c != '\t') { - c ^= '\x40'; + c ^= 0x40; tputc("^", 1); } tputc(&c, 1); @@ -2339,6 +2489,19 @@ tdeftran(char ascii) { } void +tdectest(char c) { + static char E[UTF_SIZ] = "E"; + int x, y; + + if(c == '8') { /* DEC screen alignment test. */ + for(x = 0; x < term.col; ++x) { + for(y = 0; y < term.row; ++y) + tsetchar(E, &term.c.attr, x, y); + } + } +} + +void tstrsequence(uchar c) { if (c & 0x80) { switch (c) { @@ -2390,7 +2553,7 @@ tcontrolcode(uchar ascii) { if(!(xw.state & WIN_FOCUSED)) xseturgency(1); if (bellvolume) - XBell(xw.dpy, bellvolume); + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); } break; case '\033': /* ESC */ @@ -2398,11 +2561,9 @@ tcontrolcode(uchar ascii) { term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST); term.esc |= ESC_START; return; - case '\016': /* SO */ - term.charset = 0; - return; - case '\017': /* SI */ - term.charset = 1; + case '\016': /* SO (LS1 -- Locking shift 1) */ + case '\017': /* SI (LS0 -- Locking shift 0) */ + term.charset = 1 - (ascii - '\016'); return; case '\032': /* SUB */ tsetchar(question, &term.c.attr, term.c.x, term.c.y); @@ -2429,7 +2590,7 @@ tcontrolcode(uchar ascii) { case 0x98: /* TODO: SOS */ break; case 0x9a: /* DECID -- Identify Terminal */ - ttywrite(VT102ID, sizeof(VT102ID) - 1); + ttywrite(vtiden, sizeof(vtiden) - 1); break; case 0x9b: /* TODO: CSI */ case 0x9c: /* TODO: ST */ @@ -2446,17 +2607,87 @@ tcontrolcode(uchar ascii) { return; } -void -tdectest(char c) { - static char E[UTF_SIZ] = "E"; - int x, y; - - if(c == '8') { /* DEC screen alignment test. */ - for(x = 0; x < term.col; ++x) { - for(y = 0; y < term.row; ++y) - tsetchar(E, &term.c.attr, x, y); +/* + * returns 1 when the sequence is finished and it hasn't to read + * more characters for this sequence, otherwise 0 + */ +int +eschandle(uchar ascii) { + switch(ascii) { + case '[': + term.esc |= ESC_CSI; + return 0; + case '#': + term.esc |= ESC_TEST; + return 0; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + case ']': /* OSC -- Operating System Command */ + case 'k': /* old title set compatibility */ + tstrsequence(ascii); + return 0; + case 'n': /* LS2 -- Locking shift 2 */ + case 'o': /* LS3 -- Locking shift 3 */ + term.charset = 2 + (ascii - 'n'); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + term.icharset = ascii - '('; + term.esc |= ESC_ALTCHARSET; + return 0; + case 'D': /* IND -- Linefeed */ + if(term.c.y == term.bot) { + tscrollup(term.top, 1, true); + } else { + tmoveto(term.c.x, term.c.y+1); } + break; + case 'E': /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 'H': /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 'M': /* RI -- Reverse index */ + if(term.c.y == term.top) { + tscrolldown(term.top, 1, true); + } else { + tmoveto(term.c.x, term.c.y-1); + } + break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(vtiden, sizeof(vtiden) - 1); + break; + case 'c': /* RIS -- Reset to inital state */ + treset(); + xresettitle(); + xloadcols(); + break; + case '=': /* DECPAM -- Application keypad */ + term.mode |= MODE_APPKEYPAD; + break; + case '>': /* DECPNM -- Normal keypad */ + term.mode &= ~MODE_APPKEYPAD; + break; + case '7': /* DECSC -- Save Cursor */ + tcursor(CURSOR_SAVE); + break; + case '8': /* DECRC -- Restore Cursor */ + tcursor(CURSOR_LOAD); + break; + case '\\': /* ST -- String Terminator */ + if(term.esc & ESC_STR_END) + strhandle(); + break; + default: + fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", + (uchar) ascii, isprint(ascii)? ascii:'.'); + break; } + return 1; } void @@ -2472,7 +2703,10 @@ tputc(char *c, int len) { unicodep = ascii = *c; } else { utf8decode(c, &unicodep, UTF_SIZ); - width = wcwidth(unicodep); + if ((width = wcwidth(unicodep)) == -1) { + c = "\357\277\275"; /* UTF_INVALID */ + width = 1; + } control = ISCONTROLC1(unicodep); ascii = unicodep; } @@ -2543,76 +2777,9 @@ tputc(char *c, int len) { } else if(term.esc & ESC_TEST) { tdectest(ascii); } else { - switch(ascii) { - case '[': - term.esc |= ESC_CSI; - return; - case '#': - term.esc |= ESC_TEST; + if (!eschandle(ascii)) return; - case 'P': /* DCS -- Device Control String */ - case '_': /* APC -- Application Program Command */ - case '^': /* PM -- Privacy Message */ - case ']': /* OSC -- Operating System Command */ - case 'k': /* old title set compatibility */ - tstrsequence(ascii); - return; - 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; - return; - case 'D': /* IND -- Linefeed */ - if(term.c.y == term.bot) { - tscrollup(term.top, 1); - } else { - tmoveto(term.c.x, term.c.y+1); - } - break; - case 'E': /* NEL -- Next line */ - tnewline(1); /* always go to first col */ - break; - case 'H': /* HTS -- Horizontal tab stop */ - term.tabs[term.c.x] = 1; - break; - case 'M': /* RI -- Reverse index */ - if(term.c.y == term.top) { - tscrolldown(term.top, 1); - } else { - tmoveto(term.c.x, term.c.y-1); - } - break; - case 'Z': /* DECID -- Identify Terminal */ - ttywrite(VT102ID, sizeof(VT102ID) - 1); - break; - case 'c': /* RIS -- Reset to inital state */ - treset(); - xresettitle(); - xloadcols(); - break; - case '=': /* DECPAM -- Application keypad */ - term.mode |= MODE_APPKEYPAD; - break; - case '>': /* DECPNM -- Normal keypad */ - term.mode &= ~MODE_APPKEYPAD; - break; - case '7': /* DECSC -- Save Cursor */ - tcursor(CURSOR_SAVE); - break; - case '8': /* DECRC -- Restore Cursor */ - tcursor(CURSOR_LOAD); - break; - case '\\': /* ST -- String Terminator */ - if(term.esc & ESC_STR_END) - strhandle(); - break; - default: - fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", - (uchar) ascii, isprint(ascii)? ascii:'.'); - break; - } + /* sequence already finished */ } term.esc = 0; /* @@ -2628,13 +2795,16 @@ tputc(char *c, int len) { if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { gp->mode |= ATTR_WRAP; tnewline(1); + gp = &term.line[term.c.y][term.c.x]; } - if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) - memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph)); + if(IS_SET(MODE_INSERT) && term.c.x+width < term.col) + memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); - if(term.c.x+width > term.col) + if(term.c.x+width > term.col) { tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } tsetchar(c, &term.c.attr, term.c.x, term.c.y); @@ -2652,18 +2822,20 @@ tputc(char *c, int len) { } } -int +void tresize(int col, int row) { - int i; + int i, j; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); int slide = term.c.y - row + 1; bool *bp; - Line *orig; TCursor c; - if(col < 1 || row < 1) - return 0; + if(col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } /* free unneeded rows */ i = 0; @@ -2688,19 +2860,26 @@ tresize(int col, int row) { /* resize to new height */ term.line = xrealloc(term.line, row * sizeof(Line)); term.alt = xrealloc(term.alt, row * sizeof(Line)); + term.hist = xrealloc(term.hist, histsize * sizeof(Line)); term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + for(i = 0; i < histsize; i++) { + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); + for(j = mincol; j < col; j++) { + term.hist[i][j] = term.c.attr; + memcpy(term.hist[i][j].c, " ", 2); + } + } + /* resize each row to new width, zero-pad if needed */ for(i = 0; i < minrow; i++) { - term.dirty[i] = 1; term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); } /* allocate any new rows */ for(/* i == minrow */; i < row; i++) { - term.dirty[i] = 1; term.line[i] = xmalloc(col * sizeof(Glyph)); term.alt[i] = xmalloc(col * sizeof(Glyph)); } @@ -2720,10 +2899,9 @@ tresize(int col, int row) { tsetscroll(0, row-1); /* make use of the LIMIT in tmoveto */ tmoveto(term.c.x, term.c.y); - /* Clearing both screens */ - orig = term.line; + /* Clearing both screens (it makes dirty all lines) */ c = term.c; - do { + for(i = 0; i < 2; i++) { if(mincol < col && 0 < minrow) { tclearregion(mincol, 0, col - 1, minrow - 1); } @@ -2732,10 +2910,8 @@ tresize(int col, int row) { } tswapscreen(); tcursor(CURSOR_LOAD); - } while(orig != term.line); + } term.c = c; - - return (slide > 0); } void @@ -2947,7 +3123,7 @@ xloadfonts(char *fontstr, double fontsize) { if(!pattern) die("st: can't open font %s\n", fontstr); - if(fontsize > 0) { + if(fontsize > 1) { FcPatternDel(pattern, FC_PIXEL_SIZE); FcPatternDel(pattern, FC_SIZE); FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); @@ -2967,6 +3143,7 @@ xloadfonts(char *fontstr, double fontsize) { FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); usedfontsize = 12; } + defaultfontsize = usedfontsize; } FcConfigSubstitute(0, pattern, FcMatchPattern); @@ -2979,6 +3156,8 @@ xloadfonts(char *fontstr, double fontsize) { FcPatternGetDouble(dc.font.match->pattern, FC_PIXEL_SIZE, 0, &fontval); usedfontsize = fontval; + if(fontsize == 0) + defaultfontsize = fontval; } /* Setting character width and height. */ @@ -3034,14 +3213,32 @@ xunloadfonts(void) { void xzoom(const Arg *arg) { + Arg larg; + + larg.i = usedfontsize + arg->i; + xzoomabs(&larg); +} + +void +xzoomabs(const Arg *arg) { xunloadfonts(); - xloadfonts(usedfont, usedfontsize + arg->i); + xloadfonts(usedfont, arg->i); cresize(0, 0); - redraw(0); + redraw(); xhints(); } void +xzoomreset(const Arg *arg) { + Arg larg; + + if(defaultfontsize > 0) { + larg.i = defaultfontsize; + xzoomabs(&larg); + } +} + +void xinit(void) { XGCValues gcvalues; Cursor cursor; @@ -3081,8 +3278,8 @@ xinit(void) { | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; xw.attrs.colormap = xw.cmap; - parent = opt_embed ? strtol(opt_embed, NULL, 0) : \ - XRootWindow(xw.dpy, xw.scr); + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) + parent = XRootWindow(xw.dpy, xw.scr); xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity @@ -3144,7 +3341,7 @@ void xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, width = charlen * xw.cw, xp, i; - int frcflags; + int frcflags, charexists; int u8fl, u8fblen, u8cblen, doesexist; char *u8c, *u8fs; long unicodep; @@ -3327,8 +3524,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { /* Search the font cache. */ for(i = 0; i < frclen; i++) { - if(XftCharExists(xw.dpy, frc[i].font, unicodep) - && frc[i].flags == frcflags) { + charexists = XftCharExists(xw.dpy, frc[i].font, unicodep); + /* Everything correct. */ + if(charexists && frc[i].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if(!charexists && frc[i].flags == frcflags \ + && frc[i].unicodep == unicodep) { break; } } @@ -3359,8 +3561,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcMatchPattern); FcDefaultSubstitute(fcpattern); - fontpattern = FcFontSetMatch(0, fcsets, - FcTrue, fcpattern, &fcres); + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); /* * Overwrite or create the new cache entry. @@ -3368,11 +3570,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(frclen >= LEN(frc)) { frclen = LEN(frc) - 1; XftFontClose(xw.dpy, frc[frclen].font); + frc[frclen].unicodep = 0; } frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern); frc[frclen].flags = frcflags; + frc[frclen].unicodep = unicodep; i = frclen; frclen++; @@ -3438,39 +3642,60 @@ xdrawcursor(void) { xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, width, sl); + if(IS_SET(MODE_HIDE)) + return; + /* draw the new one */ - if(!(IS_SET(MODE_HIDE))) { - if(xw.state & WIN_FOCUSED) { - if(IS_SET(MODE_REVERSE)) { - g.mode |= ATTR_REVERSE; - g.fg = defaultcs; - g.bg = defaultfg; - } + 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; + } - sl = utf8len(g.c); - width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ - ? 2 : 1; - xdraws(g.c, g, term.c.x, term.c.y, width, sl); - } else { - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + curx * xw.cw, - borderpx + term.c.y * xw.ch, - xw.cw - 1, 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + curx * xw.cw, - borderpx + term.c.y * xw.ch, - 1, xw.ch - 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + (curx + 1) * xw.cw - 1, - borderpx + term.c.y * xw.ch, - 1, xw.ch - 1); - XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + curx * xw.cw, - borderpx + (term.c.y + 1) * xw.ch - 1, - xw.cw, 1); + sl = utf8len(g.c); + width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ + ? 2 : 1; + xdraws(g.c, g, term.c.x, term.c.y, width, sl); + 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 - 1, + xw.cw, 1); + 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, + 1, xw.ch); + break; } - oldx = curx, oldy = term.c.y; + } else { + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + curx * xw.cw, + borderpx + term.c.y * xw.ch, + xw.cw - 1, 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + curx * xw.cw, + borderpx + term.c.y * xw.ch, + 1, xw.ch - 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + (curx + 1) * xw.cw - 1, + borderpx + term.c.y * xw.ch, + 1, xw.ch - 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + curx * xw.cw, + borderpx + (term.c.y + 1) * xw.ch - 1, + xw.cw, 1); } + oldx = curx, oldy = term.c.y; } @@ -3491,16 +3716,9 @@ xresettitle(void) { } void -redraw(int timeout) { - struct timespec tv = {0, timeout * 1000}; - +redraw(void) { tfulldirt(); draw(); - - if(timeout > 0) { - nanosleep(&tv, NULL); - XSync(xw.dpy, False); /* necessary for a good tput flash */ - } } void @@ -3530,10 +3748,10 @@ drawregion(int x1, int y1, int x2, int y2) { xtermclear(0, y, term.col, y); term.dirty[y] = 0; - base = term.line[y][0]; + base = TLINE(y)[0]; ic = ib = ox = 0; for(x = x1; x < x2; x++) { - new = term.line[y][x]; + new = TLINE(y)[x]; if(new.mode == ATTR_WDUMMY) continue; if(ena_sel && selected(x, y)) @@ -3556,7 +3774,8 @@ drawregion(int x1, int y1, int x2, int y2) { if(ib > 0) xdraws(buf, base, ox, y, ic, ib); } - xdrawcursor(); + if(term.scr == 0) + xdrawcursor(); } void @@ -3567,7 +3786,7 @@ expose(XEvent *ev) { if(!e->count) xw.state &= ~WIN_REDRAW; } - redraw(0); + redraw(); } void @@ -3804,15 +4023,16 @@ run(void) { } if(FD_ISSET(cmdfd, &rfd)) { ttyread(); - if(blinktimeout) { - blinkset = tattrset(ATTR_BLINK); - if(!blinkset) - MODBIT(term.mode, 0, MODE_BLINK); - } } - if(FD_ISSET(xfd, &rfd)) + if(FD_ISSET(xfd, &rfd)) { xev = actionfps; + if(blinktimeout) { + lastblink = now; + MODBIT(term.mode, 1, MODE_BLINK); + blinkset = 1; + } + } clock_gettime(CLOCK_MONOTONIC, &now); drawtimeout.tv_sec = 0; @@ -3858,6 +4078,9 @@ run(void) { TIMEDIFF(now, lastblink))); } + drawtimeout.tv_sec = \ + drawtimeout.tv_nsec / 1E9; + drawtimeout.tv_nsec %= (long)1E9; } else { tv = NULL; } @@ -3868,9 +4091,9 @@ run(void) { void usage(void) { - die("%s " VERSION " (c) 2010-2014 st engineers\n" \ - "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \ - " [-t title] [-w windowid] [-e command ...]\n", argv0); + 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); } int @@ -3880,6 +4103,7 @@ main(int argc, char *argv[]) { xw.l = xw.t = 0; xw.isfixed = False; + xw.cursor = 0; ARGBEGIN { case 'a':