第14章:Linux桌面与打印概览

本章快速介绍典型Linux桌面系统中的组件。在Linux系统的所有不同软件中,桌面领域是最丰富多彩、最具多样性的领域之一,因为可供选择的环境和应用程序非常多,而大多数发行版也让你能够相对容易地尝试它们。

与Linux系统其他部分(如存储和网络)不同,构建桌面结构不需要涉及复杂的层次体系。相反,每个组件执行特定的任务,并在必要时与其他组件通信。某些组件确实共享通用的构建块(特别是图形工具包库),你可以将这些视为简单的抽象层,但深度也就到此为止了。

本章将从较高层次讨论桌面组件,但我们会更详细地研究两个部分:大多数桌面背后的核心基础设施,以及系统许多部分中使用的进程间通信服务——D-Bus。我们将动手讨论和示例限制在少数诊断工具上,这些工具虽然日常用处不大(大多数图形界面不需要你输入shell命令来交互),但能帮助你理解系统底层机制,并可能在此过程中带来一些乐趣。我们还会快速浏览打印部分,因为桌面工作站通常共享一台打印机。

14.1 桌面组件

Linux桌面配置提供了极大的灵活性。Linux用户所体验到的大部分内容(桌面的“外观与感觉”)来自应用程序或应用程序的构建块。如果你不喜欢某个特定的应用程序,通常可以找到替代品。如果找不到你想要的,你可以自己编写。Linux开发者对于桌面的行为方式往往有着广泛的偏好,因此选择非常多。

为了协同工作,所有应用程序需要有一些共同点。在撰写本书时,Linux桌面的核心正处于一个过渡状态。从开始到不久前,Linux桌面一直使用X(X Window系统,也称为Xorg,以其维护组织命名)。然而,这种情况正在改变;许多发行版已经过渡到基于Wayland协议的软件集来构建窗口系统。

要理解这一底层技术变革的驱动力,让我们退一步,看看一些图形学基础知识。

14.1.1 帧缓冲

在任何图形显示机制的底层是帧缓冲(framebuffer),这是一块内存区域,图形硬件读取它并将其传输到屏幕进行显示。帧缓冲中的几个字节代表显示器上的每个像素,因此,如果你想改变某个事物的外观,就需要向帧缓冲内存写入新值。

窗口系统必须解决的一个问题是如何管理对帧缓冲的写入。在任何现代系统上,窗口(或窗口组)属于各个进程,它们独立进行所有图形更新。因此,如果允许用户移动窗口并使它们重叠,应用程序如何知道在哪里绘制其图形?如何确保一个应用程序不能覆盖其他窗口的图形?

14.1.2 X Window系统

X Window系统采用的方法是有一个服务器(称为X服务器),它充当桌面的“内核”,管理从渲染窗口到配置显示器再到处理键盘、鼠标等设备输入的一切。X服务器并不规定任何事物应该如何行为或外观。相反,X客户端程序处理用户界面。基本的X客户端应用程序(如终端窗口和Web浏览器)连接到X服务器,请求绘制窗口。作为响应,X服务器计算出窗口放置位置和客户端图形渲染位置,并承担一部分将图形渲染到帧缓冲的责任。X服务器在适当的时候也将输入路由到客户端。

由于X服务器作为所有事物的中介,它可能成为显著的瓶颈。此外,它包含了许多现已不再使用的功能,而且它的历史相当悠久,可以追溯到20世纪80年代。尽管如此,它足够灵活,容纳了许多新特性,从而延长了其寿命。我们将在本章后面描述如何与X Window系统交互的基本知识。

14.1.3 Wayland

与X不同,Wayland在设计上显著去中心化。没有大型显示服务器为众多图形客户端管理帧缓冲,也没有集中的图形渲染权威。相反,每个客户端获得自己的内存缓冲(可以想象成子帧缓冲)用于其窗口,然后一个称为合成器(compositor)的软件将所有客户端的缓冲组合成必要的形式,以便复制到屏幕的帧缓冲。由于通常有硬件支持此任务,合成器可以非常高效。

在某些方面,Wayland中的图形模型与多年来大多数X客户端实际所做的并没有太大不同。大多数X客户端不是从X服务器获得任何帮助,而是将所有数据渲染为位图,然后将位图发送给X服务器。X为了承认这一点,已经有一个合成扩展(compositing extension),已经使用了好几年。

