Hello Wayland -- Wayland教程

翻译自https://hdante.wordpress.com/2014/07/08/the-hello-wayland-tutorial/

TLDR

我写了一个wayland下的hello world,源码在 https://github.com/hdante/hello_wayland

介绍

从最终用户的角度,很容易理解wayland是什么:它是一个新的窗口系统,它将显示服务器和窗口管理器合并了[1]。从技术角度来看,wayland是为了摆脱传统,使用现代设计来实现一个高效的窗口系统,解决X窗口系统中长期存在的效率问题和一些极端情况[2]。这个教程展示如何实现一个作为wayland客户端的hello world程序、解释基础的wayland概念、创建一个GUI程序的必要流程。hello world程序不需要任何GUI工具包,它直接使用底层的wayland协议,以便解释wayland的基础概念。本教程是我自己研究wayland协议的结果。教程分为两部分。这是第一篇教程,解释所有的概念和程序的高级部分。

再问一次,什么是wayland?

wayland窗口系统的的完整设计分为好几层。如果你下载了wayland library的代码[3],或者你看了下wayland的API[4],你会注意到两层:

  1. 最基础的一层是进程间通讯功能的实现,以及一些实用工具。比如主循环调度器和一些数据类型。大部分这些代码都出现在wayland library中(所有在src文件夹[5]中的内容),并且和窗口系统无关。
  2. 第二层是窗口系统协议。它的描述在protocol/wayland.xml[6]文件中,这个文件应该算是一种接口定义语言。IDL文件可以用wayland-scanner 工具处理,并在 wayland-client-protocol.h 和 wayland-server-protocol.h中生成代理方法。协议定义了客户端程序和显示服务器的基础功能。比如访问输入设备、注册共享缓存以便显示在屏幕上。wayland library并不实现这些协议。这些协议的实现被分割到一个第三方层。服务端的参考实现是weston的一部分[7],它在客户端和服务端都定义了一些附加层。以实现wayland协议。在hello world程序中,我们并不需要了解任何关于weston的东西。我们仅仅需要IDL文件。

从上面关于wayland library的描述中,我们发现wayland的三个定义。它是一个(额听用途的)IPC库,不像D-Bus库,它仅仅用于显示服务器,并且它没有定义wayland到底是什么、wayland协议的定义以及如何找到协议定义。我相信即使人们在阅读官方文档后,大部分人也不明白wayland到底是什么。我想,这三个定义澄清了“什么是wayland”这个问题,每一个定义都能够用在不同的上下文中。

Hello, World!

阅读更多

[译]输入系统如何工作——指针输入

翻译自 How input works – pointer input。 在上一篇博文中,我讨论了键盘输入。这篇博文将会讨论指针设备——多被称为鼠标。就像本系列文章一样,本文仅仅讨论了KWin/Wayland上面的情形。

不同的硬件类型

有好几种不同的设备被识别为指针设备。有轨迹球这样的传统鼠标,也有在笔记本上的触摸板。此外,还有可绝对定位的设备,比如触摸屏。 在libinput中,对于不同的设备,有很多不同的选项可供配置。比如指针加速等其他选项。我们正在开发Wayland的触摸板配置模块,看起来会合并到Plasma 5.9中。像第一篇博文描述的,一旦设备创建,一系列配置选项会被立马设置。

指针运动

指针设备生成不同种类的事件,其中一种就是指针运动事件。通常来说,有两种指针运动事件:绝对运动和相对运动。大多数设备,比如鼠标,产生相对运动事件,所以我们在本文中只关注相对运动事件。

确定新的位置

相对运动是一组带x和y坐标的距离向量,它描述了指针位置该如何移动。 所以,一旦事件从KWin队列中读取出来,需要确定新的指针位置。这并不单单是最后的指针位置再加上一个运动向量。这会导致指针离开可视区域。 相反,指针运动得验证和约束。我们确保光标不会离开可视区域,并且还要遵守应用程序窗口对指针的约束。 这是KWin在Plasma 5.9中支持的新协议。它允许Wayland窗口将指针锁定到某个位置或将指针限制在某个区域。在第一种情况下,指针根本不移动,在第二种情况下,只允许指针在窗口的特定区域移动。

处理新的位置

