mirror of
https://github.com/Gloridust/WechatOnCloud.git
synced 2026-09-20 11:33:32 +08:00
实例深色不再靠 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>
114 lines
6.6 KiB
Bash
114 lines
6.6 KiB
Bash
#!/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-scheme(D-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
|
||
# 显式拉起 portal(gtk 后端提供 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
|