Skip to main content

技术讨论:Electron 如何原生支持 Wayland,以及这对你的应用意味着什么

· 23 min read
info

技术讲座是一个新的博客文章系列,我们在其中分享关于 Electron 的工作点滴。如果你觉得这项工作有趣,请考虑贡献

去年秋天,Electron 在 Linux 上切换到 Wayland 时,大多数人没有注意到。

🌐 When Electron switched to Wayland on Linux last fall, most people didn't notice.

主要的 Linux 发行版多年前就采用了现代显示协议,KDE Plasma 和 GNOME 桌面环境都正在完全放弃 X11 支持

🌐 Major Linux distributions adopted the modern display protocol years ago, and both the KDE Plasma and GNOME desktop environments are in the process of dropping X11 support completely.

但是,如果没有应用,平台迁移就不算完成,而很大一部分 Linux 应用生态系统在去年八月经历了第二次 Wayland 转型——那时大多数发行版已经更改了默认设置。那时 Chromium 默认启用了 Wayland,同时带动了 Electron 和数十个 Linux 桌面应用。

🌐 But a platform migration isn't complete without apps, and a large part of the Linux app ecosystem went through a second Wayland transition last August — well after most distros had changed their defaults. That's when Chromium turned on Wayland by default, bringing Electron and dozens of Linux desktop apps along with it.

第三次影响:Electron 走向 Wayland 原生化

🌐 The third impact: Electron goes Wayland-native

Wayland 从 Electron 38.2 及更高版本开始即开箱支持。只要你的应用是最新的,它就可以直接使用。(如果你以前是用像 CONFUSING_OZONE_VARIABLE --ozone-platform=wayland 这样很长的命令启动 Electron 应用,现在就不需要这样做了。)

🌐 Wayland is supported out of the box in Electron 38.2 and newer. As long as your apps are up-to-date, it just works. (If you were previously launching your Electron apps with very long commands like CONFUSING_OZONE_VARIABLE --ozone-platform=wayland, you no longer need to do that.)

