xps13(9370) Linux之路



简介

我希望通过戴尔xps13的实例让喜欢爱折腾的玩家加入Linux,出现的代码可以在我的Github仓库xps-13-conf查找。

选择发行版和桌面环境分别是ArchLinux和GNOME。

新手强烈建议Manjaro起步,不要碰ArchLinux,不要碰ArchLinux,不要碰ArchLinux。哪怕给你安装了ArchLinux,你后续的时间成本也很重。

文章更新于2020-04-05

选择ArchLinux的原因

  1. 滚动更新,ArchLinux Wiki和社区论坛可以解决大部分入坑者的问题;
  2. 通过Arch Build System(ABS)Arch User Repository(AUR)安装维护软件十分方便,享受前人的成果,我使用yay安装各种软件和工具;
  3. 自定义程度极高,例如我就是从Manjaro转到ArchLinux,遇到个别问题可以参考Manjaro是如何实现和解决的;

选择GNOME的原因

  1. Ubuntu是目前最多人使用的Linux的发行版,桌面环境默认是GNOME,如果一个UI界面使用群体低的话,会有非常多的坑;
  2. GNOME界面风格最接近现代操作系统,如macOS;
  3. 扩展能力非常强,有Gnome shell extensions

简述ArchLinux启动过程

在安装前简述ArchLinux我认为还是很有必要的,方便后续理解。

如今BIOS已经被UEFI取代,这里就略过过时的技术了,直接使用UEFI。

通电后,一个完整的Linux启动过程大致如下:

  1. UEFI:选择启动Bootloader,双/多系统就是从这里选择的;
  2. Bootloader:初始化硬件(内存和磁盘驱动等)并加载Kernel镜像;
  3. Kernel:系统核心调度和驱动硬件,初始化后引导initramfs;
  4. initramfs:本质是一个最小镜像,最主要用途是挂载真实文件系统,最终调用init;
  5. init最后调用getty或者Display Manger服务,也就是我们正常操作的界面;

这里安装的ArchLinux中,Bootloader实例是GRUB,Kernel的镜像是vmlinuxz-linux-lts,initramfs是initramfs-linux-lts.img,init是systemd。

参考来源:

  1. Arch_boot_process

安装预备

下载镜像

Arch Linux Downloads选择中国镜像并下载。

制作USB启动盘

  1. Windows下可使用Rufus,按照官方教程即可;
  2. Linux下使用dd命令:sudo dd if=/path/to/archlinux-date-x86_64.iso of=/dev/sdX bs=4M && sync,请修改镜像的实际路径和U盘实际设备号;

修改boot menu

按F2进入bios修改:

如果没有修成上述的设置,xps13进入引导程序后可能无法发现ssd。

参考来源:

  1. Arch XPS 9370#UEFI

如果是其他笔记本,可以在ArchLinux选择对应型号搜索即可。

安装过程

以下的安装流程都是离不开Installation guide。这里的安装目标是可以登录GNOME Display Manager(GDM)。

如果没有意外,通过引导USB启动盘能进入到终端。

我的显示器分辨率为4K,默认的字体太小,需要设置终端字体:

执行setfont latarcyrheb-sun32,这是终端自带字体包目前最大的字体。

参考来源:

  1. HiDPI#Linux_console

/root/install.txt有一个离线安装指导,离线的情况下可以参考。

检验UEFI启动

通过ls /sys/firmware/efivars命令检验这个文件是否存在,存在则代表UEFI启动。

配置网络

我使用笔记本,这里使用Wi-Fi连接网络,步骤会比有线网络稍微复杂。

  1. 获取笔记本网卡的设备名称:ip link,我的机器是wlan0
  2. 使网卡上线:ip link set wlan0 up
  3. 获取局域网的Wi-Fi的帐号:iw dev interface scan | grep 'SSID'
  4. 如今一般的Wi-Fi的帐号都是WPA/WPA2密码,需要用wpa_supplicant这个命令连上Wi-Fi。执行:wpa_supplicant -B -i wlan0 -c <(wpa_passphrase MYSSID passphrase);
  5. 检验Wi-Fi是否连接上:iw dev wlan0 link
  6. 自动获取动态ip地址:dhcpcd
  7. 检验是否获取ip地址:ip a wlan0

