美文网首页
3. Wayland库的实现

3. Wayland库的实现

作者: 夕月风 | 来源:发表于2023-11-29 11:03 被阅读0次

[TOC]
我们在1.3章简单介绍过Wayland库——这是最流行的Wayland实现。本书的大部分内容适用于任何实现,但我们将用接下来的两章来让您熟悉这一实现。

Wayland软件包包括用于wayland-client和wayland-server的pkg-config规范——请查阅您的构建系统文档以了解如何链接它们。当然,大多数应用程序只会链接到其中一个。该库包括一些简单的原语(例如链表)和预先编译的wayland.xml版本——这是核心的Wayland协议。

我们将从介绍原语开始。

3.1 Wayland库的实用程序原语

在客户端和服务器库中常见的是wayland-util.h,它定义了许多结构、实用程序函数和宏,为Wayland应用程序建立了一些原语。其中包括:

  • 用于在生成的代码中序列化和反序列化Wayland协议消息的结构
  • 一个链表(wl_list)实现
  • 一个数组(wl_array)实现(与相应的Wayland原语相关联)
  • 用于转换Wayland标量(例如定点数)和C类型的实用程序
  • 从libwayland内部冒泡信息的调试日志设施

该头文件本身包含许多注释,其中包含相当好的文档-您应该自己阅读它们。我们将在接下来的几页中详细介绍如何应用这些原语。

3.2 wayland-scanner

Wayland软件包附带一个二进制文件:wayland-scanner。此工具用于从第2.3章讨论的Wayland协议XML文件生成C头文件和粘合代码。该工具在“wayland”包的构建过程中用于预生成核心协议wayland.xml的头文件和粘合代码。头文件成为wayland-client-protocol.h和wayland-server-protocol.h,不过你通常包括wayland-client.h和wayland-server.h而不是直接使用这些。

此工具的使用相当简单(可通过wayland-scanner -h进行总结),但可以总结如下。要生成客户端头文件:

wayland-scanner client-header < protocol.xml > protocol.h

要生成服务器端头文件:

wayland-scanner server-header < protocol.xml > protocol.h

要生成粘合代码:

wayland-scanner private-code < protocol.xml > protocol.c

不同的构建系统将采用不同的方法来配置自定义命令-请查阅您构建系统的文档。一般来说,您想在构建时运行wayland-scanner,然后将您的应用程序编译并链接到粘合代码。

如果您现在手头有任何Wayland协议,请继续进行(例如,wayland.xml可能在/usr/share/wayland中可用)。打开粘合代码和头文件,并在阅读以下章节时参考它,以了解libwayland中提供的原语如何在生成的代码中实际应用。

3.3 代理和资源

对象是客户端和服务器双方都知晓的实体,它具有一定的状态,通过协商在电线上进行更改。在客户端方面,libwayland通过wl_proxy接口引用这些对象。这些都是对抽象对象的实际友好的C“代理”,并提供间接供客户端使用的函数,以便将请求转换为电线的格式。如果您查看wayland-client-core.h文件,您会发现几个用于此目的的低级函数。一般来说,您不直接使用这些。

在服务器上,通过wl_resource对对象进行抽象,这是非常相似的,但具有额外的复杂性-服务器必须跟踪哪个对象属于哪个客户端。每个wl_resource由单个客户端拥有。除此之外,该接口非常相似,并为向相关客户端发送Marshall事件提供低级抽象。您在服务器上直接使用wl_resource的频率将比在客户端上直接使用wl_proxy的频率更高。这样使用的一个例子是,当您正在上下文之外操作资源时,获取对拥有该资源的wl_client的引用,或者在客户端尝试执行无效操作时发送协议错误。

再往上一层是另一组更高级别的接口,大多数Wayland客户端和服务器都与之交互以完成其大部分任务。我们将在下一部分中介绍它们。

3.4 接口和监听器

最后,我们达到了libwayland抽象的顶峰:接口和监听器。前几章讨论的想法-wl_proxy和wl_resource以及原始类型-是单例实现,它们存在于libwayland中,并且它们的存在为这一层提供支持。当您通过wayland-scanner运行XML文件时,它生成接口和监听器,以及它们之间和低级电报协议接口之间的粘合代码,所有这些都是针对每个高级协议中的接口的。

请记住,Wayland连接上的每个参与者都可以接收和发送消息。客户端正在监听事件并发送请求,而服务器正在监听请求并发送事件。每一方都在使用一个恰当地称为wl_listener的接口来监听另一方的消息。以下是这个接口的一个例子:

struct wl_surface_listener {
    /** surface enters an output */
    void (*enter)(void *data,
              struct wl_surface *wl_surface,
              struct wl_output *output);

    /** surface leaves an output */
    void (*leave)(void *data,
              struct wl_surface *wl_surface,
              struct wl_output *output);
};

这是wl_surface的客户端监听器。wayland-scanner用于生成此监听器的XML是:

<interface name="wl_surface" version="4">
  <event name="enter">
    <arg name="output"
      type="object"
      interface="wl_output"/>
  </event>

  <event name="leave">
    <arg name="output"
      type="object"
      interface="wl_output"/>
  </event>
  <!-- additional details omitted for brevity -->
</interface>

这些事件如何成为监听器接口应该相当清楚。每个函数指针都采用一些任意的用户数据,该事件所涉及的资源的引用以及该事件的参数。我们可以将监听器绑定到wl_surface上,如下所示:

static void wl_surface_enter(void *data,
        struct wl_surface *wl_surface, struct wl_output *output) {
    // ...
}

static void wl_surface_leave(void *data,
        struct wl_surface *wl_surface, struct wl_output *output) {
    // ...
}

static const struct wl_surface_listener surface_listener = {
    .enter = wl_surface_enter,
    .leave = wl_surface_leave,
};

// ...

struct wl_surface *surf;
wl_surface_add_listener(surf, &surface_listener, NULL);

wl_surface接口还定义了一些客户端可以为该表面提出的请求:

<interface name="wl_surface" version="4">
  <request name="attach">
    <arg name="buffer"
      type="object"
      interface="wl_buffer"
      allow-null="true"/>
    <arg name="x" type="int"/>
    <arg name="y" type="int"/>
  </request>
  <!-- additional details omitted for brevity -->
</interface>

wayland-scanner生成以下原型,以及Marshals此消息的粘合代码。

void wl_surface_attach(struct wl_surface *wl_surface,
    struct wl_buffer *buffer, int32_t x, int32_t y);

接口和监听器在服务器端代码上是相同的,但方向相反-它为请求生成监听器,并为事件生成粘合代码。当libwayland收到消息时,它会查找对象ID及其接口,然后使用该ID解码消息的其余部分。然后,它会在该对象上查找监听器并使用消息的参数调用您的函数。

这就是全部!我们经过了几层抽象才到达这里,但您现在应该理解了事件如何在您的服务器代码中启动,如何在电线上成为消息,被客户端理解,并分派到您的客户端代码中。然而,仍有一个未解决的问题。所有这些都假定您已经有了对Wayland对象的引用。您是如何获得这些引用的?

相关文章

  • Linux伪进阶之路

    系统环境:Archlinux+Wayland+lightdm+E22(Enlightenment)任务:安装在小米...

  • Wayland入门0:说明

    X X是Linux下默认的桌面协议,X是W(indows)的后一个字母,现在Wayland协议将补充和扩展X协议(...

  • 腾讯iOS面试题- 分析 一

    网络相关: 1. 项目使用过哪些网络库?用过ASIHttp库嘛 2. 断点续传怎么实现的?需要怎么设置 3. HT...

  • iOS打包.a静态库步骤

    打包静态库流程 1.创建静态库 2.实现类 3.公开.h文件 4.打包模拟器静态库 5.打包真机静态库 6.合并模...

  • Flask_login登陆 注销

    flask的扩展库中有一个Flaks_login库,可以快速实现登陆,注销功能 1.安装 2.登陆模版 3.后台 ...

  • 升职加薪的必备良品之玩转Spring事务源码

    今日内容: 1.什么是数据库的事务? 2.为什么说Spring的事务就是数据库的事务? 3. 实现Spring事务...

  • Python模块·PyMySQL数据库

    一、PyMySQL实现思路流程 1.建立连接2.创建游标:游标数据库操作的接口3.数据库操作(建表、插入数据、查询...

  • 秒杀思路思考

    1.表设计 2. 核心业务: 3. 基本实现 4. 优化点: ***************** 1. 查询商品库...

  • 分布式锁的三种实现方式

    1. 概述 2. 特点 3. 实现方式 4. 数据库实现4.1. 前提4.1.1. 乐观锁4.1.2. 悲观锁4....

  • robot自定义库

    1.文档结构,文件夹名使用库名,初始化文件使用库名,但是继承实现类 2.初始化函数 注意此处的注释就是库介绍3.实...

网友评论

      本文标题:3. Wayland库的实现

      本文链接:https://www.haomeiwen.com/subject/wootgdtx.html