一句话结论
Dolphin 是单例包装(同名命令压过 Plasma 自带的那份):已有实例时用 DBus 让它在现有窗口里开标签(不堆进程),再补一步 wmctrl -x -a dolphin 把窗口提升到前台。两件事都写在 modules/system/explorer/dolphin.nix 里,全部声明式。
一、两个需求 → 两个机制
| 需求 | 机制 | 落在哪 |
|---|
| 不堆进程(单例) | 已有实例 ⇒ DBus 调用它的 MainWindow 接口在现有窗口开标签 | dolphin.nix 的 lib.hiPrio singleInstance 包装脚本 |
| 打开时到前台(提升) | DBus 调用之后再 wmctrl -x -a dolphin(按 WM_CLASS 匹配) | 同上,脚本末行 |
| 真启动(无实例时) | exec 真 dolphin | 包装脚本 svc 为空的分支 |
二、单例部分的实际行为
| 输入 | 包装行为 |
|---|
普通目录参数 dolphin ~/x | 已有实例 ⇒ DBus openDirectories asb <n> <uri…> <split> |
--select <file> | 同上但走 openFiles;无实例时原样交给真 dolphin |
--split | 作为 split 布尔传给 DBus |
--new-window | 被忽略(本包装的意义就是不允许堆实例) |
--sudo / --admin / --daemon / --help / --version / --author / --license / --desktopfile* | 原样 exec 真 dolphin |
| 其它未知开关 | 忽略 |
| 无参数 | 默认目标 file://$HOME |
三、提升部分(本页重点)
为什么不能靠 DBus 自带的“激活”:
busctl --user call org.kde.dolphin-<pid> /dolphin/Dolphin_1 org.kde.dolphin.MainWindow activate
⇒ Call failed: No such method 'activate' in interface … ✗
同上试 show ✗
该接口只有 openDirectories / openFiles;而且 introspection 数据有重复方法(duplicate method)⇒ busctl introspect 会 Failed ✗
所以用 X11 的窗口管理命令(本机图形会话就是 X11):
wmctrl -x -a dolphin # -x 按 WM_CLASS 匹配;-a 切到该窗口所在桌面并提升
实测 Dolphin 的 WM_CLASS = "dolphin", "dolphin" ⇒ 匹配得上 ✓
四、模块里的最终形态(关键几行)
# 脚本内变量(⚠ 必须在脚本体里赋值:写成 let 绑定 + 脚本里用 $wmctrl 会 unbound variable)
wmctrl="${pkgs.wmctrl}/bin/wmctrl"
# DBus 开标签 / 开文件之后:
"$wmctrl" -x -a dolphin
五、自查判据(可自行复核)
① 包装是否在生效(应该命中 hiPrio 那份):
command -v dolphin ; head -3 $(command -v dolphin)
② 有没有实例、实例的 DBus 服务名:
pgrep -a dolphin
busctl --user list | grep -o 'org\.kde\.dolphin-[0-9]*'
③ 窗口类名(提升靠它匹配):
wmctrl -x -l | grep -i dolphin
④ 提升是否真的发生(端到端):
dolphin "$HOME"; echo $?
xprop -root _NET_ACTIVE_WINDOW | awk '{print $NF}'
xprop -id <上一步的 id> WM_CLASS # 应输出 "dolphin", "dolphin"
六、踩过的坑(本机真实发生)
| 坑 | 现象 | 正解 |
|---|
把 wmctrl 定义写在 nix 的 let 里 | 脚本报 wmctrl: unbound variable(退出码 1) | 脚本内自己赋值(同 busctl= 的写法) |
用 2>&1 >/dev/null 跑包装验收 | 错误被吞,只看到“退出码非零” | 验收命令不要重定向掉 stderr |
| 想用 DBus 的 activate/show 提升 | 接口里根本没这两个方法 | 用 wmctrl(X11) |
busctl introspect 看方法 | Failed: duplicate method 'openDirectories' | 直接按已知签名调用(asb 必须连写) |
七、可复用性
| 项 | 位置 | nix rebuild 后 | 重装系统(拷 /etc/nixos)后 |
|---|
| 单例包装 + 提升 | modules/system/explorer/dolphin.nix | 保留 ✓ | 可复用 ✓ |
wmctrl 包 | 由模块内表达式引用 | 保留 ✓ | 可复用 ✓ |
| 窗口类名/桌面环境前提 | X11 会话(非 nix 值) | — | 需同样是 X11 会话(Wayland 下 wmctrl 不适用) |
停用/回退:注释掉 configuration.nix 里 dolphin 那一行 ⇒ 恢复 Plasma 原生 dolphin(不再单例、不再提升);或从 /etc/nixos/backup/ 里取起改动前的 dolphin.nix 拷回后 rebuild。
八、相关笔记
- 「服务:nix收敛代理配置」
xi6ugMzM4rB0(代理链路与 30 秒故障定位) - 「服务:docker的rootful和rootless困惑」
915vFpZhWb2s(本机 docker 两个 daemon 的差异与处置)