参考来源:

  1. Network configuration/Wireless
  2. wpa_supplican

配置系统时钟

执行timedatectl set-ntp true

磁盘分区并格式化

因为是UEFI启动,所以需要GPT分区表,而不能使用MBR分区表。

磁盘分区

  1. 通过lsblk显示磁盘名称,这里我的ssd是nvme0n1
  2. 用fdisk对ssd分区:fdisk /dev/nvme0n1

fdisk用到的快捷键:

分区流程如下:

  1. g创建GPT分区表;
  2. n创建分区,我这里分别创建300MB EFI,375GB的Root和SWAP 20GB(我的内存是16GB)的分区;
  3. t给已经创建的分区分配类型;
  4. w保存设置;

因为我需要深度休眠Hibernation,所以SWAP需要20GB左右,划分SWAP分区的大小可以参考下面的链接。

参考来源:

  1. SwapFaq

格式化分区

每一种分区类型对应的命令稍有不同。

  1. 格式化EFI分区:mkfs.vfat /dev/nvme0n1p1
  2. 格式化Root分区为ext4格式:mkfs.ext4 /dev/nvme0n1p2
  3. 格式化SWAP分区:mkswap /dev/nvme0n1p3
  4. 激活SWAP分区:swapon /dev/nvme0n1p3

挂载系统文件

这里要挂载刚才创建的EFI和Root分区,挂载EFI分区是为了安装引导程序,挂载Root分区当然是为了安装最小的镜像。

  1. 挂载Root分区到/mntmount /dev/nvme0n1p2 /mnt
  2. 创建/mnt/boot/efi目录,mkdir -p /mnt/boot/efi
  3. 挂载EFI分区,mount /dev/nvme0n1p1 /mnt/boot/efi

EFI的分区可能有部分人是/mnt/efi,因为我是Manjaro入门,所以这里参考Manjaro的目录路径。

制作最小镜像

更换镜像源

默认的镜像源是国外的,速度对国内用户极度不友善,国内用户需要手动更新源文件。编辑/etc/pacman.d/mirrorlist,选择一个China服务器移放到顶部或者注释其他国家的服务器。

pacman是ArchLinux的Arch Build System(ABS)包的管理工具。

pacstrap脚本安装包

pacstrap只是一个安装包的工具到指定目录上,安装包类似于pacman。

不建议安装linux这个包,除非你的驱动需要最新内核,否则建议linux-lts长期支持的内核版本。

pacstrap /mnt base base-devel linux-lts linux-lts-headers linux-firmware

最终要安装到系统的包都可以通过pacstrap预先安装。

生成Fstab

生成fstab:genfstab -U /mnt >> /mnt/etc/fstab,并确认分区cat /mnt/etc/fstab

通电后启动GRUB的时候(GRUB配置内已经记录Root分区信息),会把Root分区信息以参数形式传递到Kernel,Kernel以只读的方式挂载Root分区,然后读取fstab的信息,最后init的时候重新挂载fstab内容的分区。

参考来源:

  1. how-is-etc-fstab-accessed-before-root-is-mounted

配置镜像

Chroot

Chroot大体用途是改变你当前的根目录为指定目录并加载指定目录镜像,非常有用。特别是你可以在系统无法正常启动的时候,利用USB引导盘执行chroot进入故障根目录并排查问题。

chroot到刚才我们已经基本完善的根目录镜像/mntarch-chroot /mnt,此后我们犹如进入预装系统,后续一切操作都是真实操作,对系统是真实生效的。

配置终端字体

4K分辨率默认的字体太小,下载稍微好看的终端字体包,并设置终端字体。

  1. 下载终端字体:pacman -Sy terminus-font
  2. 设置终端字体:setfont ter-132n

配置时区时间

执行ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && hwclock --systohc

设置locale

  1. 编辑/etc/locale.gen,取消en_US.UTF-8 UTF-8的注释并保存;
  2. 执行locale-gen
  3. 设置环境变量LANG:echo 'LANG=en_US.UTF-8' > /etc/locale.conf;

