X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=64366afb3e9393613db1460faed9c5bd9090c05c;hp=7b0fb21e076e41730117dc52ebd736ac7dbfd50b;hb=f4a6c20f464df79a9b15b4a2a11daaa7a06c60a0;hpb=15c2bff9faa87644abf96c19b17133d03d40b974 diff --git a/st.c b/st.c index 7b0fb21..64366af 100644 --- a/st.c +++ b/st.c @@ -44,7 +44,7 @@ #endif #define USAGE \ - "st " VERSION " (c) 2010-2012 st engineers\n" \ + "st " VERSION " (c) 2010-2013 st engineers\n" \ "usage: st [-v] [-c class] [-f font] [-g geometry] [-o file]" \ " [-t title] [-w windowid] [-e command ...]\n" @@ -61,6 +61,7 @@ #define DRAW_BUF_SIZ 20*1024 #define XK_ANY_MOD UINT_MAX #define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ @@ -117,7 +118,8 @@ enum term_mode { MODE_KBDLOCK = 256, MODE_HIDE = 512, MODE_ECHO = 1024, - MODE_APPCURSOR = 2048 + MODE_APPCURSOR = 2048, + MODE_MOUSESGR = 4096, }; enum escape_state { @@ -152,7 +154,7 @@ typedef struct { uchar state; /* state flags */ } Glyph; -typedef Glyph* Line; +typedef Glyph *Line; typedef struct { Glyph attr; /* current char attributes */ @@ -303,7 +305,7 @@ static void strhandle(void); static void strparse(void); static void strreset(void); -static void tclearregion(int, int, int, int); +static void tclearregion(int, int, int, int, int); static void tcursor(int); static void tdeletechar(int); static void tdeleteline(int); @@ -666,11 +668,10 @@ getbuttoninfo(XEvent *e) { void mousereport(XEvent *e) { - int x = x2col(e->xbutton.x); - int y = y2row(e->xbutton.y); - int button = e->xbutton.button; - int state = e->xbutton.state; - char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 }; + 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 ob, ox, oy; /* from urxvt */ @@ -679,7 +680,9 @@ mousereport(XEvent *e) { return; button = ob + 32; ox = x, oy = y; - } else if(e->xbutton.type == ButtonRelease || button == AnyButton) { + } else if(!IS_SET(MODE_MOUSESGR) + && (e->xbutton.type == ButtonRelease + || button == AnyButton)) { button = 3; } else { button -= Button1; @@ -691,11 +694,23 @@ mousereport(XEvent *e) { } } - buf[3] = 32 + button + (state & ShiftMask ? 4 : 0) + button += (state & ShiftMask ? 4 : 0) + (state & Mod4Mask ? 8 : 0) + (state & ControlMask ? 16 : 0); - ttywrite(buf, sizeof(buf)); + 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 @@ -1113,7 +1128,7 @@ treset(void) { term.bot = term.row - 1; term.mode = MODE_WRAP; - tclearregion(0, 0, term.col-1, term.row-1); + tclearregion(0, 0, term.col-1, term.row-1, 0); tmoveto(0, 0); tcursor(CURSOR_SAVE); } @@ -1157,7 +1172,7 @@ tscrolldown(int orig, int n) { LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); + tclearregion(0, term.bot-n+1, term.col-1, term.bot, 0); for(i = term.bot; i >= orig+n; i--) { temp = term.line[i]; @@ -1177,7 +1192,7 @@ tscrollup(int orig, int n) { Line temp; LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, orig, term.col-1, orig+n-1); + tclearregion(0, orig, term.col-1, orig+n-1, 0); for(i = orig; i <= term.bot-n; i++) { temp = term.line[i]; @@ -1305,7 +1320,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) { } void -tclearregion(int x1, int y1, int x2, int y2) { +tclearregion(int x1, int y1, int x2, int y2, int bce) { int x, y, temp; if(x1 > x2) @@ -1320,8 +1335,15 @@ 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++) - term.line[y][x].state = 0; + for(x = x1; x <= x2; x++) { + if(bce) { + term.line[y][x] = term.c.attr; + memcpy(term.line[y][x].c, " ", 2); + term.line[y][x].state |= GLYPH_SET; + } else { + term.line[y][x].state = 0; + } + } } } @@ -1334,13 +1356,13 @@ tdeletechar(int n) { term.dirty[term.c.y] = 1; if(src >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y, 0); } void @@ -1352,13 +1374,13 @@ tinsertblank(int n) { term.dirty[term.c.y] = 1; if(dst >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst - 1, term.c.y); + tclearregion(src, term.c.y, dst - 1, term.c.y, 0); } void @@ -1398,7 +1420,8 @@ tsetattr(int *attr, int l) { case 4: term.c.attr.mode |= ATTR_UNDERLINE; break; - case 5: + case 5: /* slow blink */ + case 6: /* rapid blink */ term.c.attr.mode |= ATTR_BLINK; break; case 7: @@ -1415,6 +1438,7 @@ tsetattr(int *attr, int l) { term.c.attr.mode &= ~ATTR_UNDERLINE; break; case 25: + case 26: term.c.attr.mode &= ~ATTR_BLINK; break; case 27: @@ -1534,16 +1558,23 @@ tsetmode(bool priv, bool set, int *args, int narg) { break; case 1000: /* 1000,1002: enable xterm mouse report */ MODBIT(term.mode, set, MODE_MOUSEBTN); + MODBIT(term.mode, 0, MODE_MOUSEMOTION); break; case 1002: MODBIT(term.mode, set, MODE_MOUSEMOTION); + MODBIT(term.mode, 0, MODE_MOUSEBTN); + break; + case 1006: + MODBIT(term.mode, set, MODE_MOUSESGR); break; case 1049: /* = 1047 and 1048 */ case 47: case 1047: { alt = IS_SET(MODE_ALTSCREEN); - if(alt) - tclearregion(0, 0, term.col-1, term.row-1); + if(alt) { + tclearregion(0, 0, term.col-1, + term.row-1, 0); + } if(set ^ alt) /* set is always 1 or 0 */ tswapscreen(); if(*args != 1049) @@ -1662,17 +1693,19 @@ csihandle(void) { sel.bx = -1; switch(csiescseq.arg[0]) { case 0: /* below */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); - if(term.c.y < term.row-1) - tclearregion(0, term.c.y+1, term.col-1, term.row-1); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1); + if(term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1, 1); + } break; case 1: /* above */ if(term.c.y > 1) - tclearregion(0, 0, term.col-1, term.c.y-1); - tclearregion(0, term.c.y, term.c.x, term.c.y); + tclearregion(0, 0, term.col-1, term.c.y-1, 1); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, 0, term.col-1, term.row-1); + tclearregion(0, 0, term.col-1, term.row-1, 1); break; default: goto unknown; @@ -1681,13 +1714,14 @@ csihandle(void) { case 'K': /* EL -- Clear line */ switch(csiescseq.arg[0]) { case 0: /* right */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y, 1); break; case 1: /* left */ - tclearregion(0, term.c.y, term.c.x, term.c.y); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, term.c.y, term.col-1, term.c.y); + tclearregion(0, term.c.y, term.col-1, term.c.y, 1); break; } break; @@ -1712,7 +1746,8 @@ csihandle(void) { break; case 'X': /* ECH -- Erase char */ DEFAULT(csiescseq.arg[0], 1); - tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], term.c.y); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y, 1); break; case 'P': /* DCH -- Delete char */ DEFAULT(csiescseq.arg[0], 1); @@ -1987,10 +2022,13 @@ tputc(char *c, int len) { term.esc = ESC_START; return; case '\016': /* SO */ - term.c.attr.mode |= ATTR_GFX; - return; case '\017': /* SI */ - term.c.attr.mode &= ~ATTR_GFX; + /* + * 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. + */ return; case '\032': /* SUB */ case '\030': /* CAN */ @@ -2171,9 +2209,11 @@ tresize(int col, int row) { /* free unneeded rows */ i = 0; if(slide > 0) { - /* slide screen to keep cursor where we expect it - + /* + * 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 */ + * memmove because we're freeing the earlier lines + */ for(/* i = 0 */; i < slide; i++) { free(term.line[i]); free(term.alt[i]); @@ -2238,7 +2278,7 @@ xresize(int col, int row) { XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, 0); + XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); } @@ -2403,7 +2443,9 @@ xloadfonts(char *fontstr, int fontsize) { xw.cw = dc.font.width; xw.ch = dc.font.height; + FcPatternDel(pattern, FC_SLANT); FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if(xloadfont(&dc.bfont, pattern)) die("st: can't open font %s\n", fontstr); @@ -2414,6 +2456,7 @@ xloadfonts(char *fontstr, int fontsize) { die("st: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_MEDIUM); if(xloadfont(&dc.ifont, pattern)) die("st: can't open font %s\n", fontstr); @@ -2421,8 +2464,7 @@ xloadfonts(char *fontstr, int fontsize) { } void -xunloadfonts(void) -{ +xunloadfonts(void) { int i, ip; /* @@ -2452,8 +2494,7 @@ xunloadfonts(void) } void -xzoom(const Arg *arg) -{ +xzoom(const Arg *arg) { xunloadfonts(); xloadfonts(usedfont, usedfontsize + arg->i); cresize(0, 0); @@ -2463,6 +2504,7 @@ xzoom(const Arg *arg) void xinit(void) { XSetWindowAttributes attrs; + XGCValues gcvalues; Cursor cursor; Window parent; int sw, sh, major, minor; @@ -2502,6 +2544,7 @@ xinit(void) { xw.fy = 0; } + /* Events */ attrs.background_pixel = dc.col[defaultbg].pixel; attrs.border_pixel = dc.col[defaultbg].pixel; attrs.bit_gravity = NorthWestGravity; @@ -2527,10 +2570,13 @@ xinit(void) { usedbe = True; } else { */ - dc.gc = XCreateGC(xw.dpy, parent, 0, 0); + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, 0); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); //xw.buf = xw.win; /* @@ -2854,8 +2900,7 @@ draw(void) { } else { XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w, xw.h, 0, 0); - XSetForeground(xw.dpy, dc.gc, 0); - XSync(xw.dpy, False); + XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); } } @@ -2895,6 +2940,7 @@ drawregion(int x1, int y1, int x2, int y2) { ox = x; base = new; } + sl = utf8size(new.c); memcpy(buf+ib, new.c, sl); ib += sl; @@ -2946,6 +2992,11 @@ xseturgency(int add) { void focus(XEvent *ev) { + XFocusChangeEvent *e = &ev->xfocus; + + if(e->mode == NotifyGrab) + return; + if(ev->type == FocusIn) { XSetICFocus(xw.xic); xw.state |= WIN_FOCUSED; @@ -2958,6 +3009,8 @@ focus(XEvent *ev) { 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) @@ -3069,8 +3122,10 @@ kpress(XEvent *ev) { void cmessage(XEvent *e) { - /* See xembed specs - http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) { if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) { xw.state |= WIN_FOCUSED; @@ -3086,8 +3141,7 @@ cmessage(XEvent *e) { } void -cresize(int width, int height) -{ +cresize(int width, int height) { int col, row; if(width != 0) @@ -3115,10 +3169,12 @@ void run(void) { XEvent ev; fd_set rfd; - int xfd = XConnectionNumber(xw.dpy), i; - struct timeval drawtimeout, *tv = NULL; + int xfd = XConnectionNumber(xw.dpy), xev; + struct timeval drawtimeout, *tv = NULL, now, last; + + gettimeofday(&last, NULL); - for(i = 0;; i++) { + for(xev = actionfps;;) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); @@ -3128,35 +3184,36 @@ run(void) { die("select failed: %s\n", SERRNO); } - /* - * Stop after a certain number of reads so the user does not - * feel like the system is stuttering. - */ - if(i < 1000 && FD_ISSET(cmdfd, &rfd)) { + gettimeofday(&now, NULL); + drawtimeout.tv_sec = 0; + drawtimeout.tv_usec = (1000/xfps) * 1000; + tv = &drawtimeout; + + if(FD_ISSET(cmdfd, &rfd)) ttyread(); - /* - * Just wait a bit so it isn't disturbing the - * user and the system is able to write something. - */ - drawtimeout.tv_sec = 0; - drawtimeout.tv_usec = 5; - tv = &drawtimeout; - continue; - } - i = 0; - tv = NULL; + if(FD_ISSET(xfd, &rfd)) + xev = actionfps; - while(XPending(xw.dpy)) { - XNextEvent(xw.dpy, &ev); - if(XFilterEvent(&ev, None)) - continue; - if(handler[ev.type]) - (handler[ev.type])(&ev); - } + if(TIMEDIFF(now, last) > \ + (xev ? (1000/xfps) : (1000/actionfps))) { + while(XPending(xw.dpy)) { + XNextEvent(xw.dpy, &ev); + if(XFilterEvent(&ev, None)) + continue; + if(handler[ev.type]) + (handler[ev.type])(&ev); + } + + draw(); + XFlush(xw.dpy); + last = now; - draw(); - XFlush(xw.dpy); + if(xev && !FD_ISSET(xfd, &rfd)) + xev--; + if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) + tv = NULL; + } } }