从 X11 到 Wayland:WSLg 为什么不是简单开了一个 X Server
原创 · 约 22 分钟阅读 · 阅读 --

从 X11 到 Wayland:WSLg 为什么不是简单开了一个 X Server

作者: Alex Xiang


古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。更完整的更新写在微信公众号「字与码」:工作经历、对新技术的想法,以及这些年走弯路的记录,会不定期发在那里。若觉得博客对你有用,欢迎顺手关注。

如果你搜索“WSL 运行 Linux 图形程序”,很容易翻到一堆老教程:安装 VcXsrv,打开 XLaunch,防火墙放行,手动设置 DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0

这些教程不是错,只是很多已经不适合现在的 WSLg 了。

X11、Wayland 与 WSLg 的窗口链路

今天在 Windows 11 上跑 Ubuntu,装个 xeyesgedit,很多时候什么都不用配:

sudo apt install x11-apps gedit -y
xeyes
gedit

窗口会直接出现在 Windows 桌面上,能 Alt+Tab,能复制粘贴,像普通 Windows 程序一样和其他窗口排在一起。

这件事表面上像“微软帮你内置了一个 X Server”。但 WSLg 真正做的事要绕一点:它不是倒退回 X11,而是把 Wayland、XWayland、Weston、PulseAudio 和 RDP 拼成了一条桥。理解这条桥,很多 WSL GUI 问题就不再玄学。

xeyes 开始看协议,而不是看窗口

先跑一个最老派的 X11 小程序:

sudo apt install x11-apps -y
xeyes

再跑一个现代一点的 GTK 程序:

sudo apt install gedit -y
gedit

两个窗口都能显示在 Windows 桌面上,但它们走的路线可能不同。

xeyes 是典型 X11 程序。它和 X server 说话。
gedit 这样的 GTK 程序,在现代 Linux 桌面上可以走 Wayland,也可以回退到 X11。
在 WSLg 里,Wayland 程序通常直接和 Weston 这个 compositor 交互;X11 程序则先经过 XWayland,再交给 Weston。

你可以看一下环境变量:

echo "$WAYLAND_DISPLAY"
echo "$DISPLAY"
ls -la /mnt/wslg

在 WSLg 正常工作时,WAYLAND_DISPLAYDISPLAY 往往都存在。很多人看到 DISPLAY 就以为“还是 X11”。其实这个变量更多是在照顾旧程序。新的主路是 Wayland,X11 通过 XWayland 兼容。

X11 的强项:把显示当成网络服务

X11 很老,但它的设计有一种今天看仍然大胆的味道。

在 X11 里,术语是反直觉的:X server 通常跑在有显示器和键鼠的机器上,应用程序是 X client。应用把“画窗口、收键鼠”的请求发给 X server,X server 负责真正显示。

这就是早年 Unix 工作站很喜欢的模式:程序可以跑在远程大机器上,窗口显示在你面前的小终端上。X.Org 的手册里也把 X Window System 描述成 network transparent window system。你在一台机器上启动程序,在另一台机器上显示窗口,这是 X11 的老本行。

典型命令是:

ssh -X user@server
xclock

如果一切配置正确,xclock 的窗口会出现在本地机器上。它的可贵之处在于简单:应用不用知道显示设备在哪,X server 把显示和输入抽象成网络协议。

但这个设计也带来了代价。

第一,安全模型很粗。能连上同一个 X server 的客户端,天然离其他窗口和输入事件太近。历史上可以做访问控制和安全扩展,但基础模型不是“每个应用只看自己的窗口”。

第二,现代图形栈越来越复杂。OpenGL、GPU 合成、HiDPI、多屏、触控、沙箱、屏幕录制、输入法、剪贴板、无障碍,很多事情都不是 1980 年代的 X11 模型最舒服的表达方式。

第三,所谓网络透明在现代桌面应用上经常不如想象中透明。一个程序不只是画窗口,它还可能依赖 D-Bus、音频、GPU、文件选择器、门户、主题、字体、输入法。只转发 X11 协议,体验未必完整。

所以 X11 不是“烂”,它只是背着太多历史。

Wayland 的思路:让 compositor 成为真正的桌面边界

Wayland 的思路简单很多:应用把自己的内容渲染到 buffer,compositor 负责把这些 buffer 组合到屏幕上,并统一处理输入、窗口管理和显示输出。