配置网络

我的hostname是kevin-pc,可以根据自己喜好命名。 趁现在已经联网,执行pacman -S networkmanager安装networkmanager,不然后续重启后没办法上网

配置hostname

配置/etc/hostnameecho 'kevin-pc' > /etc/hostname

配置hosts

编辑/etc/hosts,内容如下:

1
2
3
127.0.0.1	localhost
127.0.1.1	kevin-pc
::1	localhost ip6-localhost ip6-loopback

更改root的密码

执行passwd,后面就可以输入自定义的密码。

配置Bootloader

目前大部分发行版都是GRUB作为Bootloader,这里随大流,少踩坑。遇上多系统无法引导的问题,可以利用配置Bootloader的这小节的步骤进行修复。

安装GRUB

  1. 安装必要的包:pacman -S grub efibootmgr
  2. 在EFI分区生成Bootlaoder文件:grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ArchLinux,–efi-directory是EFI分区的文件路径,–bootloader-id就是id,随你喜欢;
  3. 检查是否生成/boot/efi/EFI/ArchLinux/grubx64.efi文件和/boot/grub/x86_64-efi目录;

配置GRUB

  1. 编辑/etc/default/grub,保存你所需要的设置;
  2. 生成grub.cfg文件:grub-mkconfig -o /boot/grub/grub.cfg

参考来源:

  1. Boot_loader
  2. GRUB

到这里配置镜像基本完成了,按ctrl-d退出chroot,执行umount -R /mntreboot后便可以拔掉USB启动盘了。

进入图形界面的前置配置

添加普通用户

登录root帐号后,不可能以root角色使用Linux桌面,需要一个普通权限的用户。

添加名为kevin的用户,并设置zsh为默认的shell:

  1. 安装zsh:pacman -S zsh
  2. 添加普通用户:useradd -m -U -G sys,power,wheel,input,network -s /bin/zsh kevin
  3. 修改密码:passwd kevin,后面就可以输入自定义的密码;

添加完用户后需要验证用户是否创建成功,直接切换到新的用户:su kevin,输入密码完成登录。

参考来源:

  1. Users_and_groups

配置网络

此时是没办法上网的,利用之前安装的networkmanager,现在可以直接执行:

  1. 启动NetworkManager服务,可以动态获取IP地址:systemctl start NetworkManager.service
  2. 激活NetworkManager服务,开机自动启动:systemctl enable NetworkManager.service

启动NetworkManager服务后,需要用nmcli命令行连接上具体的Wi-Fi,这个命令在日常使用Linux中也是非常有用,推荐使用。

  1. 检测网络连接状态:nmcli radio
  2. 若Wi-Fi连接状态是off可以:nmcli radio wifi on打开Wi-Fi;
  3. 重新刷新并列出Wi-Fi:nmcli device wifi rescan && nmcli detail wifi list
  4. 选择一个Wi-Fi连接:nmcli device wifi connect 'ssid' password 'password'

参考来源: nmcli_examples

安装显卡

通过lspci | grep VGA查看显卡信息,我的显卡是uhd 620。

KMS下默认已经有modesetting驱动,xf86-video-intel这个包问题还是比较多,不建议在uhd620下安装。如果用其他显卡,请自行搜索资料。

安装GNOME桌面

如果喜欢默认的GNOME全家桶可以直接:sudo pacman -S gnome安装以gnome为group的所有包。

我喜欢一个较为纯净的GNOME,根据自身需求安装,如下:

sudo pacman -S gdm gnome-control-center gnome-keyring gnome-disk-utility xdg-user-dirs xorg-init

这里会根据依赖安装GNOME被依赖的包,所以并没有罗列全部包。

安装完GNOME会根据依赖自动安装蓝牙服务,这里启动蓝牙服务:

  1. 启动bluetooth服务:systemctl start bluetooth.service
  2. 激活bluetooth服务,开启自动启动:systemctl enable bluetooth.service