对于将输入路由到正确应用程序的任务,大多数Wayland设置和许多X服务器使用一个名为libinput的库来标准化发送给客户端的事件。这个库并非Wayland协议所要求,但在桌面系统上几乎是通用的。我们将在14.3.2节讨论libinput。

14.1.4 窗口管理器

X系统和Wayland系统之间的一个主要区别在于窗口管理器(window manager),即决定如何在屏幕上排列窗口的软件,也是用户体验的核心。在X中,窗口管理器是作为服务器助手的客户端;它绘制窗口装饰(如标题栏和关闭按钮),处理对这些装饰的输入事件,并告诉服务器窗口应该移动到哪里。

然而,在Wayland中,窗口管理器或多或少就是服务器。它负责将所有客户端窗口缓冲合成到显示帧缓冲中,并处理输入设备事件的路由。因此,它需要比X中的窗口管理器做更多的工作,但其中许多代码可以在不同窗口管理器实现之间共享。

两种系统中存在许多窗口管理器实现,但X由于历史悠久而拥有多得多的实现。然而,大多数流行的窗口管理器,如Mutter(在GNOME中)和Kwin(来自KDE),也已扩展为支持Wayland合成。无论底层技术如何,不太可能有一个标准的Linux窗口管理器;因为用户的品味和需求多样且不断变化,新的窗口管理器不断涌现。

14.1.5 工具包

桌面应用程序包含一些常见元素,如按钮和菜单,称为控件(widgets)。为了加速开发并提供统一的外观,程序员使用图形工具包(graphical toolkits)来提供这些元素。在Windows或macOS等操作系统上,供应商提供通用的工具包,大多数程序员使用它。在Linux上,GTK+工具包是最常见的,但你也会经常看到基于Qt框架和其他框架构建的控件。

工具包通常由共享库和支持文件(如图片和主题信息)组成。

14.1.6 桌面环境

虽然工具包为用户提供了统一的外观,但桌面的某些细节需要不同应用程序之间的协作。例如,一个应用程序可能希望与另一个应用程序共享数据,或者更新桌面上的公共通知栏。为了满足这些需求,工具包和其他库被捆绑成更大的包,称为桌面环境(desktop environments)。GNOME、KDE和Xfce是一些常见的Linux桌面环境。

工具包是大多数桌面环境的核心,但为了创建一个统一的桌面,环境还必须包含大量支持文件,如图标和配置,这些构成了主题。所有这些都与描述设计约定的文档绑定在一起,例如应用程序菜单和标题应如何显示,以及应用程序应如何响应某些系统事件。

14.1.7 应用程序

桌面顶层是应用程序,如Web浏览器和终端窗口。X应用程序可以从简陋(如古老的xclock程序)到复杂(如Chrome Web浏览器和LibreOffice套件)。这些应用程序通常独立运行,但它们经常使用进程间通信来了解相关事件。例如,当连接新的存储设备、收到新邮件或即时消息时,应用程序可以表达兴趣。这种通信通常通过D-Bus进行,在14.5节描述。

14.2 你运行的是Wayland还是X?

在我们开始动手讨论之前,你需要确定你使用的是哪种图形系统。只需打开一个shell并检查$WAYLAND_DISPLAY环境变量的值。如果值是类似wayland-0的东西,那么你运行的是Wayland。如果没有设置,那么你运行的是X(很可能;也有例外,但通过这个测试你不大可能遇到)。

这两个系统并不互斥。如果你的系统使用Wayland,它很可能也在运行X兼容性服务器。也可以在X内部启动Wayland合成器,但这可能会有点奇怪(稍后会详细介绍)。

14.3 深入Wayland

我们将从Wayland开始,因为它是新兴标准,目前许多发行版默认使用。不幸的是,部分由于其设计和年轻,用于探查Wayland的工具不如X那样多。我们会尽力而为。

但首先,让我们谈谈Wayland是什么和不是什么。“Wayland”这个名字指的是合成窗口管理器(compositing window manager)和图形客户端程序之间的通信协议。如果你去寻找一个大的Wayland核心包,你不会找到,但你会找到大多数客户端用来与该协议通信的Wayland库(至少目前如此)。

还有一个名为Weston的参考合成窗口管理器以及一些关联的客户端和工具。这里的“参考”意味着Weston包含合成器必要的功能,但它并不面向大众使用,因为它有一个极简的界面。其理念是合成窗口管理器的开发者可以查看Weston的源代码,了解如何正确实现关键功能。

关于Wayland的现状

Wayland是新兴标准,但工具较少。检查$WAYLAND_DISPLAY可判断当前环境。Wayland与X可以共存。

(注意:原始文本的14.3节之后还有内容,但根据指示,这是第一部分,我们只处理到这里。后续部分将在后续翻译中继续。)

14.3.1 合成窗口管理器

听起来可能很奇怪,你也许并不清楚自己实际运行的是哪个Wayland合成窗口管理器。你或许能从界面的某个信息选项中找到其名称,但并没有固定的位置可以查看。不过,你几乎总能通过追踪合成器用于与客户端通信的Unix域套接字来找到正在运行的合成器进程。该套接字就是WAYLAND_DISPLAY环境变量中的显示名称,通常是wayland-0,一般位于/run/user/<uid>目录下,其中<uid>是你的用户ID(如果不是,请检查$XDG_RUNTIME_DIR环境变量)。以root身份运行,你可以用ss命令找到监听该套接字的进程,但输出看起来会有点混乱:

