Files
WechatOnCloud/docker/autostart
Gloridust 335b839e9a feat(dark): 面板/实例统一深色开关(portal 实时切换)+ 修复 KasmVNC 致命崩溃自愈
实例深色不再靠 GTK_THEME(微信 Chromium 内核不吃),改用 freedesktop 桌面 portal:
每个实例常驻 session D-Bus + xdg-desktop-portal(gtk 后端) + dconf(固定总线地址),
面板顶栏主题开关(管理员)统一控制面板 + 实例深色,持久化进 accounts.json,并对运行中实例
docker exec woc-dark.sh 实时切换 color-scheme(微信据 SettingChanged 实时重绘),无需改 env。

- docker/Dockerfile: 装 xdg-desktop-portal(+gtk) / dconf / gsettings / dbus-x11(单独成层)
- docker/autostart: woc_setup_portal 常驻 portal,初始明暗由 WOC_DARK 决定
- docker/woc-dark.sh: 面板经 exec 调用,实时改 gsettings color-scheme
- store.ts: 持久化 desktopDark;docker.ts: envList 读它 + setInstanceDark;index.ts: /api/desktop-theme
- AppShell 主题开关接 setDesktopTheme(含 auto 跟随系统联动);移除 WOC_INSTANCE_DARK env

KasmVNC 客户端 bundle 长跑空闲后偶发 'lastActiveAt' 致命崩溃 → 仅在其致命错误浮层出现时
做一次干净整页重载(安全重连路径,非激进 churn),5min 限 4 次防死循环。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 02:11:47 +08:00

114 lines
6.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# 由 KasmVNC base 的 openbox 会话在桌面就绪后执行(以 app 用户身份)。
# v1.2.0 多应用:实例承载的应用(微信/Telegram/Chromium/自定义)由面板写入容器环境 WOC_APP_TYPE
# 再由 02-woc-app 钩子落到数据卷 /config/.woc-app。本脚本据此等待对应应用就绪并常驻拉起
# (关窗自动重开;更新后从新版本路径重启)。读不到类型 → 回退微信,老实例零改动。
set -u
# 容器内无 GPU强制软件渲染
export LIBGL_ALWAYS_SOFTWARE=1
# 解析本实例应用类型与启动信息APP_BIN / APP_LAUNCH / APP_NAME
APP_TYPE=wechat
# shellcheck source=/dev/null
[ -f /config/.woc-app ] && . /config/.woc-app 2>/dev/null || true
APP_TYPE="${WOC_APP_TYPE:-wechat}"
# shellcheck source=/dev/null
. /woc/app-defs.sh
woc_app_def "$APP_TYPE"
# 深色模式freedesktop 桌面 portal 方案)。微信内核是 Chromium它判断"系统是否深色"读的是 portal 的
# org.freedesktop.appearance→color-schemeD-Bus 信号),不是 GTK_THEME/settings.ini那只影响纯 GTK chrome
# 极简 KasmVNC 默认无 portal故每个实例都常驻一套 session D-Bus + xdg-desktop-portal(gtk 后端) + dconf
# - 这样面板顶栏的主题开关能"远程拨开关"实时切换实例深色(面板 docker exec 改 gsettings color-scheme →
# portal 发 SettingChanged → 微信实时重绘),无需重启实例;
# - 初始明暗由 WOC_DARK 决定(面板把开关持久化、经容器环境下发),微信由本脚本拉起、继承这套环境,启动即跟随。
# 这些服务空闲极轻、且与 VNC 连接完全无关(不参与重连/重启),不影响连接稳定性。总线地址固定,便于 exec 复用。
# 整段 best-effort任一步失败都不阻断后续启动应用。
woc_setup_portal() {
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp/woc-run-$(id -u)}"
mkdir -p "$XDG_RUNTIME_DIR" 2>/dev/null && chmod 700 "$XDG_RUNTIME_DIR" 2>/dev/null || true
# 让 xdg-desktop-portal 明确选用 gtk 后端来实现 Settings即 color-scheme 来源)
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-GNOME}"
_xcfg="${HOME:-/config}/.config/xdg-desktop-portal"
mkdir -p "$_xcfg" 2>/dev/null || true
printf '[preferred]\ndefault=gtk\norg.freedesktop.impl.portal.Settings=gtk\n' >"$_xcfg/portals.conf" 2>/dev/null || true
# 固定地址的 session 总线:微信(本脚本拉起,继承此变量)与面板 docker exec 的 woc-dark.sh 用同一条,
# 改的才是同一个 dconf、portal 才读得到。已在跑socket 存在)则复用。
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/woc-bus"
if [ ! -S "${XDG_RUNTIME_DIR}/woc-bus" ] && command -v dbus-daemon >/dev/null 2>&1; then
dbus-daemon --session --address="$DBUS_SESSION_BUS_ADDRESS" --nopidfile --fork 2>/dev/null || true
_i=0; while [ ! -S "${XDG_RUNTIME_DIR}/woc-bus" ] && [ "$_i" -lt 25 ]; do sleep 0.2; _i=$((_i + 1)); done
fi
[ -S "${XDG_RUNTIME_DIR}/woc-bus" ] || { echo "[autostart] 深色session 总线未就绪,跳过 portal"; return 0; }
# 把环境推进总线的"激活环境",使 dbus 激活起来的 portal 能看到 DISPLAY/XDG_CURRENT_DESKTOP 等
command -v dbus-update-activation-environment >/dev/null 2>&1 && \
dbus-update-activation-environment --all >/dev/null 2>&1 || true
# 初始明暗dconf 共享后端portal 据此对外报告;之后面板 woc-dark.sh 改这同一个键即实时切换)
if command -v gsettings >/dev/null 2>&1; then
if [ "${WOC_DARK:-}" = "1" ] || [ "${WOC_DARK:-}" = "true" ]; then
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' 2>/dev/null || true
gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark' 2>/dev/null || true
else
gsettings set org.gnome.desktop.interface color-scheme 'default' 2>/dev/null || true
gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita' 2>/dev/null || true
fi
fi
# 显式拉起 portalgtk 后端提供 Settings比纯 dbus 激活更稳,重复启动会自行退出、无害)
for _b in xdg-desktop-portal-gtk xdg-desktop-portal; do
for _d in /usr/libexec /usr/lib/xdg-desktop-portal /usr/lib; do
if [ -x "$_d/$_b" ]; then ( "$_d/$_b" >/dev/null 2>&1 & ); break; fi
done
done
echo "[autostart] 深色 portal 已就绪(初始 $([ "${WOC_DARK:-}" = "1" ] || [ "${WOC_DARK:-}" = "true" ] && echo prefer-dark || echo light)"
}
woc_setup_portal || true
# Chromium 实例(浏览器)初始深色再加 app 级强制UI + 网页);微信不吃命令行参数,靠 portal 信号实时跟随。
if { [ "${WOC_DARK:-}" = "1" ] || [ "${WOC_DARK:-}" = "true" ]; } && [ "$APP_TYPE" = "chromium" ]; then
APP_LAUNCH="${APP_LAUNCH} --force-dark-mode --enable-features=WebContentsForceDark"
fi
# 防“最小化后丢失”本桌面openbox无任务栏窗口被最小化就无处恢复 → 黑屏。
# 看守进程:每 2s 把“被最小化(不可见)”的顶层窗口重新激活,相当于禁用最小化。对任意应用通用。
(
export DISPLAY="${DISPLAY:-:1}"
while sleep 2; do
all=$(xdotool search --name '.+' 2>/dev/null) || continue
vis=$(xdotool search --onlyvisible --name '.+' 2>/dev/null)
for w in ${all}; do
printf '%s\n' "${vis}" | grep -qx "${w}" || xdotool windowactivate "${w}" 2>/dev/null || true
done
done
) &
# 自定义应用若未配置启动命令,给出提示并退出(避免空等)
if [ "$APP_TYPE" = "custom" ] && [ -z "${APP_LAUNCH:-}" ]; then
echo "[autostart] 自定义应用尚未配置启动命令,请在面板「数据卷」上传安装包并设定后重启实例"
exit 0
fi
# 1) 等待应用安装就绪(首次需在面板点「下载并安装」)
notified=0
while [ -n "${APP_BIN:-}" ] && [ ! -x "${APP_BIN}" ]; do
if [ "${notified}" -eq 0 ]; then
echo "[autostart] ${APP_NAME} 尚未安装,等待面板触发下载…(首次使用请在面板点「下载并安装」)"
notified=1
fi
sleep 2
done
# 3) 常驻拉起应用
while true; do
if [ -n "${APP_BIN:-}" ] && [ ! -x "${APP_BIN}" ]; then
# 更新过程中本体被临时挪走,等就位再继续
sleep 2
continue
fi
echo "[autostart] 启动 ${APP_NAME}: ${APP_LAUNCH}"
# APP_LAUNCH 可带参数,按 word-split 执行(各应用参数均不含空格,见 app-defs.sh
${APP_LAUNCH}
echo "[autostart] ${APP_NAME} 已退出2 秒后重启"
sleep 2
done