至此已经基本把ArchLinux和GNOME安装完毕,执行reboot重启进入GDM登录界面选择kevin登录即可以进入GNOME。

调教系统

安装yay

默认pacman不太好用,例如一定要在pacman前面加sudo,并且不能安装Arch User Repository(AUR)的包。所以需要一款工具,这里使用yay。

  1. git clone https://aur.archlinux.org/yay.git
  2. cd yay && makepkg -si

yay受pacman的配置影响,我偏好开启颜色和包的详细信息。编辑/etc/pacman.conf并注释掉ColorVerbosePkgLists即可。

参考来源:

  1. yay

配置sudo

sudo输入正确密码后,默认的超时时间是5分钟,这个时间太短,并且我使用的是tmux,默认配置在不同窗口下是不能共享正确密码,一旦超时,需要繁琐且不断重复输入密码,这里可以适当延长超时时间和把超时时间设置成全局。

在root权限下(su root或者sudo),编辑/etc/sudoers.d/10-installer文件如下:

1
2
3
%wheel ALL=(ALL) ALL
Defaults timestamp_timeout=60
Defaults timestamp_type=global

参考来源:

  1. sudo

电源节能

笔记本有续航的需求,需要一款节能的软件,TLP可以解决这个问题。

  1. 安装TLP:yay -S tlp tlp-rdw
  2. 启动并激活tlp服务:sudo systemctl start tlp.service && sudo systemctl enable tlp.service
  3. 屏蔽systemd-rfkill:sudo systemctl mask systemd-rfkill.service && sudo systemctl mask systemd-rfkill.socket

参考来源:

  1. tlp

配置深度休眠

配置Hibernation

在安装系统的时候虽然为SWAP分区预留出空间,但initramfs引导起来后并不能利用这个空间,需要重新生成initramfs。

  1. 编辑/etc/mkinitcpio.conf,在HOOKS=(base ......)基础上修改成HOOKS=(base ...... resume)
  2. 生成initramfs:sudo mkinitcpio -p linux-lts

参考来源:

  1. Configure_the_initramfs

修复无法进入深度睡眠

当晚上睡觉前合上盖子休眠,早上醒来打开会掉电20%,原因是未进入深度休眠。

可以通过cat /sys/power/mem_sleep查看输出是[s2idle] deep,还是s2idle [deep],若是后者请自行查找相关资料。

  1. 编辑’/etc/default/grub’,修改GRUB_CMDLINE_LINUX_DEFAULT添加内核启动参数mem_sleep_default=deep,如GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"更改成GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep"
  2. 执行sudo grub-mkconfig -o /boot/grub/grub.cfg更新grub;
  3. 重启系统后,执行cat /sys/power/mem_sleep确保输出是s2idle [deep]

参考来源:

  1. Ubuntu 18.04 - Dell XPS13 9370 no longer suspends on lid close
  2. Arch XPS 9370 PowerManagement

解锁AC电源模式下的CPU性能

XPS 9370在下CPU封装的限制温度是95摄氏度,而Linux却是80摄氏度,应该算是一个Bug,这极大限制了CPU的性能,需要安装throttled解除限制。

  1. 安装s-tui测试CPU数据yay -S s-tui,安装后root权限打开s-tui,在Modes栏中选中Stress进行压力测试,看稳定温度是否超过80摄氏度,不能则执行下面步骤;
  2. 安装throttled:yay -S throttled
  3. 开启并激活throttled服务sudo systemctl enable lenovo_fix.service && sudo systemctl start lenovo_fix.service
  4. 在s-tui压力模式下稳定温度是否超过80摄氏度;
  5. 修改/etc/lenovo_fix.conf可以调整参数;

性能对比

没有启动lenovo_fix.service

CPU功耗很难突破15W和稳定温度无法超过80摄氏度。

在默认配置的条件下开启后

CPU可以稳定保持在2.8-3.0Ghz并且功耗在27W左右,稳定温度在95摄氏度左右。

修改undervolt的配置

