Всем здравствуйте.
TL;DR: Похоже, что X-сервер отдаёт серверные шрифты в фиксированном разрешении 100 dpi, а не в разрешении, текущем для сервера.
Немного теории. Есть серверные шрифты, которые X-клиенту по сети (через TCP либо UNIX socket) «отдаёт» либо сам X-сервер, либо отдельный X Font Server (один или несколько). В отличие от привычных всем клиентских шрифтов (Xft, GTK 2+, Qt 2+), «серверный» backend (он ещё называется core X font backend) не поддерживает антиалиасинг, но поддерживает сетевую прозрачность (т. е. по сети перегоняются bitmap’ы без альфа-канала). На уровне приложения серверные шрифты задаются не в виде XftFontStruct
(что чаще всего вырождается в привычное нам DejaVu Sans Mono 12
), а в виде XLFD. Если мы говорим о локальной машине, то один и тот же файл шрифта может быть зарегистрирован сразу в двух подсистемах и доступен и современным приложениям на базе GTK и Qt, и «суровому легаси» (Xt, Athena, Motif, GTK 1.2, Qt 1.x).
Исторически серверные шрифты были растровыми (*.pcf
), а для растра существует такое понятие, как его собственное, растра, разрешение. Поэтому в XLFD есть такие поля, как RESOLUTION_X
и RESOLUTION_Y
. Чтобы растровый шрифт выглядел на экране адекватно, разрешение растра должно быть близким к разрешению экрана, поэтому растровые шрифты обычно поставлялись с собственным разрешением в 75 dpi и 100 dpi (каталоги /usr/share/fonts/X11/75dpi
и /usr/share/fonts/X11/100dpi
– как раз про это). Так,
-bitstream-charter-bold-r-normal--12-120-75-75-p-75-iso8859-1
-bitstream-charter-bold-r-normal--17-120-100-100-p-107-iso8859-1
– это один и тот же шрифт размером 12 pt, имеющий характерный размер символа
- 12 px при разрешении 75 dpi, и
- 17 px – при 100 dpi, соответственно.
Но, помимо растровых шрифтов, есть ещё векторные (TrueType, OpenType, Adobe Type 1), которые мы все любим и которые можно безбоязненно масштабировать. Некоторые реализации X-сервера (напр., XSun) поддерживали ещё формат Adobe Type 3, в котором шрифт описывался с помощью языка PostScript
(Тьюринг-полного, кстати).
К векторным шрифтам понятие разрешения растра, естественно, неприменимо, поэтому в полях RESOLUTION_X
и RESOLUTION_Y
я могу запрашивать 0
, а могу запрашивать «звёздочки» (*
), и, в теории, X-сервер должен отдать мне нужный шрифт. Об этом напрямую говорится в статье Arch Wiki по ссылке выше:
Scalable fonts were designed to be resized. A scalable font name, as shown in the example below, has zeroes in the pixel and point size fields, the two resolution fields, and the average width field.
…
To specify a scalable font at a particular size you only need to provide a value for the
POINT_SIZE
field, the other size related values can remain at zero. ThePOINT_SIZE
value is in tenths of a point, so the entered value must be the desired point size multiplied by ten.
Так, любой из этих запросов должен мне вернуть шрифт Courier New
размером 12 pt в разрешении X-сервера:
-monotype-courier new-medium-r-normal--*-120-*-*-m-*-iso10646-1
-monotype-courier new-medium-r-normal--0-120-0-0-m-0-iso10646-1
Или, по кр. мере, я так думал. Штука в том, что, пересев с мониторов с разрешением в 96…115 dpi за 4k-монитор с разрешением в 162 dpi, я заметил, что мои заботливо выбранные векторные шрифты внезапно стали мелковаты.
И выяснилось, что, если явно не указывать RESOLUTION_X
и RESOLUTION_Y
равными 162 (а никто в здравом уме этого не делает – это пришлось бы каждый раз при изменении монитора переписывать сотни строк Xresources), то X-сервер по умолчанию отдаёт шрифт в разрешении 100 dpi вместо 162. Разница между 17-ю пикселями и 27-ю (пресловутый коэффициент 1.62 = 162 / 100) достаточно заметна. Вот пример для современного Debian 10 (сверху для сравнения дан снимок font-manager, отрисовывающего клиентский шрифт): Debian 10, Courier New 12pt.
Я было подумал, что это следствие постепенного выпиливания устаревших подсистем из X11, но в Debian Woody, выпущенном в 2002 году и имеющем ядро 2.2, увидел ровно то же самое: Debian 3, Courier New 12pt. Разве что сам шрифт старый Debian отрисовывает «чище», видимо, выполняя хинтинг на серверной стороне, до пересылки bitmap’ов по сети.
Проблема существовала всегда и в равной степени затрагивает все векторные шрифты (TrueType, OpenType, Type 1).
Собственно, вопрос. Старожилы, посоветуйте – есть ли способ, не зашивая жёстко в пользовательские настройки для каждого отдельного ресурса разрешение X-сервера, обойтись меньшей кровью, чем рекомендует автор статьи Sharing Xresources between systems? Поддержка препроцессора в xrdb
, увы, всё-таки достаточно убога.
Можно ли решить что-то на уровне глобальной конфигурации собственно X-сервера?
Или меня спасёт m4
?
Cast Zubok.
Update. По здравом размышлении я пришёл к выводу, что схема XLFD сама по себе ущербна. Дело в том, что X-ресурсы (речь в первую очередь о шрифтах) для каждой конкретной программы могут существовать как на стороне сервера (всё то, что даётся на вход xrdb
), так и на стороне клиента (см. XUSERFILESEARCHPATH
). И настройки, скажем, шрифта для пресловутого xterm
должны храниться где-то в одном месте – либо на клиенте, либо на сервере. А XLFD включает в себя и серверные параметры (RESOLUTION_X
и RESOLUTION_Y
), и клиентские (CHARSET_REGISTRY
и CHARSET_ENCODING
– ведь потенциально удалённый, «сетевой» X-клиент может быть запущен в окружении и с региональными настройками, отличными от окружения и настроек X-сервера) – и вот это как раз-таки и неправильно. При разработке Xft Кит Пакард всё сделал по уму: имя и размер шрифта в пунктах (DejaVu Sans Mono:size=12
) задаёт X-клиент, а X-ресурс Xft.dpi
является частью состояния X-сервера.
Возможно, мою проблему удастся решить с помощью серверных псевдонимов шрифтов (font aliases, файлы fonts.alias
).