4. Wayland中的display

现在,我们忽略了Wayland协议如何管理客户端和服务器之间对象的共同所有权的一个重要细节:这些对象是如何创建的。Wayland显示或wl_display在每个Wayland连接上隐式存在。它具有以下接口:

<interface name="wl_display" version="1">
  <request name="sync">
    <arg name="callback" type="new_id" interface="wl_callback"
       summary="callback object for the sync request"/>
  </request>

  <request name="get_registry">
    <arg name="registry" type="new_id" interface="wl_registry"
      summary="global registry object"/>
  </request>

  <event name="error">
    <arg name="object_id" type="object" summary="object where the error occurred"/>
    <arg name="code" type="uint" summary="error code"/>
    <arg name="message" type="string" summary="error description"/>
  </event>

  <enum name="error">
    <entry name="invalid_object" value="0" />
    <entry name="invalid_method" value="1" />
    <entry name="no_memory" value="2" />
    <entry name="implementation" value="3" />
  </enum>

  <event name="delete_id">
    <arg name="id" type="uint" summary="deleted object ID"/>
  </event>
</interface>

对于普通Wayland用户来说,这些中最有趣的是get_registry,我们将在下一章中详细讨论它。简而言之,注册表用于分配其他对象。接口的其余部分用于维护连接,除非您正在编写自己的libwayland替代品,否则它们通常不重要。

相反,本章将重点关注libwayland与wl_display对象相关联的一些函数,以建立和维护您的Wayland连接。这些函数用于操作libwayland的内部状态,而不是直接与电报协议请求和事件相关联。

我们将从最重要的函数开始:建立显示器。对于客户端,这将涵盖连接到服务器的实际过程,对于服务器,将是配置显示器以供客户端连接的过程。

4.1 创建display

打开你的文本编辑器——是时候编写我们的第一行代码了。

对于Wayland客户端
连接到Wayland服务器并创建一个wl_display来管理连接状态很容易:

#include <stdio.h>
#include <wayland-client.h>

int
main(int argc, char *argv[])
{
    struct wl_display *display = wl_display_connect(NULL);
    if (!display) {
        fprintf(stderr, "Failed to connect to Wayland display.\n");
        return 1;
    }
    fprintf(stderr, "Connection established!\n");

    wl_display_disconnect(display);
    return 0;
}

让我们编译并运行这个程序。假设你在阅读这篇文章时使用的是Wayland合成器,结果应该如下所示:

$ cc -o client client.c -lwayland-client
$ ./client
Connection established!

wl_display_connect是客户端建立Wayland连接的最常见方式。其签名是:

struct wl_display *wl_display_connect(const char *name);