1
2
3
4
5
6
7
8
9
10
11
[UNDERVOLT.AC]
# CPU core voltage offset (mV)
CORE: -95
# Integrated GPU voltage offset (mV)
GPU: -125
# CPU cache voltage offset (mV)
CACHE: -95
# System Agent voltage offset (mV)
UNCORE: 0
# Analog I/O voltage offset (mV)
ANALOGIO: 0

以上是我的xps13修改的undervolt参数,每台笔记本参数不一致,需要在Windows的intel xtu下调优适合的参数(使用双系统)。

修改参数后CPU可以稳定保持在3.1-3.2Ghz并功耗在27W左右,稳定温度在95摄氏度左右。

参考来源:

  1. Arch XPS 9370 Thermal Throttling
  2. github-throttled

降低热量

  1. 更换CPU和散热器间的硅脂,我用的是信越7921的硅脂。
  2. xps13是金属背壳,通过散热垫片把热量导到背壳,使用1.5mm厚度的散热垫片(每款笔记本厚度间隙不一致)。

xps13-repaste

通过更换硅脂和添加散热垫后,温度从95摄氏度变成81摄氏度,CPU频率有所提升。

xps13-repaste

参考来源:

  1. reddit_dell_xps_13_8th_gen_thermal_optimization_repaste

改变风扇特性

默认情况下是bios控制主板的风扇。不得不说这控制逻辑真的很奇葩。如果按照默认的bios控制风扇,xps13这部笔记本绝对是不建议购买的。CPU温度在50+摄氏度风扇就会猛转。

正确安装风扇驱动

lm_sensors(yay -S lm_sensors),看不到主板风扇的sensors。因缺少或者加载错误驱动。对于xps13而言就是加载dell_smm_hwmon驱动错误。

执行sudo modprobe dell_smm_hwmon ignore_dmi=1后,再运行sensors查看是否有风扇的参数或者cat /proc/i8k是否运行正确。

modinfo dell-smm-hwmon可以查看驱动信息,包括参数的含义。

参考来源:

  1. reddit_configuring_the_xps_to_play_nice_with_linux

安装驱动工具

只要加载驱动成功就可以继续安装i8kutils,执行yay -S i8kutils。 i8kfan只可以调控左右两个风扇3档调速,分别是0 0,1 1, 2 2。执行i8kfan 2 2发现不能工作。重新加载驱动执行sudo modprobe dell_smm_hwmon ignore_dmi=1 restricted=0后,可以控制风扇的3档调速。

  1. 避免每次开机都要手动加载驱动,可以创建echo 'options dell-smm-hwmon ignore_dmi=1 restricted=0' > /etc/modprobe.d/dell-smm-hwmon.conf
  2. 开启并激活i8kmon服务sudo systemctl enable i8kmon.service && sudo systemctl start i8kmon.service

禁止bios控制风扇

虽然可以手动或开启服务控制风扇的转速,但bios仍然参与风扇控制。这导致风扇的控制特性不符合预期,需要禁止bios控制风扇。

  1. 执行yay -S dell-bios-fan-control-git安装禁止bios控制风扇的命令。
  2. 安装后执行sudo dell-bios-fan-control 0,终端输出BIOS CONTROL DISABLED

禁用bios控制风扇是在应用态而不是内核态(driver)。当系统进入休眠再次唤醒的时候,bios将会重新接管风扇的控制。这里有两种方案:

  1. 修改内核,为其添加禁用bios控制风扇的driver(例如Wi-Fi休眠后唤醒可正常工作)。
  2. 在应用态添加服务,触发时机是在休眠前后。

方案1对于ArchLinux是很危险的,滚动更新内核。最好别自行更改内核,所以这里选择方案2。方案2最佳的例子就是TLP,参照TLP的版本是1.22以前的,最新版对sleep的策略已经略有不同。

已经制作Makefile适合懒人:fan

参照tlp.servicetlp-sleep.service,分别编写dell-fan-control.servicedell-fan-control-sleep.service并放置到/etc/systemd/system/路径下。

dell-fan-control.service代码如下:

[Unit]
Description=Disables BIOS control of fans at boot.
Before=i8kmon.service

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/bin/dell-fan-control 1
ExecStop=/usr/bin/dell-fan-control 0

