Wayland窗口系统

本文详细介绍了窗口系统的基础知识,包括XWindowSystem、Windows的DesktopWindowManager和macOS的QuartzCompositor。重点讲解了Wayland窗口协议,包括其基本概念、架构、通信方式、协议结构以及Wayland客户端和服务器的交互过程。此外,还分析了Wayland的协议实现和对象管理,以及客户端和服务器如何通过共享内存进行高效通信。
摘要由CSDN通过智能技术生成
1. 窗口系统
1.1 窗口系统简介

任何窗口系统的主要组件通常称为显示服务器(Display Server),也可以称作窗口服务器(Window Server)或合成器(Compositor)。在窗口中运行并显示其GUI的任何应用程序都是显示服务器的客户端。显示服务器及其客户端通过通信协议相互通信,通信协议通常称为显示服务器协议(Display Server Protocol)。显示服务器接收并处理输入事件,例如键盘、鼠标或触摸屏并将其传递给正确的客户端,显示服务器还负责将客户端内容输出到显示器。如下所示:

1.2 不同OS平台的窗口系统
1.2.1 X Window System

X窗口系统用于类Unix操作系统,使用C/S模型,服务器接受图形输出请求并且分发用户输入事件。服务器和客户端之间的通信协议可以通过网络进行操作:客户端和服务器可以在同一台机器上运行,也可以在不同的机器上运行,可能使用不同的架构和操作系统。如下所示:

1.2.2 Desktop Window Manager

DWM是微软Windows系统中的窗口管理器,它最初是为了实现新的“ Windows Aero ”用户体验的一部分而创建的,这允许诸如透明度,3D窗口切换等效果。DWM以不同的方式工作,具体取决于操作系统(Windows 7或Windows Vista)以及它使用的图形驱动程序版本(WDDM 1.0或1.1)。在Windows 7和WDDM 1.1驱动程序下,DWM仅将程序的缓冲区写入视频RAM,即使它是图形设备接口(GDI)程序。这是因为Windows 7为GDI 支持(有限的)硬件加速,并且这样做不需要在系统RAM中保留缓冲区的副本,以便CPU可以写入它。

1.2.3 Quartz Compositor

Quartz Compositor是macOS中的显示服务器(同时也是合成窗口管理器)。Quartz 2D,OpenGL,Core Image,QuickTime或其他进程的位图输出被写入特定的内存位置或后备存储区。然后,Compositor从后备存储区中读取数据,并将每个数据组合成一个用于显示的图像,将该图像写入图形卡的帧缓冲存储区。Quartz Compositor只接受栅格化数据,是唯一可以直接访问图形帧缓冲区的进程。

在管理单个窗口时,Quartz Compositor 从其渲染器接受窗口内容的位图图像及其位置。渲染器的选择取决于单个应用程序,尽管大多数使用Quartz 2D。

作为窗口管理器,Quartz Compositor还有一个事件队列,用于接收事件,例如击键和鼠标点击。Quartz Compositor从队列中获取事件,确定哪个进程拥有事件发生的窗口,并将事件传递给进程。

2. Wayland
2.1 Wayland简介

Wayland是一个合成器与客户端通信的窗口协议,以及该协议的C库实现。合成器可以是在Linux内核模式设置和evdev输入设备,X应用程序或Wayland客户端本身上运行的独立显示服务器。客户端可以是传统应用程序,X服务器或其他显示服务器。

Wayland协议遵循C/S模型,其中客户端是请求在屏幕上显示像素缓冲区的图形应用程序,并且服务器(合成器)是控制这些缓冲区的显示的服务提供者。

2.2 Wayland架构
2.2.1 Wayland整体架构

通过跟踪从输入设备活动到其影响屏幕上的内容这一整个过程来了解Wayland架构是一个不错的方法。如下所示:

  • 内核获取一个事件并将其发送给合成器

  • 合成器将该事件发送给需要处理该事件的客户端

  • 当客户端收到事件时,它会更新UI作为响应。接着客户端向合成器发送请求以指示其UI区域已经更新

  • 合成器收到客户端UI已更新请求,然后重新合成屏幕内容

2.2.2 Wayland协议架构

Wayland参考实现被设计为两层协议:

  • 一种底层协议,用于处理两个进程(客户端和合成器)之间的进程间通信,以及它们交换的数据的序列化过程。该层是基于消息的,通常使用内核IPC服务实现,比如Unix domain sockets。

  • 构建在其上的高级层协议,用于处理客户端和合成器需要交换的信息,以实现窗口系统的基本功能。该层实现为“异步面向对象的协议”。

Wayland协议的参考实现分为两个库:Wayland客户端调用libwayland-client库,Wayland合成器调用libwayland-server库。如下所示:

2.2.3 Wayland渲染方式

在Wayland架构中,客户端窗口内容的渲染是由客户端自己负责的,客户端可以使用软件渲染,也可以使用硬件渲染,比如OpenGL。它知道如何编程硬件并直接渲染到缓冲区。合成器反过来可以获取缓冲区,并将其用作纹理用于合成桌面。在初始设置之后,客户端只需要告诉合成器使用哪个缓冲区以及它何时何地将新内容呈现到其中。

这使应用程序有两种方法来更新其窗口内容:

  • 将新内容渲染到新缓冲区并告诉合成器使用新的而不是旧缓冲区。应用程序可以在每次需要更新窗口内容时分配新的缓冲区,或者它可以保留两个(或更多)缓冲区并在它们之间循环使用。缓冲区管理完全受应用程序控制。

  • 将新内容渲染到之前告诉合成器要使用的缓冲区中。虽然可以直接渲染到与合成器共享的缓冲区,但这可能会与合成器产生竞争。可能发生的情况是,重新绘制窗口内容可能会被重构桌面的合成器中断。如果应用程序在清除窗口之后但在渲染内容之前被中断,则合成器将从空白缓冲区进行纹理处理。结果是应用程序窗口将在空白窗口或半渲染内容之间闪烁。避免这种情况的传统方法是将新内容渲染到后台缓冲区,然后从那里复制到合成器。后台缓冲区可以在运行中分配,并且足够大以容纳新内容,或者应用程序可以保留缓冲区。同样,这也是由应用程序控制。

在任何一种情况下,应用程序必须告诉合成器哪个区域包含新内容。当应用程序直接呈现给共享缓冲区时,需要将更新的内容通知合成器。但是,当交换缓冲区时,合成器不会假设任何更改,并且在重新绘制桌面之前需要接受来自应用程序的请求。

2.2.4 Wayland项目组成

Wayland项目主要由4个部分组成:Wayland协议、Wayland参考C库实现、Wayland合成器参考实现Weston、Wayland和Weston一些demo。如下所示:

  • Wayland协议:合成器和客户端通信的协议。

  • Wayland参考C库实现:有4个库,libwayland-client、libwayland-server、libwayland-cursor、libwayland-egl。

  • Weston:主要包括窗口管理(shell),合成器(compositor)和输入管理几个部分。

  • Demo:主要是一些简单的客户端用例,用于测试Wayland协议以及Weston合成器。

3. Wayland协议
3.1 基本概念

Wayland协议被描述为“异步面向对象的协议”。 面向对象意味着合成器提供的服务是以一系列对象呈现的。每个对象实现一个接口,该接口具有名称,许多方法(称为请求)以及若干相关事件。客户端发往服务端的操作成为请求(request),反之成为一个事件(event)。每个请求和事件都有零个或多个参数,每个参数都有一个名称和一个数据类型。在请求不必等待同步回复或ACK这个意义上,协议是异步的,从而避免了往返延迟时间并提高了性能。如下所示:

如果对象的接口支持该请求,Wayland客户端可以对某个对象发出请求(方法调用)。客户端还必须为此类请求的参数提供所需的数据。这是客户端从合成器请求服务的方式。合成器通过对象发出事件(也可能带有参数)将信息发送回客户端。这些事件可以由合成器发出,作为对特定请求的响应,或者异步地发生(例如来自输入设备的事件)或状态更改事件。错误事件也由合成器发出。

为了使客户端能够向对象发出请求,它首先需要告诉服务器它将用于标识该对象的ID号。合成器中有两种类型的对象:全局对象和非全局对象。合成器在创建客户端时(以及在销毁它们时)将全局对象通告给客户端,而非全局对象通常由已作为其功能的一部分的其他对象创建。

接口以及其请求和事件是定义Wayland协议的核心元素。协议的每个版本都包含一组接口,以及它们的请求和事件。另外,Wayland合成器也可以定义和实现自己的接口以用来支持新请求和事件,从而将功能扩展到核心协议之外。为了便于更改协议,每个接口除了名称外还包含“版本号”属性,此属性允许区分同一接口的不同变体。

3.2 生成协议头文件

Wayland协议定义为xml格式文件,文件在protocol目录,通信协议实现在src目录。它主要编译出三个库,libwayland-client,libwayland-server和libwayland-cursor。第一个为协议的client端实现,第二个为协议的server端实现,第三个是协议中鼠标相关处理实现。编译时会首先编译出wayland-scanner这个可执行文件,它利用expat这个库来解析xml文件,将wayland.xml生成相应的wayland-protocol.c,wayland-client-protocol.h和wayland-server-protocol.h。它们会被Wayland的client和server在编译时用到。同时wayland-scanner在生成Weston中的Wayland扩展协议中起同样作用。如下所示:

3.3 协议通信信息格式

Wayland协议是一种异步面向对象的协议。所有请求都是对某些对象的方法调用。请求包含唯一标识服务器上对象的对象ID。每个对象都实现一个接口,请求包含一个操作码,用于标识要调用的接口中的哪个方法。

该协议是基于消息的。客户端发送到服务器的消息称为请求。从服务器到客户端的消息称为事件。消息有许多参数,每个参数都有一定的类型。

每条消息有3个部分组成,如下所示:

3.3.1 信息头部

信息头部由两个部分组成:

  • 第一个字数据表示发送对象的ID(32位数据)。

  • 第二个字数据由2个16位数据组成。高16位数据表示整条信息的大小,以字节为单位;低16位数据表示发送的请求或者事件的操作码。

3.3.2 信息主体

余下的数据称之为payload区域,存放着请求/事件的参数值。每个参数都是32位数据对齐的,如果不对齐需要填充数据对齐,填充的数值未作规定,默认是0。

传输的参数的类型共有8种,如下所示:

  • int,uint:表示有符号/无符号32位数据的值。

  • fixed:它是带符号的十进制类型,提供1位符号位,23位整数精度和8位小数精度。可以通过相关API和double、int类型数据相互转换。

  • string:以无符号32位长度开始,然后跟着字符串内容,包括终止空字符,然后填充对齐到32位边界。如下所示:

  • object:32位对象ID。

  • new_id:同样还是32位对象ID。当客户端发起请求时(该请求需要服务端创建新对象以和客户端一一对应),客户端确定对象ID,接着将此ID告知服务端,服务端用此ID创建和客户端一一映射的对象。

  • array:以无符号32位长度开始,然后跟着数组内容,然后填充对齐到32位边界。如下所示:

  • fd:文件描述符不存储在payload中,而是存储在UNIX domain socket消息的辅助数据中(msg_control)。