# ss -xlp | grep wayland-
u_str             LISTEN              0                    128                                                                         
/run/user/1000/wayland-0 755881                                                
* 0             users:(("gnome-shell",pid=1522,fd=30),("gnome-
shell",pid=1522,fd=28))

不过,你只需从中筛选即可;这里可以看到合成器进程是gnome-shell,PID为1522。遗憾的是,这里还存在另一层间接关系;GNOME Shell是Mutter的一个插件,而Mutter是GNOME桌面环境中使用的合成窗口管理器。(这里,把GNOME Shell称为插件,只是一种 fancy 的说法,表明它是以库的形式调用Mutter。)

NOTE

Wayland系统一个比较不寻常的方面是绘制窗口装饰(如标题栏)的机制。在X中,窗口管理器负责所有工作,但在Wayland的初始实现中,这项工作留给了客户端应用程序,有时会导致同一屏幕上出现许多不同风格的窗口装饰。现在,协议中有一个名为XDG-Decoration 的部分,允许客户端与窗口管理器协商,看窗口管理器是否愿意绘制装饰。

在Wayland合成器的上下文中,你可以把显示(display)视为可视空间,由帧缓冲区表示。如果一台计算机连接了多个显示器,一个显示可以跨越多个显示器。

虽然不常见,但你可以同时运行多个合成器。一种方法是在不同的虚拟终端上运行合成器。在这种情况下,第一个合成器通常会将显示名称设置为wayland-0,第二个设置为wayland-1,依此类推。

你可以通过weston-info命令了解一些关于合成器的信息,它会显示合成器可用接口的一些特性。不过,除了显示器和一些输入设备的信息外,你不会期望得到太多其他内容。

14.3.2 libinput

为了将来自键盘等设备的输入从内核传递到客户端,Wayland合成器需要收集这些输入,并以标准化的形式将其定向到合适的客户端。libinput库包含收集来自各种/dev/input内核设备输入并进行处理所需的功能。在Wayland中,合成器通常不会直接传递输入事件,而是先将事件转换为Wayland协议,再发送给客户端。

通常情况下,libinput这类库并不值得多谈,但它附带了一个小工具(也叫libinput),可以让你检查内核呈现的输入设备和事件。尝试以下命令查看可用的输入设备(可能会输出大量内容,请做好准备分页查看):

# libinput list-devices
--snip--
Device:           Cypress USB Keyboard
Kernel:           /dev/input/event3
Group:            6
Seat:             seat0, default
Capabilities:     keyboard 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
--snip--

在这个部分视图中,你可以看到设备类型(键盘)以及内核 evdev 设备的位置(/dev/input/event3)。当你像这样监听事件时,该设备就会出现:

# libinput debug-events --show-keycodes
-event2   DEVICE_ADDED     Power Button                      seat0 default 
group1  cap:k
--snip--
-event5   DEVICE_ADDED     Logitech T400                     seat0 default 
group5  cap:kp left scroll-nat scroll-button
-event3   DEVICE_ADDED     Cypress USB Keyboard              seat0 default 
group6  cap:k
--snip--
 event3   KEYBOARD_KEY      +1.04s      KEY_H (35) pressed
 event3   KEYBOARD_KEY      +1.10s      KEY_H (35) released
 event3   KEYBOARD_KEY      +3.06s      KEY_I (23) pressed
 event3   KEYBOARD_KEY      +3.16s      KEY_I (23) released

运行此命令后,移动鼠标指针并按下一些键。你会看到描述这些事件的输出。

请记住,libinput库只是一个用于捕获内核事件的系统。因此,它不仅用于Wayland下,也用于X Window系统下。

14.3.3 Wayland中的X兼容性

在讨论X Window系统之前,我们先来探讨一下它与Wayland的兼容性。X有无数应用程序,任何从X迁移到Wayland的努力,如果没有X支持,都会受到很大阻碍。有两种方法可以同时弥合这一差距。

第一种方法是为应用程序添加Wayland支持,创建原生Wayland应用程序。大多数在X上运行的图形应用程序已经使用了诸如GNOME和KDE中的工具包。由于这些工具包已经完成了添加Wayland支持的工作,因此将X应用程序转变为原生Wayland应用程序并不困难。除了关注窗口装饰和输入设备配置的支持外,开发人员只需要处理应用程序中很少出现的X库依赖。对于许多主要应用程序来说,这项工作已经完成。

另一种方法是通过Wayland中的兼容层运行X应用程序。这是通过让整个X服务器作为Wayland客户端运行来实现的。这个服务器被称为Xwayland,它实际上是塞在X客户端之下的另一层,大多数合成器启动序列默认都会运行它。Xwayland服务器需要单独转换输入事件并维护其窗口缓冲区。引入这样的中间人总是会稍微降低速度,但影响不大。

反向操作就没那么顺利了。你不能以相同的方式在X上运行Wayland客户端(理论上,编写这样的系统是可能的,但意义不大)。不过,你可以在X窗口内部运行一个合成器。例如,如果你正在运行X,可以直接在命令行上运行weston来启动一个合成器。你可以在其中打开一个终端窗口和任何其他Wayland应用,如果你正确启动了Xwayland,甚至可以在合成器内运行X客户端。

但是,如果你让这个合成器继续运行,然后切换回常规的X会话,你可能会发现某些实用程序的行为与你预期不符,而且它们可能会出现在合成器窗口中,而你原本希望它们以X窗口的形式出现。原因是,GNOME和KDE等系统上的许多应用程序现在同时支持X和Wayland。它们会首先查找Wayland合成器,默认情况下,libwayland中查找显示的代码会在WAYLAND_DISPLAY环境变量未设置时将默认值设为wayland-0。能找到工作合成器的应用程序会尽可能地使用它。

避免这种情况的最佳方法是不要在X内部或与X服务器同时运行合成器。

14.4 更深入地了解X Window系统

与基于Wayland的系统相比,X Window系统(http://www.x.org/)历来非常庞大,基本发行版包括X服务器、客户端支持库和客户端。由于GNOME和KDE等桌面环境的出现,X的角色随着时间的推移发生了变化,现在的重点更多地放在管理渲染和输入设备的核心服务器以及简化的客户端库上。

X服务器在你的系统上很容易识别。它被称为XXorg。在进程列表中查找它;你通常会看到它带有多项选项运行,如下所示:

Xorg -core :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch

这里显示的:0被称为X显示(X display),它是一个标识符,代表一个或多个使用共用键盘和/或鼠标的显示器。通常,显示仅对应连接到计算机的单个显示器,但你可以将多个显示器置于同一个显示之下。对于在X会话下运行的进程,DISPLAY环境变量被设置为该显示标识符。

NOTE

显示可以进一步细分为屏幕(screen),例如:0.0:0.1,但这非常罕见,因为RandR等X扩展可以将多个监视器合并成一个更大的虚拟屏幕。

在Linux上,X服务器运行在一个虚拟终端上。在这个例子中,vt7参数表明它被告知在/dev/tty7上运行(通常,服务器从第一个可用的虚拟终端开始)。你可以通过在Linux上运行多个X服务器,每个服务器运行在不同的虚拟终端上,每个服务器具有唯一的显示标识符。你可以使用CTRL-ALT-FN键或chvt命令在服务器之间切换。

14.4.1 显示管理器

你通常不会在命令行上启动X服务器,因为启动服务器并不会定义任何应该在其上运行的客户端。如果你单独启动服务器,只会得到一个空白屏幕。相反,启动X服务器的最常见方式是使用显示管理器(display manager),这是一个启动服务器并在屏幕上显示登录框的程序。登录后,显示管理器会启动一组客户端,例如窗口管理器和文件管理器,以便你可以开始使用机器。

有许多不同的显示管理器可用,例如gdm(用于GNOME)和kdm(用于KDE)。前面X服务器调用参数列表中的lightdm是一个跨平台的显示管理器,旨在能够启动GNOME或KDE会话。

如果你坚持从虚拟控制台而不是使用显示管理器启动X会话,可以运行startxxinit命令。但是,你得到的会话很可能非常简单,与显示管理器的会话完全不同,因为其机制和启动文件不同。

14.4.2 网络透明性

X的一个特性是网络透明性。由于客户端使用协议与服务器通信,因此可以通过网络在远程机器上直接运行客户端,连接到运行在不同机器上的X服务器,X服务器监听TCP端口6000。连接到该端口的客户端可以认证,然后向服务器发送窗口。

不幸的是,这种方法通常不提供任何加密,因此不安全。为了堵住这个漏洞,大多数发行版现在都禁用了X服务器的网络监听器(使用-nolisten tcp选项)。然而,你仍然可以通过SSH隧道从远程机器运行X客户端,如第10章所述,将X服务器的Unix域套接字连接到远程机器上的套接字。

NOTE

在Wayland中,没有简单的方法进行远程运行,因为客户端拥有自己的屏幕内存,合成器必须直接访问才能显示。然而,许多新兴系统,如RDP(远程桌面协议),可以与合成器协同工作以提供远程功能。

第14章:Linux桌面与打印

14.4.3 探索X客户端的方式

虽然通常不会想到从命令行操作图形用户界面,但有几个实用工具可以让你探索X Window系统的各个部分。特别是,你可以在客户端运行时检查它们。

最简单的工具之一是 xwininfo。不带任何参数运行时,它会要求你点击一个窗口:

$ xwininfo 
xwininfo: Please select the window about which you
          would like information by clicking the
          mouse in that window.

点击后,它会打印出该窗口的一系列信息,例如其位置和大小:

xwininfo: Window id: 0x5400024 "xterm"
  Absolute upper-left X:  1075
  Absolute upper-left Y:  594
--snip--

注意这里的窗口ID。X服务器和窗口管理器使用此标识符来跟踪窗口。要获取所有窗口ID和客户端的列表,请使用 xlsclients -l 命令。

14.4.4 X事件

X客户端通过事件系统获取输入以及服务器状态的其他信息。X事件的工作原理与其他异步进程间通信事件(如udev事件和D-Bus事件)类似。X服务器从某个来源(例如输入设备)接收信息,然后将该输入作为事件重新分发给任何感兴趣的X客户端。

你可以通过 xev 命令来试验事件。运行它会打开一个新窗口,你可以将鼠标移入其中、点击和键入。当你操作时,xev 会生成描述它从服务器接收到的X事件的输出。例如,以下是鼠标移动的示例输出:

$ xev
--snip--
MotionNotify event, serial 36, synthetic NO, window 0x6800001,
    root 0xbb, subw 0x0, time 43937883, (47,174), root:(1692,486),
    state 0x0, is_hint 0, same_screen YES
MotionNotify event, serial 36, synthetic NO, window 0x6800001,
    root 0xbb, subw 0x0, time 43937891, (43,177), root:(1688,489),
    state 0x0, is_hint 0, same_screen YES

注意括号中的坐标。第一对表示鼠标指针在窗口内的x和y坐标,第二对(root:)是指针在整个显示器上的位置。

其他低级事件包括按键和按钮点击,但更高级的事件指示鼠标是否进入或退出窗口,或者窗口是否获得或失去了窗口管理器的焦点。例如,以下是相应的退出和失去焦点事件:

LeaveNotify event, serial 36, synthetic NO, window 0x6800001,
    root 0xbb, subw 0x0, time 44348653, (55,185), root:(1679,420),
    mode NotifyNormal, detail NotifyNonlinear, same_screen YES,
    focus YES, state 0
FocusOut event, serial 36, synthetic NO, window 0x6800001,
    mode NotifyNormal, detail NotifyNonlinear

xev 的一个常见用途是在重新映射键盘时为不同的键盘提取键码和键符号。以下是按下L键时的输出;这里的键码是46:

KeyPress event, serial 32, synthetic NO, window 0x4c00001,
    root 0xbb, subw 0x0, time 2084270084, (131,120), root:(197,172),
    state 0x0, keycode 46 (keysym 0x6c, l), same_screen YES,
    XLookupString gives 1 bytes: (6c) "l"
    XmbLookupString gives 1 bytes: (6c) "l"
    XFilterEvent returns: False

你也可以使用 -id id 选项将 xev 附加到现有的窗口ID。将 id 替换为从 xwininfo 获取的ID(它将是一个以 0x 开头的十六进制数字)。

14.4.5 X输入与首选项设置

X的一个最令人困惑的特性是,通常有多种方法来设置首选项,而某些方法可能不起作用。例如,Linux系统上一个常见的键盘首选项是将CAPS LOCK键重新映射为CTRL键。有多种方法可以实现这一点,从使用旧的 xmodmap 命令进行小幅调整,到使用 setxkbmap 实用程序提供全新的键盘映射。你怎么知道该用哪个(如果有的话)?这取决于知道系统的哪些部分负责,但要确定这一点可能很困难。请记住,桌面环境可能会提供自己的设置和覆盖。

话虽如此,以下是关于底层基础设施的一些指导。

输入设备(通用)

X服务器使用X输入扩展来管理来自许多不同设备的输入。有两种基本类型的输入设备——键盘和指针(鼠标)——你可以连接任意多个设备。为了同时处理多个同一类型的设备,X输入扩展创建了一个虚拟核心设备,将设备输入汇集到X服务器。

要查看机器上的设备配置,请运行 xinput --list 命令:

$ xinput --list
 Virtual core pointer                           id=2    [master pointer  (3)]
 Virtual core XTEST pointer                 id=4    [slave  pointer  (2)]
 Logitech Unifying Device                   id=8    [slave  pointer  (2)]
 Virtual core keyboard                            id=3    [master keyboard (2)]
 Virtual core XTEST keyboard                  id=5    [slave  keyboard (3)]
 Power Button                              id=6    [slave  keyboard (3)]
 Power Button                              id=7    [slave  keyboard (3)]
 Cypress USB Keyboard                      id=9    [slave  keyboard (3)]

每个设备都有一个关联的ID,你可以在 xinput 和其他命令中使用它。在这个输出中,ID 2和3是核心设备,ID 8和9是实际设备。注意机器上的电源按钮也被视为X输入设备。

大多数X客户端监听来自核心设备的输入,因为它们没有必要关心是哪个特定设备发起的事件。实际上,大多数客户端对X输入扩展一无所知。然而,客户端可以使用该扩展来专门处理某个特定设备。

每个设备都有一组关联的属性。要查看属性,请使用带有设备编号的 xinput 命令:

$ xinput --list-props 8
Device 'Logitech Unifying Device. Wireless PID:4026':
        Device Enabled (126):   1
        Coordinate Transformation Matrix (128): 1.000000, 0.000000, 0.000000, 
0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
        Device Accel Profile (256):     0
        Device Accel Constant Deceleration (257):       1.000000
        Device Accel Adaptive Deceleration (258):       1.000000
        Device Accel Velocity Scaling (259):    10.000000
--snip--

你可以使用 --set-prop 选项更改许多属性。更多信息请参见 xinput(1) 手册页。

鼠标

你可以使用 xinput 命令操作与设备相关的设置,许多最有用的选项与鼠标(指针)相关。你可以直接作为属性更改许多设置,但通常使用 xinput 的专用 --set-ptr-feedback--set-button-map 选项更简单。例如,如果你有一个三键鼠标 dev,并且想要反转按钮的顺序(这对左撇子用户很方便),请尝试:

$ xinput --set-button-map dev 3 2 1

键盘

国际上可用的多种不同键盘布局给集成到任何窗口系统中带来了特殊的困难。X在其核心协议中一直具有内部键盘映射功能,你可以使用 xmodmap 命令进行操作,但任何较新的系统都使用XKB(X键盘扩展)来获得更精细的控制。

XKB很复杂,以至于很多人仍然在需要快速更改时使用 xmodmap。XKB的基本思想是,你可以定义一个键盘映射,用 xkbcomp 命令编译它,然后用 setxkbmap 命令将该映射加载并激活到X服务器中。该系统有两个特别有趣的特性:

  • 你可以定义部分映射来补充现有的映射。这对于某些任务(例如将CAPS LOCK键更改为CTRL键)特别方便,并且被桌面环境中的许多图形键盘首选项工具所使用。
  • 你可以为每个连接的键盘定义单独的映射。

桌面背景

X服务器的根窗口是显示器的背景。旧的X命令 xsetroot 允许你设置根窗口的背景颜色和其他特性,但在大多数机器上它没有效果,因为根窗口从不可见。相反,大多数桌面环境在其他所有窗口后面放置一个大窗口,以实现“动态壁纸”和桌面文件浏览等功能。有一种方法可以从命令行更改背景(例如,在某些GNOME安装中使用 gsettings 命令),但如果你真的想这样做,你的时间可能太多了。

xset

可能最古老的首选项命令是 xset。它现在已经不常用了,但你可以运行 xset q 来快速查看一些功能的状态。其中最有用的可能是屏幕保护程序和显示电源管理信号(DPMS)设置。

14.5 D-Bus

Linux桌面最重要的进展之一是桌面总线(D-Bus),一种消息传递系统。D-Bus之所以重要,是因为它作为一种进程间通信机制,允许桌面应用程序相互通信,而且大多数Linux系统使用它来通知进程系统事件,例如插入USB驱动器。

D-Bus本身由一个库组成,该库通过协议和支持功能标准化了任意两个进程之间的进程间通信。就其本身而言,这个库提供的功能并不比普通的IPC机制(如Unix域套接字)的高级版本多多少。使D-Bus有用的是一个名为 dbus-daemon 的中心“枢纽”。需要响应事件的进程可以连接到 dbus-daemon 并注册接收某些类型的事件。连接进程也会创建事件。例如,进程 udisks-daemon 监视udev的磁盘事件,并将它们发送给 dbus-daemon,然后 dbus-daemon 将这些事件重新传输给对磁盘事件感兴趣的应用程序。

14.5.1 系统与会话实例

D-Bus已成为Linux系统的一个组成部分,现在它的应用范围已超越桌面。例如,systemd和Upstart都有D-Bus通信通道。然而,在核心系统中添加对桌面工具的依赖违背了Linux的一条设计规则。

为了解决这个问题,实际上可以运行两种类型的 dbus-daemon 实例(进程)。第一种是系统实例,它在引导时由init使用 --system 选项启动。系统实例通常以D-Bus用户身份运行,其配置文件是 /etc/dbus-1/system.conf(虽然你可能不应该更改配置)。进程可以通过Unix域套接字 /var/run/dbus/system_bus_socket 连接到系统实例。

与系统D-Bus实例独立的是可选的会话实例,它仅在你启动桌面会话时运行。你运行的桌面应用程序连接到这个实例。

14.5.2 D-Bus消息监控

了解系统dbus-daemon实例和会话dbus-daemon实例之间区别的最佳方法之一是监控经过总线的事件。尝试像这样在系统模式下使用 dbus-monitor 实用程序:

(注意:原文在此处中断,下一部分将在后续内容中继续。)

第14章:Linux桌面与打印

14.5.2 D-Bus消息监控

观察系统与会话dbus-daemon实例之间差异的最佳方法之一是监控总线上传输的事件。尝试以系统模式使用dbus-monitor工具,如下所示:

# dbus-monitor --system
signal sender=org.freedesktop.DBus -> dest=:1.952 serial=2 path=/org/
freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
   string ":1.952"

这里的启动消息表明监控器已连接并获得了一个名称。按上述方式运行时,你不应该看到太多活动,因为系统实例通常并不繁忙。若要观察到一些事件发生,可以尝试插入一个USB存储设备。

相比之下,会话实例有更多事情要做。假设你已登录到一个桌面会话,尝试执行以下命令:

$ dbus-monitor --session

现在尝试使用一个桌面应用程序,例如文件管理器;如果你的桌面是支持D-Bus的,你应该会看到大量指示各种变化的消息。请注意,并非所有应用程序都会产生消息。

14.6 打印

在Linux上打印文档是一个多阶段的过程:

  1. 执行打印的程序通常会将文档转换为PostScript格式。此步骤是可选的。
  2. 程序将文档发送到打印服务器。
  3. 打印服务器接收文档并将其放入打印队列。
  4. 当文档在队列中的顺序轮到它时,打印服务器将文档发送到打印过滤器。
  5. 如果文档不是PostScript格式,打印过滤器可能会执行格式转换。
  6. 如果目标打印机不支持PostScript,打印机驱动程序会将文档转换为打印机兼容的格式。
  7. 打印机驱动程序向文档添加可选指令,例如纸盘和双面打印选项。
  8. 打印服务器使用后端将文档发送到打印机。

此过程中最令人困惑的部分是为什么如此多地围绕PostScript。PostScript实际上是一种编程语言,因此当你使用它打印文件时,你是在向打印机发送一个程序。PostScript在类Unix系统中作为打印标准,类似于.tar格式作为归档标准。(现在有些应用程序使用PDF输出,但这相对容易转换。)

稍后我们将进一步讨论打印格式,但首先让我们看一下队列系统。

14.6.1 CUPS

Linux中的标准打印系统是CUPS(http://www.cups.org/),macOS也使用相同的系统。CUPS服务器守护进程称为cupsd,你可以使用lpr命令作为简单客户端向守护进程发送文件。

CUPS的一个重要特性是它实现了Internet打印协议(IPP),该系统允许客户端与服务器在TCP端口631上进行类似HTTP的事务。事实上,如果你的系统上运行着CUPS,你很可能可以连接到http://localhost:631/查看当前配置并检查任何打印作业。大多数网络打印机和打印服务器都支持IPP,Windows也支持,这使得设置远程打印机成为一项相对简单的任务。

你可能无法通过Web界面管理系统,因为默认设置不太安全。相反,你的发行版可能有一个图形化的设置界面来添加和修改打印机。这些工具会操作通常位于/etc/cups中的配置文件。通常最好让这些工具为你工作,因为配置可能很复杂。即使你遇到问题并需要手动配置,通常也最好先使用图形工具创建一个打印机,这样你就有了一个起点。

14.6.2 格式转换和打印过滤器

许多打印机,包括几乎所有低端型号,都不理解PostScript或PDF。为了支持这类打印机,Linux打印系统必须将文档转换为打印机特定的格式。CUPS将文档发送到光栅图像处理器(RIP)以生成位图。RIP几乎总是使用Ghostscriptgs)程序来完成大部分实际工作,但这有些复杂,因为位图必须符合打印机的格式。因此,CUPS使用的打印机驱动程序会查阅特定打印机的PostScript打印机定义(PPD)文件,以确定分辨率和纸张尺寸等设置。

14.7 其他桌面话题

Linux桌面环境的一个有趣特征是,你通常可以选择要使用的组件,并停止使用你不喜欢的部分。若要了解众多不同的桌面项目,请访问https://www.freedesktop.org/上的邮件列表和项目链接。

Linux桌面的另一个重大发展是Chromium OS开源项目及其在Chromebook PC上的对应产品Google Chrome OS。这是一个Linux系统,使用了本章描述的许多桌面技术,但以Chromium/Chrome网络浏览器为中心。Chrome OS中剥离了传统桌面上的许多内容。

尽管桌面环境看起来有趣且值得尝试,但我们在此将结束讨论。不过,如果本章激发了你的兴趣,并且你认为自己可能愿意从事相关工作,那么你将需要了解开发工具的工作原理,这正是我们接下来要讨论的内容。

图像说明

本页(第373页)包含以下图像占位符,但原始文本中未提供图像内容或上下文:

  • [Image 2327]
  • [Image 2321]
  • [Image 2325]
  • [Image 2317]
  • [Image 2323]
  • [Image 2316]
  • [Image 2320]
  • [Image 2315]
  • [Image 2319]

这些图像可能包含与D-Bus监控示例或打印流程图相关的图形,但无法从现有文本中重现。