fix(fonts): turn stroke thickening off in gpui, not through AppleFontSmoothing (#1135)

* fix(fonts): turn stroke thickening off in gpui, not through AppleFontSmoothing

font_thicken: false pinned AppleFontSmoothing to 0 in the process's
argument domain. That never left the process, but AppKit reads the same
preference, so tty7's native menus and alerts lost their smoothing too,
most visibly dark text in light mode. The terminal's own dark text looked
unchanged, since gpui never thickens it in the first place.

The gpui fork now exposes set_glyph_dilation, which reaches its
rasterizer alone; apply_font_thicken calls that and writes no
preference. A test checks that turning thickening off leaves
AppleFontSmoothing alone (red on the old implementation).

Fixes #1119

* test(fonts): keep the font_thicken test out of config_reload_tests' doc comment
This commit is contained in:
l0ng-ai
2026-10-09 11:30:39 +08:00
committed by GitHub
parent e166f82ced
commit 1cefcc6a46
6 changed files with 82 additions and 66 deletions
Generated
+25 -25
View File
@@ -1623,7 +1623,7 @@ dependencies = [
[[package]]
name = "collections"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"gpui_util",
"indexmap",
@@ -2286,7 +2286,7 @@ dependencies = [
[[package]]
name = "derive_refineable"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"proc-macro2",
"quote",
@@ -3783,7 +3783,7 @@ dependencies = [
[[package]]
name = "gpui"
version = "0.2.2"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"accesskit",
"anyhow",
@@ -3974,7 +3974,7 @@ dependencies = [
[[package]]
name = "gpui_linux"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"accesskit",
"accesskit_unix",
@@ -4025,7 +4025,7 @@ dependencies = [
[[package]]
name = "gpui_macos"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"accesskit",
"accesskit_macos",
@@ -4072,7 +4072,7 @@ dependencies = [
[[package]]
name = "gpui_macros"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -4083,7 +4083,7 @@ dependencies = [
[[package]]
name = "gpui_platform"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"console_error_panic_hook",
"gpui",
@@ -4096,7 +4096,7 @@ dependencies = [
[[package]]
name = "gpui_shared_string"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"schemars",
"serde",
@@ -4106,7 +4106,7 @@ dependencies = [
[[package]]
name = "gpui_util"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"log",
@@ -4115,7 +4115,7 @@ dependencies = [
[[package]]
name = "gpui_web"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"console_error_panic_hook",
@@ -4139,7 +4139,7 @@ dependencies = [
[[package]]
name = "gpui_wgpu"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"bytemuck",
@@ -4168,7 +4168,7 @@ dependencies = [
[[package]]
name = "gpui_windows"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"accesskit",
"accesskit_windows",
@@ -4537,7 +4537,7 @@ dependencies = [
[[package]]
name = "http_client"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"async-compression",
@@ -4562,7 +4562,7 @@ dependencies = [
[[package]]
name = "http_client_tls"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"rustls",
"rustls-platform-verifier 0.5.3",
@@ -6054,7 +6054,7 @@ checksum = "7ebb8d8732c6a6df3d8f032a82911cfc747e00efb95cc46e8d0acd5b5b88570c"
[[package]]
name = "media"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"bindgen",
@@ -7585,7 +7585,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "perf"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"collections",
"serde",
@@ -8690,7 +8690,7 @@ dependencies = [
[[package]]
name = "refineable"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"derive_refineable",
]
@@ -8770,7 +8770,7 @@ dependencies = [
[[package]]
name = "reqwest_client"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"bytes",
@@ -9356,7 +9356,7 @@ dependencies = [
[[package]]
name = "scheduler"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"async-task",
"backtrace",
@@ -10296,7 +10296,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "sum_tree"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"heapless 0.9.3",
"log",
@@ -11944,7 +11944,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "util"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"async-fs",
@@ -11983,7 +11983,7 @@ dependencies = [
[[package]]
name = "util_macros"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"perf",
"quote",
@@ -13963,7 +13963,7 @@ dependencies = [
[[package]]
name = "zlog"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"anyhow",
"chrono",
@@ -14008,7 +14008,7 @@ dependencies = [
[[package]]
name = "ztracing"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
dependencies = [
"tracing",
"tracing-subscriber",
@@ -14019,7 +14019,7 @@ dependencies = [
[[package]]
name = "ztracing_macro"
version = "0.1.0"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#3d46ee70fb1c574d30671d55006c6de359c8bf28"
source = "git+https://github.com/l0ng-ai/zed?branch=tty7#fb4472347db56abd807008a7a9c5557474679363"
[[package]]
name = "zune-core"
+10 -3
View File
@@ -242,10 +242,10 @@ objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSResponder", "
# `set_dock_icon_for_bare_binary` in main.rs.
# NSUserNotification is the click-to-reveal notification path — see
# `terminal::remote::macos_notify` for why it is driven directly.
# NSUserDefaults (with NSDictionary / NSValue for the domain it takes) pins
# `AppleFontSmoothing` for this process when `font_thicken` is off — see
# NSUserDefaults (with NSDictionary for the domain it returns) is how a test
# checks that `font_thicken: false` leaves `AppleFontSmoothing` alone — see
# `apply_font_thicken` in main.rs.
objc2-foundation = { version = "0.3", features = ["NSData", "NSDictionary", "NSString", "NSUserDefaults", "NSUserNotification", "NSValue"] }
objc2-foundation = { version = "0.3", features = ["NSData", "NSDictionary", "NSString", "NSUserDefaults", "NSUserNotification"] }
# Dictionary-based Chinese word segmentation for double-click selection
# (`terminal::smart_select`), as a *fallback* where the OS has no tokenizer of
@@ -451,6 +451,13 @@ codegen-units = 1
# the text showed through — the Changes panel's flush-right directory drew
# through the hover action buttons.
#
# 8. `gpui_platform::set_glyph_dilation` turns off the stroke thickening macOS
# font smoothing applies to light glyphs, for gpui's rasterizer alone. The
# only other lever is `AppleFontSmoothing`, which AppKit reads too, so
# `font_thicken: false` used to thin the native menus and alerts while the
# terminal's dark text — never dilated to begin with — looked the same
# (issue #1119).
#
# Patching by source rather than editing the `gpui`/`gpui_platform` pins above is
# deliberate: `gpui-component` declares its own `gpui` from the upstream URL, and
# a plain pin swap would put two incompatible copies of gpui in the tree. `[patch]`
+5 -4
View File
@@ -139,10 +139,11 @@ pub struct Config {
/// more the lighter the text, which is why light-on-dark looks bolder.
/// On by default, because it is what every macOS app draws with.
///
/// Off pins `AppleFontSmoothing` to `0` for this process alone, so glyphs
/// are drawn at the face's own weight. gpui reads that preference once, the
/// first time it rasterizes text, so a change applies at the next launch.
/// Ignored elsewhere, where there is no such dilation to turn off.
/// Off tells gpui's rasterizer not to dilate, so tty7's glyphs are drawn
/// at the face's own weight. `AppleFontSmoothing` is left alone, so menus
/// and other natively drawn text keep the system's look (#1119). Applied
/// at launch, so a change takes hold at the next one. Ignored elsewhere,
/// where there is no such dilation to turn off.
#[serde(default = "default_true")]
pub font_thicken: bool,
pub font_size: f32,
+4 -3
View File
@@ -90,9 +90,10 @@ turns it off, so glyphs draw at the face's own weight whatever their colour:
```
<Note>
The change applies the next time tty7 starts: the preference is read once,
when text is first drawn. It covers tty7 alone — no other app, and not the
system-wide setting.
The change applies the next time tty7 starts. It covers the terminal and
tty7's own interface text alone: menus and other native macOS controls, other
apps, and the system-wide setting all keep their look. Dark text is barely
thickened to begin with, so on a light theme the difference is small.
</Note>
Leaving it on changes nothing, so an existing
+36 -29
View File
@@ -524,39 +524,21 @@ fn set_dock_icon_for_bare_binary() {
}
}
/// Turns CoreGraphics' stroke thickening off for this process when
/// `font_thicken` is off; with it on there is nothing to do, and whatever the
/// system (or a hand-written `defaults write`) says stands.
/// Turns gpui's stroke thickening off for tty7's text when `font_thicken` is
/// off; with it on, whatever the system (or a hand-written `defaults write`)
/// says stands.
///
/// gpui decides whether to dilate a glyph from `AppleFontSmoothing`, read with
/// `CFPreferencesCopyAppValue` the first time it rasterizes text and cached for
/// the life of the process. So this has to land before the application exists,
/// and a change waits for the next launch.
/// The switch lives in gpui's rasterizer and nowhere else. Pinning
/// `AppleFontSmoothing` to `0` for the process (which is how this used to be
/// done) reached AppKit as well: the menus, alerts and every other natively
/// drawn string lost their smoothing, while the terminal's dark-on-light text,
/// which gpui never thickens, looked no different (#1119).
///
/// The value goes into the argument domain — the volatile one that
/// `-AppleFontSmoothing 0` on the command line would fill. It outranks both this
/// app's persisted defaults and the global domain, and it lives only in this
/// process's memory: nothing reaches disk, so no other app sees it and a later
/// launch with the key back on does not inherit it.
/// Applied once at launch, before any text is drawn; a change made in Settings
/// waits for the next one.
#[cfg(target_os = "macos")]
fn apply_font_thicken(thicken: bool) {
use objc2_foundation::{
NSArgumentDomain, NSMutableCopying, NSNumber, NSUserDefaults, ns_string,
};
if thicken {
return;
}
let defaults = NSUserDefaults::standardUserDefaults();
// SAFETY: a Foundation constant, initialized before `main` runs.
let domain = unsafe { NSArgumentDomain };
// Merged into, not replaced: the domain already holds any `-Key value`
// pairs the process was launched with.
let arguments = defaults.volatileDomainForName(domain).mutableCopy();
arguments.insert(ns_string!("AppleFontSmoothing"), &*NSNumber::new_i32(0));
// SAFETY: keys are `NSString` and values property-list objects, which is
// the shape a defaults domain requires.
unsafe { defaults.setVolatileDomain_forName(&arguments, domain) };
gpui_platform::set_glyph_dilation(thicken);
}
/// Delivers Finder document opens and LaunchServices URL opens after gpui has
@@ -841,6 +823,31 @@ fn main() {
});
}
#[cfg(all(test, target_os = "macos"))]
mod font_thicken_tests {
use super::apply_font_thicken;
use objc2_foundation::{NSArgumentDomain, NSUserDefaults, ns_string};
/// #1119: turning thickening off must not reach AppKit. `AppleFontSmoothing`
/// in any domain this process reads restyles its native menus and alerts,
/// so the switch may only ever talk to gpui.
#[test]
fn turning_thickening_off_leaves_the_smoothing_preference_alone() {
let defaults = NSUserDefaults::standardUserDefaults();
let key = ns_string!("AppleFontSmoothing");
let before = defaults.objectForKey(key);
apply_font_thicken(false);
// SAFETY: a Foundation constant, initialized before `main` runs.
let arguments = defaults.volatileDomainForName(unsafe { NSArgumentDomain });
assert!(arguments.objectForKey(key).is_none());
assert_eq!(defaults.objectForKey(key).is_some(), before.is_some());
apply_font_thicken(true);
}
}
/// The watcher tick, from a reloaded file to the keys the app dispatches on.
///
/// The one thing #548 is for — hand-editing config.json and having the new
+2 -2
View File
@@ -3908,8 +3908,8 @@ impl Tty7App {
self.update_config(cx, |cfg| cfg.show_tray_icon = on);
}
/// Saved only: gpui reads the preference this drives once per process, so
/// it takes hold at the next launch (see `apply_font_thicken` in main.rs).
/// Saved only: it is handed to gpui once, at launch, so it takes hold at
/// the next one (see `apply_font_thicken` in main.rs).
pub(crate) fn set_font_thicken(&mut self, on: bool, cx: &mut Context<Self>) {
self.update_config(cx, |cfg| cfg.font_thicken = on);
}