[Install]
WantedBy=multi-user.target

dell-fan-control-sleep.service代码如下:

[Unit]
Description=Enable BIOS control of fans at sleep.
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/dell-fan-control 0
ExecStop=/usr/bin/dell-fan-control 1

[Install]
WantedBy=sleep.target

dell-fan-control是封装了dell-bios-fan-control的简单可执行shell,把其放置到/usr/bin/路径下,其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env bash

if [ "$(whoami)" != root ]; then
    echo 'You need to be root.'
    exit
fi

if [[ ! -x "$(command -v dell-bios-fan-control)" ]]; then
    echo 'dell-bios-fan-control is not found.'
    exit
fi

if [[ ! -x "$(command -v i8kfan)" ]]; then
    echo 'dell-bios-fan-control is not found.'
    exit
fi

if (($1 == 1)); then
    dell-bios-fan-control 0 >/dev/null
    i8kfan 0 0 >/dev/null
    echo 'User control fan is enabled.'
else
    dell-bios-fan-control 1 >/dev/null
    echo 'User control fan is disabled.'
fi
  1. 执行sudo dell-fan-control 1,终端输出User control fan is enabled.表示成功。
  2. 分别开启dell-fan-control.service和dell-fan-control-sleep.service服务sudo systemctl enable dell-fan-control.service && sudo systemctl enable dell-fan-control-sleep.service并start。

参考来源:

  1. github-i8kutils-issues-6
  2. github-dell-bios-fan-control

自定义温度vs风扇转速曲线

i8kutils默认配置文件是/etc/i8kutils/i8kmon.conf,修改部分的代码如下:

1
2
3
4
5
6
set config(acpi) "acpi -a"

set config(0)   { {0 0}  -1  75  -1  60 }
set config(1)   { {1 1}  70  85  55  70 }
set config(2)   { {2 2}  75  92  60  80 }
set config(3)   { {2 2}  90 128  75 128 }
  1. 控制风扇特性曲线有两种状态分别是电源和电池。i8kutils依赖acpi判断是电源还是电池状态。发现电源状态曲线失效,查看/usr/bin/i8kmon的代码,发现默认配置的acpi命令有误,无法正确匹配,添加set config(acpi) "acpi -a"就能正确匹配(怀疑是用了老版本的acpi,这里不深究);
  2. 简单解释一下怎么自定义曲线的参数。如{ {1 1} 70 85 55 70 },{1 1}代表左右风扇的档速,这里是左右风扇的第一档(0关闭,2转速最大)。70 85代表电源状态下的滞回温度,低于70摄氏度左右风扇调节0档,高于85摄氏度左右风扇调节到2档。55 70则是电池状态下的滞回温度;
  3. 这个参数是追求风扇噪声低的前提下配置出来的。电池状态的温度比电源状态低的缘故就是怕放在膝盖的时候烫人= =!不过测试过CPU在85摄氏度的时候,背壳也就55摄氏度左右;
  4. 修改完毕后重启i8kmon.service即可生效;

修复蓝牙音频漏洞

在蓝牙音频设备与XPS 9370连接成功后,在sound settings声音选项中大概率无法找到该蓝牙设备选项,也就是无法切换音源。

原因是系统启动的时候,蓝牙服务会初始pulseaudio蓝牙音频模块,pulseaudio需要X-server(图形界面)启动后才能正常初始化,但实际情况蓝牙服务早于X-server初始化完成,导致pulseaudio初始化失败。

只需要把初始化pulseaudio的代码放到X-server后面即可。

  1. 编辑/etc/pulse/default.pa,注释掉蓝牙服务初始化pulseaudio的代码;
    1
    2
    3
    
    # .ifexists module-bluetooth-discover.so
    # load-module module-bluetooth-discover
    # .endif
    
  2. 编辑/usr/bin/start-pulseaudio-x11,找到以下代码段
    1
    2
    3
    
    if [ x”$SESSION_MANAGER!= x ] ; then
      /usr/bin/pactl load-module module-x11-xsmp “display=$DISPLAY session_manager=$SESSION_MANAGER> /dev/null
    fi
    

    ,修改为

    1
    2
    3
    4
    5
    
    if [ x”$SESSION_MANAGER!= x ] ; then
      /usr/bin/pactl load-module module-x11-xsmp “display=$DISPLAY session_manager=$SESSION_MANAGER> /dev/null
      /usr/bin/pactl load-module module-bluetooth-discover
      /usr/bin/pactl load-module module-switch-on-connect
    fi
    
  3. 重启机器即可正常工作;

