4. 多屏显示核心概念
在 Wayland 多屏开发中,最容易混淆的不是 API 调用,而是几个基础概念之间的边界:输出(output)、显示器(monitor)、工作区(workspace),以及克隆模式与扩展模式。如果这些概念没有对齐,后续的 wl_output 监听、xdg-output 绑定、层表面定位和输入区域映射都会出现难以排查的错位问题。本节从合成器视角出发,把这几个对象放回同一张关系图中理解。
一、输出、显示器与工作区的本质区别
在 Wayland 协议中,输出(wl_output)是合成器暴露给客户端的一个“可显示目标”抽象。它代表一条能够接收并呈现像素的通道,可能对应物理接口(HDMI、DP、eDP),也可能对应虚拟输出(headless、VNC、录屏)。输出是协议层对象,客户端通过 wl_registry 绑定它,并监听 geometry、mode、scale、name、description 等事件。
显示器(monitor)更偏向物理或用户语义:一台真实的屏幕设备。一个显示器可能被合成器识别为一个输出,也可能因为镜像、分屏或虚拟化被拆成多个输出,或者多个物理显示器被合并为一个逻辑输出。因此“显示器数量”和“输出数量”并不总是相等。
工作区(workspace)则是窗口管理层概念,不属于 Wayland 核心协议。它描述一组窗口的逻辑集合,通常与某个输出绑定,也可以跨输出移动。工作区决定“哪些窗口当前可见”,输出决定“像素画到哪里”,显示器决定“用户看到哪块屏”。三者是不同层级的概念,不能互相替代。
二、克隆模式与扩展模式的差异
克隆模式(clone / mirror)指多个输出呈现同一份逻辑画面。合成器把所有输出视为同一逻辑区域,窗口坐标系统只有一份,光标在所有屏幕上同步移动。它的优点是演示、投影场景下操作简单;缺点是分辨率必须取所有输出的交集或最小公倍数,缩放比例难以同时满足,且无法为不同屏幕分配独立工作区。
扩展模式(extend)指每个输出拥有独立的逻辑区域,合成器把它们拼接成一个全局坐标空间。窗口可以在输出之间移动,工作区可以分别绑定到不同输出,输入设备也可以按输出划分。扩展模式是多屏生产力的基础,但要求客户端正确处理 output 的 position、scale 和 transform。
三、客户端如何正确获取多屏信息
客户端不应假设输出数量,而应通过 registry 动态发现。下面是一段典型的绑定与监听流程:
// 监听 wl_registry 全局对象
static void registry_global(void *data, struct wl_registry *reg,
uint32_t name, const char *iface, uint32_t ver) {
if (strcmp(iface, wl_output_interface.name) == 0) {
struct wl_output *out = wl_registry_bind(reg, name,
&wl_output_interface, ver);
wl_output_add_listener(out, &output_listener, app);
}
}
// 关键事件
static void output_geometry(void *data, struct wl_output *out,
int32_t x, int32_t y, int32_t pw, int32_t ph,
int32_t subpixel, const char *make, const char *model,
int32_t transform) {
// x/y 是输出在全局逻辑坐标中的位置
// transform 表示旋转/翻转
}
static void output_mode(void *data, struct wl_output *out,
uint32_t flags, int32_t w, int32_t h, int32_t refresh) {
if (flags & WL_OUTPUT_MODE_CURRENT) {
// 当前模式,用于创建全屏 surface
}
}
static void output_scale(void *data, struct wl_output *out, int32_t scale) {
// 整数缩放因子,HiDPI 下为 2 或 3
}
如果使用 xdg-output 扩展,还可以获得逻辑位置与逻辑尺寸,这对层表面(layer-shell)和面板定位尤其重要。注意:wl_output.geometry 的 x/y 在部分合成器中可能为 0,必须结合 xdg_output 的 logical_position 使用。
四、典型场景与常见误区
| 场景 | 推荐模式 | 关键注意点 |
|---|---|---|
| 会议室投影 | 克隆模式 | 取最小分辨率,避免投影仪不支持高分辨率 |
| 笔记本 + 外接显示器 | 扩展模式 | 两屏 scale 可能不同,需分别处理缓冲区尺寸 |
| 三屏监控墙 | 扩展模式 | 按 x 坐标排序输出,工作区绑定到固定输出 |
| 远程桌面 / 录屏 | 虚拟输出 | 虚拟输出没有物理 EDID,需自行提供 mode |
常见误区二:在克隆模式下为每个输出创建独立全屏 surface。克隆模式下逻辑区域只有一份,重复创建会导致层叠冲突。
常见误区三:忽略 scale 变化。当输出 scale 从 1 变为 2 时,必须重新计算缓冲区大小并提交新的 surface 状态,否则画面会模糊或错位。
五、复盘:用一句话区分四个概念
- 输出:合成器暴露的协议对象,客户端通过 wl_output 绑定和监听。
- 显示器:物理或虚拟的屏幕设备,是用户语义,不一定与输出一一对应。
- 工作区:窗口的逻辑分组,决定哪些窗口可见,可绑定到输出。
- 克隆模式:多输出共享同一逻辑画面,坐标唯一,适合演示。
- 扩展模式:多输出各自独立逻辑区域,坐标拼接,适合生产力。
掌握这些边界后,后续处理多屏输入映射、层表面定位、分数缩放和输出热插拔时,就能准确判断问题出在协议层、窗口管理层还是物理设备层,而不是在错误的抽象层级上反复调试。