3.4 协议接口

协议接口(interface)是客户端和服务端交互的入口。每个接口都有自己的名字、版本、方法表(request请求表)、事件表(event事件表)等信息。Wayland协议包含了一系列核心接口,比如wl_display、wl_registry等。通过一个给定的接口就可以知道该接口有哪些方法和事件,这是最重要的两个属性。

3.4.1 wl_display

我们主要关注下接口中有哪些reauest和event。

Request:

  • sync:同步请求。该请求返回一个wl_callback对象。这个接口的作用是提供客户端一个确认它前面所有的请求都被处理的保证。

  • get_registry:此请求创建并返回一个wl_registry对象,该对象允许客户端列出并绑定合成器中可用的全局对象(服务)。

Event:

  • error:用于发生不可恢复错误时发送错误事件。

  • delete_id:当客户端删除对象时,服务器将发送此事件以确认客户端已看到删除请求。当客户端收到此事件时,它将知道它可以安全地重用对象ID。

3.4.2 wl_registry

Request:

  • bind:使用指定的名称作为标识符,将新的客户端创建的对象绑定到服务器。

Event:

  • global:通知客户端服务端有哪些全局对象。

  • global_remove:通知客户端已删除的全局对象。此事件通知客户端全局对象不再可用。如果客户端使用绑定请求绑定到全局对象,则客户端现在应该销毁该对象。该对象仍然有效,但对该对象的请求将被忽略,直到客户端销毁该对象。

3.4.3 wl_callback

Request:

  • 无。

Event:

  • done:完成相关请求后通知客户端。

3.4.4 wl_compositor

Request:

  • create_surface:让合成器创建一个新的surface,此请求返回一个wl_surface对象。此surface表示窗口中的内容,不代表窗口本身,窗口本身由另外一个对象表示。

  • create_region:让合成器创建一个新的region,此请求返回一个wl_surface对象。这个对象的作用是描述一块wl_surface 上的区域,以便对这个区域进行操作。

Event:

  • 无。

3.4.5 wl_shm_pool

wl_shm_pool封装了合成器和客户端之间共享的一块内存。通过wl_shm_pool,客户端可以分配共享内存wl_buffer。通过同一个池创建的所有对象共享相同的底层映射内存。重复利用映射内存在交互式调整surface大小或许多小缓冲区时非常有用。

Request:

  • create_buffer:通过共享内存的空间来创建窗口绘制使用的 wl_buffer。

  • destroy:请求销毁共享内存池。当从此池创建的所有缓冲区都消失后,将释放已经映射的内存。

  • resize:此请求将使服务器从使用新的大小重新映射共享内存。此请求只能用于使池更大的请求。

Event:

无。

3.4.6 wl_shm

Request:

  • create_pool:创建一个新的wl_shm_pool对象。该池可用于创建基于共享内存的缓冲区对象。服务器和客户端通过mmap文件描述符fd来实现内存共享。

Event:

  • format:通知客户端有关可用于缓冲区的有效像素格式。已知格式包括argb8888和xrgb8888。

3.4.7 wl_buffer

缓冲区为wl_surface提供内容。缓冲区是通过接口创建,例如wl_drm,wl_shm等。它具有宽度和高度,可以附加到wl_surface,但是客户端提供和更新内容的机制由缓冲区接口定义。

Request:

  • destroy:请求销毁一个wl_buffer。

Event:

  • release:当合成器不再使用此wl_buffer时发送此事件。客户端然后可以自由地重用或销毁此缓冲区及其后备存储区。

3.4.8 wl_shell

这个是管理真正窗口的服务接口类。 通过这个接口,可以创建某一个wl_surface显示用窗口。目前该接口已经被官方放弃,建议使用xdg_shell替代。

Request:

  • get_shell_surface:请求创建指定wl_surface 的显示窗口对象wl_shell_surface。 一般情况下,一个wl_surface对应一个wl_shell_surface。

Event:无。

3.4.9 wl_shell_surface

此接口提供了处理窗口的请求,比如设置为顶层窗口、最大化、全屏化等。

Reauest:

  • pong、move、resize、set_toplevel、transient、set_transient、set_fullscreen、set_popup、set_maximized、set_title、set_class。

Event:

  • ping、configure、popup_done。

3.4.10 wl_surface

surface是显示在屏幕上的矩形区域。它具有位置,大小和像素内容。此接口提供对窗口内容的操作,比如销毁、缩放等。

Request:

  • destroy、attach、damage、frame、set_opaque_region、set_input_region、set_buffer_transform、set_buffer_scale、damage_buffer、commit。

Event:

  • enter、leave。

3.5 协议对象

协议对象在服务端和客户端是一一对应的,并且协议对象是对接口的进一步封装。每个对象都有一个ID,此ID在服务端和客户端是相同的(其实就是数组下标),用于将两边的对象进行一一映射。

对象在服务端分为两类,全局对象和非全局对象。全局对象代表着服务端能提供的服务,比如wl_compositor、wl_shm、wl_shell等。非全局对象由wl_display接口对象创建出来。

4. Wayland协议实现浅析
4.1 几个重要的数据结构
4.1.1 wl_object

