Files
WechatOnCloud/docker/autostart
Gloridust 94b591e0b2 fix(critical): xsettingsd Xft/DPI 单位错误 —— v1.2.9~v1.3.1 微信公众号/附件秒关、浏览器黑屏的总根因
XSETTINGS 规范中 Xft/DPI 的单位是「DPI×1024」(96 DPI 应写 98304),#101 引入的 xsettingsd
配置误写成 96 → 所有 Chromium 内核应用把 DPI 读成 96/1024≈0.09 → 缩放因子≈0 → 显示变换
矩阵 [0 0 0 0;…] 不可逆(transform.cc NOTREACHED)→ GPU/viz 进程连崩 3 次 → 窗口/应用退出:
- 微信内嵌 CEF:点公众号/附件/小程序 → 窗口秒关/白屏(issue #111,日志与本地复现完全吻合)
- 系统 Chromium:整个浏览器崩溃循环 → 黑屏(v1.3.1 的 --force-device-scale-factor=1 只救了
  能加 flag 的 Chromium,是治症状;微信 CEF 无法加 flag,必须修 XSETTINGS 源头)
A/B 实证:Xft/DPI 96 → 裸 chromium 立崩(同款堆栈);改 98304 → 存活。两处写入点均已修
(docker/autostart 每次开机重写 + 面板 applyXsettingsFont 实时下发)。

配套修复本轮反馈的其余问题:
- 磁盘暴涨("1TB 没了"):实例容器注入 LogConfig 20m×2(默认 json-file 无上限,崩溃循环
  每 2s 刷错顶满磁盘);compose 面板同配;微信 crashinfo 崩溃转储 1 天过期清理;
  一键升级完成后清理悬空(<none>)旧镜像并记录释放空间。
- 一键升级"卡死":改异步——立即返回、后台顺序执行、前端轮询进度(n/总数·当前实例);
  镜像统一只拉一次(原每实例各拉一次,受限网络下每次都等停滞超时)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:31:24 +08:00

196 lines
8.6 KiB
Bash
Raw Permalink 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"
# 深色模式(实例环境 WOC_DARK=1 时;由面板顶栏主题开关持久化、经容器环境下发,改后需重启实例生效)。
# 仅浏览器(Chromium):加 --force-dark-mode 让其 UI + 网页走深色——这是极简容器里实测唯一稳的办法。
# 微信:内核虽是 Chromium 但不吃命令行参数,也不订阅桌面 portal 的 color-scheme 信号(实测 portal 方案在
# 极简容器里 session 总线不稳、微信也不跟随),故本开关对微信无效;微信深色请在微信「设置→通用→深色模式」
# 里手动选(设置随数据卷持久化)。
if { [ "${WOC_DARK:-}" = "1" ] || [ "${WOC_DARK:-}" = "true" ]; } && [ "$APP_TYPE" = "chromium" ]; then
APP_LAUNCH="${APP_LAUNCH} --force-dark-mode --enable-features=WebContentsForceDark"
echo "[autostart] 浏览器深色已启用(--force-dark-mode"
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) 应用壁纸(若用户设置了自定义背景图)。
# 关键Xvnc 启动时是默认分辨率,浏览器连上后 KasmVNC 会 resize-remote 到浏览器尺寸。若只在启动时设一次,
# 屏幕一变大X 会把当时设的小尺寸 root pixmap【平铺】填满新屏表现为壁纸被 2×2 平铺,见 issue 反馈)。
# 故用看守:每 2s 检查分辨率,一变就用 --zoom填充裁切、保持比例重设壁纸。也顺带跟随面板对壁纸文件的改动。
WALLPAPER_FILE="/config/.wallpaper"
WALLPAPER_DIR="/config/backgrounds"
(
export DISPLAY="${DISPLAY:-:1}"
last=""
while sleep 2; do
[ -f "$WALLPAPER_FILE" ] || { last=""; continue; }
wp=$(cat "$WALLPAPER_FILE" 2>/dev/null) || continue
[ -n "$wp" ] && [ -f "$WALLPAPER_DIR/$wp" ] || { last=""; continue; }
# 用「分辨率 + 壁纸名」做签名:分辨率变(resize)或换了壁纸都会重设
sig="${wp}@$(xrandr 2>/dev/null | grep -o '[0-9]\+x[0-9]\+' | head -1)"
if [ "$sig" != "$last" ]; then
last="$sig"
xwallpaper --zoom "$WALLPAPER_DIR/$wp" 2>/dev/null && echo "[autostart] 壁纸已应用/重设: $sig"
fi
done
) &
# 2) 应用自定义字体(若用户设置了)
# 从持久卷恢复系统级 fontconfig 配置(跨越容器重建)
if [ -f /config/.woc-fc-local.conf ]; then
cp /config/.woc-fc-local.conf /etc/fonts/local.conf
echo "[autostart] 系统字体配置已恢复"
fi
# 确保 ~/.local/share/fonts → /config/.fonts symlink 存在(旧容器升级兼容)
mkdir -p /config/.fonts 2>/dev/null || true
if [ ! -L /config/.local/share/fonts ] && [ ! -d /config/.local/share/fonts ]; then
mkdir -p /config/.local/share 2>/dev/null || true
ln -sfn /config/.fonts /config/.local/share/fonts 2>/dev/null || true
fi
FONT_CONF="/config/.config/fontconfig/fonts.conf"
FONT_FAMILY_FILE="/config/.woc-font-family"
if [ -f "$FONT_FAMILY_FILE" ]; then
family=$(cat "$FONT_FAMILY_FILE")
if [ -n "$family" ]; then
mkdir -p "$(dirname "$FONT_CONF")" 2>/dev/null || true
cat > "$FONT_CONF" << EOF
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- generic families -->
<alias>
<family>sans-serif</family>
<prefer><family>${family}</family></prefer>
</alias>
<alias>
<family>serif</family>
<prefer><family>${family}</family></prefer>
</alias>
<alias>
<family>monospace</family>
<prefer><family>${family}</family></prefer>
</alias>
<!-- system CJK fonts that WeChat/CEF may request -->
<alias>
<family>WenQuanYi Micro Hei</family>
<prefer><family>${family}</family></prefer>
</alias>
<alias>
<family>WenQuanYi Zen Hei</family>
<prefer><family>${family}</family></prefer>
</alias>
<alias>
<family>Noto Sans CJK SC</family>
<prefer><family>${family}</family></prefer>
</alias>
<alias>
<family>Noto Sans CJK</family>
<prefer><family>${family}</family></prefer>
</alias>
<!-- force user font for any zh text regardless of requested family -->
<match target="pattern">
<test name="lang" compare="contains"><string>zh</string></test>
<edit name="family" mode="prepend" binding="strong"><string>${family}</string></edit>
</match>
</fontconfig>
EOF
echo "[autostart] 自定义字体已恢复: ${family}"
fc-cache -f 2>/dev/null || true
fi
elif [ -f "$FONT_CONF" ]; then
echo "[autostart] 自定义字体配置已就绪"
fc-cache -f 2>/dev/null || true
fi
# 3) 启动 xsettingsd让 GTK/Qt 应用实时响应字体/DPI 等 XSETTINGS 变更,无需重启)
XSETTINGS_CONF="/config/.xsettingsd"
if command -v xsettingsd >/dev/null 2>&1; then
XSETTINGS_FONT="WenQuanYi Micro Hei"
# 若用户保存了字体偏好,优先使用
if [ -f "$FONT_FAMILY_FILE" ]; then
family=$(cat "$FONT_FAMILY_FILE")
[ -n "$family" ] && XSETTINGS_FONT="$family"
fi
# ⚠️ XSETTINGS 规范里 Xft/DPI 的单位是「DPI × 1024」96 DPI 必须写 98304。
# 若误写 96所有 Chromium 内核应用(系统 Chromium、微信内嵌 CEF会把 DPI 读成 96/1024≈0.09
# → 缩放因子≈0 → 显示变换矩阵不可逆(transform.cc NOTREACHED) → GPU 进程连崩 → 窗口秒关/黑屏。
# 这曾是 v1.2.9~v1.3.1 微信打不开公众号/附件、浏览器黑屏的总根因issue #111
cat > "${XSETTINGS_CONF}" << EOF
Xft/Antialias 1
Xft/Hinting 1
Xft/HintStyle "hintslight"
Xft/RGBA "rgb"
Xft/DPI 98304
Gtk/FontName "${XSETTINGS_FONT} 10"
EOF
xsettingsd --config="${XSETTINGS_CONF}" 2>/dev/null &
echo "[autostart] xsettingsd 已启动"
fi
# 4) 等待应用安装就绪(首次需在面板点「下载并安装」)
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.5) 清理微信崩溃转储crashinfo
# 微信内嵌浏览器崩溃时 crashpad 会往 /config/.xwechat/crashinfo 里堆 .dmp 转储与 lock/meta 文件;
# 崩溃风暴(如 DPI bug 期间每次点公众号都崩)会让它无限膨胀吃满磁盘,且启动时反复扫描刷日志。
# 转储仅用于事后诊断,保留 1 天足够;过期即删,防磁盘被吃。
if [ -d /config/.xwechat/crashinfo ]; then
find /config/.xwechat/crashinfo -type f -mtime +1 -delete 2>/dev/null || true
find /config/.xwechat/crashinfo -mindepth 1 -type d -empty -delete 2>/dev/null || true
fi
# 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