【译】从零开始的 Wayland 合成器 —— 2. 装配服务器

原文链接:Writing a Wayland Compositor, Part 2: Rigging up the server

译者注:这个系列文章中使用的为早期 wlroots 版本,大约在 0.3 到 0.4.1 之间,请注意安装的版本

这是关于使用 wlroots 从头开始编写 Wayland 合成器的系列文章中的第二篇。如果你还没有看过第一篇文章,可以看看。上一次,我们最终得到了一个应用程序,它启动了 wlroots 后端,枚举了输出设备,并在屏幕上绘制了一些漂亮的颜色。今天,我们将开始接受 Wayland 客户端的连接,尽管我们还不打算对它们做什么。

本文剖析的提交是b45c651。

关于这些博客文章的性质,我想说的是:我们将需要大量的文章来充实我们的合成器。我将会比平时更频繁地发布这些文章,大概每周1-2篇,并继续以通常的速度发布我的文章。好吗?很好。

所以我们已经启动了后端,并且正在渲染一些有趣的东西,但是我们仍然没有运行Wayland服务器–Wayland客户端没有连接到我们的应用程序。添加这个其实很容易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@@ -113,12 +113,18 @@ int main(int argc, char **argv) {
server.new_output.notify = new_output_notify;
wl_signal_add(&server.backend->events.new_output, &server.new_output);

+ const char *socket = wl_display_add_socket_auto(server.wl_display);
+ assert(socket);
+
if (!wlr_backend_start(server.backend)) {
fprintf(stderr, "Failed to start backend\n");
wl_display_destroy(server.wl_display);
return 1;
}

+ printf("Running compositor on wayland display '%s'\n", socket);
+ setenv("WAYLAND_DISPLAY", socket, true);
+
wl_display_run(server.wl_display);
wl_display_destroy(server.wl_display);
return 0;

这就是了! 如果你再次运行 McWayface,它将打印出这样的东西:

1
Running compositor on wayland display 'wayland-1'

Weston 是 Wayland 的参考合成器,包括一些简单的参考客户端。我们可以使用 weston-info 连接到我们的服务器并列出全局变量:

1
2
$ WAYLAND_DISPLAY=wayland-1 weston-info
interface: 'wl_drm', version: 2, name: 1

如果你还记得我的《Wayland 简介》,Wayland 服务器通过 Wayland 注册表向客户端输出了一个全局变量列表。这些全局变量提供了客户端可以用来与服务器互动的接口。我们通过 wlroots 获得了 wl_drm,但我们实际上还没有连接上任何有用的东西。wlroots提供了许多 “类型”,其中大部分是像这样的 Wayland 全局接口的实现。

一些 wlroots 的实现需要你进行一些操纵,但其中有几个是自动搞定的。装配这些东西很容易:

1
2
3
4
5
6
7
8
9
10
11
        printf("Running compositor on wayland display '%s'\n", socket);
setenv("WAYLAND_DISPLAY", socket, true);
+
+ wl_display_init_shm(server.wl_display);
+ wlr_gamma_control_manager_create(server.wl_display);
+ wlr_screenshooter_create(server.wl_display);
+ wlr_primary_selection_device_manager_create(server.wl_display);
+ wlr_idle_create(server.wl_display);

wl_display_run(server.wl_display);
wl_display_destroy(server.wl_display);

请注意,这些接口中的一些并不一定是你通常想要暴露给所有 Wayland 客户端的接口–例如,screenshooter 是应该被保护起来的东西。我们将在后面的文章中讨论安全问题。现在,如果我们再次运行 weston-info,我们会看到更多的全局变量已经出现:

1
2
3
4
5
6
7
8
$ WAYLAND_DISPLAY=wayland-1 weston-info
interface: 'wl_shm', version: 1, name: 3
formats: XRGB8888 ARGB8888
interface: 'wl_drm', version: 2, name: 1
interface: 'gamma_control_manager', version: 1, name: 2
interface: 'orbital_screenshooter', version: 1, name: 3
interface: 'gtk_primary_selection_device_manager', version: 1, name: 4
interface: 'org_kde_kwin_idle', version: 1, name: 5

你会发现 wlroots 实现了各种不同来源的协议–在这里我们看到 Orbital、GTK 和 KDE的 协议。wlroots 包括一个 Orbital 屏幕截图的客户端实例–我们现在可以用它来给我们的合成器截个图:

1
2
$ WAYLAND_DISPLAY=wayland-1 ./examples/screenshot
cannot set buffer size

啊,这是个问题–你可能已经注意到,我们没有任何 wl_output 的全局变量,屏幕截图客户端依靠它来计算屏幕截图缓冲区的分辨率。我们也可以添加这些:

1
2
3
4
5
6
7
@@ -95,6 +99,8 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->frame.notify = output_frame_notify;
wl_signal_add(&wlr_output->events.frame, &output->frame);
+
+ wlr_output_create_global(wlr_output);
}

再次运行 weston-info 会给我们提供一些关于我们现在的 output 的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ WAYLAND_DISPLAY=wayland-1 weston-info
interface: 'wl_drm', version: 2, name: 1
interface: 'wl_output', version: 3, name: 2
x: 0, y: 0, scale: 1,
physical_width: 0 mm, physical_height: 0 mm,
make: 'wayland', model: 'wayland',
subpixel_orientation: unknown, output_transform: normal,
mode:
width: 952 px, height: 521 px, refresh: 0.000 Hz,
flags: current
interface: 'wl_shm', version: 1, name: 3
formats: XRGB8888 ARGB8888
interface: 'gamma_control_manager', version: 1, name: 4
interface: 'orbital_screenshooter', version: 1, name: 5
interface: 'gtk_primary_selection_device_manager', version: 1, name: 6
interface: 'org_kde_kwin_idle', version: 1, name: 7

现在我们可以拍下那张截图了! 给它一个机会(wwwwww)!

我们现在已经接近完成了。下一篇文章将介绍 Surface 的概念,我们将用它们来渲染我们的第一个窗口。如果你在这篇文章中遇到任何问题,请联系我,[email protected],或者联系 wlroots 团队,#sway-devel。

本文及原文使用 CC-BY-SA 协议开放。