wl_object是一个很重要的数据结构,在客户端和服务端都有此数据结构的封装,是wl_proxy、wl_resource数据结构的第一个成员,wayland中所有对象的概念都是基于wl_object而言的。wl_object包括interface、implementation、id三个重要成员,每个成员的作用如下:

  • interface:是客户端和服务端交互的接口。Interface主要包含以下几项内容:

  1. name:接口的名字。

  1. version:此接口的版本号。

  1. request信息表:用于表明有哪些request以及每项request具体参数的类型。

  1. event信息表:类似request信息表,用于表明有哪些event事件以及每项event具体参数的类型。

  • implementation:在服务端此成员表示request方法的具体实现,在客户端此成员表示event事件的具体实现。

  • id:该object的ID,用于client/server端索引此object,服务端和客户端就是通过此ID建立映射。

如下所示:

4.1.2 wl_proxy

这是wl_object在客户端的封装,wayland客户端的对象都是对wl_proxy进一步的封装。wl_proxy主要包含以下成员:

  • object:wl_object,通过此成员可以获得interface等信息。

  • display:wl_display,服务端和客户端启动后最先创建的就是wl_display。

  • version:对象的版本。

4.1.3 wl_resource

这是wl_object在服务端的封装,wayland服务端的对象都是对wl_resource进一步的封装。wl_resource主要包含以下成员:

  • object:wl_object,通过此成员可以获得interface等信息。

  • destroy:用于对象销毁时回调的销毁函数。

  • link:用于将对象连接成链表。

  • client:wl_client,每有一个客户端连接到服务端时,在服务端就会创建一个wl_client结构,用于表示客户端的信息。

4.1.4 wl_global

wl_global用于表示服务端的全局对象,一个全局对象就表示服务端提供的一个服务,比如wl_compositor、wl_shm、wl_shell等。wl_global主要包括以下内容:

  • display:wl_display,服务端和客户端启动后最先创建的就是wl_display。

  • interface:wl_interface,客户端和服务端交互的接口。

  • name:全局对象的名字。

  • version:全局对象的版本。

  • bind:在wl_registry接口进行bind这个request这个操作时会回调wl_global中的bind回调函数。

  • link:用于将全局对象连接成链表。

4.1.5 wl_array

动态数组,数组中的每一项内容都是服务端和客户端对象数据结构的地址,也就是说,wl_array其实就是一个指针数组。在服务端和客户端的对象通过数组下标建立映射关系,也就是说,同一个对象在服务端和客户端数组中的位置是相同的,这样在client/server两端进行对象传递时,只需要传递数组下标就可以了。当数组内容满了的时候,如果继续插入数据会自动扩充数组的大小。wl_array的内容如下:

  • size:数组已经使用的空间大小。

  • alloc:整个数组的空间大小。

  • data:实际数据缓存区地址。

client/server端的对象映射关系如下所示:

需要注意的是,不管服务端还是客户端,映射表中的第0项都是空的,新的对象从第一项开始。

4.1.6 wl_map

wl_map是对wl_array的封装,服务端和客户端都有此数据结构,主要成员如下:

  • client_entries:wl_array类型,客户端使用。

  • server_entries:wl_array类型,服务端使用。

  • side:用于表示当前的wl_map是服务端还是客户端的。

4.1.7 wl_buffer

wl_buffer用于缓存客户端和服务端通信数据,通信数据格式见3.3章节。此buffer不同是环形缓冲区,不同于wl_array,如果填满了会回到起始处继续填充。wl_buffer包含的内容如下:

  • data[4096]:这是4KB的缓存区。

  • head:用于表示当前缓存中待发送数据的位置。

  • tail:用于表示当前缓存中已经发送完后数据的位置。

4.1.8 wl_connection

wl_connection是对wl_buffer进一步的封装,当服务端和客户端需要发送和接受数据时,都会对wl_connection数据结构进行操作。wl_connection的内容如下:

  • in:wl_buffer类型,用于缓存接受到的数据。

  • out:wl_buffer类型,用于缓存发送的数据。

  • fds_in:wl_buffer类型,如果要接收的数据有文件描述符类参数,缓存在fds_in中。

  • fds_out:wl_buffer类型,如果要发送的数据有文件描述符类参数,缓存在fds_out中。

  • fd:表示已经建立连接的socket fd。

  • want_flush:表示缓存区中的数据是否需要强制发送。

客户端和服务端通信的示意图如下所示:

4.1.9 wl_event_source

wl_event_source由服务端使用,服务端启动后会通过epool机制等待一系列的事件信息,wl_event_source就表示某个等待的事件的信息,其内容如下:

  • interface:wl_event_source_interface类型,当事件激活时会调用interface中的dispatch函数。

  • loop:wl_event_loop类型,用于描述服务端循环等待事件的epool fd相关信息。

  • link:用于形成链表。

  • fd:等待的事件fd。

服务端真正使用的表示事件资源的数据结构会对wl_event_source做进一步封装,比如wl_event_source_fd,表示等待fd可读可写事件。wl_event_source_fd有一个func成员,此成员会被wl_event_source中的interface中的dispatch函数调用,比如当有客户端链接socket fd时,此回调函数是socket_data,当客户端有数据通信时,此回调函数是wl_client_connection_data。

4.1.10 wl_closure

wl_closure用于表示函数调用信息和要调用的函数的参数信息。此数据结构是一个非常重要的数据结构,客户端和服务端在发送前都会先将数据组织到wl_closure数据结构中,然后由此数据结构解析到wl_connection中进行发送;接收时会将wl_connection中的原始数据解析成wl_closure数据结构,然后进行函数调用。