“name”参数是Wayland显示器的名称,通常为“wayland-0”。您可以在我们的测试客户端中将NULL替换为该名称并自己尝试一下——很可能会起作用。这与$XDG_RUNTIME_DIR中的Unix套接字名称相对应。然而,在NULL的情况下,libwayland将:

  • 如果设置了WAYLAND_DISPLAY,则尝试连接到XDG_RUNTIME_DIR/WAYLAND_DISPLAY
  • 否则,尝试连接到XDG_RUNTIME_DIR/wayland-0
  • 否则,失败:(

这允许用户通过将$WAYLAND_DISPLAY设置为所需显示来指定要在其上运行客户端的Wayland显示。如果您有更复杂的要求,您还可以自己建立连接并从文件描述符创建Wayland显示:

struct wl_display *wl_display_connect_to_fd(int fd);

无论您是如何创建的显示器,您都可以通过wl_display_get_fd获得wl_display使用的文件描述符。

int wl_display_get_fd(struct wl_display *display);

Wayland服务端

对于服务器来说,这个过程也很简单。显示器的创建和绑定到套接字是分开的,以便在任何客户端能够连接到它之前,您有时间对显示器进行配置。这里再给出一个最小化的示例程序:

#include <stdio.h>
#include <wayland-server.h>

int
main(int argc, char *argv[])
{
    struct wl_display *display = wl_display_create();
    if (!display) {
        fprintf(stderr, "Unable to create Wayland display.\n");
        return 1;
    }

    const char *socket = wl_display_add_socket_auto(display);
    if (!socket) {
        fprintf(stderr, "Unable to add socket to Wayland display.\n");
        return 1;
    }

    fprintf(stderr, "Running Wayland display on %s\n", socket);
    wl_display_run(display);

    wl_display_destroy(display);
    return 0;
}

编译运行:

$ cc -o server server.c -lwayland-server
$ ./server &
Running Wayland display on wayland-1
$ WAYLAND_DISPLAY=wayland-1 ./client
Connection established!

使用wl_display_add_socket_auto将允许libwayland自动为显示器的名称做出决定,默认为wayland-0,或者wayland-n,具体取决于是否有其他Wayland合成器在XDG_RUNTIME_DIR中有套接字。然而,与客户端一样,您还有一些其他选项可以配置显示器:

int wl_display_add_socket(struct wl_display *display, const char *name);

int wl_display_add_socket_fd(struct wl_display *display, int sock_fd);

添加套接字后,调用wl_display_run将运行libwayland的内部事件循环并阻塞,直到调用wl_display_terminate。这个事件循环是什么?翻页了解!

4.2 加入事件循环

libwayland为Wayland服务器提供了自己的事件循环实现以利用,但维护人员已经认识到这是一个设计上的越位。对于客户端来说,没有这样的等价物。无论如何,Wayland服务器事件循环非常有用,即使它超出了范围。

Wayland服务端事件循环

libwayland-server创建的每个wl_display都有与之对应的wl_event_loop,您可以使用wl_display_get_event_loop来获取其引用。如果您正在编写新的Wayland合成器,您可能希望将其用作您唯一的事件循环。您可以使用wl_event_loop_add_fd向其添加文件描述符,使用wl_event_loop_add_timer添加计时器。它还通过wl_event_loop_add_signal处理信号,这非常方便。

将事件循环配置为您要监视的事件的配置,以响应该合成器必须响应的所有事件,您可以通过调用wl_display_run来一次性处理事件和分发Wayland客户端,这将处理事件循环并阻塞,直到显示器终止(通过wl_display_terminate)。大多数从Wayland开始构建的Wayland合成器(与从X11移植的不同)使用这种方法。

然而,也有可能将Wayland显示纳入您自己的事件循环。wl_display在内部使用事件循环来处理客户端,您可以选择自己监视Wayland事件循环,根据需要分发它,或者完全忽略它并手动处理客户端更新。如果您希望让Wayland事件循环自己照顾自己并将其视为自己事件循环的下属,您可以使用wl_event_loop_get_fd获取可轮询的文件描述符,然后在该文件描述符上有活动时调用wl_event_loop_dispatch来处理事件。您还需要在有需要写入客户端的数据时调用wl_display_flush_clients。

Wayland客户端事件循环

另一方面,libwayland-client没有自己的事件循环。然而,由于通常只有一个文件描述符,因此没有它更容易管理。如果Wayland事件是您的程序期望的唯一类型,那么这个简单的循环就足够了:

while (wl_display_dispatch(display) != -1) {
    /* This space deliberately left blank */
}

但是,如果您有更复杂的应用程序,您可以以任何您喜欢的方式构建自己的事件循环,并使用wl_display_get_fd获取Wayland显示的文件描述符。在POLLIN事件发生时,调用wl_display_dispatch处理传入事件。要刷新传出的请求,请调用wl_display_flush。

结尾

此时,您已经具备了设置Wayland显示和处理事件和请求所需的所有上下文。剩下的唯一一步是为与连接的另一方进行交谈分配对象。为此,我们使用注册表。在下章末尾,我们将拥有第一个有用的Wayland客户端!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 窗口管理器有好几种,stacking 、tiling 和 compositing 其中 瓦片式(tiling wi...
    LinuxDE阅读 7,478评论 0 4
  • Wayland协议是由几层抽象构建的。它从基本的线路协议格式开始,这是一种可解码的消息流,使用事先商定的接口。然后...
    夕月风阅读 227评论 0 0
  • Wayland是Unix类系统的下一代显示服务器,由可敬的Xorg-Server的校友设计和建造,是将您的应用程序...
    夕月风阅读 431评论 0 1
  • 如何扩展 wayland 协议 为了能够扩展 wayland 协议,首先需要理解 wayland 协议,并且知道怎...
    LinuxDE阅读 5,970评论 6 8
  • 桌面环境做了好几年,对 X 和 wayland 比较感兴趣,但是一直没有机会深入去看。正好我要离职了,在现在这个单...
    LinuxDE阅读 3,134评论 2 2