即使在光标被限定的情况下,不需要移动鼠标指针,事件也会得到进一步处理。即使光标不移动,应用程序也可能对相对运动感兴趣,并对其做出反应。 像键盘的情况一样,为了进一步处理,会生成QMouseEvent并发送到KWin的输入过滤器。指针运动可能在KWin内部处理,例如:指针位置超出了当前的屏幕边缘。或者通过KWayland将指针运动转发到窗口。

更新获取焦点的窗口

阅读更多

[译]输入系统如何工作——键盘输入

本文是 How input works – Keyboard input 的翻译。

上一篇博客中,原作者解释了KWin中,输入设备是如何打开和处理的。在这篇博文中,我们将仔细关注下键盘设备和键盘事件。

键盘并不总是键盘

在Linux中,键盘是一个非常奇特的设备。你不会只有一个键盘,你肯定会有很多个。很多设备宣称自己是键盘,但是只支持一个键。比如,电源按钮或者带静音按钮、音量加减按钮的外置耳机。从输入系统的角度来看,这些设备也是键盘。

对于KWin,发现真正支持的键盘是很重要的。如果没有一个“真的”键盘连接(或者说开启),我们的虚拟键盘应该自动激活。比如,如果你从平板PC二合一设备上拔了键盘,它应该转换为平板模式,即有虚拟键盘的模式。如果连接上了键盘,虚拟键盘就不是主要的输入设备了。libinput提供了函数来检测键盘支持哪些键。我们使用这个功能来区分不同的键盘类型。

键盘事件

在这里,键盘是最简单的输入设备。libinput仅仅触发一个LIBINPUT_EVENT_KEYBOARD_KEY事件,并包含了被按下或者释放的键。KWin有一个专用线程,用来从libinput读取事件。所以这些事件现在仅仅是放在处理队列中,主线程同时也得到新事件通知。一旦主线程处理事件,事件就被转换成我们的输入重定向类。不管事件是通过哪种源头抵达,所有输入事件都会通过输入重定向。KWin不仅仅支持来自libinput的事件,并且支持嵌套会话(即KWin运行在X11之上,或者在另一个Wayland服务器之上),还有在集成测试中使用的模拟事件。这意味着一旦事件到达输入重定向,我们基本上就丢失了事件来自哪个设备这些信息。最近,我们扩展了内部API,可以在事件处理函数中包含设备源,这是可选的。可以在调试终端中使用,来显示哪些设备产生了哪些事件。

xkbcommon

现在,一个键的按下、释放事件到达了中心分发方法KeyboardInputRedirection::processKey。第一件也是重要的一件事就是在xbkcommon中更新键盘状态。xkbcommon被用将物理键为事件,转换过程根据键盘布局、键盘状态(比如激活的修饰符)来进行。比如:如果我按下了“y”键(键码是21)并且“Shift”键是按下的状态,在德语键盘布局下,就会创建“Z”按下的事件;但是在英语键盘布局下,它会是“Y”。

在KWin中,我们将所有需要的xkbcommon功能都封装到Xkb类中。这个类追踪活跃的键盘布局、执行键盘布局切换(当布局变换的时候展示OSD)。它知道上一次按键的符号,当前活跃的修饰符和快捷键相关的修饰符。

阅读更多

[译]输入系统如何工作——创建设备

本文是How input works – creating a Device的翻译。

最近,我(原作者,下同)在KWin/Wayland输入栈上做了一些工作,比如实现了鼠标手势和鼠标限制协议(pointer constraints protocol),并且想写一些系列博客来描述输入事件是如何从设备传递到应用的。在第一篇博文中,我将关注于创建和配置输入设备,以及与此相关的其他事情。

evdev

Linux内核通过evdev API来产生输入事件。如果你对evdev如何工作感兴趣,我推荐你读一读Peter Hutterer写的优秀的博文。对于我们关注的层面来说,输入事件API太底层了,我们仅仅想用对它的一个抽象。

libinput 和设备文件

对输入事件API的抽象叫做libinput。它允许我们得到通知,不论何时添加、删除输入设备、不论何时产生输入事件。但是别急,我们首先需要打开输入设备,这是我们的第一个挑战。