wl_closure内容如下:

  • count:表示要调用的函数中的参数个数。

  • message:表示request/event信息表。

  • opcode:表示request/event信息表中的哪一个。

  • sender_id:发送对象的ID。

  • args[20]:函数调用的每个参数值都会存放在args数组中,每次最多20个参数。

  • link:用于形成链表。

  • proxy:表明是哪个对象。

通过wl_closure进行数据通信过程示意如下所示:

4.2 几个重要的链表
4.2.1 global_list

global_list用于将服务端的所有全局对象连接成链表,在客户端进行获取注册表操作时会将全局对象链表中的每一个全局对象信息发送给客户端。global_list链表头是在服务端的wl_display数据结构中,如下所示:

4.2.2 socket_list

服务端使用,socket_list用于将所有监听的socket信息连接成链表,一般情况下链表中只有一个监听的socket,名字默认为“wayland-0”,如下所示:

4.2.3 client_list

服务端使用,每当有一个客户端和服务端连接时,服务端就会创建一个wl_client数据结构,用于表示连接信息。wl_client主要包含以下内容:

  • wl_connection:发送/接收数据都是缓存在wl_connection中。

  • wl_event_source_fd:用于表示已经连接的client fd信息。

  • wl_resource:服务端的wl_display对象。

  • link:用于形成链表。

  • wl_map:用于client/server进行映射对象。

如下所示:

4.2.4 registry_resource_list

服务端使用,每当客户端发送get_registry这个request时,服务端都会创建一个新的wl_ resource对象,这些wl_ resource对象通过registry_resource_list形成链表,如下所示:

4.2.5 display_queue

客户端使用,当客户端收到服务端发送的数据后,将其解析成wl_closure数据结构,然后将wl_closure插入到display_queue中。随后在客户端dispatch_queue的时候会将display_queue中的wl_closure取出解析进行函数调用。如下所示:

4.2.6 default_queue

default_queue作用和display_queue一样,只是在收到服务端发送的数据后,如果解析出的发送对象proxy就是客户端wl_display中的proxy,那么就会将wl_closure插入到display_queue中,否则插入到default_queue中。

dispatch_queue时会首先处理display_queue中的wl_closure,然后再处理default_queue中的wl_closure。

4.3 跨进程调用

客户端和服务端跨进程进行函数调用的大致流程如下所示:

4.3.1 wl_closure_marshal()

创建wl_closure数据结构,并根据具体的参数初始化。客户端/服务端在发送数据之前都需要调用此函数将要发送的参数等信息组织到wl_closure数据结构中。

4.3.2 wl_connection_write()

将wl_closure数据结构解析成具体要发送的数据填入到wl_connection中。在这个函数中会将对象指针替换成对象ID,以及对fd类型参数做特殊处理等。

4.3.3 wl_conntction_flush()

将wl_buffer中缓存的数据通过sendmsg接口发送出去。

4.3.4 wl_connection_read()

通过recvmsg接口将socket中的数据接收到wl_buffer中。

4.3.5 wl_closure_demarshal()

将wl_connection缓存中的数据解析成wl_closure数据结构,用来传递给wl_closure_invoke进行函数调用。每一条IPC信息都会被解析成一个wl_closure数据结构。

4.3.6 wl_closure_invoke()

根据wl_closure数据结构进行真正的函数调用,注意,这个函数中使用了libffi接口以作为函数调用的跳板。

4.4 Server端IPC信息循环处理流程
  • Server端在进行一些初始化操作之后会阻塞在wl_event_loop_dispatch中的epool_wait上。

  • epool_wait主要在等待两个事件:

  1. listen socket fd,如果有client连接,调用socket_data处理。

  1. connect socket fd,如果有client传送数据,调用wl_client_connection_data处理。

4.5 Client端IPC信息循环处理流程
  • Client端在进行初始化后调用wl_display_dispatch_queue。

  • Client阻塞在wl_display_poll中的poll上,等待server端发送数据。

  • 如果server端有数据传送,则调用read_events,最终调用到queue_event,主要做以下几件事:

  1. 将收到的数据组织成wl_closure数据结构。

  1. 将wl_closure插入到queue->event_list中。

  1. 这里有两个queue:display_queue和default_queue。具体插到哪个queue请参见2.5和4.2.6章节。

  • 调用dispatch_queue,首先处理display_queue,然后处理default_queue。主要是将queue中的wl_closure逐个进行解析,然后进行真正的函数调用。

4.6 基于SHM机制传递窗口
  • 客户端首先打开一个临时文件。

  • 然后通过ftruncate改变文件的大小,这个大小根据实际的窗口大小决定。

  • 客户端mmap临时文件fd,客户端通过socket机制将此fd发送给服务端。

  • 服务端收到fd后,同样mmap此fd,那么客户端和服务端分别使用mmap后获得的地址来访问同一块共享内存区。

  • 客户端对共享内存区进行渲染绘制,完成后通知服务端。

  • 服务端拿到共享内存区数据进行合成。

5. Demo合成器、客户端实现简析
5.1 demo合成器分析
5.1.1 wl_display_create

此函数主要进行如下工作:

  • 分配wl_display结构体空间。

  • 初始化event_loop,event_loop是服务端用于循环处理各种等待事件的机制。

  • 初始化global_list、socket_list等各种链表。

  • 初始化shm formats array,这个数组中记录了服务端将以何种格式解析共享内存区中的数据。

5.1.2 wl_display_add_socket_auto

此函数主要进行如下工作:

  • 创建wayland lock文件并锁住此文件,一般名为wayland-0.lock。

  • 创建、绑定、监听socket,名字一般为wayland-0。

  • 将上个步骤创建的wayland socket fd加入到epool中监听。

  • 将wl_socket加入到display的socket_list链表中。

