Skip to content

Instantly share code, notes, and snippets.

@ihipop
Last active November 25, 2025 05:27
Show Gist options
  • Select an option

  • Save ihipop/b3daaa8fba69f3dbe4189a5e63dbb001 to your computer and use it in GitHub Desktop.

Select an option

Save ihipop/b3daaa8fba69f3dbe4189a5e63dbb001 to your computer and use it in GitHub Desktop.
根据外接显示器/笔记本盖子的情况 开启关闭 krfb-virtualmonitor
#!/bin/bash
# 监听 KDE 6 的 org.kde.Solid.PowerManagement 用户级会话信号,控制 krfb-virtualmonitor 服务
# 完全用户级,无需 root 权限,增强信号解析和错误处理
# 用于后台监听显示器插拔事件
start_monitor_listener() {
gdbus monitor --session --dest org.freedesktop.PowerManagement -o /org/kde/ScreenBrightness |
while IFS= read -r line; do
if echo "$line" | grep --line-buffered -q -E "DisplayAdded|DisplayRemoved"; then
echo "检测到显示器相关事件,重新检查 4K 状态"
control_krfb_service $(check_lid_not_closed_state)
fi
done
}
start_lock_listener(){
gdbus monitor --session --dest org.freedesktop.ScreenSaver --object-path /ScreenSaver "member='ActiveChanged'"|
while IFS= read -r line; do
if echo "$line" | grep --line-buffered -q -E "ActiveChanged"; then
echo "检测到锁屏相关事件,重新检查 4K 状态"
control_krfb_service $(check_not_lock_state)
fi
done
}
check_not_lock_state(){
locked=$(gdbus call --session \
--dest org.freedesktop.ScreenSaver \
--object-path /ScreenSaver \
--method org.freedesktop.ScreenSaver.GetActive |sed -E "s/.*?(true|false).*?/\1/g")
if [ "$locked" = "true" ]; then
echo "false"
elif [ "$locked" = "false" ]; then
echo "true"
else
echo "unknown"
fi
}
# 函数:根据状态控制 krfb-virtualmonitor 服务
control_krfb_service() {
if has_4k_monitor; then
echo "检测到 4K 显示器,禁止启动 krfb-virtualmonitor 服务"
systemctl --user stop krfb-virtualmonitor.service
return 0
fi
local state="$1"
if [ "$state" = "false" ]; then
echo "停止 krfb-virtualmonitor 服务"
systemctl --user stop krfb-virtualmonitor.service
elif [ "$state" = "true" ]; then
echo "启动 krfb-virtualmonitor 服务"
systemctl --user start krfb-virtualmonitor.service
else
echo "错误:无法控制服务,未知状态 '$state'"
fi
}
# 函数:检查盖子状态并返回状态
check_lid_not_closed_state() {
local lid_state
lid_state=$(loginctl show-session -p LidClosed | cut -d= -f2)
if [ "$lid_state" = "yes" ]; then
echo "false"
elif [ "$lid_state" = "no" ]; then
echo "true"
else
echo "unknown"
fi
}
# 函数:检查是否存在物理 4K(2160 高度)的显示器
has_4k_monitor() {
for modes in $(kscreen-doctor -o | grep -oP '\d+x\d+@\d+(?=\*)'); do
if echo "$modes" | grep -q 'x2160'; then
return 0 # 存在 4K
fi
done
return 1 # 没有 4K
}
# 函数:检查是否存在物理 4K(2160 高度)的显示器
has_4k_monitor_from_drm() {
for modes in /sys/class/drm/*/modes; do
[ -f "$modes" ] || continue
if grep -q 'x2160' "$modes"; then
return 0 # 存在 4K
fi
done
return 1 # 没有 4K
}
start_lid_listener() {
# 监听 org.kde.Solid.PowerManagement 的用户级信号
gdbus monitor --session -d org.kde.Solid.PowerManagement -o /org/kde/Solid/PowerManagement |
while IFS= read -r line; do
# 检查 D-Bus 连接是否有效
if echo "$line" | grep -q "org.freedesktop.DBus.Error"; then
echo "错误:D-Bus 连接失败,信号内容:'$line'"
continue
fi
# 检查信号是否包含盖子状态相关内容
if echo "$line" | grep -q -E "lidClosed|onLidClosed|lidClosedChanged"; then
# 尝试解析信号中的盖子状态
if echo "$line" | grep -q -E "lidClosed.*true|onLidClosed.*true|lidClosedChanged.*true"; then
CURRENT_STATE="closed"
elif echo "$line" | grep -q -E "lidClosed.*false|onLidClosed.*false|lidClosedChanged.*false"; then
CURRENT_STATE="open"
else
# 后备:调用 loginctl 检查函数
CURRENT_STATE=$(check_lid_state)
fi
control_krfb_service "$CURRENT_STATE"
fi
done
}
# 初始化:启动 D-Bus 监听前执行一次 loginctl 检测
control_krfb_service $(check_lid_not_closed_state)
control_krfb_service $(check_not_lock_state)
# 启动后台监听
start_monitor_listener &
MONITOR_LISTENER_PID=$!
start_lid_listener &
LID_LISTENER_PID=$!
start_lock_listener &
LOCK_LISTENER_PID=$!
# 捕获退出信号,确保后台进程被杀掉
cleanup() {
echo "脚本退出,停止后台监听..."
kill $MONITOR_LISTENER_PID $LID_LISTENER_PID $LOCK_LISTENER_PID 2>/dev/null
wait $MONITOR_LISTENER_PID $LID_LISTENER_PID $LOCK_LISTENER_PID 2>/dev/null
}
trap cleanup EXIT INT TERM
wait -n $MONITOR_LISTENER_PID $LID_LISTENER_PID $LOCK_LISTENER_PID
echo "有后台进程退出,脚本结束"
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment