From 08369e718e4038fb9ee9fec3aab6b836049b1cdc Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 14 Aug 2026 15:17:00 +0900 Subject: [PATCH] popup: use system fonts exclusively --- README.md | 24 ++++++++++-------------- dat.h | 1 - docs/PROVENANCE.md | 13 +++++-------- fn.h | 2 +- font.c | 25 +------------------------ main.c | 8 ++------ run.sh | 21 ++++----------------- tests/daemon_collision_test.c | 7 ++----- tests/daemon_failure_test.c | 5 +---- tests/daemon_restart_test.c | 7 ++----- tests/font_test.c | 18 +----------------- tests/ibus_live_test.c | 7 ++----- tests/ipc_live_test.c | 7 ++----- win.c | 5 +---- 14 files changed, 34 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 488ca18..edc9e9d 100644 --- a/README.md +++ b/README.md @@ -51,26 +51,22 @@ dependencies listed in [`Dockerfile`](Dockerfile) are installed. ## Run -The popup needs one to four font files. No fonts are bundled. Each file is -validated and registered with Pango as an application font. Pango shapes the -complete string and chooses glyph fallback from those fonts and the normal -system fonts; command-line file order is not an exact per-glyph fallback -contract. - -`run.sh` uses installed Noto Color Emoji, DejaVu, Jigmo, or Noto CJK fonts when -available, or accepts explicit files. Supply a color emoji font such as Noto -Color Emoji to render emoji in color: +The popup uses the normal system fonts found by Pango and Fontconfig; no font +file argument or system-wide strans installation is required. Run it directly +from the build tree: ```sh ./run.sh -./run.sh /path/to/primary.ttf /path/to/fallback.ttc +# daemon only +./strans map ``` -The popup renderer requires Pango/PangoCairo 1.56 or newer and Cairo 1.18 or -newer. +Pango shapes the complete string and selects glyph fallback from the system +font set. -The script starts the daemon and, when `DISPLAY` is set, the XIM frontend. It -restarts any existing `strans` processes owned by the current user. +The popup renderer requires Pango/PangoCairo 1.56 or newer and Cairo 1.18 or +newer. `run.sh` starts the daemon and, when `DISPLAY` is set, the XIM frontend. +It restarts existing `strans` processes owned by the current user. Configure clients as needed: diff --git a/dat.h b/dat.h index dd87fa9..e08250a 100644 --- a/dat.h +++ b/dat.h @@ -18,7 +18,6 @@ enum LangVI = 0x16, Fontsz = 32, - Maxfonts = 4, Maxrunes = 64, Maxutf = Maxrunes * UTFmax + 1, }; diff --git a/docs/PROVENANCE.md b/docs/PROVENANCE.md index b30e08e..65a1b14 100644 --- a/docs/PROVENANCE.md +++ b/docs/PROVENANCE.md @@ -46,14 +46,11 @@ new SKK revision. ## Fonts -No font binaries are bundled. The daemon receives one to four font file paths -on its command line, validates them, and registers them as Pango application -fonts. Pango shapes each complete string and selects glyph fallback from the -registered fonts and the normal system font set. Exact command-line file order -is deliberately not promised: preserving it would require a separate -Fontconfig policy alongside Pango's fallback. `font/PROVENANCE` retains the -exact checksums, source revisions, and license records for the three Noto faces -that were formerly stored in the repository. +No font binaries are bundled. The daemon asks Pango and Fontconfig to select +from the user's normal system font set. Pango shapes each complete string and +selects glyph fallback. `font/PROVENANCE` retains the exact checksums, source +revisions, and license records for the three Noto faces that were formerly +stored in the repository. The Docker renderer tests obtain their fonts from signed Arch packages rather than the source checkout. On August 14, 2026 the tested package contract was: diff --git a/fn.h b/fn.h index bcde748..d9cbcda 100644 --- a/fn.h +++ b/fn.h @@ -43,6 +43,6 @@ void ibusthread(void*); void* emalloc(ulong); void* erealloc(void*, ulong); -int textinit(char**, int); +int textinit(void); int textwidth(Str*); void textdraw(u32int*, int, int, int, int, Str*); diff --git a/font.c b/font.c index cc1bbb0..ae867ed 100644 --- a/font.c +++ b/font.c @@ -43,37 +43,14 @@ setfont(void) } int -textinit(char **path, int npath) +textinit(void) { - GError *err; - int i; - textclear(); - if(path == nil || npath < 1 || npath > Maxfonts){ - fprint(2, "strans: popup: need 1-%d font files\n", Maxfonts); - return 0; - } fontmap = pango_cairo_font_map_new(); if(fontmap == nil){ fprint(2, "strans: popup: can't initialize PangoCairo\n"); return 0; } - for(i = 0; i < npath; i++){ - if(path[i] == nil){ - fprint(2, "strans: popup: invalid font file\n"); - textclear(); - return 0; - } - err = nil; - if(!pango_font_map_add_font_file(fontmap, path[i], &err)){ - fprint(2, "strans: popup: can't register font: %s: %s\n", - path[i], err == nil ? "unknown error" : err->message); - if(err != nil) - g_error_free(err); - textclear(); - return 0; - } - } pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), 96); context = pango_font_map_create_context(fontmap); if(context != nil) diff --git a/main.c b/main.c index 87e3cd7..0de1751 100644 --- a/main.c +++ b/main.c @@ -5,13 +5,11 @@ Channel *drawc; Channel *keyc; Channel *dictreqc; Channel *dictresc; -char **fontfiles; -int nfontfiles; void usage(void) { - fprint(2, "usage: strans mapdir fontfile [fontfile ...]\n"); + fprint(2, "usage: strans mapdir\n"); threadexitsall("usage"); } @@ -51,11 +49,9 @@ erealloc(void *p, ulong n) void threadmain(int argc, char **argv) { - if(argc < 3 || argc > Maxfonts + 2) + if(argc != 2) usage(); - fontfiles = argv + 2; - nfontfiles = argc - 2; drawc = chancreate(sizeof(Drawcmd), 4); keyc = chancreate(sizeof(Keyreq), 0); dictreqc = chancreate(sizeof(Dictreq), 4); diff --git a/run.sh b/run.sh index 8b3f7d7..cd3a7eb 100755 --- a/run.sh +++ b/run.sh @@ -2,22 +2,9 @@ cd "$(dirname "$0")" || exit 1 -if test "$#" -eq 0; then - set -- - for font in \ - /usr/share/fonts/noto/NotoColorEmoji.ttf \ - /usr/share/fonts/TTF/DejaVuSans.ttf \ - /usr/share/fonts/TTF/Jigmo.ttf \ - /usr/share/fonts/TTF/Jigmo2.ttf \ - /usr/share/fonts/noto/NotoSansCJK-Regular.ttc - do - test "$#" -ge 4 && break - test -f "$font" && set -- "$@" "$font" - done - if test "$#" -eq 0; then - echo "run.sh: no default font found; pass a font file" >&2 - exit 1 - fi +if test "$#" -ne 0; then + echo "usage: run.sh" >&2 + exit 1 fi if ! test -x ./strans; then @@ -40,7 +27,7 @@ sleep 0.1 pkill -KILL -u "$uid" -x strans-xim 2>/dev/null || : pkill -KILL -u "$uid" -x strans 2>/dev/null || : -./strans map "$@" home, sizeof t->home, "%s/home", t->root) >= (int)sizeof t->home || snprintf(t->socket, sizeof t->socket, "%s/strans.sock", t->runtime) - >= (int)sizeof t->socket || - snprintf(t->missing, sizeof t->missing, "%s/missing-font.ttf", t->root) - >= (int)sizeof t->missing) + >= (int)sizeof t->socket) return fail("temporary path is too long"); if(!makedir(t->runtime) || !makedir(t->config) || !makedir(t->ibus) || !makedir(t->bus) || !makedir(t->home)) @@ -224,7 +221,7 @@ startchild(Test *t, char *program, char *mapdir, pid_t *child, int *errfd) strerror(errno)); _exit(126); } - execl(program, program, mapdir, t->missing, (char*)0); + execl(program, program, mapdir, (char*)0); dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno)); _exit(127); } diff --git a/tests/daemon_failure_test.c b/tests/daemon_failure_test.c index f4e02f6..7df7a33 100644 --- a/tests/daemon_failure_test.c +++ b/tests/daemon_failure_test.c @@ -40,7 +40,6 @@ struct Test char home[320]; char socket[384]; char badmap[320]; - char missingfont[384]; char expected[768]; char err[4096]; size_t nerr; @@ -156,8 +155,6 @@ setup(Test *t) >= (int)sizeof t->socket || snprintf(t->badmap, sizeof t->badmap, "%s/missing-map", t->root) >= (int)sizeof t->badmap || - snprintf(t->missingfont, sizeof t->missingfont, - "%s/missing-font.ttf", t->root) >= (int)sizeof t->missingfont || snprintf(t->expected, sizeof t->expected, "strans: can't open: %s/hira.map\n", t->badmap) >= (int)sizeof t->expected) @@ -213,7 +210,7 @@ startchild(Test *t, char *program) strerror(errno)); _exit(126); } - execl(program, program, t->badmap, t->missingfont, (char*)0); + execl(program, program, t->badmap, (char*)0); dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno)); _exit(127); } diff --git a/tests/daemon_restart_test.c b/tests/daemon_restart_test.c index a4a33f3..3238e8a 100644 --- a/tests/daemon_restart_test.c +++ b/tests/daemon_restart_test.c @@ -67,7 +67,6 @@ struct Test char bus[448]; char home[320]; char socket[384]; - char missing[384]; char addrfile[512]; char addrbase[256]; char firstaddress[512]; @@ -221,9 +220,7 @@ setup(Test *t) snprintf(t->home, sizeof t->home, "%s/home", t->root) >= (int)sizeof t->home || snprintf(t->socket, sizeof t->socket, "%s/strans.sock", t->runtime) - >= (int)sizeof t->socket || - snprintf(t->missing, sizeof t->missing, "%s/missing-font.ttf", t->root) - >= (int)sizeof t->missing) + >= (int)sizeof t->socket) return fail("temporary path is too long"); if(!makedir(t->runtime) || !makedir(t->config) || !makedir(t->ibus) || !makedir(t->bus) || !makedir(t->home)) @@ -292,7 +289,7 @@ startchild(Test *t, char *program, char *mapdir, pid_t *child, int *errfd) strerror(errno)); _exit(126); } - execl(program, program, mapdir, t->missing, (char*)0); + execl(program, program, mapdir, (char*)0); dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno)); _exit(127); } diff --git a/tests/font_test.c b/tests/font_test.c index 06676ae..653e5b0 100644 --- a/tests/font_test.c +++ b/tests/font_test.c @@ -10,15 +10,6 @@ enum }; static u32int guardcolor = 0x5a5a5a5a; -static char *testfonts[] = { - "/usr/share/fonts/noto/NotoColorEmoji.ttf", - "/usr/share/fonts/TTF/DejaVuSans.ttf", - "/usr/share/fonts/TTF/Jigmo.ttf", - "/usr/share/fonts/TTF/Jigmo2.ttf", -}; -static char *missingfonts[] = { - "/strans-test-no-such-font", -}; static void fillpixels(u32int *p, int n, u32int color) @@ -195,14 +186,7 @@ font_render(struct ct *t) buf = mem + Guard; fillpixels(buf, Testn, Colbg); a = mkstr("A"); - CT_CHECK(t, !textinit(missingfonts, nelem(missingfonts))); - CT_EQ_INT(t, 0, textwidth(&a)); - textdraw(buf, Testw, Testh, 0, 0, &a); - for(i = 0; i < Testn; i++) - CT_EQ_UINT(t, Colbg, buf[i]); - checkguards(t, mem); - - if(!CT_CHECK(t, textinit(testfonts, nelem(testfonts)))){ + if(!CT_CHECK(t, textinit())){ free(mem); return; } diff --git a/tests/ibus_live_test.c b/tests/ibus_live_test.c index 016c438..f3c6f29 100644 --- a/tests/ibus_live_test.c +++ b/tests/ibus_live_test.c @@ -228,7 +228,6 @@ waitaddress(Daemon *d, int notifyfd) static int startdaemon(Daemon *d, char *program, char *mapdir) { - char missing[384]; int fd, notifyfd, watch, errpipe[2]; long maxfd; pid_t pid; @@ -250,9 +249,7 @@ startdaemon(Daemon *d, char *program, char *mapdir) snprintf(d->home, sizeof d->home, "%s/home", d->root) >= (int)sizeof d->home || snprintf(d->socket, sizeof d->socket, "%s/strans.sock", d->runtime) - >= (int)sizeof d->socket || - snprintf(missing, sizeof missing, "%s/missing-font.ttf", d->root) - >= (int)sizeof missing) + >= (int)sizeof d->socket) return fail("temporary path is too long"); if(!makedir(d->runtime) || !makedir(d->config) || !makedir(d->ibus) || !makedir(d->bus) || !makedir(d->home)) @@ -299,7 +296,7 @@ startdaemon(Daemon *d, char *program, char *mapdir) strerror(errno)); _exit(126); } - execl(program, program, mapdir, missing, (char*)0); + execl(program, program, mapdir, (char*)0); dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno)); _exit(127); } diff --git a/tests/ipc_live_test.c b/tests/ipc_live_test.c index 662819a..e24adab 100644 --- a/tests/ipc_live_test.c +++ b/tests/ipc_live_test.c @@ -174,7 +174,6 @@ waitsocket(Daemon *d, int notifyfd) static int startdaemon(Daemon *d, char *program, char *mapdir) { - char missing[384]; int fd, notifyfd, watch, errpipe[2]; long maxfd; pid_t pid; @@ -196,9 +195,7 @@ startdaemon(Daemon *d, char *program, char *mapdir) snprintf(d->home, sizeof d->home, "%s/home", d->root) >= (int)sizeof d->home || snprintf(d->socket, sizeof d->socket, "%s/strans.sock", d->runtime) - >= (int)sizeof d->socket || - snprintf(missing, sizeof missing, "%s/no-such-font.ttf", d->root) - >= (int)sizeof missing) + >= (int)sizeof d->socket) return fail("temporary path is too long"); if(!makedir(d->runtime) || !makedir(d->config) || !makedir(d->ibus) || !makedir(d->bus) || !makedir(d->home)) @@ -246,7 +243,7 @@ startdaemon(Daemon *d, char *program, char *mapdir) strerror(errno)); _exit(126); } - execl(program, program, mapdir, missing, (char*)0); + execl(program, program, mapdir, (char*)0); dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno)); _exit(127); } diff --git a/win.c b/win.c index f082568..0f8bbed 100644 --- a/win.c +++ b/win.c @@ -6,9 +6,6 @@ enum { Asciitofull = 0xFEE0, }; -extern char **fontfiles; -extern int nfontfiles; - static xcb_connection_t *conn; static xcb_screen_t *scr; static xcb_window_t win; @@ -141,7 +138,7 @@ wininit(void) mask = XCB_CW_BACK_PIXMAP; xcb_change_window_attributes(conn, win, mask, &pix); img = emalloc(Imgw * Imgh * sizeof(img[0])); - if(!textinit(fontfiles, nfontfiles)){ + if(!textinit()){ fprint(2, "strans: popup disabled: no usable fonts\n"); wincleanup(); return 0;