在 X11 里,X server 是中心,窗口管理器、合成器、客户端之间有一堆历史协议和扩展。到了 Wayland,compositor 的角色更重,也更明确。GNOME 的 Mutter、KDE 的 KWin、Weston 都可以是 Wayland compositor。

这带来一个很重要的变化:应用默认不应该随便看别的应用。

截图、录屏、全局快捷键、输入法、拖拽、文件选择,这些在 Wayland 世界里往往通过 compositor 或 portal 做显式授权。它比 X11 麻烦一些,但边界更清楚。对普通桌面用户来说,这个变化并不显眼;对沙箱、安全和远程桌面来说,这个变化很大。

Wayland 官方文档把协议描述成异步、面向对象的协议。它不像 X11 那样承担一整个跨网络窗口系统的历史目标,而是更像“应用和 compositor 之间的本地协作协议”。

这也解释了一个常见误会:Wayland 不是“新版 X11”。它是换了思路。

XWayland:不能把四十年的应用一刀切掉

既然 Wayland 是新路,为什么 WSLg 里还需要 DISPLAY,为什么 xeyes 还能跑?

答案是 XWayland。

XWayland 可以理解成跑在 Wayland 世界里的 X server。旧 X11 应用连到 XWayland,以为自己还在跟 X server 说话;XWayland 再把窗口内容交给 Wayland compositor。

这层兼容非常关键。Linux GUI 生态里还有大量程序、工具包、插件、老应用、调试工具依赖 X11。没有 XWayland,Wayland 的迁移会痛苦很多。

在 WSLg 里也是一样。微软没有要求所有 Linux GUI 程序都支持 Wayland。它让现代程序优先走 Wayland,又用 XWayland 接住旧 X11 程序。你能一边跑 gedit,一边跑 xeyes,就是这个兼容层在工作。

如果要观察某个 GTK 程序到底走哪条路,可以临时指定后端:

GDK_BACKEND=wayland gedit
GDK_BACKEND=x11 gedit

不是每个程序都支持这样切,也不是每次切都有肉眼差异。但这能帮你理解:在 WSLg 下,“能显示”不等于“协议都一样”。

WSLg 的关键不是 X,而是 Weston + RDP

WSLg 官方架构文章里最有意思的地方,是它没有选择“让 Windows 直接当 X Server”。它的核心是一个系统发行版里的图形栈:Weston、XWayland、PulseAudio,再通过 RDP 后端把窗口集成到 Windows。

WSLg 仓库 README 里也写到,WSLGd 会启动 Weston、XWayland、PulseAudio,并通过静默方式启动 Windows 侧的 mstsc.exe 建立 RDP 连接。这条 RDP 连接会保持就绪,后续 GUI 应用启动时不用重新建立连接。

这几个名字分别做什么?

Weston 是 Wayland compositor。它接收 Wayland 客户端,也接 XWayland 转过来的 X11 客户端。
XWayland 负责兼容旧 X11 应用。
PulseAudio 负责音频输入输出,WSLg 里有专门插件把音频接到 RDP transport。
RDP 负责把窗口、输入、音频等集成到 Windows 侧。
mstsc.exe 是 Windows 侧远程桌面客户端,但 WSLg 把它用成了“无感桥”。

所以 WSLg 的用户体验不像传统远程桌面。你不是看到一个完整 Linux 桌面,而是看到单个 Linux 应用窗口混在 Windows 桌面里。RDP 里有 RemoteApp/RAIL 这样的能力,能让远程应用以本地窗口形式出现。WSLg 借的正是这类思路。

为什么旧教程现在经常制造问题

老 WSL GUI 教程通常会让你手工设置:

export DISPLAY=172.xx.xx.xx:0

或者写进 ~/.bashrc

export DISPLAY=$(grep nameserver /etc/resolv.conf | awk '{print $2}'):0

在没有 WSLg 的时代,这样做是为了连接 Windows 上的第三方 X Server,比如 VcXsrv、Xming。那时 WSL 只提供命令行,Linux GUI 程序要显示到 Windows,只能找一个 Windows X Server。

现在如果你已经有 WSLg,再把 DISPLAY 强行改掉,就可能把应用从 WSLg 的默认通道带偏。结果是:有的程序打不开,有的剪贴板失效,有的缩放不对,有的窗口跑到第三方 X Server 上。

所以我的建议是:

