Skip to content

feat(theme): add a switch to use the system's UI font - #1362

Merged
KnifeLemon merged 5 commits into
mainfrom
feat/os-default-fonts-1065
Nov 10, 2026
Merged

KnifeLemon merged 5 commits into
mainfrom
feat/os-default-fonts-1065

Conversation

@KnifeLemon

@KnifeLemon KnifeLemon commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner

What users notice

Settings → Theme has a new switch, Use the system font. When it's on, Filee draws its UI in the font the system uses, like other apps: Segoe UI Variable on Windows 11 (Segoe UI on Windows 10), San Francisco on macOS, fontconfig's default sans-serif on Linux. The switch applies right away. Filee's built-in Noto fonts stay behind the system fonts and still draw any script those lack. Han still follows the interface language (#1121): on Windows, a Japanese UI draws it in Yu Gothic UI, a Korean or English one in Malgun Gothic, Simplified Chinese in Microsoft YaHei and Traditional Chinese in Microsoft JhengHei. The switch is off by default, so nothing changes for anyone who doesn't turn it on.

What changed

  • src/Filee.Core/Settings/AppSettings.cs: adds ThemeSettings.UseSystemFont, false by default. Settings saved before it existed read it as false, so no schema step is needed.
  • src/Filee.App/Services/SoftPalette.cs: FontFamilies(language, systemFont). With the switch on, the platform's UI fonts go first, followed by the embedded chain, which stays unchanged. Only fonts without Han go ahead of the CJK fonts. On Linux, a fontconfig default that has Han is left out, so a CJK default can't give every language its Han shapes.
  • src/Filee.App/SystemUiFontCollection.cs (new, registered in Program.cs and the test app): the system fonts under fonts:System#…, which match a letter only in the family asked for. This is needed because Avalonia's own system collection doesn't look in the requested family. It hands the letter to the platform's fallback, and on Windows that returns Yu Gothic UI for Han whatever family or language is asked. I checked it: "Segoe UI, Malgun Gothic" and even "Malgun Gothic" alone matched 直 in Yu Gothic UI. Without the wrapper, every language would draw Han in Japanese shapes. FileeFontCollection does the same for the embedded fonts ([Bug]: zh-CN UI renders some Han characters with Japanese/Korean glyph forms (bundled Noto Sans SC not used) #1095).
  • ThemeService / AnnotationFonts: pass the switch through. Annotate's labels follow the same chain, because the text box they're typed in uses the UI font.
  • ThemePage.axaml + ThemePageViewModel: the switch and its hint, in a card before "Reduce animations".
  • i18n: theme.system_font and theme.system_font_hint in all 22 languages.
  • docs/ARCHITECTURE.md: a short note on the font chain and why fonts:System exists.

Tests

  • SystemFontTests (App): for every language, the embedded chain is the unchanged tail of the system chain. The first Han font is still the UI language's, for ja, ko, zh-CN, zh-TW, en and ar. On Windows, real lookups for A, م, न, ก and 直 at regular and semibold weight expect the first system font in the chain whose face has the letter, or the embedded font when none does, never the platform fallback. Each machine is asked for its own fonts: on the GitHub Windows Server images Segoe UI has no Arabic, so م correctly lands in Noto Sans Arabic there. Han must also land in a font of the UI language's region. The collection only matches the family it's asked for. The page switch saves and swaps AppFontFamily live.
  • SystemFontSettingsTests (Core): off for new settings and for settings saved before this change, and kept once switched on.
  • Run on Windows 11: SystemFontTests, LocalizationTests, LocalizationResourceTests, FileeFontCollectionTests, ThemePageTests, MaterialYouThemeTests: all pass. In the full Filee.App.Tests suite, 2266 passed, 33 were skipped and 2 failed, neither because of this change. RenderTests.Engines_page_shows_versions_descriptions_and_download_speed fails on this PC because it has its own Tesseract in Program Files, and an installed copy shows no version by design. DonutHighlightTests.A_lost_animation_frame_does_not_keep_the_slice_dark is a timing check that failed while the machine was busy; it passes when run on its own. dotnet format --verify-no-changes is clean on all four touched projects, and Filee.Setup still builds (it links SoftPalette).

Not covered

  • macOS untested. The chain asks for .AppleSystemUIFont, then SF Pro Text and SF Pro. Whether Skia on macOS resolves the hidden system name needs a real Mac. If it doesn't, the chain falls through to the embedded fonts as before.
  • Linux untested. fontconfig's default stands in for the desktop's UI font. GNOME and KDE can set their own UI font outside fontconfig's sans-serif, and that one isn't read.
  • Found while testing, not changed here: the installer (SoftPalette.SystemFontFamilies) uses plain system names. By the lookup above, it probably draws Han in Yu Gothic UI in every language.

Closes #1065

🤖 Generated with Claude Code

Theme -> "Use the system font" puts the system's own UI fonts ahead of the
embedded Noto chain: Segoe UI Variable / Segoe UI with Nirmala UI, Leelawadee
UI and the UI language's CJK font on Windows, San Francisco and its script
fonts on macOS, fontconfig's default sans-serif on Linux. The embedded chain
stays whole behind them, so it still draws any script the system fonts lack.

The system fonts are named through a new fonts:System collection that matches
a letter only in the family asked for. Avalonia's own system collection hands
any letter to the platform fallback, which on Windows answers Yu Gothic UI for
Han whatever the family, so a plain chain drew every language's Han in
Japanese shapes. With the wrapper, Han keeps the UI language's font (#1121).

Annotate's labels follow the same chain, as the text box they are typed in
does. The setting is off by default and needs no schema step.

Refs #1065

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the feature New features label Nov 10, 2026
KnifeLemon and others added 4 commits November 11, 2026 02:40
GitHub's Windows Server images have a Segoe UI without Arabic, so the
system-font chain rightly drew م in the embedded Noto Sans Arabic there and
the test, which named Segoe UI, failed. The test now asks each system font in
the chain, face by face at the weight drawn, whether it has the letter, and
expects the first that does, else the embedded font. Han must still land in a
font of the UI language's region.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Avalonia's font manager (12.1.4, FontManager.TryMatchCharacter) passes over a
match whose family is named like its default font unless that family ends
the chain, taking it for a collection's "nothing found" answer. On Windows
the default is Segoe UI, so a letter Segoe UI Variable lacks, Arabic above
all, skipped Segoe UI for the embedded Noto Sans Arabic. That is what CI's
Windows jobs saw: the glyph check found م in Segoe UI, the chain gave Noto.

SystemUiFontCollection only answers for the family asked for, so its answer
for the default font is a real one: it now returns that family under an
alias only it reads back. A test builds a chain with the default font in the
middle and checks it is taken.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KnifeLemon
KnifeLemon merged commit 28b221c into main Nov 10, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Use OS default fonts

1 participant