切换到 KDE Plasma Wayland 后,有时会遇到这样一种现象:每次登录桌面,系统都会自动弹出一个屏幕共享选择窗口,要求选择显示器,并显示类似以下名称:

xdg-desktop-portal-kde
org.freedesktop.impl.portal.desktop.kde

窗口底部还可能出现:

Allow restoring on future sessions

乍看之下,很容易怀疑 KDE Portal、PipeWire 或 Wayland 配置出现了问题。但在这次排查中,真正的问题并不在 KDE,而是一个基于 Electron 的聊天客户端在启动时错误地申请了屏幕捕获权限。

本文记录完整的判断过程、定位方法以及最终解决方案。


一、现象:切换到 Wayland 后,每次开机都要求共享屏幕

系统环境大致如下:

  • Linux 桌面系统
  • KDE Plasma
  • 显示协议由 X11 切换为 Wayland
  • 登录桌面后自动启动若干应用
  • 每次登录都会出现屏幕共享授权窗口

窗口要求用户选择:

  • Laptop screen
  • 某个外接显示器
  • 某个应用窗口

即使完全没有进行视频会议、录屏或远程桌面操作,这个窗口仍然会自动出现。

这种现象通常说明:

某个登录自启动应用,在启动过程中调用了 Wayland 的屏幕捕获接口。


二、为什么切换到 Wayland 后才出现

X11 和 Wayland 对屏幕内容访问的安全模型完全不同。

X11 的方式

在传统 X11 环境中,桌面应用通常可以直接读取屏幕内容。录屏软件、截图工具、远程桌面和视频会议程序不一定需要经过系统级授权。

这也意味着,理论上任何连接到 X Server 的程序都可能读取其他窗口内容。

Wayland 的方式

Wayland 不允许普通应用随意读取整个屏幕。

应用如果需要:

  • 录制屏幕
  • 共享屏幕
  • 远程控制
  • 获取显示器画面
  • 创建 WebRTC 屏幕流

通常必须通过以下组件:

应用
  ↓
xdg-desktop-portal
  ↓
xdg-desktop-portal-kde
  ↓
PipeWire
  ↓
KDE 屏幕共享授权窗口

因此,切换到 Wayland 后首次看到这种窗口,本身并不异常。

异常之处在于:

没有主动进行屏幕共享,但窗口却在每次登录时自动出现。

这说明某个程序在启动时主动发起了 ScreenCast 或 RemoteDesktop 请求。


三、xdg-desktop-portal-kde 不是罪魁祸首

屏幕共享窗口中出现的名称通常包括:

xdg-desktop-portal-kde

以及:

org.freedesktop.impl.portal.desktop.kde

这两个名称分别对应:

  • KDE 的 XDG Desktop Portal 后端程序
  • 该后端在 D-Bus 上注册的服务名称

它们的作用是:

  1. 接收应用发出的屏幕共享请求;
  2. 显示由桌面环境控制的授权窗口;
  3. 将用户选择的屏幕或窗口通过 PipeWire 提供给申请程序。

因此,Portal 是窗口的显示者,但通常不是请求的发起者。

可以将它理解为操作系统的权限管理器:

门卫负责显示授权窗口,但真正敲门的是其他应用。

所以不应该因为看到 xdg-desktop-portal-kde,就直接禁用或删除它。

禁用 KDE Portal 可能导致以下功能失效:

  • Spectacle 截图和录屏
  • 浏览器屏幕共享
  • 视频会议软件
  • OBS Wayland 捕获
  • 远程桌面
  • Flatpak 文件选择窗口
  • 部分沙盒应用的系统集成

正确做法是定位真正的调用者。


四、通过 D-Bus 请求路径查找申请程序

当屏幕共享窗口保持打开时,XDG Portal 通常会创建一个活动请求对象,其路径格式类似:

/org/freedesktop/portal/desktop/request/1_98/webrtc850831072

其中:

1_98

对应 D-Bus 唯一连接名:

:1.98

通过这个连接名,可以进一步查询对应的进程 PID。

自动定位脚本

保持屏幕共享窗口打开,然后在终端中运行:

req="$(
    busctl --user tree org.freedesktop.portal.Desktop --no-pager 2>/dev/null |
    grep -o '/org/freedesktop/portal/desktop/request/[^[:space:]]*' |
    head -n1
)"

if [[ -z "$req" ]]; then
    echo "没有找到活动的 Portal 请求。"
    echo "请保持屏幕共享窗口打开后重新运行。"
    exit 1
fi

caller="${req#*/request/}"
caller="${caller%%/*}"
sender=":${caller//_/.}"

