diff --git a/generators/middleware.py b/generators/middleware.py index d6ebcf9..78d761d 100644 --- a/generators/middleware.py +++ b/generators/middleware.py @@ -59,6 +59,14 @@ class VNCSrv(Generator): "对 VNC 连接无影响,只影响原生 X11 客户端直连能力。"), Field("use_xvfb", "使用 Xvfb (无显卡)", "checkbox", default="yes", help="Headless 服务器必须启用 — VNC 通过 Xvfb 渲染,无需物理显卡。"), + Field("disable_wayland", "禁用 GDM Wayland (强制 X11)", "checkbox", default="yes", + help="强烈建议启用 — Ubuntu 22.04 默认用 Wayland + GDM,但 Wayland 下 x11vnc " + "会出现键盘映射异常、剪贴板双向不通、gnome-shell 偶发闪退等问题。" + "此选项写 /etc/gdm3/custom.conf 把 WaylandEnable 设为 false,所有 GDM session " + "(包括物理登录和锁屏)都强制走 X11。注意:在有活动的物理桌面登录时会断开一次。"), + Field("restart_gdm", "立即重启 GDM 应用 Wayland 更改", "checkbox", default="no", + help="yes = 立刻 systemctl restart gdm 让 Wayland 禁用生效(会断开当前物理会话);" + "no = 仅改配置,下次重启后生效。生产机器建议 no,自己本地实验可以 yes。"), ] # ---- per-DE helpers (chosen at render time) ---- @@ -134,6 +142,8 @@ class VNCSrv(Generator): nolisten_unix = bool_str(p.get("nolisten_unix", True)) nolisten_tcp_local = bool_str(p.get("nolisten_tcp_local")) use_xvfb = bool_str(p.get("use_xvfb", True)) + disable_wayland = bool_str(p.get("disable_wayland", True)) + restart_gdm = bool_str(p.get("restart_gdm")) if de not in self.DE_PACKAGES: raise ValueError(f"Unknown desktop_env: {de}. Choose one of: {', '.join(self.DE_PACKAGES)}") @@ -184,6 +194,48 @@ class VNCSrv(Generator): ' gnome-tweaks') out.append(install) + # GDM Wayland disable — only relevant for GNOME on a machine that + # has a physical GDM (i.e. ubuntu-desktop-01, not a headless server). + # Ubuntu 22.04 defaults to WaylandEnable=true in /etc/gdm3/custom.conf. + # Wayland + x11vnc has known issues: keyboard remapping gets + # confused, clipboard isn't bidirectional, gnome-shell occasionally + # crashes on X client events. Forcing X11 makes the VNC session + # behave like a normal X11 desktop. + if de == "gnome" and disable_wayland: + out.append('log "Disabling GDM Wayland (forcing X11 session)..."') + # custom.conf may not exist on a server (no gdm3 installed) — guard + out.append('if [ -d /etc/gdm3 ] && [ -f /etc/gdm3/custom.conf ] || [ ! -f /etc/gdm3/custom.conf ]; then') + out.append(' mkdir -p /etc/gdm3') + out.append(' if [ -f /etc/gdm3/custom.conf ]; then') + # Replace any existing WaylandEnable line, else add under [daemon] + out.append(' if grep -q "^[[:space:]]*WaylandEnable" /etc/gdm3/custom.conf; then') + out.append(' sed -i "s/^[[:space:]]*WaylandEnable.*/WaylandEnable=false/" /etc/gdm3/custom.conf') + out.append(' else') + out.append(' sed -i "/^[[:space:]]*\\[daemon\\]/a WaylandEnable=false" /etc/gdm3/custom.conf') + out.append(' fi') + out.append(' else') + # No custom.conf yet — write a minimal one + out.append(' cat > /etc/gdm3/custom.conf <&1 | head -5 || warn "gdm restart failed (no gdm installed?)"') + else: + out.append('log "Wayland disabled in custom.conf; will take effect after next gdm restart or reboot."') + out.append('log "Preparing VNC directory..."') out.append(f'USER_HOME="$(getent passwd {quote(user)} | cut -d: -f6 || echo /root)"') # If getent returned /root for a non-root user, the account is in a