Files
omarchycn/bin/omarchy-display-text-size
T
David Heinemeier HanssonandClaude Fable 5 fa95901b6f Quantize GTK text scaling to whole point sizes to stop menu clipping
Raw size/12 ratios hand GTK a fractional point size (11px -> 10.08pt),
which clips ascenders in GTK4 menus on scale-1 monitors. Round the
scaled interface font to a whole point and derive the factor from that,
keeping 12px anchored at exactly 1.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 22:05:00 -05:00

227 lines
7.5 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# omarchy:summary=Scale text everywhere — omarchy shell, GTK apps, and terminals
# omarchy:args=[size|reset]
# omarchy:examples=omarchy display text size | omarchy display text size 16 | omarchy display text size reset
# One knob for apparent text size across the desktop. It drives three settings
# in lockstep, all anchored to the shell default of 12px:
# • the omarchy shell's font base-size (~/.config/omarchy/shell.toml [font])
# • GNOME/GTK's text-scaling-factor (12px -> 1.0, quantized so the GTK
# interface font lands on a whole point size, so 16 -> 15pt/11pt = 1.3636)
# • the terminal font point size (12px -> 9pt, so terminal_pt = px * 9/12)
# The shell override layers on top of the active theme (so the size survives
# theme switches) and the shell watches the file, so shell text re-flows live.
# Accepts an integer from 9 to 20 (px).
MIN=9
MAX=20
GKEY_SCHEMA="org.gnome.desktop.interface"
GKEY_NAME="text-scaling-factor"
# Anchors: 12px shell base == factor 1.0 == 9pt terminal font.
TERM_DEFAULT_PT=9
SHELL_DEFAULT_PX=12
shell_config="$HOME/.config/omarchy/shell.toml"
usage() {
echo "Usage: omarchy-display-text-size [size|reset]"
echo " (no args) print the current text size, GTK factor, and terminal size"
echo " <size> set text size in px ($MIN$MAX); shell + GTK + terminals together"
echo " reset return all three to their defaults (12px / 1.0 / 9pt)"
}
# ---- shell base-size: the rem root every shell type size derives from ----
# Print the base-size currently set under [font], or nothing if unset.
current_base_size() {
[[ -f $shell_config ]] || return 0
awk '
/^[[:space:]]*\[/ { in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/); next }
in_font && /^[[:space:]]*base-size[[:space:]]*=/ {
v = $0
sub(/^[^=]*=[[:space:]]*/, "", v)
sub(/[[:space:]]*(#.*)?$/, "", v)
print v
exit
}
' "$shell_config"
}
# Upsert base-size under [font]: replace it in place if present, insert it into
# an existing [font] section, or append a fresh [font] section otherwise. Other
# sections and keys in the user override are left untouched.
set_base_size() {
local size="$1"
mkdir -p "$(dirname "$shell_config")"
if [[ ! -f $shell_config ]]; then
printf '[font]\nbase-size = %s\n' "$size" >"$shell_config"
return
fi
local tmp
tmp="$(mktemp)"
awk -v val="$size" '
function emit_base() { print "base-size = " val; done = 1 }
/^[[:space:]]*\[/ {
if (in_font && !done) emit_base()
in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/)
print
next
}
in_font && /^[[:space:]]*base-size[[:space:]]*=/ {
if (!done) emit_base()
next
}
{ print }
END {
if (in_font && !done) emit_base()
if (!done) {
if (NR > 0) print ""
print "[font]"
emit_base()
}
}
' "$shell_config" >"$tmp"
mv "$tmp" "$shell_config"
}
# Drop the base-size line, returning the shell to the theme/default size.
reset_base_size() {
[[ -f $shell_config ]] || return 0
local tmp
tmp="$(mktemp)"
awk '
/^[[:space:]]*\[/ { in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/) }
in_font && /^[[:space:]]*base-size[[:space:]]*=/ { next }
{ print }
' "$shell_config" >"$tmp"
mv "$tmp" "$shell_config"
}
# ---- GTK text-scaling-factor ----
# Point size of the GTK interface font (font-name), used to quantize the
# scaling factor. Falls back to the GNOME default when unreadable.
gtk_font_pt() {
local name pt
name="$(gsettings get "$GKEY_SCHEMA" font-name 2>/dev/null)"
pt="${name%\'}"
pt="${pt##* }"
if [[ $pt =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
echo "$pt"
else
echo 11
fi
}
set_factor() {
gsettings set "$GKEY_SCHEMA" "$GKEY_NAME" "$1" 2>/dev/null || true
}
# ---- terminal font point size ----
# px base-size -> terminal point size, rounded to the nearest integer.
term_pt_for() {
awk -v s="$1" -v p="$TERM_DEFAULT_PT" -v b="$SHELL_DEFAULT_PX" \
'BEGIN { printf "%d", int(s * p / b + 0.5) }'
}
# Set the font point size in every terminal config that exists. Family is left
# untouched — that is omarchy-font-set's job. Live-reload signals mirror
# omarchy-font-set; foot has no reload signal, so running instances are nudged.
set_terminal_size() {
local pt="$1"
if [[ -f ~/.config/alacritty/alacritty.toml ]]; then
sed -i -E "s/^size[[:space:]]*=.*/size = $pt/" ~/.config/alacritty/alacritty.toml
fi
if [[ -f ~/.config/kitty/kitty.conf ]]; then
sed -i -E "s/^font_size[[:space:]]+.*/font_size $pt.0/" ~/.config/kitty/kitty.conf
pkill -USR1 kitty 2>/dev/null || true
fi
if [[ -f ~/.config/ghostty/config ]]; then
sed -i -E "s/^font-size = .*/font-size = $pt/" ~/.config/ghostty/config
pkill -SIGUSR2 ghostty 2>/dev/null || true
fi
if [[ -f ~/.config/foot/foot.ini ]]; then
sed -i -E "s/(:size=)[0-9.]+/\1$pt/" ~/.config/foot/foot.ini
# Foot has no config-reload signal, so a running instance keeps its startup
# size until relaunched (new windows pick up the change). Nudge the user —
# but reuse the same notification id (freedesktop replaces_id) so dragging
# through several sizes refreshes one toast instead of stacking a pile.
if pgrep -x foot >/dev/null 2>&1; then
local id_file="${XDG_RUNTIME_DIR:-/tmp}/omarchy-display-text-size.foot-notif-id"
local prev_id=""
[[ -f $id_file ]] && read -r prev_id <"$id_file" 2>/dev/null
local replace=()
[[ $prev_id =~ ^[0-9]+$ ]] && replace=(-r "$prev_id")
local new_id
new_id="$(omarchy-notification-send \
"Restart Foot to apply the new terminal font size" \
"${replace[@]}" -p 2>/dev/null)" || true
[[ $new_id =~ ^[0-9]+$ ]] && printf '%s\n' "$new_id" >"$id_file"
fi
fi
}
# Report the current terminal point size from whichever config we find first.
term_current_pt() {
if [[ -f ~/.config/ghostty/config ]]; then
grep -oP '^font-size = \K[0-9.]+' ~/.config/ghostty/config | head -1
elif [[ -f ~/.config/alacritty/alacritty.toml ]]; then
grep -oP '^size[[:space:]]*=[[:space:]]*\K[0-9.]+' ~/.config/alacritty/alacritty.toml | head -1
elif [[ -f ~/.config/kitty/kitty.conf ]]; then
grep -oP '^font_size[[:space:]]+\K[0-9.]+' ~/.config/kitty/kitty.conf | head -1
elif [[ -f ~/.config/foot/foot.ini ]]; then
grep -oP ':size=\K[0-9.]+' ~/.config/foot/foot.ini | head -1
fi
}
case "${1:-}" in
-h | --help)
usage
exit 0
;;
"")
cur="$(current_base_size)"
size="${cur:-12 (default)}"
factor="$(gsettings get "$GKEY_SCHEMA" "$GKEY_NAME" 2>/dev/null)"
term="$(term_current_pt)"
printf 'text size: %s px\ngtk text-scaling-factor: %s\nterminal font: %s pt\n' \
"$size" "$factor" "${term:-n/a}"
exit 0
;;
reset | default)
reset_base_size
gsettings reset "$GKEY_SCHEMA" "$GKEY_NAME" 2>/dev/null || true
set_terminal_size "$TERM_DEFAULT_PT"
exit 0
;;
esac
size="$1"
if [[ ! $size =~ ^[0-9]+$ ]] || ((size < MIN || size > MAX)); then
echo "Size must be an integer between $MIN and $MAX (px)." >&2
usage >&2
exit 1
fi
# Shell side: base-size in px (the omarchy shell's rem root).
set_base_size "$size"
# GTK side: multiplier anchored so 12px == 1.0, quantized so the interface
# font renders at a whole point size. Raw ratios yield fractional point sizes,
# which GTK4 menus clip at the ascenders on scale-1 monitors.
factor="$(awk -v s="$size" -v b="$SHELL_DEFAULT_PX" -v f="$(gtk_font_pt)" \
'BEGIN { printf "%.4f", int(f * s / b + 0.5) / f }')"
set_factor "$factor"
# Terminal side: point size anchored so 12px == 9pt.
set_terminal_size "$(term_pt_for "$size")"