X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=c938ff43a65363dd957c354801c89194a24d4648;hb=b1813b14d956978ae8af37166b3cccc3a7b4b720;hp=f4b419eb1a6f70a8d11def687a197e12ae7d48eb;hpb=95033753be32e93915ddce14ea41b8765b665771;p=st.git diff --git a/st.c b/st.c index f4b419e..c938ff4 100644 --- a/st.c +++ b/st.c @@ -1,5 +1,4 @@ /* See LICENSE for licence details. */ -#define _XOPEN_SOURCE 600 #include #include #include @@ -25,10 +24,13 @@ #include #include #include -#include #include #include +#include "arg.h" + +char *argv0; + #define Glyph Glyph_ #define Font Font_ #define Draw XftDraw * @@ -43,10 +45,6 @@ #include #endif -#define USAGE \ - "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" /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 @@ -61,6 +59,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 */ @@ -136,6 +135,11 @@ enum window_state { WIN_FOCUSED = 4 }; +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + /* bit macro */ #undef B0 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; @@ -233,6 +237,7 @@ typedef struct { /* TODO: use better name for vars... */ typedef struct { int mode; + int type; int bx, by; int ex, ey; struct { @@ -260,9 +265,10 @@ typedef struct { } Shortcut; /* function definitions used in config.h */ -static void xzoom(const Arg *); -static void selpaste(const Arg *); +static void clippaste(const Arg *); static void numlock(const Arg *); +static void selpaste(const Arg *); +static void xzoom(const Arg *); /* Config.h for applying patches and the configuration. */ #include "config.h" @@ -341,8 +347,10 @@ static void xclear(int, int, int, int); static void xdrawcursor(void); 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 xsettitle(char *); static void xresettitle(void); static void xseturgency(int); static void xsetsel(char*); @@ -415,8 +423,6 @@ static char *opt_embed = NULL; static char *opt_class = NULL; static char *opt_font = NULL; -bool usedbe = False; - static char *usedfont = NULL; static int usedfontsize = 0; @@ -643,17 +649,25 @@ selected(int x, int y) { if(sel.ey == y && sel.by == y) { bx = MIN(sel.bx, sel.ex); ex = MAX(sel.bx, sel.ex); + return BETWEEN(x, bx, ex); } + if(sel.type == SEL_RECTANGULAR) { + return ((sel.b.y <= y && y <= sel.e.y) + && (sel.b.x <= x && x <= sel.e.x)); + } return ((sel.b.y < y && y < sel.e.y) - || (y == sel.e.y && x <= sel.e.x)) - || (y == sel.b.y && x >= sel.b.x - && (x <= sel.e.x || sel.b.y != sel.e.y)); + || (y == sel.e.y && x <= sel.e.x)) + || (y == sel.b.y && x >= sel.b.x + && (x <= sel.e.x || sel.b.y != sel.e.y)); } void getbuttoninfo(XEvent *e) { + int type; + uint state = e->xbutton.state &~Button1Mask; + sel.alt = IS_SET(MODE_ALTSCREEN); sel.ex = x2col(e->xbutton.x); @@ -663,6 +677,14 @@ getbuttoninfo(XEvent *e) { sel.b.y = MIN(sel.by, sel.ey); sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; sel.e.y = MAX(sel.by, sel.ey); + + sel.type = SEL_REGULAR; + for(type = 1; type < LEN(selmasks); ++type) { + if(match(selmasks[type], state)) { + sel.type = type; + break; + } + } } void @@ -723,6 +745,7 @@ bpress(XEvent *e) { draw(); } sel.mode = 1; + sel.type = SEL_REGULAR; sel.ex = sel.bx = x2col(e->xbutton.x); sel.ey = sel.by = y2row(e->xbutton.y); } else if(e->xbutton.button == Button4) { @@ -745,7 +768,8 @@ selcopy(void) { ptr = str = xmalloc(bufsize); /* append every set & selected glyph to the selection */ - for(y = 0; y < term.row; y++) { + for(y = sel.b.y; y < sel.e.y + 1; y++) { + is_selected = 0; gp = &term.line[y][0]; last = gp + term.col; @@ -753,8 +777,11 @@ selcopy(void) { /* nothing */; for(x = 0; gp <= last; x++, ++gp) { - if(!(is_selected = selected(x, y))) + if(!selected(x, y)) { continue; + } else { + is_selected = 1; + } p = (gp->state & GLYPH_SET) ? gp->c : " "; size = utf8size(p); @@ -763,7 +790,7 @@ selcopy(void) { } /* \n at the end of every selected line except for the last one */ if(is_selected && y < sel.e.y) - *ptr++ = '\n'; + *ptr++ = '\r'; } *ptr = 0; } @@ -798,7 +825,17 @@ selpaste(const Arg *dummy) { xw.win, CurrentTime); } -void selclear(XEvent *e) { +void +clippaste(const Arg *dummy) { + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +selclear(XEvent *e) { if(sel.bx == -1) return; sel.bx = -1; @@ -906,7 +943,7 @@ brelease(XEvent *e) { void bmotion(XEvent *e) { - int starty, endy, oldey, oldex; + int oldey, oldex, oldsby, oldsey; if(IS_SET(MODE_MOUSE)) { mousereport(e); @@ -918,12 +955,12 @@ bmotion(XEvent *e) { oldey = sel.ey; oldex = sel.ex; + oldsby = sel.b.y; + oldsey = sel.e.y; getbuttoninfo(e); if(oldey != sel.ey || oldex != sel.ex) { - starty = MIN(oldey, sel.ey); - endy = MAX(oldey, sel.ey); - tsetdirt(starty, endy); + tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey)); } } @@ -1215,13 +1252,20 @@ selscroll(int orig, int n) { sel.bx = -1; return; } - if(sel.by < term.top) { - sel.by = term.top; - sel.bx = 0; - } - if(sel.ey > term.bot) { - sel.ey = term.bot; - sel.ex = term.col; + if(sel.type == SEL_RECTANGULAR) { + if(sel.by < term.top) + sel.by = term.top; + if(sel.ey > term.bot) + sel.ey = term.bot; + } else { + if(sel.by < term.top) { + sel.by = term.top; + sel.bx = 0; + } + if(sel.ey > term.bot) { + sel.ey = term.bot; + sel.ex = term.col; + } } sel.b.y = sel.by, sel.b.x = sel.bx; sel.e.y = sel.ey, sel.e.x = sel.ex; @@ -1242,27 +1286,30 @@ tnewline(int first_col) { void csiparse(void) { - /* int noarg = 1; */ - char *p = csiescseq.buf; + char *p = csiescseq.buf, *np; + long int v; csiescseq.narg = 0; - if(*p == '?') - csiescseq.priv = 1, p++; + if(*p == '?') { + csiescseq.priv = 1; + p++; + } + csiescseq.buf[csiescseq.len] = '\0'; while(p < csiescseq.buf+csiescseq.len) { - while(isdigit(*p)) { - csiescseq.arg[csiescseq.narg] *= 10; - csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */; - } - if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) { - csiescseq.narg++, p++; - } else { - csiescseq.mode = *p; - csiescseq.narg++; - - return; - } + np = NULL; + v = strtol(p, &np, 10); + if(np == p) + v = 0; + if(v == LONG_MAX || v == LONG_MIN) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; + if(*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; } + csiescseq.mode = *p; } /* for absolute user moves, when decom is set */ @@ -1568,7 +1615,10 @@ tsetmode(bool priv, bool set, int *args, int narg) { break; case 1049: /* = 1047 and 1048 */ case 47: - case 1047: { + case 1047: + if (!allowaltscreen) + break; + alt = IS_SET(MODE_ALTSCREEN); if(alt) { tclearregion(0, 0, term.col-1, @@ -1578,8 +1628,7 @@ tsetmode(bool priv, bool set, int *args, int narg) { tswapscreen(); if(*args != 1049) break; - } - /* pass through */ + /* FALLTRU */ case 1048: tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; @@ -1661,7 +1710,7 @@ csihandle(void) { tmoveto(0, term.c.y-csiescseq.arg[0]); break; case 'g': /* TBC -- Tabulation clear */ - switch (csiescseq.arg[0]) { + switch(csiescseq.arg[0]) { case 0: /* clear current tab stop */ term.tabs[term.c.x] = 0; break; @@ -1816,32 +1865,37 @@ csireset(void) { void strhandle(void) { - char *p; + char *p = NULL; + int i, j, narg; - /* - * TODO: make this being useful in case of color palette change. - */ strparse(); - - p = strescseq.buf; + narg = strescseq.narg; switch(strescseq.type) { case ']': /* OSC -- Operating System Command */ - switch(p[0]) { - case '0': - case '1': - case '2': - /* - * TODO: Handle special chars in string, like umlauts. - */ - if(p[1] == ';') { - XStoreName(xw.dpy, xw.win, strescseq.buf+2); - } - break; - case ';': - XStoreName(xw.dpy, xw.win, strescseq.buf+1); + switch(i = atoi(strescseq.args[0])) { + case 0: + case 1: + case 2: + if(narg > 1) + xsettitle(strescseq.args[1]); break; - case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */ + case 4: /* color set */ + if(narg < 3) + break; + p = strescseq.args[2]; + /* fall through */ + case 104: /* color reset, here p = NULL */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (!xsetcolorname(j, p)) { + fprintf(stderr, "erresc: invalid color %s\n", p); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(0); + } break; default: fprintf(stderr, "erresc: unknown str "); @@ -1850,7 +1904,7 @@ strhandle(void) { } break; case 'k': /* old title set compatibility */ - XStoreName(xw.dpy, xw.win, strescseq.buf); + xsettitle(strescseq.args[0]); break; case 'P': /* DSC -- Device Control String */ case '_': /* APC -- Application Program Command */ @@ -1865,11 +1919,12 @@ strhandle(void) { void strparse(void) { - /* - * TODO: Implement parsing like for CSI when required. - * Format: ESC type cmd ';' arg0 [';' argn] ESC \ - */ - return; + 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, ";"); } void @@ -1880,7 +1935,9 @@ strdump(void) { printf("ESC%c", strescseq.type); for(i = 0; i < strescseq.len; i++) { c = strescseq.buf[i] & 0xff; - if(isprint(c)) { + if(c == '\0') { + return; + } else if(isprint(c)) { putchar(c); } else if(c == '\n') { printf("(\\n)"); @@ -1926,7 +1983,7 @@ techo(char *buf, int len) { if(c == '\033') { /* escape */ tputc("^", 1); tputc("[", 1); - } else if (c < '\x20') { /* control code */ + } else if(c < '\x20') { /* control code */ if(c != '\n' && c != '\r' && c != '\t') { c |= '\x40'; tputc("^", 1); @@ -1936,7 +1993,7 @@ techo(char *buf, int len) { break; } } - if (len) + if(len) tputc(buf, len); } @@ -1946,7 +2003,7 @@ tputc(char *c, int len) { bool control = ascii < '\x20' || ascii == 0177; if(iofd != -1) { - if (xwrite(iofd, c, len) < 0) { + if(xwrite(iofd, c, len) < 0) { fprintf(stderr, "Error writing in %s:%s\n", opt_io, strerror(errno)); close(iofd); @@ -1968,7 +2025,7 @@ tputc(char *c, int len) { strhandle(); break; default: - if(strescseq.len + len < sizeof(strescseq.buf)) { + if(strescseq.len + len < sizeof(strescseq.buf) - 1) { memmove(&strescseq.buf[strescseq.len], c, len); strescseq.len += len; } else { @@ -2044,9 +2101,11 @@ tputc(char *c, int len) { if(term.esc & ESC_CSI) { csiescseq.buf[csiescseq.len++] = ascii; if(BETWEEN(ascii, 0x40, 0x7E) - || csiescseq.len >= ESC_BUF_SIZ) { + || csiescseq.len >= \ + sizeof(csiescseq.buf)-1) { term.esc = 0; - csiparse(), csihandle(); + csiparse(); + csihandle(); } } else if(term.esc & ESC_STR_END) { term.esc = 0; @@ -2273,21 +2332,24 @@ xresize(int col, int row) { xw.tw = MAX(1, col * xw.cw); xw.th = MAX(1, row * xw.ch); - if(!usedbe) { - 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, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); - } + 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, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); XftDrawChange(xw.draw, xw.buf); } +static inline ushort +sixd_to_16bit(int x) { + return x == 0 ? 0 : 0x3737 + 0x2828 * x; +} + void xloadcols(void) { int i, r, g, b; - XRenderColor color = { .alpha = 0 }; + XRenderColor color = { .alpha = 0xffff }; /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */ for(i = 0; i < LEN(colorname); i++) { @@ -2302,9 +2364,9 @@ xloadcols(void) { for(i = 16, r = 0; r < 6; r++) { for(g = 0; g < 6; g++) { for(b = 0; b < 6; b++) { - color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; - color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; - color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; + color.red = sixd_to_16bit(r); + color.green = sixd_to_16bit(g); + color.blue = sixd_to_16bit(b); if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) { die("Could not allocate color %d\n", i); } @@ -2322,6 +2384,38 @@ xloadcols(void) { } } +int +xsetcolorname(int x, const char *name) { + XRenderColor color = { .alpha = 0xffff }; + Colour colour; + if (x < 0 || x > LEN(colorname)) + return -1; + if(!name) { + if(16 <= x && x < 16 + 216) { + int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6; + color.red = sixd_to_16bit(r); + color.green = sixd_to_16bit(g); + color.blue = sixd_to_16bit(b); + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour)) + return 0; /* something went wrong */ + dc.col[x] = colour; + return 1; + } else if (16 + 216 <= x && x < 256) { + color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216)); + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour)) + return 0; /* something went wrong */ + dc.col[x] = colour; + return 1; + } else { + name = colorname[x]; + } + } + if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour)) + return 0; + dc.col[x] = colour; + return 1; +} + void xtermclear(int col1, int row1, int col2, int row2) { XftDrawRect(xw.draw, @@ -2393,7 +2487,7 @@ xloadfont(Font *f, FcPattern *pattern) { f->lbearing = 0; f->rbearing = f->match->max_advance_width; - f->height = f->match->height; + f->height = f->ascent + f->descent; f->width = f->lbearing + f->rbearing; return 0; @@ -2443,20 +2537,18 @@ xloadfonts(char *fontstr, int fontsize) { 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)) + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if(xloadfont(&dc.ifont, pattern)) die("st: can't open font %s\n", fontstr); - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if(xloadfont(&dc.ibfont, pattern)) 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)) + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if(xloadfont(&dc.bfont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDestroy(pattern); @@ -2470,8 +2562,8 @@ xunloadfonts(void) { * Free the loaded fonts in the font cache. This is done backwards * from the frccur. */ - for (i = 0, ip = frccur; i < frclen; i++, ip--) { - if (ip < 0) + for(i = 0, ip = frccur; i < frclen; i++, ip--) { + if(ip < 0) ip = LEN(frc) - 1; XftFontClose(xw.dpy, frc[ip].font); } @@ -2506,7 +2598,7 @@ xinit(void) { XGCValues gcvalues; Cursor cursor; Window parent; - int sw, sh, major, minor; + int sw, sh; if(!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); @@ -2514,7 +2606,7 @@ xinit(void) { xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ - if (!FcInit()) + if(!FcInit()) die("Could not init fontconfig.\n"); usedfont = (opt_font == NULL)? font : opt_font; @@ -2561,26 +2653,14 @@ xinit(void) { | CWColormap, &attrs); - /* double buffering */ - /* - if(XdbeQueryExtension(xw.dpy, &major, &minor)) { - xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, - XdbeBackground); - usedbe = True; - } else { - */ - 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, dc.col[defaultbg].pixel); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); - //xw.buf = xw.win; - /* - } - */ + 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, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); @@ -2633,12 +2713,28 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg], - *temp, revfg, revbg; + Colour *fg, *bg, *temp, revfg, revbg; XRenderColor colfg, colbg; frcflags = FRC_NORMAL; + if(base.mode & ATTR_ITALIC) { + if(base.fg == defaultfg) + base.fg = defaultitalic; + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) { + if(base.fg == defaultfg) + base.fg = defaultitalic; + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if(base.mode & ATTR_UNDERLINE) { + if(base.fg == defaultfg) + base.fg = defaultunderline; + } + fg = &dc.col[base.fg]; + bg = &dc.col[base.bg]; + if(base.mode & ATTR_BOLD) { if(BETWEEN(base.fg, 0, 7)) { /* basic system colors */ @@ -2660,15 +2756,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { frcflags = FRC_BOLD; } - if(base.mode & ATTR_ITALIC) { - font = &dc.ifont; - frcflags = FRC_ITALIC; - } - if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) { - font = &dc.ibfont; - frcflags = FRC_ITALICBOLD; - } - if(IS_SET(MODE_REVERSE)) { if(fg == &dc.col[defaultfg]) { fg = &dc.col[defaultbg]; @@ -2717,7 +2804,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch); fcsets[0] = font->set; - for (xp = winx; bytelen > 0;) { + for(xp = winx; bytelen > 0;) { /* * Search for the range in the to be printed string of glyphs * that are in the main font. Then print that range. If @@ -2727,22 +2814,22 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fs = s; u8fblen = 0; u8fl = 0; - for (;;) { + for(;;) { u8c = s; u8cblen = utf8decode(s, &u8char); s += u8cblen; bytelen -= u8cblen; doesexist = XftCharIndex(xw.dpy, font->match, u8char); - if (!doesexist || bytelen <= 0) { - if (bytelen <= 0) { - if (doesexist) { + if(!doesexist || bytelen <= 0) { + if(bytelen <= 0) { + if(doesexist) { u8fl++; u8fblen += u8cblen; } } - if (u8fl > 0) { + if(u8fl > 0) { XftDrawStringUtf8(xw.draw, fg, font->match, xp, winy + font->ascent, @@ -2756,23 +2843,23 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fl++; u8fblen += u8cblen; } - if (doesexist) + if(doesexist) break; frp = frccur; /* Search the font cache. */ - for (i = 0; i < frclen; i++, frp--) { - if (frp <= 0) + for(i = 0; i < frclen; i++, frp--) { + if(frp <= 0) frp = LEN(frc) - 1; - if (frc[frp].c == u8char + if(frc[frp].c == u8char && frc[frp].flags == frcflags) { break; } } /* Nothing was found. */ - if (i >= frclen) { + if(i >= frclen) { /* * Nothing was found in the cache. Now use * some dozen of Fontconfig calls to get the @@ -2795,14 +2882,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcTrue, fcpattern, &fcres); /* - * Overwrite or create the new cache entry - * entry. + * Overwrite or create the new cache entry. */ frccur++; frclen++; - if (frccur >= LEN(frc)) + if(frccur >= LEN(frc)) frccur = 0; - if (frclen > LEN(frc)) { + if(frclen > LEN(frc)) { frclen = LEN(frc); XftFontClose(xw.dpy, frc[frccur].font); } @@ -2871,9 +2957,19 @@ xdrawcursor(void) { } } + +void +xsettitle(char *p) { + XTextProperty prop; + + Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop); + XSetWMName(xw.dpy, xw.win, &prop); +} + void xresettitle(void) { - XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st"); + xsettitle(opt_title ? opt_title : "st"); } void @@ -2891,16 +2987,12 @@ redraw(int timeout) { void draw(void) { - XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}}; - drawregion(0, 0, term.col, term.row); - if(usedbe) { - XdbeSwapBuffers(xw.dpy, swpinfo, 1); - } else { - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w, - xw.h, 0, 0); - XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); - } + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w, + xw.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); } void @@ -3008,6 +3100,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) @@ -3082,7 +3176,7 @@ kpress(XEvent *ev) { Status status; Shortcut *bp; - if (IS_SET(MODE_KBDLOCK)) + if(IS_SET(MODE_KBDLOCK)) return; len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status); @@ -3104,7 +3198,7 @@ kpress(XEvent *ev) { if(len == 0) return; - if (len == 1 && e->state & Mod1Mask) + if(len == 1 && e->state & Mod1Mask) *cp++ = '\033'; memcpy(cp, xstr, len); @@ -3166,12 +3260,12 @@ void run(void) { XEvent ev; fd_set rfd; - int xfd = XConnectionNumber(xw.dpy); + int xfd = XConnectionNumber(xw.dpy), xev; struct timeval drawtimeout, *tv = NULL, now, last; gettimeofday(&last, NULL); - for(;;) { + for(xev = actionfps;;) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); @@ -3182,24 +3276,18 @@ run(void) { } gettimeofday(&now, NULL); - /* usecs until (next) frame */ drawtimeout.tv_sec = 0; - drawtimeout.tv_usec = \ - ((1000/framespersecond) - TIMEDIFF(now, last)) * 1000; - - /* Let us draw a frame. */ - if(drawtimeout.tv_usec <= 0) { - draw(); - XFlush(xw.dpy); - - last = now; - tv = NULL; - } + drawtimeout.tv_usec = (1000/xfps) * 1000; + tv = &drawtimeout; if(FD_ISSET(cmdfd, &rfd)) ttyread(); - if(FD_ISSET(xfd, &rfd)) { + if(FD_ISSET(xfd, &rfd)) + xev = actionfps; + + if(TIMEDIFF(now, last) > \ + (xev ? (1000/xfps) : (1000/actionfps))) { while(XPending(xw.dpy)) { XNextEvent(xw.dpy, &ev); if(XFilterEvent(&ev, None)) @@ -3208,81 +3296,78 @@ run(void) { (handler[ev.type])(&ev); } - if(drawtimeout.tv_usec <= 0) { - draw(); - XFlush(xw.dpy); - } - } + draw(); + XFlush(xw.dpy); + last = now; - /* There is still some time to wait until next frame. */ - if(drawtimeout.tv_usec > 0) { - tv = &drawtimeout; - continue; + if(xev && !FD_ISSET(xfd, &rfd)) + xev--; + if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) + tv = NULL; } } } +void +usage(void) { + die("%s " VERSION " (c) 2010-2013 st engineers\n" \ + "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \ + " [-t title] [-w windowid] [-e command ...]\n", argv0); +} + int main(int argc, char *argv[]) { - int i, bitm, xr, yr; + int bitm, xr, yr; uint wr, hr; xw.fw = xw.fh = xw.fx = xw.fy = 0; xw.isfixed = False; - for(i = 1; i < argc; i++) { - switch(argv[i][0] != '-' || argv[i][2] ? -1 : argv[i][1]) { - case 'c': - if(++i < argc) - opt_class = argv[i]; - break; - case 'e': - /* eat all remaining arguments */ - if(++i < argc) - opt_cmd = &argv[i]; - goto run; - case 'f': - if(++i < argc) - opt_font = argv[i]; - break; - case 'g': - if(++i >= argc) - break; - - bitm = XParseGeometry(argv[i], &xr, &yr, &wr, &hr); - if(bitm & XValue) - xw.fx = xr; - if(bitm & YValue) - xw.fy = yr; - if(bitm & WidthValue) - xw.fw = (int)wr; - if(bitm & HeightValue) - xw.fh = (int)hr; - if(bitm & XNegative && xw.fx == 0) - xw.fx = -1; - if(bitm & XNegative && xw.fy == 0) - xw.fy = -1; - - if(xw.fh != 0 && xw.fw != 0) - xw.isfixed = True; - break; - case 'o': - if(++i < argc) - opt_io = argv[i]; - break; - case 't': - if(++i < argc) - opt_title = argv[i]; - break; - case 'v': - default: - die(USAGE); - case 'w': - if(++i < argc) - opt_embed = argv[i]; - break; - } - } + ARGBEGIN { + case 'a': + allowaltscreen = false; + break; + case 'c': + opt_class = EARGF(usage()); + break; + case 'e': + /* eat all remaining arguments */ + opt_cmd = &argv[1]; + goto run; + case 'f': + opt_font = EARGF(usage()); + break; + case 'g': + bitm = XParseGeometry(EARGF(usage()), &xr, &yr, &wr, &hr); + if(bitm & XValue) + xw.fx = xr; + if(bitm & YValue) + xw.fy = yr; + if(bitm & WidthValue) + xw.fw = (int)wr; + if(bitm & HeightValue) + xw.fh = (int)hr; + if(bitm & XNegative && xw.fx == 0) + xw.fx = -1; + if(bitm & XNegative && xw.fy == 0) + xw.fy = -1; + + if(xw.fh != 0 && xw.fw != 0) + xw.isfixed = True; + break; + case 'o': + opt_io = EARGF(usage()); + break; + case 't': + opt_title = EARGF(usage()); + break; + case 'w': + opt_embed = EARGF(usage()); + break; + case 'v': + default: + usage(); + } ARGEND; run: setlocale(LC_CTYPE, "");