pid="$(
    busctl --user call \
        org.freedesktop.DBus \
        /org/freedesktop/DBus \
        org.freedesktop.DBus \
        GetConnectionUnixProcessID \
        s "$sender" 2>/dev/null |
    awk '{print $2}'
)"

echo "Portal 请求路径:$req"
echo "D-Bus 请求者:$sender"
echo "PID:$pid"

echo
echo "程序文件:"
readlink -f "/proc/$pid/exe"

echo
echo "启动命令:"
tr '\0' ' ' < "/proc/$pid/cmdline"
echo

echo
echo "所属 cgroup:"
cat "/proc/$pid/cgroup"

这个脚本完成了四件事:

  1. 查找活动的 Portal 请求;
  2. 从请求路径提取 D-Bus 调用者;
  3. 根据 D-Bus 名称反查 PID;
  4. 根据 PID 查找可执行文件和完整启动命令。

五、定位结果:Rocket.Chat Desktop

最终获得的信息类似:

Portal 请求路径:
/org/freedesktop/portal/desktop/request/1_98/webrtc850831072

D-Bus 请求者:
:1.98

PID:
1637

程序文件:
/opt/Rocket.Chat/rocketchat-desktop.bin

启动命令:
/opt/Rocket.Chat/rocketchat-desktop.bin

这说明真正发起屏幕共享请求的是:

Rocket.Chat Desktop

而不是:

xdg-desktop-portal-kde

也不是 KDE Plasma、PipeWire 或 Wayland 本身。


六、为什么 cgroup 中显示 Chromium

进程所属 cgroup 可能显示为:

app-org.chromium.Chromium-1637.scope

这可能再次引起误解,让人怀疑 Chromium 浏览器在请求屏幕共享。

但 Rocket.Chat Desktop 是一个 Electron 应用。

Electron 的底层由以下组件组成:

  • Chromium
  • Node.js
  • 桌面应用封装层

因此,Electron 应用在进程、窗口类、沙盒和 systemd scope 中,经常表现出 Chromium 的特征。

类似情况也常见于:

  • Discord
  • Slack
  • Microsoft Teams
  • Visual Studio Code
  • Obsidian
  • Chatbox
  • 各类 Electron 聊天客户端

所以:

app-org.chromium.Chromium-xxxx.scope

并不一定代表真正的 Chromium 浏览器。

判断时应优先查看:

readlink -f /proc/PID/exe

以及:

tr '\0' ' ' < /proc/PID/cmdline

这两个位置更能准确反映实际程序。


七、检查已安装版本

确认问题程序后,需要检查当前安装的软件包和版本。

先查询可执行文件属于哪个包:

pacman -Qo /opt/Rocket.Chat/rocketchat-desktop.bin

结果类似:

/opt/Rocket.Chat/rocketchat-desktop.bin is owned by rocketchat-client-bin

可以进一步自动提取包名:

pkg="$(
    pacman -Qo /opt/Rocket.Chat/rocketchat-desktop.bin |
    awk '{print $5}'
)"

echo "软件包:$pkg"

然后查询版本:

pacman -Qi "$pkg" |
grep -E '^(Name|Version)'

当时的版本为:

Name    : rocketchat-client-bin
Version : 4.14.1-1

这是一个 AUR 安装的软件包。

使用以下命令也能看到它:

yay -Qm

不过需要注意:

yay -Qm

只负责列出“非官方仓库软件包”,并不能判断这些软件包是否存在更新。


八、真正的解决方案:升级 Rocket.Chat Desktop

问题最终通过升级 Rocket.Chat Desktop 解决。

可以先检查远程软件包版本:

yay -Si rocketchat-client-bin |
grep -E '^(Name|Version|Out Of Date|Last Modified)'

然后执行更新:

yay -S rocketchat-client-bin

或者在正常进行完整系统升级时执行:

yay -Syu

升级完成后确认版本:

pacman -Qi rocketchat-client-bin |
grep -E '^(Name|Version)'

更新后不需要立即进行专门测试。

等下一次正常登录 Wayland 桌面时观察即可:

  • 如果屏幕共享窗口不再出现,说明问题已经解决;
  • 如果仍然出现,可以再次使用 D-Bus 方法确认请求者是否仍为 Rocket.Chat;
  • 如果请求者已经变化,则说明还有其他自启动应用也在申请屏幕捕获。

九、为什么不建议通过“永久允许”绕过问题

窗口底部的选项:

Allow restoring on future sessions

并不意味着“以后不再显示这个窗口”。

它的作用更接近于:

允许申请程序保存一个恢复令牌,并在未来尝试恢复同一个屏幕共享会话。