正常情况下,设备文件不能被用户读取。这有好的一面,否则每个程序都能够读取所有的键盘事件。这种情况下,键盘记录器太容易实现了。

但是如果KWin以普通用户的方式运行,普通用户又无法读取设备文件,那KWin如何获取输入?为了让KWin获取输入,我们需要特殊的支持。libinput就是为这种情况准备的,它自己不会尝试打开文件,它会使用用户提供的open_restricted函数。KWin就是这么干的,并将打开文件的任务交给了logind。logind允许一个进程控制当前登录会话。并且这个登录会话的控制进程可以打开一些设备文件。所以KWin和logind的dbus API交互,成为登录会话的控制进程,通过logind的API打开设备文件,并将其传递回libinput。

这也是为什么对于整个Wayland会话,KWin在运行时依赖logind的DBus接口。请注意,这并不意味着你需要使用logind或者sysemd。这仅仅意味着需要一个进程来同logind的DBus接口通讯。

KWin中的设备

阅读更多

[译]什么是HiDPI?以及它为什么这么重要。

本文是What is HiDPI的翻译。

我是一名web开发者和用户体验设计师,使用System 76电脑、Ubuntu系统;也是elementary OS的联合创始人。elementary OS是一个开源的桌面操作系统。我和桌面、web、硬件开发者一起工作,来实现HiDPI支持。我注意到很多人很难理解HiDPI,因为对此没有一个全面的介绍。这是我尝试介绍HiDPI和去除一些常见误解的博文。

HiDPI显示器在计算机上变得越来越流行:苹果最新的MacBook、MacBook Pro和iMac;微软的Surface,Surface Book,和新的Surface Studio;戴尔,联想,惠普和其他厂商将HiDPI作为笔记本电脑的可选配置;LG,戴尔和飞利浦等的HiDPI桌面显示器;和System76(我的雇主)刚刚发布的旗舰Oryx Pro和Bonobo WS笔记本电脑也支持了HiDPI。

由于价格,图形性能需求和功耗的增加,HiDPI不是默认配置,但我们肯定会朝这个方向发展的。那么,HiDPI解决了什么问题呢?

像素数翻倍

HiDPI的核心是像素数量加倍:每个维度中的_物理_像素数量是所需的_虚拟_像素数的两倍。

例如,图标或图像的高度是64_虚拟_像素,但是在HiDPI显示器上,它用128个物理像素绘制(总共是4倍的像素——在每个方向上是原来的两倍)。这使得图标在任何角度都变得两倍清晰,或者说容纳了了两倍的细节。

普通显示和HiDPI。4倍的像素数量。HiDPI允许更精细的形状和更好的抗锯齿。

对于用户界面,这意味着它们比原来的一大堆像素集更加清晰、完美。对于照片,HiDPI使它们看起来更像一张打印的照片,而不仅仅是数字图像。对于文本,HiDPi使它看起来更像一个实体的杂志,而不仅仅是电脑屏幕。对于视频,HiDPI允许更多的细节和沉浸体验:屏幕渐渐消失,成为电影故事的一个窗口。

半个像素是不存在的

阅读更多

[译]UUID和Linux:你需要知道的一切

本文为 UUIDs and Linux: Everything you ever need to know Update 的翻译。

UUID在Linux中为何如此特别?我[指原作者,下同]不知道!但是这儿有你需要知道的、关于UUID在Linux下的一切!

背景

UUID是128位长的数字,表示为32位的16进制数字,被用于在软件开发中、在没有上下文的情况下唯一地标识信息。RFC 4122描述了UUID的规范,一个UUID的例子是:

13152fae-d25a-4d78-b318-74397eb08184

UUID在Linux最熟悉的场景应该是块设备的标识符了吧。Windows世界中的UUID以Microsoft的全局唯一标识符GUID的形式出现,这些标识符在Microsoft的组件对象模型[COM]中使用。

UUID以各种变体生成:最初大多数是从计算机的MAC派生的,随后使用了基于name的散列值。关于这个问题,比如有多少UUID,有多大概率会生成一个已有的UUID,这是来自维基百科上 UUID 的文章的一些数字:

在100年里,每秒生成十亿个UUID,生成重复的UUID的概率约为50%。如果每个人都有6亿个UUID,下一个UUID重复的概率约为50%。

