X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=4a91073c6a269fee660f3bfb999ec9fd9a287186;hp=9a7891ed4b4799d22eef45f3a3c33e9f955c6607;hb=bef599bb279e6c9b08853ceebefade066e362c48;hpb=7530694987596642b0b83db1c4a61f2794c20397 diff --git a/st.c b/st.c index 9a7891e..4a91073 100644 --- a/st.c +++ b/st.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include "arg.h" @@ -75,6 +77,14 @@ char *argv0; #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) #define IS_SET(flag) ((term.mode & (flag)) != 0) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) +#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x)) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) + #define VT102ID "\033[?6c" @@ -87,6 +97,8 @@ enum glyph_attribute { ATTR_ITALIC = 16, ATTR_BLINK = 32, ATTR_WRAP = 64, + ATTR_WIDE = 128, + ATTR_WDUMMY = 256, }; enum cursor_movement { @@ -97,37 +109,37 @@ enum cursor_movement { enum cursor_state { CURSOR_DEFAULT = 0, CURSOR_WRAPNEXT = 1, - CURSOR_ORIGIN = 2 + CURSOR_ORIGIN = 2 }; enum term_mode { - MODE_WRAP = 1, + MODE_WRAP = 1, MODE_INSERT = 2, MODE_APPKEYPAD = 4, MODE_ALTSCREEN = 8, - MODE_CRLF = 16, + 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_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_8BIT = 8192, + MODE_BLINK = 16384, + MODE_FBLINK = 32768, + MODE_FOCUS = 65536, + MODE_MOUSEX10 = 131072, MODE_MOUSEMANY = 262144, MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ - |MODE_MOUSEMANY, + |MODE_MOUSEMANY, }; enum escape_state { ESC_START = 1, - ESC_CSI = 2, - ESC_STR = 4, /* DSC, OSC, PM, APC */ + ESC_CSI = 2, + ESC_STR = 4, /* DSC, OSC, PM, APC */ ESC_ALTCHARSET = 8, ESC_STR_END = 16, /* a final string was encountered */ ESC_TEST = 32, /* Enter in test mode */ @@ -149,26 +161,22 @@ enum selection_snap { SNAP_LINE = 2 }; -/* bit macro */ -#undef B0 -enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; - typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned short ushort; typedef struct { - char c[UTF_SIZ]; /* character code */ - uchar mode; /* attribute flags */ - ushort fg; /* foreground */ - ushort bg; /* background */ + char c[UTF_SIZ]; /* character code */ + ushort mode; /* attribute flags */ + ulong fg; /* foreground */ + ulong bg; /* background */ } Glyph; typedef Glyph *Line; typedef struct { - Glyph attr; /* current char attributes */ + Glyph attr; /* current char attributes */ int x; int y; char state; @@ -178,36 +186,36 @@ typedef struct { /* ESC '[' [[ [] [;]] ] */ typedef struct { char buf[ESC_BUF_SIZ]; /* raw string */ - int len; /* raw string length */ + int len; /* raw string length */ char priv; int arg[ESC_ARG_SIZ]; - int narg; /* nb of args */ + int narg; /* nb of args */ char mode; } CSIEscape; /* STR Escape sequence structs */ /* ESC type [[ [] [;]] ] ESC '\' */ typedef struct { - char type; /* ESC type ... */ + char type; /* ESC type ... */ char buf[STR_BUF_SIZ]; /* raw string */ - int len; /* raw string length */ + int len; /* raw string length */ char *args[STR_ARG_SIZ]; - int narg; /* nb of args */ + int narg; /* nb of args */ } STREscape; /* Internal representation of the screen */ typedef struct { - int row; /* nb row */ - int col; /* nb col */ - Line *line; /* screen */ - Line *alt; /* alternate screen */ - bool *dirty; /* dirtyness of lines */ - TCursor c; /* cursor */ - int top; /* top scroll limit */ - int bot; /* bottom scroll limit */ - int mode; /* terminal mode flags */ - int esc; /* escape state flags */ - bool numlock; /* lock numbers in keyboard */ + int row; /* nb row */ + int col; /* nb col */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + bool *dirty; /* dirtyness of lines */ + TCursor c; /* cursor */ + int top; /* top scroll limit */ + int bot; /* bottom scroll limit */ + int mode; /* terminal mode flags */ + int esc; /* escape state flags */ + bool numlock; /* lock numbers in keyboard */ bool *tabs; } Term; @@ -244,9 +252,9 @@ typedef struct { uint mask; char s[ESC_BUF_SIZ]; /* three valued logic variables: 0 indifferent, 1 on, -1 off */ - signed char appkey; /* application keypad */ - signed char appcursor; /* application cursor */ - signed char crlf; /* crlf mode */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ + signed char crlf; /* crlf mode */ } Key; typedef struct { @@ -357,7 +365,7 @@ static void tsetdirtattr(int); static void tsetmode(bool, bool, int *, int); static void tfulldirt(void); static void techo(char *, int); - +static long tdefcolor(int *, int *, int); static inline bool match(uint, uint); static void ttynew(void); static void ttyread(void); @@ -415,7 +423,6 @@ static int isfullutf8(char *, int); static ssize_t xwrite(int, char *, size_t); static void *xmalloc(size_t); static void *xrealloc(void *, size_t); -static void *xcalloc(size_t, size_t); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, @@ -465,17 +472,12 @@ enum { typedef struct { XftFont *font; - long c; int flags; } Fontcache; -/* - * Fontcache is a ring buffer, with frccur as current position and frclen as - * the current length of used elements. - */ - -static Fontcache frc[1024]; -static int frccur = -1, frclen = 0; +/* Fontcache is an array now. A new font will be appended to the array. */ +static Fontcache frc[16]; +static int frclen = 0; ssize_t xwrite(int fd, char *s, size_t len) { @@ -509,16 +511,6 @@ xrealloc(void *p, size_t len) { return p; } -void * -xcalloc(size_t nmemb, size_t size) { - void *p = calloc(nmemb, size); - - if(!p) - die("Out of memory\n"); - - return p; -} - int utf8decode(char *s, long *u) { uchar c; @@ -526,17 +518,17 @@ utf8decode(char *s, long *u) { rtn = 1; c = *s; - if(~c & B7) { /* 0xxxxxxx */ + if(~c & 0x80) { /* 0xxxxxxx */ *u = c; return rtn; - } else if((c & (B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */ - *u = c&(B4|B3|B2|B1|B0); + } else if((c & 0xE0) == 0xC0) { /* 110xxxxx */ + *u = c & 0x1F; n = 1; - } else if((c & (B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */ - *u = c&(B3|B2|B1|B0); + } else if((c & 0xF0) == 0xE0) { /* 1110xxxx */ + *u = c & 0x0F; n = 2; - } else if((c & (B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */ - *u = c & (B2|B1|B0); + } else if((c & 0xF8) == 0xF0) { /* 11110xxx */ + *u = c & 0x07; n = 3; } else { goto invalid; @@ -544,10 +536,10 @@ utf8decode(char *s, long *u) { for(i = n, ++s; i > 0; --i, ++rtn, ++s) { c = *s; - if((c & (B7|B6)) != B7) /* 10xxxxxx */ + if((c & 0xC0) != 0x80) /* 10xxxxxx */ goto invalid; *u <<= 6; - *u |= c & (B5|B4|B3|B2|B1|B0); + *u |= c & 0x3F; } if((n == 1 && *u < 0x80) || @@ -576,20 +568,20 @@ utf8encode(long *u, char *s) { *sp = uc; /* 0xxxxxxx */ return 1; } else if(*u < 0x800) { - *sp = (uc >> 6) | (B7|B6); /* 110xxxxx */ + *sp = (uc >> 6) | 0xC0; /* 110xxxxx */ n = 1; } else if(uc < 0x10000) { - *sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */ + *sp = (uc >> 12) | 0xE0; /* 1110xxxx */ n = 2; } else if(uc <= 0x10FFFF) { - *sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */ + *sp = (uc >> 18) | 0xF0; /* 11110xxx */ n = 3; } else { goto invalid; } for(i=n,++sp; i>0; --i,++sp) - *sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */ + *sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */ return n+1; invalid: @@ -612,16 +604,16 @@ isfullutf8(char *s, int b) { c3 = (uchar *)++s; if(b < 1) { return 0; - } else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1) { + } else if((*c1 & 0xE0) == 0xC0 && b == 1) { return 0; - } else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) && + } else if((*c1 & 0xF0) == 0xE0 && ((b == 1) || - ((b == 2) && (*c2&(B7|B6)) == B7))) { + ((b == 2) && (*c2 & 0xC0) == 0x80))) { return 0; - } else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) && + } else if((*c1 & 0xF8) == 0xF0 && ((b == 1) || - ((b == 2) && (*c2&(B7|B6)) == B7) || - ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7))) { + ((b == 2) && (*c2 & 0xC0) == 0x80) || + ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) { return 0; } else { return 1; @@ -632,11 +624,11 @@ int utf8size(char *s) { uchar c = *s; - if(~c&B7) { + if(~c & 0x80) { return 1; - } else if((c&(B7|B6|B5)) == (B7|B6)) { + } else if((c & 0xE0) == 0xC0) { return 2; - } else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { + } else if((c & 0xF0) == 0xE0) { return 3; } else { return 4; @@ -730,8 +722,13 @@ selsnap(int mode, int *x, int *y, int direction) { } } + if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) { + *x += direction; + continue; + } + if(strchr(worddelimiters, - term.line[*y][*x + direction].c[0])) { + term.line[*y][*x+direction].c[0])) { break; } @@ -887,11 +884,7 @@ bpress(XEvent *e) { gettimeofday(&now, NULL); /* Clear previous selection, logically and visually. */ - if(sel.ob.x != -1) { - sel.ob.x = -1; - tsetdirt(sel.nb.y, sel.ne.y); - draw(); - } + selclear(NULL); sel.mode = 1; sel.type = SEL_REGULAR; sel.oe.x = sel.ob.x = x2col(e->xbutton.x); @@ -919,7 +912,6 @@ bpress(XEvent *e) { if(sel.snap != 0) { sel.mode++; tsetdirt(sel.nb.y, sel.ne.y); - draw(); } sel.tclick2 = sel.tclick1; sel.tclick1 = now; @@ -948,7 +940,7 @@ selcopy(void) { /* nothing */; for(x = 0; gp <= last; x++, ++gp) { - if(!selected(x, y)) + if(!selected(x, y) || (gp->mode & ATTR_WDUMMY)) continue; size = utf8size(gp->c); @@ -1107,7 +1099,7 @@ brelease(XEvent *e) { selpaste(NULL); } else if(e->xbutton.button == Button1) { if(sel.mode < 2) { - sel.ob.x = -1; + selclear(NULL); } else { getbuttoninfo(e); selcopy(); @@ -1190,7 +1182,7 @@ sigchld(int a) { int stat = 0; if(waitpid(pid, &stat, 0) < 0) - die("Waiting for pid %hd failed: %s\n", pid, SERRNO); + die("Waiting for pid %hd failed: %s\n", pid, SERRNO); if(WIFEXITED(stat)) { exit(WEXITSTATUS(stat)); @@ -1375,7 +1367,7 @@ treset(void) { void tnew(int col, int row) { - memset(&term, 0, sizeof(Term)); + term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; tresize(col, row); term.numlock = 1; @@ -1440,7 +1432,7 @@ selscroll(int orig, int n) { if(BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) { if((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) { - sel.ob.x = -1; + selclear(NULL); return; } if(sel.type == SEL_RECTANGULAR) { @@ -1549,6 +1541,16 @@ tsetchar(char *c, Glyph *attr, int x, int y) { } } + if(term.line[y][x].mode & ATTR_WIDE) { + if(x+1 < term.col) { + term.line[y][x+1].c[0] = ' '; + term.line[y][x+1].mode &= ~ATTR_WDUMMY; + } + } else if(term.line[y][x].mode & ATTR_WDUMMY) { + term.line[y][x-1].c[0] = ' '; + term.line[y][x-1].mode &= ~ATTR_WIDE; + } + term.dirty[y] = 1; term.line[y][x] = *attr; memcpy(term.line[y][x].c, c, UTF_SIZ); @@ -1631,9 +1633,58 @@ tdeleteline(int n) { tscrollup(term.c.y, n); } +long +tdefcolor(int *attr, int *npar, int l) { + long idx = -1; + uint r, g, b; + + switch (attr[*npar + 1]) { + case 2: /* direct colour in RGB space */ + if (*npar + 4 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + r = attr[*npar + 2]; + g = attr[*npar + 3]; + b = attr[*npar + 4]; + *npar += 4; + if(!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) + fprintf(stderr, "erresc: bad rgb color (%d,%d,%d)\n", + r, g, b); + else + idx = TRUECOLOR(r, g, b); + break; + case 5: /* indexed colour */ + if (*npar + 2 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + *npar += 2; + if(!BETWEEN(attr[*npar], 0, 255)) + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]); + else + idx = attr[*npar]; + break; + case 0: /* implemented defined (only foreground) */ + case 1: /* transparent */ + case 3: /* direct colour in CMY space */ + case 4: /* direct colour in CMYK space */ + default: + fprintf(stderr, + "erresc(38): gfx attr %d unknown\n", attr[*npar]); + } + + return idx; +} + void tsetattr(int *attr, int l) { int i; + long idx; for(i = 0; i < l; i++) { switch(attr[i]) { @@ -1678,39 +1729,15 @@ tsetattr(int *attr, int l) { term.c.attr.mode &= ~ATTR_REVERSE; break; case 38: - if(i + 2 < l && attr[i + 1] == 5) { - i += 2; - if(BETWEEN(attr[i], 0, 255)) { - term.c.attr.fg = attr[i]; - } else { - fprintf(stderr, - "erresc: bad fgcolor %d\n", - attr[i]); - } - } else { - fprintf(stderr, - "erresc(38): gfx attr %d unknown\n", - attr[i]); - } + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.fg = idx; break; case 39: term.c.attr.fg = defaultfg; break; case 48: - if(i + 2 < l && attr[i + 1] == 5) { - i += 2; - if(BETWEEN(attr[i], 0, 255)) { - term.c.attr.bg = attr[i]; - } else { - fprintf(stderr, - "erresc: bad bgcolor %d\n", - attr[i]); - } - } else { - fprintf(stderr, - "erresc(48): gfx attr %d unknown\n", - attr[i]); - } + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.bg = idx; break; case 49: term.c.attr.bg = defaultbg; @@ -1829,7 +1856,7 @@ tsetmode(bool priv, bool set, int *args, int narg) { tclearregion(0, 0, term.col-1, term.row-1); } - if(set ^ alt) /* set is always 1 or 0 */ + if(set ^ alt) /* set is always 1 or 0 */ tswapscreen(); if(*args != 1049) break; @@ -1950,7 +1977,7 @@ csihandle(void) { tputtab(1); break; case 'J': /* ED -- Clear screen */ - sel.ob.x = -1; + selclear(NULL); switch(csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); @@ -2192,10 +2219,10 @@ techo(char *buf, int len) { for(; len > 0; buf++, len--) { char c = *buf; - if(c == '\033') { /* escape */ + 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); @@ -2213,6 +2240,15 @@ void tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; + long u8char; + int width; + + if(len == 1) { + width = 1; + } else { + utf8decode(c, &u8char); + width = wcwidth(u8char); + } if(iofd != -1) { if(xwrite(iofd, c, len) < 0) { @@ -2266,31 +2302,33 @@ tputc(char *c, int len) { */ if(control) { switch(ascii) { - case '\t': /* HT */ + case '\t': /* HT */ tputtab(1); return; - case '\b': /* BS */ + case '\b': /* BS */ tmoveto(term.c.x-1, term.c.y); return; - case '\r': /* CR */ + case '\r': /* CR */ tmoveto(0, term.c.y); return; - case '\f': /* LF */ - case '\v': /* VT */ - case '\n': /* LF */ + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ /* go to first col if the mode is set */ tnewline(IS_SET(MODE_CRLF)); return; - case '\a': /* BEL */ + case '\a': /* BEL */ if(!(xw.state & WIN_FOCUSED)) xseturgency(1); + if (bellvolume) + XBell(xw.dpy, bellvolume); return; - case '\033': /* ESC */ + case '\033': /* ESC */ csireset(); term.esc = ESC_START; return; - case '\016': /* SO */ - case '\017': /* SI */ + case '\016': /* SO */ + case '\017': /* SI */ /* * Different charsets are hard to handle. Applications * should use the right alt charset escapes for the @@ -2298,15 +2336,15 @@ tputc(char *c, int len) { * rest is incompatible history st should not support. */ return; - case '\032': /* SUB */ - case '\030': /* CAN */ + case '\032': /* SUB */ + case '\030': /* CAN */ csireset(); return; - case '\005': /* ENQ (IGNORED) */ - case '\000': /* NUL (IGNORED) */ - case '\021': /* XON (IGNORED) */ - case '\023': /* XOFF (IGNORED) */ - case 0177: /* DEL (IGNORED) */ + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ return; } } else if(term.esc & ESC_START) { @@ -2409,6 +2447,7 @@ tputc(char *c, int len) { treset(); term.esc = 0; xresettitle(); + xloadcols(); break; case '=': /* DECPAM -- Application keypad */ term.mode |= MODE_APPKEYPAD; @@ -2447,7 +2486,7 @@ tputc(char *c, int len) { if(control && !(term.c.attr.mode & ATTR_GFX)) return; if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y)) - sel.ob.x = -1; + selclear(NULL); if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { term.line[term.c.y][term.c.x].mode |= ATTR_WRAP; tnewline(1); @@ -2459,9 +2498,20 @@ tputc(char *c, int len) { (term.col - term.c.x - 1) * sizeof(Glyph)); } + if(term.c.x+width > term.col) + tnewline(1); + tsetchar(c, &term.c.attr, term.c.x, term.c.y); - if(term.c.x+1 < term.col) { - tmoveto(term.c.x+1, term.c.y); + + if(width == 2) { + term.line[term.c.y][term.c.x].mode |= ATTR_WIDE; + if(term.c.x+1 < term.col) { + term.line[term.c.y][term.c.x+1].c[0] = '\0'; + term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY; + } + } + if(term.c.x+width < term.col) { + tmoveto(term.c.x+width, term.c.y); } else { term.c.state |= CURSOR_WRAPNEXT; } @@ -2515,8 +2565,8 @@ tresize(int col, int row) { /* allocate any new rows */ for(/* i == minrow */; i < row; i++) { term.dirty[i] = 1; - term.line[i] = xcalloc(col, sizeof(Glyph)); - term.alt [i] = xcalloc(col, sizeof(Glyph)); + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); } if(col > term.col) { bp = term.tabs + term.col; @@ -2570,6 +2620,13 @@ void xloadcols(void) { int i, r, g, b; XRenderColor color = { .alpha = 0xffff }; + static bool loaded; + Colour *cp; + + if(loaded) { + for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp) + XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */ for(i = 0; i < LEN(colorname); i++) { @@ -2602,6 +2659,7 @@ xloadcols(void) { die("Could not allocate color %d\n", i); } } + loaded = true; } int @@ -2749,8 +2807,8 @@ xloadfonts(char *fontstr, int fontsize) { die("st: can't open font %s\n", fontstr); /* Setting character width and height. */ - xw.cw = dc.font.width; - xw.ch = dc.font.height; + xw.cw = CEIL(dc.font.width * cwscale); + xw.ch = CEIL(dc.font.height * chscale); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); @@ -2789,18 +2847,12 @@ xunloadfont(Font *f) { void xunloadfonts(void) { - int i, ip; + int i; - /* - * 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) - ip = LEN(frc) - 1; - XftFontClose(xw.dpy, frc[ip].font); + /* Free the loaded fonts in the font cache. */ + for(i = 0; i < frclen; i++) { + XftFontClose(xw.dpy, frc[i].font); } - frccur = -1; frclen = 0; xunloadfont(&dc.font); @@ -2926,7 +2978,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 frp, frcflags; + int frcflags; int u8fl, u8fblen, u8cblen, doesexist; char *u8c, *u8fs; long u8char; @@ -2935,9 +2987,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - Colour *fg, *bg, *temp, revfg, revbg; + Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg; XRenderColor colfg, colbg; Rectangle r; + int oneatatime; frcflags = FRC_NORMAL; @@ -2955,8 +3008,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(base.fg == defaultfg) base.fg = defaultunderline; } - fg = &dc.col[base.fg]; - bg = &dc.col[base.bg]; + if(IS_TRUECOL(base.fg)) { + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } + + if(IS_TRUECOL(base.bg)) { + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } + + if(base.mode & ATTR_BOLD) { if(BETWEEN(base.fg, 0, 7)) { @@ -2971,9 +3043,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } /* * Those ranges will not be brightened: - * 8 - 15 – bright system colors - * 196 - 231 – highest 256 color cube - * 252 - 255 – brightest colors in greyscale + * 8 - 15 – bright system colors + * 196 - 231 – highest 256 color cube + * 252 - 255 – brightest colors in greyscale */ font = &dc.bfont; frcflags = FRC_BOLD; @@ -3046,15 +3118,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fs = s; u8fblen = 0; u8fl = 0; + oneatatime = font->width != xw.cw; 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) { + doesexist = XftCharExists(xw.dpy, font->match, u8char); + if(oneatatime || !doesexist || bytelen <= 0) { + if(oneatatime || bytelen <= 0) { if(doesexist) { u8fl++; u8fblen += u8cblen; @@ -3067,7 +3140,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { winy + font->ascent, (FcChar8 *)u8fs, u8fblen); - xp += font->width * u8fl; + xp += xw.cw * u8fl; } break; @@ -3076,17 +3149,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fl++; u8fblen += u8cblen; } - if(doesexist) + if(doesexist) { + if (oneatatime) + continue; break; + } - frp = frccur; /* Search the font cache. */ - for(i = 0; i < frclen; i++, frp--) { - if(frp <= 0) - frp = LEN(frc) - 1; - - if(frc[frp].c == u8char - && frc[frp].flags == frcflags) { + for(i = 0; i < frclen; i++) { + if(XftCharExists(xw.dpy, frc[i].font, u8char) + && frc[i].flags == frcflags) { break; } } @@ -3121,31 +3193,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { /* * Overwrite or create the new cache entry. */ - frccur++; - frclen++; - if(frccur >= LEN(frc)) - frccur = 0; - if(frclen > LEN(frc)) { - frclen = LEN(frc); - XftFontClose(xw.dpy, frc[frccur].font); + if(frclen >= LEN(frc)) { + frclen = LEN(frc) - 1; + XftFontClose(xw.dpy, frc[frclen].font); } - frc[frccur].font = XftFontOpenPattern(xw.dpy, + frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern); - frc[frccur].c = u8char; - frc[frccur].flags = frcflags; + frc[frclen].flags = frcflags; + + i = frclen; + frclen++; FcPatternDestroy(fcpattern); FcCharSetDestroy(fccharset); - - frp = frccur; } - XftDrawStringUtf8(xw.draw, fg, frc[frp].font, - xp, winy + frc[frp].font->ascent, + XftDrawStringUtf8(xw.draw, fg, frc[i].font, + xp, winy + frc[i].font->ascent, (FcChar8 *)u8c, u8cblen); - xp += font->width; + xp += xw.cw * wcwidth(u8char); } /* @@ -3165,18 +3233,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { void xdrawcursor(void) { static int oldx = 0, oldy = 0; - int sl; + int sl, width, curx; Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); + curx = term.c.x; + + /* adjust position if in dummy */ + if(term.line[oldy][oldx].mode & ATTR_WDUMMY) + oldx--; + if(term.line[term.c.y][curx].mode & ATTR_WDUMMY) + curx--; + memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); /* remove the old cursor */ sl = utf8size(term.line[oldy][oldx].c); + width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1; xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, - oldy, 1, sl); + oldy, width, sl); /* draw the new one */ if(!(IS_SET(MODE_HIDE))) { @@ -3188,26 +3265,28 @@ xdrawcursor(void) { } sl = utf8size(g.c); - xdraws(g.c, g, term.c.x, term.c.y, 1, sl); + 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 + term.c.x * xw.cw, + borderpx + curx * xw.cw, borderpx + term.c.y * xw.ch, xw.cw - 1, 1); XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + term.c.x * xw.cw, + borderpx + curx * xw.cw, borderpx + term.c.y * xw.ch, 1, xw.ch - 1); XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + (term.c.x + 1) * xw.cw - 1, + borderpx + (curx + 1) * xw.cw - 1, borderpx + term.c.y * xw.ch, 1, xw.ch - 1); XftDrawRect(xw.draw, &dc.col[defaultcs], - borderpx + term.c.x * xw.cw, + borderpx + curx * xw.cw, borderpx + (term.c.y + 1) * xw.ch - 1, xw.cw, 1); } - oldx = term.c.x, oldy = term.c.y; + oldx = curx, oldy = term.c.y; } } @@ -3219,6 +3298,7 @@ xsettitle(char *p) { Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); XSetWMName(xw.dpy, xw.win, &prop); + XFree(prop.value); } void @@ -3255,6 +3335,7 @@ drawregion(int x1, int y1, int x2, int y2) { Glyph base, new; char buf[DRAW_BUF_SIZ]; bool ena_sel = sel.ob.x != -1; + long u8char; if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) ena_sel = 0; @@ -3272,6 +3353,8 @@ drawregion(int x1, int y1, int x2, int y2) { ic = ib = ox = 0; for(x = x1; x < x2; x++) { new = term.line[y][x]; + if(new.mode == ATTR_WDUMMY) + continue; if(ena_sel && selected(x, y)) new.mode ^= ATTR_REVERSE; if(ib > 0 && (ATTRCMP(base, new) @@ -3284,10 +3367,10 @@ drawregion(int x1, int y1, int x2, int y2) { base = new; } - sl = utf8size(new.c); + sl = utf8decode(new.c, &u8char); memcpy(buf+ib, new.c, sl); ib += sl; - ++ic; + ic += (new.mode & ATTR_WIDE)? 2 : 1; } if(ib > 0) xdraws(buf, base, ox, y, ic, ib); @@ -3359,17 +3442,17 @@ focus(XEvent *ev) { } } -inline bool +static inline bool match(uint mask, uint state) { - state &= ~(ignoremod); + state &= ~ignoremod; if(mask == XK_NO_MOD && state) return false; if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state) return false; - if((state & mask) != state) - return false; - return true; + if(mask == XK_ANY_MOD) + return true; + return state == mask; } void @@ -3379,7 +3462,6 @@ numlock(const Arg *dummy) { char* kmap(KeySym k, uint state) { - uint mask; Key *kp; int i; @@ -3394,12 +3476,10 @@ kmap(KeySym k, uint state) { } for(kp = key; kp < key + LEN(key); kp++) { - mask = kp->mask; - if(kp->k != k) continue; - if(!match(mask, state)) + if(!match(kp->mask, state)) continue; if(kp->appkey > 0) { @@ -3463,7 +3543,7 @@ kpress(XEvent *ev) { if(len == 1 && e->state & Mod1Mask) { if(IS_SET(MODE_8BIT)) { if(*xstr < 0177) { - c = *xstr | B7; + c = *xstr | 0x80; ret = utf8encode(&c, cp); cp += ret; len = 0; @@ -3531,10 +3611,28 @@ resize(XEvent *e) { void run(void) { XEvent ev; + int w = xw.w, h = xw.h; fd_set rfd; int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0; struct timeval drawtimeout, *tv = NULL, now, last, lastblink; + /* Waiting for window mapping */ + while(1) { + XNextEvent(xw.dpy, &ev); + if(ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } else if(ev.type == MapNotify) { + break; + } + } + + if(!xw.isfixed) + cresize(w, h); + else + cresize(xw.fw, xw.fh); + ttynew(); + gettimeofday(&lastblink, NULL); gettimeofday(&last, NULL); @@ -3552,8 +3650,8 @@ run(void) { ttyread(); if(blinktimeout) { blinkset = tattrset(ATTR_BLINK); - if(!blinkset && term.mode & ATTR_BLINK) - term.mode &= ~(MODE_BLINK); + if(!blinkset) + MODBIT(term.mode, 0, MODE_BLINK); } } @@ -3622,6 +3720,7 @@ int main(int argc, char *argv[]) { int bitm, xr, yr; uint wr, hr; + char *titles; xw.fw = xw.fh = xw.fx = xw.fy = 0; xw.isfixed = False; @@ -3635,8 +3734,13 @@ main(int argc, char *argv[]) { break; case 'e': /* eat all remaining arguments */ - if(argc > 1) + if(argc > 1) { opt_cmd = &argv[1]; + if(argv[1] != NULL && opt_title == NULL) { + titles = strdup(argv[1]); + opt_title = basename(titles); + } + } goto run; case 'f': opt_font = EARGF(usage()); @@ -3653,7 +3757,7 @@ main(int argc, char *argv[]) { xw.fh = (int)hr; if(bitm & XNegative && xw.fx == 0) xw.fx = -1; - if(bitm & XNegative && xw.fy == 0) + if(bitm & YNegative && xw.fy == 0) xw.fy = -1; if(xw.fh != 0 && xw.fw != 0) @@ -3678,10 +3782,7 @@ run: XSetLocaleModifiers(""); tnew(80, 24); xinit(); - ttynew(); selinit(); - if(xw.isfixed) - cresize(xw.h, xw.w); run(); return 0;