diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-29 09:55:20 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-29 09:55:20 +0100 |
| commit | 28beb8a9600b6e74cab454401cc94c664d90bfe5 (patch) | |
| tree | c91a0731af8f3204e2c2b07a96a8bbfeaae68e35 /desktop/modules/fonts/test_fonts.js | |
| parent | 38cda58f0969fbdda2c33a38356ab43b2869b955 (diff) | |
| download | quickshell-archive/companion.tar.gz quickshell-archive/companion.zip | |
fonts: one font size for the desktop, with per-system overridesarchive/companion
A settings page under Appearance > Fonts holds one pixel size for the
whole desktop and an override wherever a system needs its own, saved as
~/.config/keystone/fonts.json, all in px. At scale 1 the logical DPI is
96, so a point is 4/3 px, and each system is written in its own unit:
Theme.fontSize reads the json itself, so every shell follows live;
qt5ct/qt6ct and the GTK settings files are edited in place, size only,
plus gsettings; kitty, rofi and hyprlock read generated files under
~/.config/keystone that their configs include over designed fallbacks;
the groupbar is a keystone.lua line.
rofi and hyprlock are sections of designed sizes that scale together
from their body text, the smallest entry, each keeping its ratio unless
given its own size. The design is read from the fallbacks themselves,
var(kf-..., "Family N") in the rofi files and $kf_... = N in
hyprlock.conf, so a new entry appears on the page with no list to keep.
With no fonts.json the page starts from what the files say, base 16 and
an override per system at its current size, so the first save changes
nothing; seeded to 0.01px, since 0.1 scaled rofi's 72pt glyph to 72.2.
Each stepper shows px then pt in fixed columns, the system's own unit
highlighted.
Check: node desktop/modules/fonts/test_fonts.js
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/fonts/test_fonts.js')
| -rw-r--r-- | desktop/modules/fonts/test_fonts.js | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/desktop/modules/fonts/test_fonts.js b/desktop/modules/fonts/test_fonts.js new file mode 100644 index 0000000..947bd42 --- /dev/null +++ b/desktop/modules/fonts/test_fonts.js @@ -0,0 +1,67 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Run: node desktop/modules/fonts/test_fonts.js +// Fonts.js is a QML library, so its .pragma line is stripped before node +// evaluates it. + +const fs = require("fs"); +const assert = require("assert"); + +const src = fs.readFileSync(__dirname + "/Fonts.js", "utf8").replace(/^\.pragma library$/m, ""); +const F = new Function(src + "\nreturn { size, entryPx, withOverride, parseModel, seed, qtPt, gtkPt, kittyPt, " + + "rofiEntries, hyprlockEntries, setQt, setGtk, gtkFamily, kittyFile, rofiFile, hyprlockFile };")(); + +const qt = '[Fonts]\nfixed="Inconsolata Nerd Font Mono,14,-1,5,400"\ngeneral="Noto Sans,14,-1,5,400,Regular"\n'; +const gtk3 = "[Settings]\ngtk-font-name=Noto Sans, 10\ngtk-theme-name=udt\n"; +const gtk2 = 'gtk-font-name="Noto Sans, 10"\n'; +assert.strictEqual(F.qtPt(qt), 14); +assert.strictEqual(F.gtkPt(gtk3), 10); +assert.strictEqual(F.gtkPt(gtk2), 10); +assert.strictEqual(F.kittyPt("font_size 15.0\n"), 15); +assert.strictEqual(F.gtkFamily(gtk3), "Noto Sans"); + +assert.strictEqual(F.setQt(qt, 13.5), '[Fonts]\nfixed="Inconsolata Nerd Font Mono,13.5,-1,5,400"\ngeneral="Noto Sans,13.5,-1,5,400,Regular"\n'); +assert.strictEqual(F.setQt("[Appearance]\n", 12), null); +assert.strictEqual(F.setGtk(gtk3, 12), "[Settings]\ngtk-font-name=Noto Sans, 12\ngtk-theme-name=udt\n"); +assert.strictEqual(F.setGtk(gtk2, 12), 'gtk-font-name="Noto Sans, 12"\n'); + +// The first save changes nothing: what differs from 16px is an override. +const m = F.seed({ quickshell: 16, qt: 14 * 4 / 3, gtk: 10 * 4 / 3, kitty: 20 }); +assert.deepStrictEqual(m, { base: 16, override: { qt: 18.67, gtk: 13.33, kitty: 20 } }); +assert.strictEqual(F.size(m, "quickshell"), 16); +assert.strictEqual(F.size(F.withOverride(m, "qt", null), "qt"), 16); +assert.strictEqual(F.parseModel("nope"), null); +assert.deepStrictEqual(F.parseModel(JSON.stringify(m)), m); + +const rasi = ['* { font: var(kf-common-font, "Noto Sans 11"); }', + 'entry { font: var(kf-launcher-entry, "Noto Sans Bold 15"); }', + 'x { font: var(kf-common-font, "Noto Sans 11"); }']; +const re = F.rofiEntries(rasi); +assert.deepStrictEqual(re.map(e => [e.name, e.family, e.pt]), + [["kf-common-font", "Noto Sans", 11], ["kf-launcher-entry", "Noto Sans Bold", 15]]); +// rofi at 22px: the 11pt body becomes 16.5pt, the 15pt entry keeps 15/11. +const r = { base: 16, override: { rofi: 22 } }; +assert.strictEqual(F.rofiFile(r, re).split("\n").slice(2, 4).join("|"), + ' kf-common-font: "Noto Sans 16.5";| kf-launcher-entry: "Noto Sans Bold 22.5";'); +const r2 = F.withOverride(r, "rofi:kf-launcher-entry", 40); +assert.ok(F.rofiFile(r2, re).includes('kf-launcher-entry: "Noto Sans Bold 30"')); + +const hl = F.hyprlockEntries("$font = Noto Sans\n$kf_clock = 120\n$kf_body = 16\n"); +assert.deepStrictEqual(hl, [{ name: "kf_clock", pt: 120 }, { name: "kf_body", pt: 16 }]); +// Following the base 16px: body 12pt, clock 120 * 12 / 16 = 90. +assert.strictEqual(F.hyprlockFile({ base: 16, override: {} }, hl).split("\n").slice(1).join("|"), "$kf_clock = 90|$kf_body = 12|"); +// A seeded rofi keeps its designed sizes exactly. +const sr = F.seed({ rofi: 11 * 4 / 3 }); +assert.ok(F.rofiFile(sr, [{ name: "kf-a", family: "M", pt: 11 }, { name: "kf-b", family: "M", pt: 72 }]).includes('kf-b: "M 72"')); +assert.strictEqual(F.kittyFile(m).split("\n")[1], "font_size 15"); + +console.log("ok"); |