5.1.3 wl_global_create

这个函数负责创建全局对象并将其插入到链表中。

  • 对interface的版本做检查。

  • 创建struct wl_global结构体空间并初始化。

  • 将全局对象插入到display中的global_list中。

  • 创建新全局对象后,给每个客户端发送registry global事件,通知客户端服务端有新全局对象创建了。

demo合成器创建了3个全局对象:wl_compositor_interface、wl_shell_interface、wl_shm_interface。每个全局对象创建的时候都会有一个bind回调函数,此函数在wl_registry对象进行bind request操作时被调用,主要作用就是根据全局对象来创建其服务端对应的resource,并设置resource对应的request实现函数。

5.1.4 wl_display_init_shm

这个函数内部调用wl_global_create来创建wl_shm_interface全局对象。

5.1.5 wl_display_add_shm_format

此函数用来设置服务端支持的共享内存像素数据格式,默认支持ARGB8888和XRGB8888。

这个函数内部调用wl_array_add,用来在wl_array中预留指定大小的空间并返回此空间的地址,这样用户就可以通过这个地址向这个空间中填写数据。

5.1.6 wl_display_run
  • 首先调用wl_display_flush_clients将client_list链表中所有客户端缓存区中的数据通过socket接口发送出去。

  • 接着调用wl_event_loop_dispatch等待接收服务端的数据。等待的事件主要是:

  1. listen socket fd,用于监听客户端连接,如果有连接,回调socket_data函数。

  1. connect socket fd,用于处理客户端数据通信,如果有数据,回调wl_client_connection_data函数。

  • 回到步骤1循环处理。

5.1.7 socket_data
  • 通过accept获得与客户端通讯的fd。

  • 创建wl_client结构,并初始化。

  • 将wl_client结构插入client_list链表中。

5.1.8 wl_client_connection_data
  • wl_connection_read:通过recvmsg将数据读取到wl_connection的缓存区中。

  • wl_connection_demarshal:将数据组织成wl_closure结构。

  • wl_closure_invoke:根据wl_closure结构进行函数调用。

5.2 demo客户端分析
5.2.1 wl_display_connect
  • 连接到服务端创建的“wayland-0”socket接口。

  • 创建并初始化wl_display数据结构。

5.2.2 wl_display_get_registry
  • 向服务端发送wl_display对象的get_registry请求。

  • 创建wl_registry对象。

5.2.3 wl_registry_add_listener
  • 设置wl_registry对象的event实现函数。

5.2.4 wl_display_roundtrip
  • 向服务端发送wl_display对象的sync请求。

  • 创建wl_callback对象。

  • 设置wl_callback对象的event实现函数。

  • 将客户端缓冲区的数据通过socket发送出去。

  • 等待接收服务端发送的数据。

  • 处理服务端发送的事件。

5.2.5 create_window
  • wl_compositor_create_surface:向服务端发送wl_compositor对象的create_surface请求,同时创建wl_surface对象。

  • wl_shell_get_shell_surface:向服务端发送wl_shell对象的get_shell_surface请求,同时创建wl_shell_surface对象。

  • wl_shell_surface_add_listener:设置wl_shell_surface对象的event实现函数。

  • 创建临时文件。

  • 通过ftruncate设置临时文件大小。

  • 通过mmap映射临时文件。

  • wl_shm_create_pool:向服务端发送wl_shm对象的create_pool请求。

  • 创建wl_shm_pool对象。

  • wl_shm_pool_create_buffer:向服务端发送wl_shm_pool对象的create_buffer请求。

5.2.6 draw_window
  • 根据create_window中mmap出来的共享内存区渲染像素数据。

  • wl_surface_attach:向服务端发送wl_surface对象的attach请求。

  • wl_surface_damage:向服务端发送wl_surface对象的damage请求。

  • wl_surface_commit:向服务端发送wl_surface对象的commit请求。

5.2.7 wl_display_dispatch
  • 将客户端缓冲区的数据通过socket发送出去。

  • 等待接收服务端发送的数据。

  • 处理服务端发送的事件。

  • 回到步骤1循环处理。

原文地址:http://www.databusworld.cn/9895.html

风起时~微凉
关注 关注
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wayland学习(1)-协议解析工具实现
LK1993的博客
04-11 3047
 wayland核心协议为wayland/protocol/wayland.xml,其中部分代码如下所示: <interface name="wl_display" version="1"> <description summary="core global object"> The core global object. This is a spe...
