显示信息协议

在 0.50.0 版本加入.

绘图程序通常不了解输出最终到达的屏幕:彩色 LCD 还是十六级灰度电子墨水屏、覆盖多少色域、亮度有多高、每个字符单元有多少物理像素、以什么频率刷新。这些都会影响最佳渲染方式,从调色板和抖动策略,到是否值得运行动画。显示信息协议让程序查询这些信息,并在答案变化时收到通知,例如窗口被移到另一块屏幕。它与其他 kitty 协议一样,是小巧、低干扰、易于实现的开放终端扩展,不改变 TTY 的本质。

消息封装

帧使用带有 display 选择器的 OSC 777::

<OSC> 777 ; display ; v=1 : op=query : id=42 <ST>

帧遵循 OSC 777 扩展封装 规定的 OSC 777 共用规则:字段语法、拒绝哪些帧、单位和时钟。终端报告中的值为单词,或可带小数、不带前导 + 的十进制数,例如 headroom=1.5。协议版本 v 为 1,op 为 query、cap、mode 或 event。

查询

程序查询窗口所在的显示器::

<OSC> 777 ; display ; v=1 : op=query : id=42 <ST>

id 是程序自行选择的非负 31 位整数,回复原样返回,以便匹配查询。支持协议的终端回答::

<OSC> 777 ; display ; v=1 : op=cap : id=42 : mode=0 : kind=lcd : color=rgb : bits=8 : gamut=p3 : headroom=1 : scale=2 : period=8333 : ppi=254 <ST>

不支持本协议的终端会忽略查询,因此程序必须设置超时,并回退为假定普通彩色显示器。

回复字段如下:

mode

下述模式的当前状态,0 或 1。

kind

lcd、oled、eink 或 unknown。电子墨水屏更新较慢且会残影,因此程序应避免动画和平滑滚动,采用低频、大步幅重绘。

color

rgb、gray 或 mono。

bits

每个颜色通道的位数,未知时为 0。十六级灰度表示为 color=gray : bits=4。该字段与 color 一起供程序选择调色板,并决定是否以及如何抖动;少量灰度级也可进行良好的抗锯齿,此字段不决定抗锯齿策略。

gamut

srgb、p3、rec2020 或 unknown,表示显示器覆盖的最宽色彩空间。

headroom

终端可显示亮度相对于普通文本白色的倍数;没有额外亮度时为 1。使用方式见 HDR 亮度协议。

scale

系统要求应用使用的帧缓冲区缩放比例:一个系统逻辑单位需要多少物理像素。多数高密度显示器为 2,其他显示器常用 1.25 或 1.5 等小数。未知时为 0。用途见 像素。

period

显示器刷新周期,单位微秒,未知时为 0。

ppi

每英寸的物理像素数:程序绘制的多少像素对应屏幕上一英寸,供程序按真实尺寸绘制。未知时为 0。

终端无法确定的值为 unknown 或 0,绝不猜测。例如未连接客户端的多路复用器,若不了解显示器,所有字段均回答未知,程序的处境不会比查询前更差。

像素

本协议及终端所有以像素度量的协议(窗口和字符单元尺寸、图像尺寸和放置、指针/笔/手指位置、滚动距离)均使用物理像素,即终端绘制的帧缓冲区中的一个像素。不使用系统逻辑单位(每个逻辑单位对应 scale 个像素),终端也不会拉伸程序绘制的内容来弥补差异。因此,程序绘制的一像素宽直线就是一像素,而非扩散到多个像素的模糊斑块,程序能使用显示器提供的每一个像素。

scale 表示系统希望应用采用的尺寸,使内容看起来符合用户选择的大小。程序用它决定绘制多大,例如将一个逻辑单位粗的标尺绘制为 scale 像素;不要用它换算已经以物理像素表示的位置或尺寸。ppi 则把这些像素与屏幕的实际尺寸联系起来。

模式

程序可按终端窗口开启变化通知::

<OSC> 777 ; display ; v=1 : op=mode : mode=1 <ST>