先不要配置任何 DISPLAY
先跑 xeyesgeditglxgears
确认 WSLg 是否已经正常。
只有确实需要第三方 X Server,才在一个临时 shell 里设置 DISPLAY

排查时可以这么看:

echo "$DISPLAY"
echo "$WAYLAND_DISPLAY"
echo "$XDG_RUNTIME_DIR"
ls -la /mnt/wslg
ps aux | grep -E 'weston|Xwayland|pulseaudio' | grep -v grep

不要把网上的 export DISPLAY=... 当成 WSL GUI 的固定步骤。它更像是旧时代的兼容方案。

一个可复制的小实验

装几个工具:

sudo apt update
sudo apt install x11-apps mesa-utils gedit -y

跑 X11 小工具:

xeyes
xclock

跑 OpenGL 测试:

glxgears

跑 GTK 编辑器:

gedit

再分别尝试:

GDK_BACKEND=wayland gedit
GDK_BACKEND=x11 gedit

你可以观察几件事。

窗口是不是都出现在 Windows 桌面,而不是某个 Linux 桌面容器里?
Alt+Tab 能不能切换?
Windows 和 Linux 之间复制粘贴是否正常?
窗口缩放、输入法、中文显示是否正常?
关闭 WSL 后再次启动,是否无需手动启动任何 X Server?

这些比单纯看“有没有 DISPLAY”更有价值。

如果要确认你没有走旧的第三方 X Server,把手工写进 shell 的 DISPLAY 配置临时注释掉:

grep -n "DISPLAY" ~/.bashrc ~/.zshrc ~/.profile 2>/dev/null

很多 WSL GUI 问题就是因为这里藏了一行几年以前留下的配置。

WSLg 不是完整 Linux 桌面

理解了 WSLg 的桥接结构,也要接受它的边界。

它适合跑单个 Linux GUI 应用:图片查看、文本编辑、绘图工具、简单 IDE、调试窗口、Matplotlib 交互图、OpenCV preview。

它不适合把 WSL 当成一个完整 Linux 桌面来用。你当然可以折腾桌面环境,但那不是 WSLg 的主线。WSLg 的主线是:Windows 仍是桌面,Linux 应用作为单个窗口融进来。

这也解释了为什么我不建议在 WSL 里追求“完整 Ubuntu 桌面”。如果你真的要完整 Linux 桌面、独立登录会话、完整 system tray、桌面组件和会话管理,一台虚拟机或者真 Linux 机器更直接。WSLg 的优势是轻、快、和 Windows 工作流贴得近。

对开发者有什么实际价值

知道这些架构细节,不是为了在聊天里背名词。它能改变几个日常判断。

第一,看到 X11 程序能跑,不要误以为 WSLg 只是 X Server。它的主路是 Wayland,X11 是兼容层。

第二,遇到 GUI 问题,先清掉旧 DISPLAY 配置,再看 /mnt/wslg 和 WSLg 进程。不要先装第三方 X Server。

第三,如果你开发 Linux 图形程序,最好同时测 Wayland 和 X11/XWayland。尤其是输入、剪贴板、拖拽、窗口缩放、HiDPI,这些地方很容易走不同路径。

第四,如果你要做截图、录屏、全局快捷键、跨窗口读取,不要拿 X11 的老习惯套 Wayland。Wayland 世界里这些能力通常需要 compositor 或 portal 的参与,不是应用想拿就拿。

第五,WSLg 适合“Windows 桌面 + Linux 工具链”的组合,不适合用来证明某个 Linux 桌面环境能不能完整替代 Windows。

我的使用边界

我现在只把 WSLg 当成开发工具链的一部分。

脚本生成图,直接弹窗口看。
OpenCV 调试图像,imshow 一下。
偶尔用 geditmeldxeyesglxgears 验证图形链路。
写 Linux GUI 小工具时,在 WSL 里先跑通,再到真正的 Linux 桌面或打包环境里补测。

我不会在 WSL 里装完整桌面,也不会为了一个 GUI 程序到处改 DISPLAY。如果默认 WSLg 能跑,就用默认;如果默认不行,先查是不是旧配置污染,再查应用是否依赖了特殊图形能力。

这就是 WSLg 最好的状态:它不抢 Windows 桌面的活,也不假装自己是一台完整 Linux 桌面。它只在你需要 Linux 窗口时,把窗口递过来。

参考资料