wayland(xdg_wm_base) + egl + opengles 最简实例(一)
lh0616的博客
01-21 1762
文章目录前言一、ubuntu 下相关环境准备1. 获取 xdg_wm_base 依赖的相关文件2. 查看 ubuntu 上安装的opengles 版本3. 查看 weston 所支持的 窗口shell 接口种类二、xdg_wm_base 介绍二、egl_wayland_demo1.egl_wayland_demo2_0.c2.egl_wayland_demo3_0.c3. xdg-shell-protocol.c和 xdg-shell-client-protocol.h4. 编译和运行4.1 编译4.2 运
Wayland中跨进程调用过程
风起时~微凉的博客
03-27 1513
Wayland跨进程调用
wayland client surface窗口创建基本流程
performance
08-20 4807
文章目录步骤基本接口和协议接口 步骤 client通过wl_display_connect连接到wayland server并且得到wl_display。 client通过wl_display_get_registry即可获取到server提供的所有基本接口(如wl_xxxx)和wayland协议接口(如xdg等协议定义的接口)。client根据自己需求来绑定这些接口,这些接口绑定后,clien...
探索未来桌面:强力推荐 sway —— 高效轻量的 Wayland 组合器
最新发布
gitblog_01031的博客
08-10 568
探索未来桌面:强力推荐 sway —— 高效轻量的 Wayland 组合器 项目地址:https://gitcode.com/gh_mirrors/swa/sway 项目介绍 sway 是一款兼容 i3 的 Wayland 组合器,专为那些追求高效且对现代图形系统有深入理解的用户而设计。这个项目不仅旨在提供一个稳定的桌面环境,还致力于通过开源和社区驱动的方式推动 Linux 桌面的发展。从初学者到...
QtWayland
脸盆的笔记
07-11 1万+
什么是QtWayland? QtWayland是封装了Wayland功能的Qt 5模块。QtWayland被分为一个客户端(client)和一个服务端(server)。客户端是wayland平台插件,提供了运行Wayland客户端Qt程序的方法。服务端是QtCompositor应用程序接口(API),允许用户编写自己的compositors。 什么是Wayland Wayland是一个用C库
waysome:Wayland窗口管理器
07-04
任性 注意:Waysome 正在进行中,尚未准备好或可用。 Waysome 是一个使用 Wayland窗口管理器。 它专为高级用户和喜欢以原子方式配置其窗口管理器的人而设计。 Waysome 是作为一个学期项目而开发的。 Waysome 没有定义任何行为。 它可以通过 API 进行配置和编写脚本,从而允许用户定义平铺、浮动和整体行为。 例如,如果您希望它的行为类似于 ,则可以通过这种方式对其进行配置。 您还可以将其配置为像 、 或其他任何东西。 您可以编写脚本,以全新的方式进行平铺,以满足您的每一点需求。 因此,waysome 可以被认为是平铺窗口管理器的“框架”。 然而,最小配置将随存储库一起提供。 贡献 如果你想为 waysome 做出贡献,请阅读 CONTRIBUTING 文件。 执照 Waysome 根据 LGPLv2 条款分发,有关更多信息,请参阅 LICENSE 文
wayland窗口显示
u012794472的专栏
05-19 3019
我们westonsimple_shm案例为例 连接server: wl_display_connect 接口通过socket建立与Server端的连接返回wl_display,display->registry = wl_display_get_registry(display->display) // 申请创建registry,得到代理对象wl_registry。这个个对象相当于Client在Server端放的一个用于嗅探资源的Observer。Client通过它得到Server端有哪些Gl
wm:[WIP] 最小浮动 Wayland 窗口管理器
05-31
西马 还是需要一个名字。 还有一句口头禅。 特征 还没有。 建造 您将需要以下内容: 韦兰 (也在) 我在自己的 fork 中添加了一些对 swc 至关重要的东西,所以除非我的更改合并到主线 swc 中,否则您将需要我的。 (也在) 库 libevdev libxkbcommon 库输入 libudev xlib(用于解析密钥) libxcb(用于 XWayland) xcb-util-wm(用于 XWayland) 像素人 Linux >= 3.12 构建和安装 swc 后,运行 make clean && make 建立wm。 用法 还没有。 去做 绑定swc的东西 制作可以处理窗口的工作 Wayland 显示器 从配置文件解析键绑定和命令 窗口移动 窗户翘曲 产卵 焦点改变 调整大小 分组的东西 监控东西 重新加载设置 退出 自定义修
探索未来桌面:PaperWM - 轻量级、自定义化的Wayland窗口管理器
gitblog_00060的博客
03-23 1187
探索未来桌面:PaperWM - 轻量级、自定义化的Wayland窗口管理器 PaperWMTiled scrollable window management for Gnome Shell项目地址:https://gitcode.com/gh_mirrors/pa/PaperWM 如果你是一位对Linux系统有深入理解的开发者或用户,热爱探索新的桌面体验,那么PaperWM可能正是你需要的。...
sway-config:我的摇摆配置(wayland平铺窗口管理器)
03-15
sway-config:我的摇摆配置(wayland平铺窗口管理器)
pywm:使用wlroots的Wayland窗口管理器-旨在处理python中的实际布局逻辑,从而实现易于访问的wm概念
04-12
PyWM-基于Python的Wayland窗口管理器 即将提供的文件 地位 见[TESTS.org] 正在安装 安装PyWM sudo pip3 install -v git+https://github.com/jbuchermn/pywm 启动触摸板并运行 确保您的用户在正确的组中 ls -al /dev/input/event* 附带说明,对于Wayland合成器而言,这通常不是必需的,因为可以通过systemd-logind或seatd或类似方式访问设备。 但是python evdev模块不允许在给定文件描述符的情况下进行实例化(只有它自己打开的路径),因此在这种情况下将无法再使用该模块(此外,在第一个方面,没有简单的方法可以实现该目的)文件描述符到Python端)。 同样, wlroots (后端中的libinput )不会将触摸板显示为它们的状态(任何数量的并行插槽的touc
壁炉:用锈写成的模块化Wayland窗口管理器
02-05
壁炉:用锈写成的模块化Wayland窗口管理器
KWin 是一个易于使用但灵活的复合窗口管理器,用于 Linux 上的 Xorg 窗口系统Wayland、X11)
03-16
KWin 是一个易于使用但灵活的复合窗口管理器,用于 Linux 上的 Xorg 窗口系统Wayland、X11)。它的主要用途是与桌面 Shell(例如 KDE Plasma 桌面)结合使用。KWin旨在让路走开;用户根本不应该注意到他们使用窗口...
wayland v1.3协议说明
02-01
Wayland的设计旨在解决X Window系统在安全性、性能和现代图形硬件支持方面的一些问题。 1. 显示服务器协议 Wayland 协议定义了显示服务器和其客户端之间的通信规范。这些通信通常涉及窗口管理、输入设备事件处理...
Ubuntu21.04 Wayland 屏幕分享录制问题
lsheevyfg的专栏
07-29 884
从Ubuntu21.04开始, 系统默认的显示服务器Wayland, 不再是xorg, 这就导致以前所有基于x window的屏幕采集工具都不能使用,需要针对Wayland开发新的屏幕采集实现。目前看来Wayland可能是个趋势,说不定将来国产操作系统也会切换到Wayland上去。未雨绸缪, 自己的推送采集SDK先提前支持上. 通过查找各种资料,推送SDK算是支持了,对外提供的调用SDK代码和以前一样。下面是部分调用片段: NT_HANDLE push_handl...
Wayland入门9:第一个窗口
qq_26056015的博客
02-23 1585
前面已经可以成功的连接服务器了。本文介绍如何显示一个窗口Wayland窗口绘制有两种方法:1) 共享内存方式(SHM)、2)EGL。 要想使用EGL,你得会EGL,还得先会OpenGL,这两个哪一个工程量都不小。本文使用方式1绘制窗口(第二种方法等OpenGL开发系列和EGL开发系列更新完再说)。 窗口 先将上一篇的代码拿过来,当然不需要输出所有的registry信息。 所以将 printf("Got a registry event for %s id %d\n", interface, id);
Wayland与Weston简介
热门推荐
世事难料,保持低调
08-08 2万+
简单地说,Wayland是一套display server(Wayland compositor)与client间的通信协议,而Weston是Wayland compositor的参考实现。其官网为http://wayland.freedesktop.org/。它们定位于在Linux上替换X图形系统。X图形系统经历了30年左右的发展,其设计在今天看来已略显陈旧。在X系统中,X Server作为中心
Wayland入门14:窗口操作
qq_26056015的博客
03-21 1159
在上一篇文章中,我们介绍的鼠标的基本操作,但是会发现已实现的操作只能捕获鼠标的位置和进入离开窗口状态,本文来实现捕获鼠标的点击状态。 先把第9篇的基本窗口的代码拿过来,因为只是实现功能,那么其他的功能没有最好。 在main()函数中,可以发现 shell_surface = wl_shell_get_shell_surface(shell, surface); if (shell_surface == NULL) { fprintf(stderr, "Can't create shell surface\
Qt与Linux嵌入式窗口系统开发详解
此外,书中还涵盖了多种窗口系统协议和标准,如X11和Wayland,以及它们与Qt的集成。 书中的主要内容分为几个部分,首先介绍了Qt库的基本概念和使用方法,然后详细讲解在Linux内核上启动和运行Qt窗口系统的过程。...
写文章

热门文章

  • 十大经典排序算法 31261
  • QJsonObject和QString互转 11955
  • QMap的遍历 9687
  • qml简介 8694
  • Qt国际化(lupdate/linguits/lrelease)生成.ts和转换成.qm文件 6880

分类专栏

  • 操作系统 5篇
  • 算法 10篇
  • Qt 51篇
  • 面试题 4篇
  • 音视频 2篇
  • qml 6篇
  • Electron 1篇
  • 其他 2篇
  • windows系统 4篇
  • 工具 8篇
  • C++ 6篇
  • 设计模式 26篇

最新评论

  • Qt的转义字符,单双斜线路径转换

    dai2zi2me: 你改正后是对的,博主是错的

  • Window11启动自带虚拟机

    风起时~微凉: 网络是在你创建创建虚拟机的时候设置的,和Hyper—V管理器没关系,看一下你创建虚拟机设置中的网络适配器

  • Window11启动自带虚拟机

    Zc夜雨: 虚拟机平台打开了,为啥连不上网呀

  • 十大经典排序算法

    cqbzcyy: 前面的动图只有我看到他没动吗表情包

  • Qt的转义字符,单双斜线路径转换

    wenfh2020: 单斜线那里是不是搞错了,我的是 qt 5.14.2。 应该是这个吧。 path = QDir::fromNativeSeparators(path);

最新文章

  • KWin事件总结和相关类介绍
  • Wayland中跨进程调用过程
  • Weston中shm window渲染
2023年7篇
2021年120篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家鼓楼商场美陈布展节庆商场美陈销售企业广州仿真玻璃钢人物雕塑深圳大型商场美陈白城商城艺术玻璃钢雕塑工厂温州商场美陈生产公司广州大型卡通玻璃钢雕塑黄山开业商场美陈曲阳玻璃钢校园雕塑丹阳玻璃钢雕塑厂商销售宁波佛像玻璃钢雕塑泰州玻璃钢仿铜雕塑定做价格息烽玻璃钢雕塑定做电话北京艺术商场美陈生产厂家专业设计的玻璃钢花盆河南大型主题商场美陈订购牡丹江玻璃钢雕塑周口大象玻璃钢雕塑玉溪玻璃钢雕塑定制长沙番禺玻璃钢人物雕塑洛阳汕头玻璃钢雕塑商场主题美陈材料茂名玻璃钢动物雕塑包括哪些玻璃钢大白菜雕塑厂家报价温州玻璃钢花盆南京襄阳玻璃钢面包雕塑浙江周年庆典商场美陈价钱邯郸玻璃钢雕塑工厂桥头玻璃钢花盆批发佛山校园雕塑玻璃钢香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化