【技术】Xorg 实现不重启调整缩放 & 多显示器不同缩放
为了帮助搜索,这里加点 tag。
(ubuntu, kde, x-server, kubuntu, plasma, x-org)
这篇文章对你有帮助吗?
首先,本文适用于使用 Xorg 图形服务的 Linux 系统,如果你不在使用 Xorg,那此文对你没有帮助。
- 目前 Gnome 默认使用 Wayland 而非 Xorg,因此默认配置的 Ubuntu 20.04~22.04 不适用。
- 目前 KDE 默认采用 Xorg,因此默认配置的 Kubuntu 仍然适用(我就在用 Kubuntu 22.04)。
- 其余系统请自行百度如何查询图形服务为 Xorg 还是 Wayland。
其次,此文操作原理是使用 xrandr 命令的 –scale 选项。如果你排斥使用 xrandr –scale,那此文对你没有帮助。
- 非整数的缩放可能会带来十分轻微的画质下降和卡顿(不过影响很小,建议先试试);
- 如果你已经熟练地阅读了 xrandr 的 manpage 并掌握其操作,那你大概率不需要阅读此文。
最后,如果你只是需要调整全局缩放,并不需要实现不重启 / 多显示器不同缩放,那建议使用更稳定的传统方法而非此文的方法。
- 调整全局缩放的传统方法一是直接使用 kde 系统设置中的全局缩放设置,二是使用 xrandr –dpi 选项。前者众所周知需要重启,后者则必须要在 X 服务启动前就设定,因此一般需要写死在 ~/.Xsession 中,也不能在系统启动后热调整缩放。
前言
本人的需求是这样的,我有一台 14 英寸分辨率为 2160x1440 的笔记本,日常缩放为 175%,在宿舍里有一台 23.8 英寸分辨率为 2560x1440 的显示器,日常缩放为 150%,回宿舍就用显示器看。然而在使用 Xorg 的 Kubuntu 下,每次回宿舍或者出门都要调缩放、重启,实在是不够完美。经过 stfw,我摸索出了一个不重启调整缩放的 workaround,这个方法同时也能实现多屏幕不同缩放比。
我的想法是让全局缩放一直开在 175%,也就是比较高的一档,然后通过渲染出超分辨率的画面再缩小到显示器上,就可以实现降低全局缩放的效果。先贴一下效果图,我的显示器分辨率为 2560x1440,这里 Resolution 显示的是 2816x1584,说明已经完成了显示缩小。
方法
首先,直接运行 xrandr
命令,可以看到目前有哪几个显示器以及它们的名字。输出应该类似于
1 |
|
接下来讲一下 xrandr 工具用得到的各个选项的含义和使用方法。以下中括号表示需要代入具体内容,实际敲的时候不需要写中括号。
--fb [A]x[B]
:指定画布大小为 A 像素长乘 B 像素宽。注意中间是小写字母 x,下同。--output [A]
:后续的选项对显示器 A 生效。- 显示器的名称可以通过上面说的方法,即直接执行
xrandr
看到
- 显示器的名称可以通过上面说的方法,即直接执行
--mode [A]x[B]
:指定当前显示器输出分辨率为 A 乘 B。--scale [A]x[B]
:指定当前显示器在长上缩小 A 倍,在宽上缩小 B 倍,因此 A > 1 表示缩小。--pos [A]x[B]
:指定当前显示器在画布上的位置。具体来说就是显示器应该显示的区域的左上角在画布上的坐标。- 坐标原点为左上角,单位为像素
--panning [A]x[B]+[C]+[D]
:设定当前显示器可点击区域为左上角坐标为 (C 像素, D 像素),长为 A 像素,宽为 B 像素的矩形。所谓可点击区域,就是说在画布上的这一块区域是实际显示内容、可以点击的。
上面这部分内容可以和 xrandr 的 manpage 结合起来看,毕竟我复述的肯定不如官方文档全。我们的原理是先使用 –fb 选项渲染出一个超分辨率的画布,然后使用 –scale 选项缩小它的大小,并且使用 –pos 选项指定屏幕显示画布那一块被缩小了的部分。
单显示器
结合上面所说的,不重启实现单显示器缩放命令形式应该类似于
1 |
|
举个例子,我们现在有一个物理分辨率为 2560 x 1440 的显示器,名字叫 HDMI-A-0,现在的全局缩放为 175%,需要改为 150%。
计算可得 $\sqrt{\frac{175}{150}}\approx 1.08$。由于渲染的分辨率需要为整数,选择缩小 1.1 倍。
我一开始忘记开根号了,缩小了 1.2 倍,然后一直寻思字怎么这么小(捂脸哭.jpg
以缩小 1.1 倍为例,需要渲染一个 (2560 * 1.1) x (1440 * 1.1) = 2816 x 1584 的画布然后再缩小。可点击区域就是左上为 (0, 0),2816 x 1584 大小的区域。因此命令为
1 |
|
多显示器
多显示器不同分辨率拼接的命令形式应该为
1 |
|
举个例子,这里参考了 Barry 的笔记。有一个物理分辨率为 2160x1440 的笔记本屏幕 eDP-1(这分辨率一眼 matebook),一个物理分辨率为 1920x1080 的显示器 DP-1 需要拼接在笔记本屏幕右侧,内容相较于笔记本屏幕需要缩小 1.5 倍。
由于是横向排布,整个画布的长应该为 1920*1.5 + 2160 = 5040,宽为 max{1080*1.5, 1440} = 1620。笔记本屏幕的位置应为 0x0,显示器的左上角位置为 2160*0。笔记本可点击区域直接使用默认设置,显示器的可点击区域为左上角为 2160*0,大小为 2880*1620 的矩形。因此,命令行为
1 |
|
这个 –dpi 选项是作者原来就写的,在我的电脑上不起作用,具体原因不明,我猜是因为 KDE 的默认缩放覆盖了这个设置。我个人是感觉不写也行,大家可以自己试试写不写 dpi 有没有区别。
后续
如果你在使用 KDE plasma 5 作为桌面,可能 plasma shell 不会根据最新的分辨率自动调整位置,这个时候需要重启 plasma shell 来适应新的分辨率。好在 plasma shell 是支持热重启的。
1 |
|
此时,如果你在屏幕下方和右方有 plasma 面板,你可能会发现它们变得十分卡顿。这估计是 KDE 的任务栏坐标不是整数导致渲染出问题,目前好像没啥办法可以根本解决(如果有大佬会请一定要娇娇我)。一个妥协的方法是将这些面板移到屏幕上方或者左侧。
花了一个小时和这个 bug 搏斗,最终还是妥协了