From 08d3749a636f9cd51f70ba1eed043be8e6c2eca9 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 5 Oct 2021 16:57:55 -0700 Subject: feat(term): added ligature support. some combining character help --- sys/cmd/dwm/config.h | 2 ++ sys/cmd/rules.mk | 4 ++-- sys/cmd/term/rules.mk | 6 ++++-- sys/cmd/term/term.c | 47 ++++++++++++++++++++++++++++++++++++----------- sys/cmd/term/term.h | 8 ++++++-- sys/cmd/term/x.c | 36 ++++++++++++++++++++++-------------- sys/cmd/wm/client.c | 15 +++++++++++---- sys/cmd/wm/config.h | 4 ++-- sys/cmd/wm/input.c | 1 + sys/cmd/wm/util.c | 1 + sys/libn/string.c | 12 ++++++------ sys/rules.mk | 9 ++++++--- 12 files changed, 99 insertions(+), 46 deletions(-) (limited to 'sys') diff --git a/sys/cmd/dwm/config.h b/sys/cmd/dwm/config.h index cb1ccdb..d14aded 100644 --- a/sys/cmd/dwm/config.h +++ b/sys/cmd/dwm/config.h @@ -93,6 +93,8 @@ static Key keys[] = { { MODKEY, XK_j, focusdirection, {.i = 'd'} }, { MODKEY|ShiftMask, XK_h, setmfact, {.f = -0.05} }, { MODKEY|ShiftMask, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_k, rotatestack, {.i = +1 } }, + { MODKEY|ShiftMask, XK_j, rotatestack, {.i = -1 } }, { MODKEY|ShiftMask, XK_Return, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_q, killclient, {0} }, diff --git a/sys/cmd/rules.mk b/sys/cmd/rules.mk index 50d9274..dc0ca08 100644 --- a/sys/cmd/rules.mk +++ b/sys/cmd/rules.mk @@ -23,8 +23,8 @@ include $(DIR)/rules.mk DIR := $(d)/term include $(DIR)/rules.mk -# DIR := $(d)/term2 -# include $(DIR)/rules.mk +DIR := $(d)/term2 +include $(DIR)/rules.mk DIR := $(d)/walk include $(DIR)/rules.mk diff --git a/sys/cmd/term/rules.mk b/sys/cmd/term/rules.mk index 38acbf7..19fcdaf 100644 --- a/sys/cmd/term/rules.mk +++ b/sys/cmd/term/rules.mk @@ -2,7 +2,7 @@ include share/push.mk # Iterate through subdirectory tree # Local sources -SRCS_$(d) := $(d)/term.c $(d)/x.c #$(d)/util.c +SRCS_$(d) := $(d)/term.c $(d)/x.c $(d)/hb.c BINS_$(d) := $(d)/term include share/paths.mk @@ -11,10 +11,12 @@ include share/paths.mk include share/dynamic.mk $(BINS_$(d)): TCFLAGS = \ `$(PKG) --cflags fontconfig` \ - `$(PKG) --cflags freetype2` + `$(PKG) --cflags freetype2` \ + `$(PKG) --cflags harfbuzz` $(BINS_$(d)): TCLIBS = \ `$(PKG) --libs fontconfig` \ `$(PKG) --libs freetype2` \ + `$(PKG) --libs harfbuzz` \ -lm -lrt -lX11 -lutil -lXft -lXrender \ $(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/sys/libn/libn.a diff --git a/sys/cmd/term/term.c b/sys/cmd/term/term.c index f7687b9..77ed5c2 100644 --- a/sys/cmd/term/term.c +++ b/sys/cmd/term/term.c @@ -627,7 +627,7 @@ ttyread(void) written = twrite(buf, buflen, 0); buflen -= written; /* keep any incomplete UTF-8 byte sequence for the next call */ - if (buflen > 0) + if(buflen > 0) memmove(buf, buf + written, buflen); return ret; } @@ -989,7 +989,7 @@ tsetchar(rune u, Letter *attr, int x, int y) }; /* - * The table is proudly stolen from rxvt. + * table is proudly stolen from rxvt. */ if (term.trantbl[term.charset] == CSgfx0 && BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) @@ -2082,6 +2082,7 @@ tputc(rune u) char c[UTFmax]; int control; int width, len; + rune nu; Letter *gp; control = ISCONTROL(u); @@ -2090,10 +2091,30 @@ tputc(rune u) width = len = 1; } else { len = utf8·runetobyte(c, &u); - if (!control && (width = wcwidth(u)) == -1) + if(!control && (width = wcwidth(u)) == -1) width = 1; } + /* combining characters */ + if(!width) { + if(term.c.x > 0) + gp = &term.line[term.c.y][term.c.x-1]; + else if(term.c.y > 0) + gp = &term.line[term.c.y-1][term.col-1]; + else + return; + + printf("%d + %d\n", gp->u, u); + + if(!hb_unicode_compose(hb_unicode_funcs_get_default(),gp->u, u, &nu)) { + assert(false); + return; + } + + gp->u = nu; + return; + } + if (IS_SET(Tprint)) tprinter(c, len); @@ -2103,7 +2124,7 @@ tputc(rune u) * receives a ESC, a SUB, a ST or any other C1 control * character. */ - if (term.esc & Xstr) { + if(term.esc & Xstr) { if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) { term.esc &= ~(Xstart|Xstr|Xdcs); @@ -2154,7 +2175,7 @@ check_control_code: * because they can be embedded inside a control sequence, and * they must not cause conflicts with sequences. */ - if (control) { + if(control) { tcontrolcode(u); /* * control codes are not shown ever @@ -2162,7 +2183,7 @@ check_control_code: if (!term.esc) term.lastc = 0; return; - } else if (term.esc & Xstart) { + } else if(term.esc & Xstart) { if (term.esc & Xcsi) { csiescseq.buf[csiescseq.len++] = u; if (BETWEEN(u, 0x40, 0x7E) @@ -2191,6 +2212,7 @@ check_control_code: */ return; } + if (selected(term.c.x, term.c.y)) selclear(); @@ -2212,7 +2234,7 @@ check_control_code: tsetchar(u, &term.c.attr, term.c.x, term.c.y); term.lastc = u; - if (width == 2) { + if(width == 2) { gp->mode |= Gwrap; if (term.c.x+1 < term.col) { gp[1].u = '\0'; @@ -2234,16 +2256,16 @@ twrite(char *buf, int buflen, int show_ctrl) int n; for (n = 0; n < buflen; n += charsize) { - if (IS_SET(Tutf8) && !IS_SET(Tsixel)) { + if(IS_SET(Tutf8) && !IS_SET(Tsixel)) { /* process a complete utf8 char */ charsize = utf8·bytetorune(&u, buf + n); - if (charsize == 0) + if(charsize == 0) break; } else { u = buf[n] & 0xFF; charsize = 1; } - if (show_ctrl && ISCONTROL(u)) { + if(show_ctrl && ISCONTROL(u)) { if (u & 0x80) { u &= 0x7f; tputc('^'); @@ -2377,7 +2399,10 @@ draw(void) cx--; drawregion(0, 0, term.col, term.row); - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], term.ocx, term.ocy, term.line[term.ocy][term.ocx]); + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col + ); term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); diff --git a/sys/cmd/term/term.h b/sys/cmd/term/term.h index 11c28c7..fd7b68c 100644 --- a/sys/cmd/term/term.h +++ b/sys/cmd/term/term.h @@ -10,6 +10,8 @@ #include #include +#include + // ----------------------------------------------------------------------- // macros @@ -17,7 +19,8 @@ #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) -#define GLYPHCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) +#define GLYPHCMP(a, b) (((a).mode & (~Gwrap) & (~Gliga)) != ((b).mode & (~Gwrap) & (~Gliga)) || \ + (a).fg != (b).fg || (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6) #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) @@ -47,6 +50,7 @@ enum { Gwrap = iota(8), Gwide = iota(9), Gwdummy = iota(10), + Gliga = iota(11), Gboldfaint = Gbold | Gfaint, }; @@ -251,7 +255,7 @@ union Arg { void xbell(void); void xclipcopy(void); -void xdrawcursor(int, int, Letter, int, int, Letter); +void xdrawcursor(int, int, Letter, int, int, Letter, Letter*, int); void xdrawline(Letter*, int, int, int); void xfinishdraw(void); void xloadcols(void); diff --git a/sys/cmd/term/x.c b/sys/cmd/term/x.c index 308478f..3079f38 100644 --- a/sys/cmd/term/x.c +++ b/sys/cmd/term/x.c @@ -11,6 +11,10 @@ #include #include +/* harfbuzz additions */ +void hbunloadfonts(); +void hbtransform(XftGlyphFontSpec *, const Letter*, size_t, int, int); + /* types used in config.h */ typedef struct Shortcut Shortcut; typedef struct MouseShortcut MouseShortcut; @@ -1021,6 +1025,8 @@ xunloadfont(Font *f) void xunloadfonts(void) { + hbunloadfonts(); + /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); @@ -1223,17 +1229,17 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, Letter *glyphs, int len, int x, int FcCharSet *fccharset; int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + for(i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { /* Fetch rune and mode for current glyph. */ r = glyphs[i].u; mode = glyphs[i].mode; /* Skip dummy wide-character spacing. */ - if (mode == Gwdummy) + if(mode & Gwdummy) continue; /* Determine font for glyph if different from previous glyph. */ - if (prevmode != mode) { + if(prevmode != mode) { prevmode = mode; font = &dc.font; frcflags = FRC_NORMAL; @@ -1251,9 +1257,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, Letter *glyphs, int len, int x, int yp = winy + font->ascent; } - /* Lookup character index with default font. */ + /* lookup character index with default font. */ glyphidx = XftCharIndex(xw.dpy, font->match, r); - if (glyphidx) { + if(glyphidx) { specs[numspecs].font = font->match; specs[numspecs].glyph = glyphidx; specs[numspecs].x = (short)xp; @@ -1264,7 +1270,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, Letter *glyphs, int len, int x, int } /* Fallback on font cache, search the font cache for match. */ - for (f = 0; f < frclen; f++) { + for(f = 0; f < frclen; f++) { glyphidx = XftCharIndex(xw.dpy, frc[f].font, r); /* Everything correct. */ if (glyphidx && frc[f].flags == frcflags) @@ -1277,7 +1283,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, Letter *glyphs, int len, int x, int } /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { + if(f >= frclen) { if (!font->set) font->set = FcFontSort(0, font->pattern, 1, 0, &fcres); @@ -1336,6 +1342,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, Letter *glyphs, int len, int x, int numspecs++; } + hbtransform(specs, glyphs, len, x, y); + return numspecs; } @@ -1474,16 +1482,16 @@ xdrawglyph(Letter g, int x, int y) } void -xdrawcursor(int cx, int cy, Letter g, int ox, int oy, Letter og) +xdrawcursor(int cx, int cy, Letter g, int ox, int oy, Letter og, Letter *line, int len) { Color drawcol; /* remove the old cursor */ - if (selected(ox, oy)) + if(selected(ox, oy)) og.mode ^= Greverse; - xdrawglyph(og, ox, oy); + xdrawline(line, 0, oy, len); - if (IS_SET(Whide)) + if(IS_SET(Whide)) return; /* @@ -1491,7 +1499,7 @@ xdrawcursor(int cx, int cy, Letter g, int ox, int oy, Letter og) */ g.mode &= Gbold|Gitalic|Gunline|Gstruck|Gwide; - if (IS_SET(Wreverse)) { + if(IS_SET(Wreverse)) { g.mode |= Greverse; g.bg = defaultfg; if (selected(cx, cy)) { @@ -1502,7 +1510,7 @@ xdrawcursor(int cx, int cy, Letter g, int ox, int oy, Letter og) g.fg = defaultcs; } } else { - if (selected(cx, cy)) { + if(selected(cx, cy)) { g.fg = defaultfg; g.bg = defaultrcs; } else { @@ -1520,7 +1528,7 @@ xdrawcursor(int cx, int cy, Letter g, int ox, int oy, Letter og) } drawnew: - if (IS_SET(Wfocused)) { + if(IS_SET(Wfocused)) { switch (win.cursor) { case 7: /* st extension */ g.u = 0x2603; /* snowman (U+2603) */ diff --git a/sys/cmd/wm/client.c b/sys/cmd/wm/client.c index 7c13545..5e0927a 100644 --- a/sys/cmd/wm/client.c +++ b/sys/cmd/wm/client.c @@ -64,11 +64,17 @@ resize_client(Arg *arg) // ----------------------------------------------------------------------- // core +static inline +void +activate(struct wlr_surface *surface, int state) +{ +} + void focus(Client *client, int lift) { - struct wlr_surface *old, *new; struct wlr_xdg_surface *xdg; + struct wlr_surface *old, *new; struct wlr_keyboard *keyboard; if(!client) { @@ -92,10 +98,11 @@ focus(Client *client, int lift) server.monitor.selected = client->monitor; client->isurgent = 0; - // XXX: do we need for non-client case? if(old) { - xdg = wlr_xdg_surface_from_wlr_surface(old); - wlr_xdg_toplevel_set_activated(xdg, false); + if(wlr_surface_is_xdg_surface(old)) { + xdg = wlr_xdg_surface_from_wlr_surface(old); + wlr_xdg_toplevel_set_activated(xdg, false); + } } keyboard = wlr_seat_get_keyboard(server.input.seat); diff --git a/sys/cmd/wm/config.h b/sys/cmd/wm/config.h index f80638f..1f5ba85 100644 --- a/sys/cmd/wm/config.h +++ b/sys/cmd/wm/config.h @@ -24,7 +24,7 @@ CONFIG(Rule*, endrule, arrend(cfg·rule)); /* commands */ CONFIG(char*, termcommand[], { "alacritty", nil }); -CONFIG(char*, menucommand[], { "bemenu-run", nil }); +CONFIG(char*, menucommand[], { "dmenu-wl_run", nil }); /* layouts */ CONFIG(Layout, layouts[], { @@ -51,7 +51,7 @@ CONFIG(MonitorRule*, endmonitorrule, arrend(cfg·monitorrule)); CONFIG(Key, binding[], { /* modifier key function argument */ { MODKEY, KEY(Return), spawn, {.v = cfg·termcommand} }, - { MODKEY, KEY(D), spawn, {.v = cfg·menucommand} }, + { MODKEY, KEY(d), spawn, {.v = cfg·menucommand} }, { MODKEY|MOD(SHIFT), KEY(Q), quit, {.v = nil} }, }); CONFIG(Key*, endbinding, arrend(cfg·binding)); diff --git a/sys/cmd/wm/input.c b/sys/cmd/wm/input.c index a91ecd8..4c6bfd4 100644 --- a/sys/cmd/wm/input.c +++ b/sys/cmd/wm/input.c @@ -18,6 +18,7 @@ int keybinding(uint32 modifier, xkb_keysym_t sym) { Key *key; + for(key=cfg·binding; key!=cfg·endbinding; ++key) { if(modifier == key->modifier && sym == key->sym && key->action){ key->action(&key->arg); diff --git a/sys/cmd/wm/util.c b/sys/cmd/wm/util.c index cf4f68a..7871d15 100644 --- a/sys/cmd/wm/util.c +++ b/sys/cmd/wm/util.c @@ -80,6 +80,7 @@ exclude(struct wlr_box *usable_area, uint32 anchor, int32 exclusive, void spawn(Arg *arg) { + wlr_log(WLR_DEBUG, "spawning %s", ((char **)arg->v)[0]); if(!fork()) { dup2(2, 1); setsid(); diff --git a/sys/libn/string.c b/sys/libn/string.c index bf5d645..22a3359 100644 --- a/sys/libn/string.c +++ b/sys/libn/string.c @@ -40,26 +40,26 @@ utf8·bytetorune(rune* r, byte* s) rune l; c[0] = *(ubyte*)(s); - if (c[0] < Tx) { + if(c[0] < Tx) { *r = c[0]; return 1; } l = c[0]; - for (i = 1; i < UTFmax; i++) { + for(i = 1; i < UTFmax; i++) { c[i] = *(ubyte*)(s+i); c[i] ^= Tx; if (c[i] & Testx) goto bad; l = (l << Bitx) | c[i]; - if (c[0] < Tbyte(i + 2)) { + if(c[0] < Tbyte(i + 2)) { l &= RuneX(i + 1); if (i == 1) { - if (c[0] < Tbyte(2) || l <= Rune1) + if (c[0] < Tbyte(2) || l <= Rune1) goto bad; - } else if (l <= RuneX(i) || l > RuneMax) + } else if (l <= RuneX(i) || l > RuneMax) goto bad; - if (i == 2 && SurrogateMin <= l && l <= SurrogateMax) + if (i == 2 && SurrogateMin <= l && l <= SurrogateMax) goto bad; *r = l; diff --git a/sys/rules.mk b/sys/rules.mk index 385c9ac..a45e8b3 100644 --- a/sys/rules.mk +++ b/sys/rules.mk @@ -2,12 +2,12 @@ include share/push.mk # Iterate through subdirectory tree -# DIR := $(d)/libc -# include $(DIR)/rules.mk - DIR := $(d)/cmd include $(DIR)/rules.mk +# DIR := $(d)/libc +# include $(DIR)/rules.mk + DIR := $(d)/libn include $(DIR)/rules.mk @@ -17,6 +17,9 @@ include $(DIR)/rules.mk DIR := $(d)/libbio include $(DIR)/rules.mk +DIR := $(d)/libdraw +include $(DIR)/rules.mk + # DIR := $(d)/libimage # include $(DIR)/rules.mk -- cgit v1.2.1