参考来源:

  1. ask ubuntu bluetooth headset connects but not showing in sound settings

休眠停止音乐播放

在图书馆或者其他安静的公共场合佩带着蓝牙耳机听音乐的时候,休眠(合盖)再唤醒,蓝牙接收不及时导致音乐外放。可以通过休眠/锁屏就关闭音乐播放。

原理是利用dbus监控锁屏事件(没禁用锁屏则休眠会产生锁屏事件)并通过playerctl暂停音乐。

已经制作Makefile适合懒人:audio

pause-audio-on-lock放置到$PATH路径下,其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env bash

if [[ ! -x $(command -v playerctl) ]]; then
    exit 1
fi

DBUS_LOCK="interface='org.gnome.ScreenSaver',member='ActiveChanged'"
LOCK_SIGNAL='true'
dbus-monitor --session "type='signal',$DBUS_LOCK" |
    (
        while read -r line; do
            if grep $LOCK_SIGNAL <<<$line 2>/dev/null; then
                for player in $(playerctl --list-all); do
                    if [[ $(playerctl --player=$player status) == Playing ]]; then
                        playerctl --player=$player pause
                    fi
                done
            fi
        done
    )

编写和dbus相关的user service,这里并不是系统级别的,因为dbus跟每个用户绑定,所以service也要和用户绑定。

pause-audio-on-lock.service放置到$HOME/.config/systemd/user路径下,其代码如下:

[Unit]
Description=Pause audio on lock
BindsTo=graphical-session.target
After=graphical-session.target

[Service]
Type=simple
ExecStart=请修改成pause-audio-on-lock的绝对路径

[Install]
WantedBy=graphical-session.target

启动并激活服务:sudo systemctl --user start pause-audio-on-lock.service && sudo systemctl --user enable pause-audio-on-lock

测试:可以开启音乐锁屏,重新进入是否音乐停止播放。

参考来源:

  1. pause-on-lock
  2. writing-a-service-that-depends-on-xorg

为触摸板添加自定义手势

默认触摸板可以只有普通的双击,三击和双手滑动的手势,这里可以添加2-4指缩放,3-4上下左右滑动的自动以手势。

可以通过libinput-gestures实现。

  1. 安装yay -S libinput-gestures
  2. 添加你的用户到input groupsudo gpasswd -a $USER input,完成后登出或者重启机器;
  3. 启动libinput-gestures守护线程libinput-gestures-setup autostart && libinput-gestures-setup start
  4. 理解阅读xdotool和wmctrl,是实现手势的方法,可以参考/etc/libinput-gestures.conf
  5. 编辑~/.config/libinput-gestures.conf

我的配置如下:

1
2
3
4
5
gesture: swipe left 3 xdotool key XF86Back
gesture: swipe right 3 xdotool key XF86Forward
gesture: swipe up 4 xdotool key super+alt+8
gesture: swipe left 4 xdotool key super+alt+minus
gesture: swipe right 4 xdotool key super+alt+equal

更改按键映射

我是一位vim用户,按键映射是必须更换的,更改的键位比较复杂,可以描述为:

  1. Esc->CapsLock
  2. ~/`->Esc
  3. CapsLock->LeftCtrl
  4. LeftCtrl->~/`

主要是为了让左小指按压Esc和LeftCtrl更轻松,代码比较冗余,就不贴了,具体代码可以查看xkbkbd

  1. 对于X-server而言,修改/usr/share/X11/xkb/symbols/pc/usr/share/X11/xkb/symbols/us
  2. 对于Vconsole而言,复制/usr/share/kbd/keymaps/i386/qwerty/us.map.gz/usr/share/kbd/keymaps/路径下并修改其按键映射。同时更改/etc/vconsole.conf的KEYMAP=对应的名字。(如我添加的文件名是personal.map,那么KEYMAP=personal);

