Wide character support.

Thanks "Eon S. Jeon" <esjeon@hyunmu.am>!
This commit is contained in:
Christoph Lohmann 2013-09-07 12:41:36 +02:00
parent a4358a1fbd
commit 210dda9570
2 changed files with 68 additions and 17 deletions

1
TODO
View File

@ -1,7 +1,6 @@
vt emulation vt emulation
------------ ------------
* wide-character support in conjunction with fallback xft code
* double-height support * double-height support
code & interface code & interface

84
st.c
View File

@ -27,6 +27,7 @@
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xft/Xft.h> #include <X11/Xft/Xft.h>
#include <fontconfig/fontconfig.h> #include <fontconfig/fontconfig.h>
#include <wchar.h>
#include "arg.h" #include "arg.h"
@ -96,6 +97,8 @@ enum glyph_attribute {
ATTR_ITALIC = 16, ATTR_ITALIC = 16,
ATTR_BLINK = 32, ATTR_BLINK = 32,
ATTR_WRAP = 64, ATTR_WRAP = 64,
ATTR_WIDE = 128,
ATTR_WDUMMY = 256,
}; };
enum cursor_movement { enum cursor_movement {
@ -165,7 +168,7 @@ typedef unsigned short ushort;
typedef struct { typedef struct {
char c[UTF_SIZ]; /* character code */ char c[UTF_SIZ]; /* character code */
uchar mode; /* attribute flags */ ushort mode; /* attribute flags */
ulong fg; /* foreground */ ulong fg; /* foreground */
ulong bg; /* background */ ulong bg; /* background */
} Glyph; } Glyph;
@ -719,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, if(strchr(worddelimiters,
term.line[*y][*x + direction].c[0])) { term.line[*y][*x+direction].c[0])) {
break; break;
} }
@ -932,7 +940,7 @@ selcopy(void) {
/* nothing */; /* nothing */;
for(x = 0; gp <= last; x++, ++gp) { for(x = 0; gp <= last; x++, ++gp) {
if(!selected(x, y)) if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
continue; continue;
size = utf8size(gp->c); size = utf8size(gp->c);
@ -1533,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.dirty[y] = 1;
term.line[y][x] = *attr; term.line[y][x] = *attr;
memcpy(term.line[y][x].c, c, UTF_SIZ); memcpy(term.line[y][x].c, c, UTF_SIZ);
@ -2222,6 +2240,15 @@ void
tputc(char *c, int len) { tputc(char *c, int len) {
uchar ascii = *c; uchar ascii = *c;
bool control = ascii < '\x20' || ascii == 0177; 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(iofd != -1) {
if(xwrite(iofd, c, len) < 0) { if(xwrite(iofd, c, len) < 0) {
@ -2469,9 +2496,20 @@ tputc(char *c, int len) {
(term.col - term.c.x - 1) * sizeof(Glyph)); (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); 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 { } else {
term.c.state |= CURSOR_WRAPNEXT; term.c.state |= CURSOR_WRAPNEXT;
} }
@ -3173,7 +3211,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
xp, winy + frc[i].font->ascent, xp, winy + frc[i].font->ascent,
(FcChar8 *)u8c, u8cblen); (FcChar8 *)u8c, u8cblen);
xp += xw.cw; xp += xw.cw * wcwidth(u8char);
} }
/* /*
@ -3193,18 +3231,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
void void
xdrawcursor(void) { xdrawcursor(void) {
static int oldx = 0, oldy = 0; static int oldx = 0, oldy = 0;
int sl; int sl, width, curx;
Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
LIMIT(oldx, 0, term.col-1); LIMIT(oldx, 0, term.col-1);
LIMIT(oldy, 0, term.row-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); memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
/* remove the old cursor */ /* remove the old cursor */
sl = utf8size(term.line[oldy][oldx].c); 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, xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
oldy, 1, sl); oldy, width, sl);
/* draw the new one */ /* draw the new one */
if(!(IS_SET(MODE_HIDE))) { if(!(IS_SET(MODE_HIDE))) {
@ -3216,26 +3263,28 @@ xdrawcursor(void) {
} }
sl = utf8size(g.c); 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 { } else {
XftDrawRect(xw.draw, &dc.col[defaultcs], XftDrawRect(xw.draw, &dc.col[defaultcs],
borderpx + term.c.x * xw.cw, borderpx + curx * xw.cw,
borderpx + term.c.y * xw.ch, borderpx + term.c.y * xw.ch,
xw.cw - 1, 1); xw.cw - 1, 1);
XftDrawRect(xw.draw, &dc.col[defaultcs], XftDrawRect(xw.draw, &dc.col[defaultcs],
borderpx + term.c.x * xw.cw, borderpx + curx * xw.cw,
borderpx + term.c.y * xw.ch, borderpx + term.c.y * xw.ch,
1, xw.ch - 1); 1, xw.ch - 1);
XftDrawRect(xw.draw, &dc.col[defaultcs], 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, borderpx + term.c.y * xw.ch,
1, xw.ch - 1); 1, xw.ch - 1);
XftDrawRect(xw.draw, &dc.col[defaultcs], XftDrawRect(xw.draw, &dc.col[defaultcs],
borderpx + term.c.x * xw.cw, borderpx + curx * xw.cw,
borderpx + (term.c.y + 1) * xw.ch - 1, borderpx + (term.c.y + 1) * xw.ch - 1,
xw.cw, 1); xw.cw, 1);
} }
oldx = term.c.x, oldy = term.c.y; oldx = curx, oldy = term.c.y;
} }
} }
@ -3284,6 +3333,7 @@ drawregion(int x1, int y1, int x2, int y2) {
Glyph base, new; Glyph base, new;
char buf[DRAW_BUF_SIZ]; char buf[DRAW_BUF_SIZ];
bool ena_sel = sel.ob.x != -1; bool ena_sel = sel.ob.x != -1;
long u8char;
if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) if(sel.alt ^ IS_SET(MODE_ALTSCREEN))
ena_sel = 0; ena_sel = 0;
@ -3301,6 +3351,8 @@ drawregion(int x1, int y1, int x2, int y2) {
ic = ib = ox = 0; ic = ib = ox = 0;
for(x = x1; x < x2; x++) { for(x = x1; x < x2; x++) {
new = term.line[y][x]; new = term.line[y][x];
if(new.mode == ATTR_WDUMMY)
continue;
if(ena_sel && selected(x, y)) if(ena_sel && selected(x, y))
new.mode ^= ATTR_REVERSE; new.mode ^= ATTR_REVERSE;
if(ib > 0 && (ATTRCMP(base, new) if(ib > 0 && (ATTRCMP(base, new)
@ -3313,10 +3365,10 @@ drawregion(int x1, int y1, int x2, int y2) {
base = new; base = new;
} }
sl = utf8size(new.c); sl = utf8decode(new.c, &u8char);
memcpy(buf+ib, new.c, sl); memcpy(buf+ib, new.c, sl);
ib += sl; ib += sl;
++ic; ic += (new.mode & ATTR_WIDE)? 2 : 1;
} }
if(ib > 0) if(ib > 0)
xdraws(buf, base, ox, y, ic, ib); xdraws(buf, base, ox, y, ic, ib);