这一变化之所以可能,是因为Chromium和Electron项目已经[在Wayland支持](https://github.com/electron/electron/pull/26022)上工作了超过五年。但直到最近,Chrome 和 Electron 应用默认仍使用 X11,即使启动于 Wayland 会话中。这并不是大问题,因为X11应用在Wayland上运行在一个名为[Xwayland](https://wayland.freedesktop.org/docs/html/ch05.html)的隐形X服务器中,运行得相当不错。

🌐 This change was possible because the Chromium and Electron projects have been working on Wayland support for more than half a decade. But until recently, Chrome and Electron apps continued to use X11 by default, even when launched in a Wayland session. This wasn’t a big issue, since X11 apps still work fairly well on Wayland by running inside an invisible X server called Xwayland.

在 Ubuntu 的 Wayland 会话中以 X11 兼容模式 (XWayland) 运行的 Electron 应用截图

通过兼容层运行应用与直接在Wayland上运行它们并不相同。在Wayland上,应用与合成器之间的中间环节更少,因此开销更低,应用之间的隔离也更强。现代Wayland合成器还允许应用利用更新的平台和显示功能,如可变刷新率、高DPI与分数缩放以及HDR。

🌐 Running apps through a compatibility layer is not the same as running them directly on Wayland. On Wayland, there’s less sitting between your app and the compositor, so there's lower overhead and much stronger isolation between applications. Modern Wayland compositors also let apps take advantage of newer platform and display features like variable refresh rates, HiDPI and fractional scaling, and HDR.

在 Wayland 上本地运行的 Electron 应用截图,演示对宽色域和 HDR 的支持

这些都是 Electron 做出改变的充分理由。在九月底,Electron 跟随 Chromium 的脚步,开始默认使用 Wayland。随着应用开始更新,那些几个月甚至几年一直“使用 Wayland”而没有问题的人们,开始第一次真正体验在 Wayland 上使用他们的应用是什么感觉。

🌐 These are all good reasons for Electron to make the switch. In late September, Electron followed Chromium’s lead and began defaulting to Wayland. And as apps began to update, people who had been “using Wayland” without issues for months or years started to find out what it was really like to experience their apps on Wayland for the first time.

韦兰的房子,韦兰的规则

🌐 Wayland’s house, Wayland’s rules

支持 Wayland 需要在 ChromiumElectron 中进行数十次更改,从内部机制到面向开发者的 API。这还需要以不同的方式思考桌面应用应该能够做什么。

🌐 Supporting Wayland required dozens of changes throughout Chromium and Electron, from internals to developer-facing APIs. It also required a different way of thinking about what desktop apps should be able to do.

Wayland 重新考虑了旧系统所做的假设,并提出质疑:应用是否应该能够:

🌐 Wayland reconsiders assumptions made by older systems and asks whether apps should be able to:

  • 将注意力从其他应用转移开
  • 查看并与其他应用的窗口进行互动
  • 在未聚焦时响应鼠标和键盘输入
  • 选择在屏幕上的窗口位置(以及显示在哪个物理显示器上)
  • 随时调整他们的窗口大小

韦兰对这些问题的回答基本上是“否”。当你打开一个窗口时,由合成器而不是应用开发者决定它的位置。应用不能在没有用户输入的情况下单方面移动、调整大小或聚焦它们的窗口,并且它们只能通过可选的协议扩展XDG门户与桌面的其他部分进行交互。

🌐 Wayland's answer to these questions is essentially “no.” When you open a window, the compositor — not the app developer — decides where it goes. Apps cannot unilaterally move, resize, or focus their windows without user input, and they can only interact with the rest of the desktop through optional protocol extensions and XDG portals.

这些规则是可以理解的;没有人喜欢当一个行为不端的应用抢走焦点或部分屏幕加载时。但当应用突然无法访问在 Wayland 上熟悉的功能时,这仍然会让人感到惊讶。对于像 Electron 这样的跨平台框架尤其如此,它的存在是为了帮助开发者在各个平台上实现一致的结果。

🌐 These kinds of rules are understandable; no one likes it when a misbehaving app steals focus or loads halfway off the screen. But it can still surprise people when their apps suddenly lose access to familiar affordances on Wayland. This is especially the case for a cross-platform framework like Electron, which exists to help developers achieve consistent results everywhere.

一些在 X11、macOS 和 Windows 上使用广泛的 Electron API 在 Wayland 上不可用。例如,win.setPosition(x, y)screen.getCursorScreenPoint() 不受支持,因为 Wayland 故意禁止 应用访问全局屏幕坐标。

🌐 Some widely used Electron APIs that work on X11, macOS, and Windows are not available on Wayland. For example, win.setPosition(x, y) and screen.getCursorScreenPoint() aren't supported, as Wayland deliberately forbids apps from accessing global screen coordinates.

其他功能的工作方式不同:使用 desktopCapturer 录制屏幕以及使用 globalShortcut 设置键盘快捷键的限制更多,并且两者都在很大程度上依赖桌面环境和门户版本。以下是在 GNOME 48 上使用 Signal Desktop 进行屏幕共享时的情况。

🌐 Other features work differently: recording the screen with desktopCapturer and setting keyboard shortcuts with globalShortcut are more restricted, and both heavily depend on the desktop environment and portal versions. Here's what it looks like when screen sharing in Signal Desktop on GNOME 48.

Signal 桌面请求在 GNOME 上共享屏幕的权限截图

让开发者感到更加复杂的是,Wayland 并不是一个单一的软件,而是一种协议。每个合成器对它的实现都有些不同,几乎就像浏览器引擎一样。(甚至还有一些协议支持跟踪器,看起来像是来自 MDN 或 CanIUse。)

所以当 Slack 尝试使用 win.focus() 聚焦其主窗口时,GNOME 的合成器(Mutter)会显示一个通知。在 KDE Plasma(KWin)上,应用图标则会在面板中闪烁。两种结果都不是应用开发者所预期的,但两者都是对 激活规范 的有效理解。

🌐 So when Slack tries to focus its main window with win.focus(), GNOME's compositor (Mutter) shows a notification. On KDE Plasma (KWin), the app icon flashes in the panel instead. Neither outcome is what the app's developers had in mind, but both are valid interpretations of the activation spec.

比较当 Slack 尝试在 GNOME 和 KDE 上聚焦自身时发生的情况的截图

有些功能在 Wayland 上的效果比在 X11 上更好,包括与颜色、透明度以及硬件加速渲染相关的任何功能。win.setOpacity(n) 是一个 Electron API 的例子,它过去在 Linux 上不可用,但现在将有可能支持。

🌐 Some capabilities simply work better on Wayland than on X11, including anything to do with colors, transparency, and hardware-accelerated rendering. win.setOpacity(n) is an example of an Electron API which hasn't been available on Linux in the past, but which will now be feasible to support.

即使是更严格的限制也能让应用受益。当 1Password 在 Wayland 上运行时,其 SSH 代理 允许用户通过单击一次来确认请求,而无需输入密码。这是安全的,因为 Wayland 的输入隔离足够强,能够防止提示被 点击劫持 跳过——只有真正的人类才能点击按钮。

🌐 Even the stricter restrictions can benefit apps. When 1Password runs on Wayland, its SSH agent lets users confirm requests with a single click instead of asking them to enter their passwords. This is safe because Wayland's input isolation is strong enough to prevent the prompt from being skipped with clickjacking — only a real human being can click the button.

1Password SSH 代理的截图,显示带有“授权”按钮的提示,漂浮在带有 SSH 命令的终端上。

基本的权衡是,Wayland 限制了应用的一些功能,但也使它们更强大和更安全。在一个字段,Wayland 给开发者比以前更多的灵活性和更多的责任:客户端装饰(CSD)。

🌐 The basic tradeoff is that Wayland restricts some of what apps can do but also enables them to be more capable and secure. And in one area, Wayland gives developers more flexibility and more responsibility than before: client-side decorations (CSD).

理解 CSD,或者当一个窗口不是窗口时

🌐 Understanding CSD, or when a window isn’t a window

Wayland 协议非常轻量,其简洁性也体现在它绘制窗口框架的方式上。在 X11 上,窗口管理器通常提供窗口的标题栏和框架装饰。但当你在 Wayland 上创建一个窗口(xdg_toplevel)时,从合成器返回给你的只是一个普通的矩形。

🌐 The Wayland protocol is very lightweight, and its simplicity extends to the way it draws window frames. On X11, the window manager typically supplies a window’s title bar and frame decorations. But when you create a window (xdg_toplevel) on Wayland, all you get back from the compositor is a plain rectangle.

在 Wayland 上一个没有装饰的空白应用窗口截图。它只是一个白色矩形。

那个矩形是一个强大的画布。在像 GNOME 的 Mutter 这样的现代合成器上,它是三缓冲并且由 GPU 加速的。但如果你想要用户可能期望的任何附加功能——标题栏按钮、阴影,甚至调整大小句柄——你必须自己添加它们。这个要求被称为客户端装饰(CSD),这是 X11 和 Wayland 之间的主要区别之一。

🌐 That rectangle is a powerful canvas. On a modern compositor like GNOME’s Mutter, it’s triple-buffered and GPU-accelerated. But if you want any of the trimmings users might expect — title bar buttons, drop shadows, even resize handles — you have to add them yourself. This requirement is called client-side decorations (CSD), and it’s one of the major differences between X11 and Wayland.

Electron 已经对客户端装饰有一些支持,由一个名为 ClientFrameViewLinux 的类提供,该类使用 GTK 来绘制逼真的本地窗口框架。这些看起来非常类似于 GNOME 曾经在 X11 上提供的窗口,但它们完全是在框架内生成的。

🌐 Electron already had some support for client-side decorations, provided by a class called ClientFrameViewLinux which uses GTK to paint convincing native window frames. These look very similar to the ones GNOME used to supply on X11, but they are produced entirely in-framework.

在 GNOME 上带有客户端装饰的 ClientFrameViewLinux 截图

但是客户端窗口框架并不完全对应 X11 窗口管理器的服务器端装饰 (SSD)。它们需要由每个应用或框架实现,因此当你将应用并排放置时,从标题栏区域到阴影和角落形状的细节都可能明显不同。

🌐 But client-side window frames are not an exact match for server-side decorations (SSD) from X11 window managers. They need to be implemented by each app or framework, so the details can look noticeably different when you put apps side by side, from their title bar areas right down to their drop shadows and corner shapes.

来自不同框架的四个带有 CSD 的应用截图(从左上角顺时针:Adwaita、Qt、Electron 和 Firefox)

这些差异通常很小,但当窗口中完全没有CSD时,结果可能会在视觉上显得刺眼。

🌐 The differences are usually minor, but when CSD is completely absent from a window, the result can be visually jarring.

许多流行的应用,包括 Visual Studio Code、Obsidian 和 Discord,使用无边框窗口自定义标题栏。在Electron 41之前,无边框窗口根本不支持 CSD,因此它们在 Wayland 上看起来像没有任何功能的矩形。

🌐 Many popular apps, including Visual Studio Code, Obsidian, and Discord, use frameless windows with custom title bars. Prior to Electron 41, frameless windows did not support CSD at all, so they looked like featureless rectangles on Wayland.

在 KDE 上无 CSD 的 VS Code 截图

提高 CSD 的覆盖率是一个具有框架范围影响的任务。最大的问题涉及窗口大小以及如何准确地测量和设置它们。Electron 已经管理两种不同类型的窗口边界:

🌐 Improving coverage for CSD was a task with framework-wide consequences. The biggest obstacle involved window sizes and how to measure and set them accurately. Electron already manages two different kinds of window boundaries:

  • “窗口边界”,窗口的大小,包括其标题栏、菜单栏和框架。
  • “内容边界”,托管应用网页内容的内部网页视图的大小。

两个值可以独立控制。如果开发者调用一个800x600的窗口,Electron会计算标题栏的高度,并将网页应用缩小到大约800x540。(对于内容大小窗口,也可以反过来操作。)

🌐 Both values can be controlled independently. If a developer calls for an 800x600 window, Electron calculates the height of the title bar and shrinks the web app to something like 800x540. (It also works the other way around for content-sized windows.)

没有CSD的Electron应用窗口和内容边界示意图

为了支持 CSD,Electron 还需要跟踪一种新的边界类型:

🌐 To support CSD, Electron also needed to keep track of a new kind of boundary:

  • “小部件边界”,指透明小部件的大小,该小部件绘制其内部的所有内容,包括窗口框架及其外部装饰。

当需要 CSD 时,Electron 首先获取窗口的底层表面(通过 Chromium 的加速组件在内部访问),并将其放大,使其足够大以容纳所有装饰。

🌐 When CSD is required, Electron first takes the window's underlying surface (accessed internally via a Chromium accelerated widget) and inflates it so it's large enough to fit all the decorations.

然后,框架会在透明小部件中以适当的大小和位置绘制窗口的不透明部分(标题栏、框架和网页内容)。最外层区域填充了投影和调整大小的点击目标,从而在不依赖服务器端装饰的情况下,创建出原生三维窗口的外观和感觉。

🌐 The framework then paints the opaque bits of the window (title bar, frame, and web content) at their appropriate sizes and positions inside the transparent widget. The outermost areas are filled in with drop shadows and resize hit targets, creating the look and feel of a native, three-dimensional window without relying on server-side decorations.

使用 CSD 时,一个 800x600 的“逻辑”窗口可能嵌入在一个 840x640 的控件中。具体的几何尺寸取决于用户的主题和窗口的状态:无论窗口当前是活跃的、最大化的、平铺的还是全屏的,都可能影响装饰的大小和存在。

🌐 With CSD, a "logical" window at 800x600 might be inset into a 840x640 widget. The exact geometries depend on the user's theme and the window's state: whether it is currently active, maximized, tiled, or fullscreen can affect the size and presence of decorations.

Electron 应用完整 CSD 边界的示意图,包括环绕窗口的透明小部件

当然,小部件的边界绝不应该泄露到公共 API 中。框架需要将这种复杂性抽象出来,开发者通常不会考虑调整大小目标的边界或阴影内边距在其下方发生变化。

🌐 Of course, widget bounds should never leak into the public API. The framework needs to abstract this complexity away from app developers, who are generally not thinking about the extents of resize targets or shadow insets changing underneath them.

好消息是,这些问题大部分在去年九月到三月之间得到解决,因此,Electron 41 在所有窗口配置中都支持 Wayland 上的 CSD,包括带有窗口控件覆盖的无框窗口。

🌐 The good news is that much of this was sorted out between last September and March, and as a result, Electron 41 supports CSD on Wayland in all window configurations, including frameless windows with Window Controls Overlay.

使用带有 CSD 阴影的 Electron 41.x 预发布版本的 VS Code 截图。

下一步是什么——以及你能如何帮助

🌐 What’s next — and how you can help

到2026年,Wayland 对 Linux 用户来说已是日常现实,因此出色的 Wayland 体验现在就是支持 Linux 的基本要求。

🌐 Wayland is an everyday reality for Linux users in 2026, so a great Wayland experience is now just what it means to support Linux.

上个月,Electron 在创建了一个 Wayland CI 测试任务 后达到了一个重要的里程碑。仍然需要移植更多的测试,但现在更容易发现回归问题了。

🌐 Electron reached an important milestone last month with the creation of a Wayland test job in CI. More tests still need to be ported over, but it’s now much easier to catch regressions.

现在基础支持已经到位,Wayland 为 Electron 应用打开了新的可能性。特别是 CSD 为开发者提供了更多方式来自定义窗口框架,并将其与他们的网页内容和平台集成。让我们知道你希望看到什么;我自己清单上排在前列的一个功能是圆角。

🌐 Now that the basic support is in place, Wayland opens up new possibilities for Electron apps. CSD in particular offers developers more ways to customize window frames and integrate them with both their web content and the platform. Let us know what you'd like to see; one feature that's high on my own shortlist is rounded corners.

无边框圆角窗口的截图(目前在 Electron 中不可行,但很快可能实现?)

框架只是故事的一部分。如果你开发了一个 Electron 应用,并且有一段时间没有在 Linux 上彻底测试它(即使是去年秋天),可以在像 Ubuntu 25.10 或 Fedora 43 这样的现代发行版上使用 Electron 41+ 试运行一下。尝试在 KDE Plasma 和 GNOME 上运行你的应用,或者尝试一些更独特的桌面环境,比如 Niri

🌐 The framework is only part of the story. If you develop an Electron app and you haven’t thoroughly tested it on Linux in a while (even as recently as last fall), give it a spin with Electron 41+ on a modern distribution like Ubuntu 25.10 or Fedora 43. Try your app on both KDE Plasma and GNOME, and maybe something more exotic like Niri.

你可能会发现一些可以进行的更改,以适应 Wayland 的独特限制。一些差异在 Electron 文档 中有所介绍,但理解新环境的最佳方法是亲自使用它。

🌐 You may discover changes you could make to accommodate Wayland's unique constraints. Some differences are covered in the Electron documentation, but the best way to understand the new environment is to use it.

如果你想看到更快的进展并支持更多平台功能,可以考虑成为贡献者。像 Linux 本身一样,Electron 是一个由社区管理的自由软件项目,对所有人开放,我们正在积极寻找 Linux 贡献者和维护者。

🌐 And if you’d like to see faster progress and support for more platform features, consider becoming a contributor. Like Linux itself, Electron is a community-run free software project that’s open to everyone, and we're actively looking for Linux contributors and maintainers.

Electron 支撑着许多跨平台最受欢迎的桌面应用,因此参与其中是帮助让桌面 Linux 对数百万人来说更可行的有效方式。

🌐 Electron powers many of the most popular desktop apps across platforms, so getting involved is an effective way to help make desktop Linux more viable for millions of people.