参考来源:

  1. a-simple-humble-but-comprehensive-guide-to-xkb-for-linux
  2. Keyboard_configuration_in_console

外置显卡

硬件环境

需求

外置显卡驱动内置4k显示器和两块外置4显示器或者两块外置4k显示器工作使用(非游戏玩家)。

选卡

eGPU.io大部分Linux系统的Build案例是N卡,所以这里直接选择N卡,驱动3个4K分辨率的显示器保守一点还是选择了1060 3GB。

安装N卡私有驱动

  1. 连接好硬件,通过lspci | grep VGA查看显卡信息,确认nvidia的显卡出现在输出;
  2. 安装nvidia-dkms:yay -S nvidia-dkms

解决无法启动外置显卡

按照A script to change Xorg config,无法启动外置显卡,通过GDM登录帐号的时候进入死循环,无法进入GNOME。

通过journalctl -b发现无法正确检测到Nvidia显卡,动态切换回Intel显卡渲染X-server。通过以下手段得知是时序问题:

  1. 禁用动态切换/etc/X11/xorg.conf,默认用Nvidia的配置,开机一段时间后,通过虚拟终端登录并startx可以成功登录并用Nvidia渲染X-server。
  2. 用机械硬盘安装系统并启动,连接外置显卡。eGPU提供的脚本能正确用Nvidia渲染X-server。
  3. xps13 9370用的是nvme存储,比机械硬盘快得多。对比两者启动的日志,发现Thunderbolt加载之间的时间差异。
  4. 在nvme启动情况下,修改脚本,延时检测动态切换的代码。eGPU提供的脚本能正常用Nvidia渲染X-server。

基于eGPU提供的脚本,我编写了一个异步延时检测切换显卡的脚本gxs,使用查看README。

启动脚本后,在GDM界面输入账户密码这段时间内,会异步延时检测动态的显卡,使得用户看起来不会闪屏卡顿。

未解决的问题

外置显卡真的遇到挺多的问题,有些问题至今仍未解决,如以下问题:

  1. 无法在X-server下动态切换显卡。只有重新配置并重启X-server,才能切换Intel和Nvidia显卡。
  2. 用Nvidia外置显卡同时渲染内置和外置显示器将会卡顿不流畅,并且会撕裂。这可能是时序同步问题和外置显卡渲染内屏损耗导致。
  3. Intel和Nvidia显卡不能在同一个X-server同时渲染。如内置显示器用Intel,而外置显示器用Nvidia。

解决tmux被杀掉的问题

切换显卡的时候按道理可以保留tmux的程序(X-server肯定要重启的)。现实情况是切换显卡过了10+秒后不重新登录X-server,整个tmux session消失了。

原因是当用户登出后,系统会在一定时间内杀掉用户启动的服务,例如tmux。这里解决的办法是让tmux作为一个systemd系统服务,这样就可以解决因为Xserver退出导致tmux也被强制退出。

tmux@service内容如下:

[Unit]
Description=Start tmux server, require to set server option exit-empty off

[Service]
Type=forking
User=%I
ExecStart=/usr/bin/zsh -i -c 'source ~/.zshrc; /usr/bin/tmux start-server'
ExecStop=/usr/bin/tmux kill-server

[Install]
WantedBy=multi-user.target
  1. 启动服务的时候并没有启动tmux的session,所以需要.tmux.conf内设置set -sg exit-empty off
  2. [email protected]放置到/etc/systemd/system下;
  3. 启动并激活服务:sudo systemctl start [email protected] && sudo systemctl enable [email protected],这里的用户名是kevin,根据你自己的实际情况替换;

参考来源:

  1. eGPU build-guides
  2. A script to change Xorg config
  3. PCI Express vs. Thunderbolt - How much performance drop of your GPU you will have if you put it in eGPU
  4. eGPU Performance: Internal vs. External Display
  5. github-systemd-issues-8486