diff options
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | st.c | 84 |
2 files changed, 68 insertions, 17 deletions
| @@ -1,7 +1,6 @@ | |||
| 1 | vt emulation | 1 | vt emulation |
| 2 | ------------ | 2 | ------------ |
| 3 | 3 | ||
| 4 | * wide-character support in conjunction with fallback xft code | ||
| 5 | * double-height support | 4 | * double-height support |
| 6 | 5 | ||
| 7 | code & interface | 6 | code & interface |
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <X11/keysym.h> | 27 | #include <X11/keysym.h> |
| 28 | #include <X11/Xft/Xft.h> | 28 | #include <X11/Xft/Xft.h> |
| 29 | #include <fontconfig/fontconfig.h> | 29 | #include <fontconfig/fontconfig.h> |
| 30 | #include <wchar.h> | ||
| 30 | 31 | ||
| 31 | #include "arg.h" | 32 | #include "arg.h" |
| 32 | 33 | ||
| @@ -96,6 +97,8 @@ enum glyph_attribute { | |||
| 96 | ATTR_ITALIC = 16, | 97 | ATTR_ITALIC = 16, |
| 97 | ATTR_BLINK = 32, | 98 | ATTR_BLINK = 32, |
| 98 | ATTR_WRAP = 64, | 99 | ATTR_WRAP = 64, |
| 100 | ATTR_WIDE = 128, | ||
| 101 | ATTR_WDUMMY = 256, | ||
| 99 | }; | 102 | }; |
| 100 | 103 | ||
| 101 | enum cursor_movement { | 104 | enum cursor_movement { |
| @@ -165,7 +168,7 @@ typedef unsigned short ushort; | |||
| 165 | 168 | ||
| 166 | typedef struct { | 169 | typedef struct { |
| 167 | char c[UTF_SIZ]; /* character code */ | 170 | char c[UTF_SIZ]; /* character code */ |
| 168 | uchar mode; /* attribute flags */ | 171 | ushort mode; /* attribute flags */ |
| 169 | ulong fg; /* foreground */ | 172 | ulong fg; /* foreground */ |
| 170 | ulong bg; /* background */ | 173 | ulong bg; /* background */ |
| 171 | } Glyph; | 174 | } Glyph; |
| @@ -719,8 +722,13 @@ selsnap(int mode, int *x, int *y, int direction) { | |||
| 719 | } | 722 | } |
| 720 | } | 723 | } |
| 721 | 724 | ||
| 725 | if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) { | ||
| 726 | *x += direction; | ||
| 727 | continue; | ||
| 728 | } | ||
| 729 | |||
| 722 | if(strchr(worddelimiters, | 730 | if(strchr(worddelimiters, |
| 723 | term.line[*y][*x + direction].c[0])) { | 731 | term.line[*y][*x+direction].c[0])) { |
| 724 | break; | 732 | break; |
| 725 | } | 733 | } |
| 726 | 734 | ||
| @@ -932,7 +940,7 @@ selcopy(void) { | |||
| 932 | /* nothing */; | 940 | /* nothing */; |
| 933 | 941 | ||
| 934 | for(x = 0; gp <= last; x++, ++gp) { | 942 | for(x = 0; gp <= last; x++, ++gp) { |
| 935 | if(!selected(x, y)) | 943 | if(!selected(x, y) || (gp->mode & ATTR_WDUMMY)) |
| 936 | continue; | 944 | continue; |
| 937 | 945 | ||
| 938 | size = utf8size(gp->c); | 946 | size = utf8size(gp->c); |
| @@ -1533,6 +1541,16 @@ tsetchar(char *c, Glyph *attr, int x, int y) { | |||
| 1533 | } | 1541 | } |
| 1534 | } | 1542 | } |
| 1535 | 1543 | ||
| 1544 | if(term.line[y][x].mode & ATTR_WIDE) { | ||
| 1545 | if(x+1 < term.col) { | ||
| 1546 | term.line[y][x+1].c[0] = ' '; | ||
| 1547 | term.line[y][x+1].mode &= ~ATTR_WDUMMY; | ||
| 1548 | } | ||
| 1549 | } else if(term.line[y][x].mode & ATTR_WDUMMY) { | ||
| 1550 | term.line[y][x-1].c[0] = ' '; | ||
| 1551 | term.line[y][x-1].mode &= ~ATTR_WIDE; | ||
| 1552 | } | ||
| 1553 | |||
| 1536 | term.dirty[y] = 1; | 1554 | term.dirty[y] = 1; |
| 1537 | term.line[y][x] = *attr; | 1555 | term.line[y][x] = *attr; |
| 1538 | memcpy(term.line[y][x].c, c, UTF_SIZ); | 1556 | memcpy(term.line[y][x].c, c, UTF_SIZ); |
| @@ -2222,6 +2240,15 @@ void | |||
| 2222 | tputc(char *c, int len) { | 2240 | tputc(char *c, int len) { |
| 2223 | uchar ascii = *c; | 2241 | uchar ascii = *c; |
| 2224 | bool control = ascii < '\x20' || ascii == 0177; | 2242 | bool control = ascii < '\x20' || ascii == 0177; |
| 2243 | long u8char; | ||
| 2244 | int width; | ||
| 2245 | |||
| 2246 | if(len == 1) { | ||
| 2247 | width = 1; | ||
| 2248 | } else { | ||
| 2249 | utf8decode(c, &u8char); | ||
| 2250 | width = wcwidth(u8char); | ||
| 2251 | } | ||
| 2225 | 2252 | ||
| 2226 | if(iofd != -1) { | 2253 | if(iofd != -1) { |
| 2227 | if(xwrite(iofd, c, len) < 0) { | 2254 | if(xwrite(iofd, c, len) < 0) { |
| @@ -2469,9 +2496,20 @@ tputc(char *c, int len) { | |||
| 2469 | (term.col - term.c.x - 1) * sizeof(Glyph)); | 2496 | (term.col - term.c.x - 1) * sizeof(Glyph)); |
| 2470 | } | 2497 | } |
| 2471 | 2498 | ||
| 2499 | if(term.c.x+width > term.col) | ||
| 2500 | tnewline(1); | ||
| 2501 | |||
| 2472 | tsetchar(c, &term.c.attr, term.c.x, term.c.y); | 2502 | tsetchar(c, &term.c.attr, term.c.x, term.c.y); |
| 2473 | if(term.c.x+1 < term.col) { | 2503 | |
| 2474 | tmoveto(term.c.x+1, term.c.y); | 2504 | if(width == 2) { |
| 2505 | term.line[term.c.y][term.c.x].mode |= ATTR_WIDE; | ||
| 2506 | if(term.c.x+1 < term.col) { | ||
| 2507 | term.line[term.c.y][term.c.x+1].c[0] = '\0'; | ||
| 2508 | term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY; | ||
| 2509 | } | ||
| 2510 | } | ||
| 2511 | if(term.c.x+width < term.col) { | ||
| 2512 | tmoveto(term.c.x+width, term.c.y); | ||
| 2475 | } else { | 2513 | } else { |
| 2476 | term.c.state |= CURSOR_WRAPNEXT; | 2514 | term.c.state |= CURSOR_WRAPNEXT; |
| 2477 | } | 2515 | } |
| @@ -3173,7 +3211,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { | |||
| 3173 | xp, winy + frc[i].font->ascent, | 3211 | xp, winy + frc[i].font->ascent, |
| 3174 | (FcChar8 *)u8c, u8cblen); | 3212 | (FcChar8 *)u8c, u8cblen); |
| 3175 | 3213 | ||
| 3176 | xp += xw.cw; | 3214 | xp += xw.cw * wcwidth(u8char); |
| 3177 | } | 3215 | } |
| 3178 | 3216 | ||
| 3179 | /* | 3217 | /* |
| @@ -3193,18 +3231,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { | |||
| 3193 | void | 3231 | void |
| 3194 | xdrawcursor(void) { | 3232 | xdrawcursor(void) { |
| 3195 | static int oldx = 0, oldy = 0; | 3233 | static int oldx = 0, oldy = 0; |
| 3196 | int sl; | 3234 | int sl, width, curx; |
| 3197 | Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; | 3235 | Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; |
| 3198 | 3236 | ||
| 3199 | LIMIT(oldx, 0, term.col-1); | 3237 | LIMIT(oldx, 0, term.col-1); |
| 3200 | LIMIT(oldy, 0, term.row-1); | 3238 | LIMIT(oldy, 0, term.row-1); |
| 3201 | 3239 | ||
| 3240 | curx = term.c.x; | ||
| 3241 | |||
| 3242 | /* adjust position if in dummy */ | ||
| 3243 | if(term.line[oldy][oldx].mode & ATTR_WDUMMY) | ||
| 3244 | oldx--; | ||
| 3245 | if(term.line[term.c.y][curx].mode & ATTR_WDUMMY) | ||
| 3246 | curx--; | ||
| 3247 | |||
| 3202 | memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); | 3248 | memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); |
| 3203 | 3249 | ||
| 3204 | /* remove the old cursor */ | 3250 | /* remove the old cursor */ |
| 3205 | sl = utf8size(term.line[oldy][oldx].c); | 3251 | sl = utf8size(term.line[oldy][oldx].c); |
| 3252 | width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1; | ||
| 3206 | xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, | 3253 | xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, |
| 3207 | oldy, 1, sl); | 3254 | oldy, width, sl); |
| 3208 | 3255 | ||
| 3209 | /* draw the new one */ | 3256 | /* draw the new one */ |
| 3210 | if(!(IS_SET(MODE_HIDE))) { | 3257 | if(!(IS_SET(MODE_HIDE))) { |
| @@ -3216,26 +3263,28 @@ xdrawcursor(void) { | |||
| 3216 | } | 3263 | } |
| 3217 | 3264 | ||
| 3218 | sl = utf8size(g.c); | 3265 | sl = utf8size(g.c); |
| 3219 | xdraws(g.c, g, term.c.x, term.c.y, 1, sl); | 3266 | width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ |
| 3267 | ? 2 : 1; | ||
| 3268 | xdraws(g.c, g, term.c.x, term.c.y, width, sl); | ||
| 3220 | } else { | 3269 | } else { |
| 3221 | XftDrawRect(xw.draw, &dc.col[defaultcs], | 3270 | XftDrawRect(xw.draw, &dc.col[defaultcs], |
| 3222 | borderpx + term.c.x * xw.cw, | 3271 | borderpx + curx * xw.cw, |
| 3223 | borderpx + term.c.y * xw.ch, | 3272 | borderpx + term.c.y * xw.ch, |
| 3224 | xw.cw - 1, 1); | 3273 | xw.cw - 1, 1); |
| 3225 | XftDrawRect(xw.draw, &dc.col[defaultcs], | 3274 | XftDrawRect(xw.draw, &dc.col[defaultcs], |
| 3226 | borderpx + term.c.x * xw.cw, | 3275 | borderpx + curx * xw.cw, |
| 3227 | borderpx + term.c.y * xw.ch, | 3276 | borderpx + term.c.y * xw.ch, |
| 3228 | 1, xw.ch - 1); | 3277 | 1, xw.ch - 1); |
| 3229 | XftDrawRect(xw.draw, &dc.col[defaultcs], | 3278 | XftDrawRect(xw.draw, &dc.col[defaultcs], |
| 3230 | borderpx + (term.c.x + 1) * xw.cw - 1, | 3279 | borderpx + (curx + 1) * xw.cw - 1, |
| 3231 | borderpx + term.c.y * xw.ch, | 3280 | borderpx + term.c.y * xw.ch, |
| 3232 | 1, xw.ch - 1); | 3281 | 1, xw.ch - 1); |
| 3233 | XftDrawRect(xw.draw, &dc.col[defaultcs], | 3282 | XftDrawRect(xw.draw, &dc.col[defaultcs], |
| 3234 | borderpx + term.c.x * xw.cw, | 3283 | borderpx + curx * xw.cw, |
| 3235 | borderpx + (term.c.y + 1) * xw.ch - 1, | 3284 | borderpx + (term.c.y + 1) * xw.ch - 1, |
| 3236 | xw.cw, 1); | 3285 | xw.cw, 1); |
| 3237 | } | 3286 | } |
| 3238 | oldx = term.c.x, oldy = term.c.y; | 3287 | oldx = curx, oldy = term.c.y; |
| 3239 | } | 3288 | } |
| 3240 | } | 3289 | } |
| 3241 | 3290 | ||
| @@ -3284,6 +3333,7 @@ drawregion(int x1, int y1, int x2, int y2) { | |||
| 3284 | Glyph base, new; | 3333 | Glyph base, new; |
| 3285 | char buf[DRAW_BUF_SIZ]; | 3334 | char buf[DRAW_BUF_SIZ]; |
| 3286 | bool ena_sel = sel.ob.x != -1; | 3335 | bool ena_sel = sel.ob.x != -1; |
| 3336 | long u8char; | ||
| 3287 | 3337 | ||
| 3288 | if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) | 3338 | if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) |
| 3289 | ena_sel = 0; | 3339 | ena_sel = 0; |
| @@ -3301,6 +3351,8 @@ drawregion(int x1, int y1, int x2, int y2) { | |||
| 3301 | ic = ib = ox = 0; | 3351 | ic = ib = ox = 0; |
| 3302 | for(x = x1; x < x2; x++) { | 3352 | for(x = x1; x < x2; x++) { |
| 3303 | new = term.line[y][x]; | 3353 | new = term.line[y][x]; |
| 3354 | if(new.mode == ATTR_WDUMMY) | ||
| 3355 | continue; | ||
| 3304 | if(ena_sel && selected(x, y)) | 3356 | if(ena_sel && selected(x, y)) |
| 3305 | new.mode ^= ATTR_REVERSE; | 3357 | new.mode ^= ATTR_REVERSE; |
| 3306 | if(ib > 0 && (ATTRCMP(base, new) | 3358 | if(ib > 0 && (ATTRCMP(base, new) |
| @@ -3313,10 +3365,10 @@ drawregion(int x1, int y1, int x2, int y2) { | |||
| 3313 | base = new; | 3365 | base = new; |
| 3314 | } | 3366 | } |
| 3315 | 3367 | ||
| 3316 | sl = utf8size(new.c); | 3368 | sl = utf8decode(new.c, &u8char); |
| 3317 | memcpy(buf+ib, new.c, sl); | 3369 | memcpy(buf+ib, new.c, sl); |
| 3318 | ib += sl; | 3370 | ib += sl; |
| 3319 | ++ic; | 3371 | ic += (new.mode & ATTR_WIDE)? 2 : 1; |
| 3320 | } | 3372 | } |
| 3321 | if(ib > 0) | 3373 | if(ib > 0) |
| 3322 | xdraws(buf, base, ox, y, ic, ib); | 3374 | xdraws(buf, base, ox, y, ic, ib); |