fstab中的用法

就像之前提到的,UUID在Linux下被经常用于标识块设备。想象一下,你有两个硬盘通过USB连接上,它们不是持久存储,只能依赖两个设备的名字来区分:有时第一个USB硬盘是“sda”,有时它是“sdb”。所以要唯一寻址正确的磁盘,比如在 /etc/fstab 中,你必须添加如下条目:

阅读更多

[译]为了更具有创造力,还是不要那么高效吧

本文为 To Get More Creative, Become Less Productive 的翻译。

高效和创造力之间存在着根本性的矛盾,在意识到这一点之前,管理者无法获取更多的创意。

高效的人们以一种系统化的方式来完成一系列必须完成的任务。他们以稳定的、可衡量的方式来完成目标。他们非常有效率、并且能够有效地利用自己的时间。

创造力——可不是这样的。

创造性的发展需要时间和空间。虽然我们可以系统地从事与创造力有关的活动,但是很难系统化创造力本身。特别是,创造力是知识的基础。

几乎所有的创意想法都涉及人们寻找现有知识的新用途——一些旧想法的新组合。James Dyson通过类比锯木厂发明了他的真空吸尘器。 Fiona Fairhurst通过研究鲨鱼皮肤设计了更快的泳装。 George de Mestral通过了解苍耳发明了魔术贴。

这意味着从他们需要创造力的开始,人们就需要时间来学习与他们的工作无关的东西,以便他们有广泛而深入的知识库。

此外,有创造力的企业很少涉及稳定和可衡量的进步。 相反,创造力包括尝试许多不同的可能性,以及在找到正确的解决方案之前努力尝试几个盲目的岔路。

但这些活动——建立一个知识库并探索它——需要时间。 很难简单地安排几个小时在这里和那里进行创造性的追求。相反,有些时候,需要花时间学习一个新的知识领域,或者与同事进行漫长的谈话,来理清楚一个新的想法。 所以在突破来临之前,很多创意活动可能看起来是非常不确定的。

许多公司想要他们的员工获得更多创造力,这其中的主要原因就是生产力和创造力之间的这种差异。

阅读更多

PEP 3107 -- 函数注解[译]

本文是PIP 3137的翻译。

背景

Python 2.x系列缺乏一个标准的方式来说明一个函数的参数和返回值,各种工具和库的出现填补了这一空白。一些工具使用了“PEP 318”中的装饰器,而其他的工具则去解析函数的文档注释,寻找注解。 在这一点上,众多已存在的机制和语法造成了很大的混乱。本PEP的目的是提供一个单一的,标准的方式指定这些信息,减少这些混乱。

函数注解的基础知识

在仔细讨论Python 3.0的函数注解的细节之前,首先让我们大致讨论下注解是什么、不是什么:

  1. 函数注解,无论是对参数的还是对返回值的函数注解,完全是可选的。

  2. 函数注解无非是一种方法,用来在编译时将任意Python表达式和函数的不同部分关联起来。就这点而言,Python并没有给注解赋予特殊的意义和重要性。Python仅仅让这些表达式可以被访问而已,以一种像本文的“访问函数注解”中描述的方法。注解对含义产生作用的唯一方式是当它们被第三方库解释的时候。这些注解的使用者可以用这些函数注解做他们想做的任何事情。例如,一个库可以利用字符串类型的注解来提供改进过的帮助信息:

    1
    2
    3
    4
    def compile(source: "something compilable",
    filename: "where the compilable thing comes from",
    mode: "is this a single statement or a suite?"):
    ...

    另一个库可以用来提供Python函数和方法的类型检查。这个库可以使用注解来说明函数的预期输入和返回值的类型:

    1
    2
    def haul(item: Haulable, \*vargs: PackAnimal) -> Distance:
    ...

    然而,不论是第一个例子中的字符串还是第二个例子中的类型信息,它们自己没有任何含义;含义来自第三方库。

  3. 根据第二点,该PEP不会试图引入一种标准的语义,即使是为那些内置类型。这个工作留给第三方库。

语法

参数

对参数的注解跟随着参数名,采用了一种可选表达式的形式:

1
2
def foo(a: expression, b: expression = 5):
...
阅读更多