是否能够真正无提示恢复,还取决于:

  • 应用是否正确保存恢复令牌;
  • 应用是否在下一次启动时重新使用令牌;
  • Portal 后端是否允许当前恢复模式;
  • 桌面环境的安全策略;
  • 应用申请的持久化级别。

更重要的是,在不知道哪个程序申请屏幕权限时,不应该轻易授权。

屏幕共享权限意味着程序可能获得:

  • 当前显示器的完整内容
  • 正在输入的信息
  • 浏览器页面
  • 聊天内容
  • 文件管理器内容
  • 终端窗口
  • 密码管理器界面

因此,正确处理方式不是盲目勾选“以后恢复”,而是先确认申请者身份。


十、为什么不应该修改 KDE Portal

遇到这种情况时,一些常见但不正确的处理方式包括:

systemctl --user disable xdg-desktop-portal-kde

或者直接删除相关软件包:

sudo pacman -R xdg-desktop-portal-kde

还有人可能尝试删除 Portal 缓存、禁用 PipeWire,甚至回退到 X11。

这些操作都没有解决真正的问题。

本次排查已经证明:

  • Portal 正常接收请求;
  • KDE 正常显示授权窗口;
  • PipeWire 屏幕捕获链路正常;
  • Wayland 安全机制正常工作;
  • 真正异常的是应用在不恰当的时机申请了屏幕捕获。

换句话说:

授权窗口的出现,反而证明 Wayland 的权限隔离正在正常工作。

如果仍处于 X11 环境,同一个程序可能直接访问屏幕,而不会出现明显提示。


十一、可以顺便检查哪些自启动位置

如果升级后问题仍然存在,可以检查程序是通过什么方式自动启动的。

KDE 自动启动目录

ls -la ~/.config/autostart/

系统级自动启动目录

ls -la /etc/xdg/autostart/

systemd 用户服务

systemctl --user list-unit-files --state=enabled

当前用户图形会话中的应用 scope

systemctl --user list-units --type=scope

查看 Rocket.Chat 相关项目

grep -Ril 'Rocket.Chat\|rocketchat' \
    ~/.config/autostart \
    ~/.config/systemd/user \
    /etc/xdg/autostart \
    2>/dev/null

不过,如果应用本身需要日常使用,通常没有必要直接关闭它的自启动。

升级到修复该问题的版本,比禁止自动启动更合理。


十二、通用排障思路

这次问题可以总结为一个适用于 Wayland 桌面的通用排障流程。

第一步:不要根据窗口标题判断请求者

看到:

xdg-desktop-portal-kde

只能说明 KDE Portal 显示了窗口,不能说明 Portal 自己发起了请求。

第二步:保持授权窗口打开

窗口关闭后,请求对象可能立即消失,导致无法继续追踪。

第三步:查找 Portal 请求路径

busctl --user tree org.freedesktop.portal.Desktop

第四步:从请求路径恢复 D-Bus 名称

例如:

1_98

转换为:

:1.98

第五步:根据 D-Bus 名称反查 PID

busctl --user call \
    org.freedesktop.DBus \
    /org/freedesktop/DBus \
    org.freedesktop.DBus \
    GetConnectionUnixProcessID \
    s ':1.98'

第六步:检查实际可执行文件

readlink -f /proc/PID/exe

第七步:检查软件版本

pacman -Qo /path/to/executable
pacman -Qi package-name

第八步:优先升级问题应用

不要首先破坏 Wayland、Portal 或 PipeWire 的正常功能。


十三、结论

这次开机自动弹出的屏幕共享窗口,并不是 KDE Wayland 配置错误,而是 Rocket.Chat Desktop 旧版本在启动时错误地发起了 WebRTC 屏幕捕获请求。

完整因果关系如下:

Rocket.Chat Desktop 自动启动
    ↓
Electron/Chromium 初始化屏幕捕获功能
    ↓
调用 XDG Desktop Portal ScreenCast 接口
    ↓
xdg-desktop-portal-kde 接收请求
    ↓
KDE 显示屏幕共享授权窗口

最终处理方式是:

定位 D-Bus 请求者
    ↓
确认进程为 Rocket.Chat Desktop
    ↓
确认已安装版本较旧
    ↓
通过 AUR 升级 rocketchat-client-bin

这次排查最重要的经验是:

Wayland 下突然出现权限窗口时,不要急着修改桌面环境。先找出真正发起请求的应用,再处理应用本身。

从安全角度看,Wayland 显示授权窗口并不是故障,而是一种保护。真正需要修复的是那个在错误时间申请权限的程序。

Leave a Reply

Your email address will not be published. Required fields are marked *