用 mode=0 关闭。模式仅作用于当前窗口,并由 RIS 重置。程序必须在退出、挂起或失败时关闭,恢复时重新开启。多路复用器与其他终端状态一起保存它,并在脱离连接时关闭。终端可允许用户针对全部或部分程序拒绝模式;被拒绝时读回为关闭,不产生任何报告,因此程序应读回状态,而不是假定已获准。

不带 mode 字段的 mode 请求读取状态而不修改,回复为::

<OSC> 777 ; display ; v=1 : op=mode : mode=1 <ST>

程序重连后恢复时,应读回模式,确认是否仍然有效,而非假定状态保留。

事件

开启模式会先发送一次包含当前值的事件,无需单独查询。此后,只要模式开启,任何字段变化都会产生一条事件:窗口移到缩放比例或刷新率不同的显示器、显示亮度设置改变了亮度余量,或切换了色彩配置文件::

<OSC> 777 ; display ; v=1 : op=event : t=408211 : kind=lcd : color=rgb : bits=8 : gamut=srgb : headroom=1 : scale=1 : period=16666 : ppi=96 <ST>

字段与 cap 回复相同,但不含 id 和 mode,并带有 t,表示终端获知变化的时刻,以全部扩展共用时钟上的毫秒表示,见 OSC 777 扩展封装。变化相对于上次事件计算,因此关闭再开启模式会报告一次当前值,此后仅报告变化。变化可能稍后才报告,程序关闭模式后仍可能收到已经在途的事件。终端和中继绝不合并或丢弃事件。

中继与多路复用器

类似 mosh 客户端、将终端画面绘制到自己显示器的中继,应使用自身显示器回答查询,因为远端终端无法得知这些信息。中继重连到不同客户端时,会向每个开启模式的窗口发送一次事件,使原本按手机布局的程序能改为桌面布局,反之亦然。

多路复用器根据所连接客户端的显示器回答;脱离连接时所有字段为未知,连接到不同显示器的客户端时发送事件。

配置

操作系统能报告多数属性,但并非全部;例如没有信息直接告诉终端它位于电子墨水屏上。在 Silkie 中,eink_mode 声明电子纸显示器,并在未明确选择浅色或深色配色时启用白底黑字。它优先于检测到的显示器类型和 display_info kind=...。运行时用 set_eink_mode 切换会立即通知显示信息订阅者。display_info 可声明操作系统无法提供的个别属性,并覆盖检测;仅设置 display_info kind=eink 会改变报告而不改变颜色。两种设置都不猜测电子纸是灰度还是彩色。目前 Silkie 仅在 macOS 上报告 kind,在 macOS 及实现色彩管理协议的 Wayland 合成器上报告 gamut。后者由合成器提供显示器基色,gamut 选择显示器在 CIE 1931 色度图上覆盖面积至少十分之九的最宽色域;两种较宽色域均未达到时为 srgb。headroom 是 HDR 亮度协议 的亮度余量,已应用 hdr_max_headroom 上限;除非启用 hdr 且窗口实际显示 HDR,否则为 1。macOS 和 Wayland 何时可使用 HDR 见该页。

scale 是窗口系统提供给窗口的比例:macOS 的 backing scale factor、Wayland 表面的首选比例(合成器支持时可为小数),以及 X11 从 Xft.dpi 取得的桌面比例。在 X11 和能声明小数比例的 Wayland 合成器上,Silkie 绘制的像素对应面板像素。在 macOS 上,它们是系统为显示器保存的帧缓冲区像素,默认分辨率下对应面板原生像素。选择缩放分辨率(显示设置中的“更多空间”及相邻选项)时,系统会将帧缓冲区重采样到面板,类似 Wayland 合成器对只能提供整数缩放比例的窗口所做的处理。这时 Silkie 的像素不再严格对应面板像素,任何应用都无法避免;macOS 上的 ppi 统计的是 Silkie 绘制的像素。

不提供物理尺寸的显示器(例如远程会话或虚拟机中的虚拟显示器),其 ppi 为 0。窗口系统可能假定每英寸 96 或 72 像素,但这是猜测,不会转发给程序。