jmri: replace TigerVNC with Xpra for JMRI GUI display

VNC had window management issues and some dialogs wouldn't open correctly.
Xpra runs in rootless mode — each JMRI window appears natively on the
client without a VNC client or XQuartz required.

Changes:
- Remove tigervnc-standalone-server, jmri-vnc.service, .vnc/ directory
- Install xpra, deploy jmri-xpra.service.j2 (systemd unit)
- Update jmri-gui wrapper: DISPLAY=:100, attach instructions printed on launch
- Update defaults: drop VNC vars, add jmri_xpra_display=100
- Rename handler: Restart jmri-vnc -> Restart jmri-xpra

Connect from macOS/Linux:
  xpra attach ssh://jmri@main-street-station/100
This commit is contained in:
Hermes Agent service account
2026-08-01 20:14:49 -05:00
parent 4cb87a57ad
commit 62e9f13a45
6 changed files with 91 additions and 93 deletions

View File

@@ -1,22 +1,22 @@
#!/bin/bash
# jmri-gui — launch JMRI GUI on VNC virtual display
# jmri-gui — launch JMRI GUI on Xpra virtual display
# Managed by Ansible — do not edit manually.
#
# Usage (connect as jmri user):
# ssh jmri@main-street-station jmri-gui panelpro
# ssh jmri@main-street-station jmri-gui decoderpro
# ssh jmri@main-street-station jmri-gui status
# jmri-gui panelpro Launch PanelPro on Xpra display
# jmri-gui decoderpro Launch DecoderPro on Xpra display
# jmri-gui status Show service status and attach command
#
# Then connect a VNC client to main-street-station.local.mk-labs.cloud:5901
# VNC password is in the Ansible vault (vault_jmri_vnc_password)
# Then attach from macOS/Linux:
# xpra attach ssh://jmri@main-street-station/{{ jmri_xpra_display }}
set -euo pipefail
JMRI_DIR="{{ jmri_install_dir }}"
JMRI_SERVICE="jmri.service"
MONITOR_SERVICE="jmri-monitor.service"
VNC_SERVICE="jmri-vnc.service"
DISPLAY=":{{ jmri_vnc_display }}"
XPRA_SERVICE="jmri-xpra.service"
DISPLAY=":{{ jmri_xpra_display }}"
export DISPLAY
usage() {
@@ -28,13 +28,13 @@ status() {
echo "=== JMRI daemon ==="
systemctl status "$JMRI_SERVICE" --no-pager -l 2>&1 | head -8
echo ""
echo "=== VNC server ==="
systemctl status "$VNC_SERVICE" --no-pager -l 2>&1 | head -5
echo "=== Xpra display ==="
systemctl status "$XPRA_SERVICE" --no-pager -l 2>&1 | head -5
echo ""
echo "=== Layout monitor ==="
systemctl status "$MONITOR_SERVICE" --no-pager -l 2>&1 | head -5
echo ""
echo "Connect VNC client to: $(hostname -f):{{ jmri_vnc_port }}"
echo "To attach: xpra attach ssh://jmri@$(hostname -f)/{{ jmri_xpra_display }}"
}
launch() {
@@ -47,32 +47,31 @@ launch() {
*) usage ;;
esac
# Ensure VNC server is running
if ! systemctl is-active --quiet "$VNC_SERVICE" 2>/dev/null; then
echo "Starting VNC server..."
sudo systemctl start "$VNC_SERVICE"
# Ensure Xpra display is running
if ! systemctl is-active --quiet "$XPRA_SERVICE" 2>/dev/null; then
echo "Starting Xpra display..."
sudo systemctl start "$XPRA_SERVICE"
sleep 2
fi
# Stop the JMRI daemon if running
# Stop the JMRI daemon if running (we're taking over the hardware connections)
if systemctl is-active --quiet "$JMRI_SERVICE" 2>/dev/null; then
echo "Stopping JMRI daemon..."
sudo systemctl stop "$JMRI_SERVICE"
fi
echo "Launching $binary on VNC display $DISPLAY..."
echo "Connect your VNC client to: $(hostname -f):{{ jmri_vnc_port }}"
echo "VNC password: see Ansible vault (vault_jmri_vnc_password)"
echo ""
# Force AWT out of headless mode
export JMRI_OPTIONS="-Djava.awt.headless=false"
# Launch on the VNC display — no --profile so JMRI uses last-session preference
echo "Launching $binary on Xpra display $DISPLAY..."
echo ""
echo "Attach from your workstation:"
echo " xpra attach ssh://jmri@$(hostname -f)/{{ jmri_xpra_display }}"
echo ""
"$JMRI_DIR/$binary" &
echo "$binary launched in background on VNC display."
echo "Close it from the VNC client, then run 'jmri-gui status' to check state."
echo "$binary launched. Attach with xpra to see windows."
echo ""
# Restart daemon if layout switch is still on

View File

@@ -1,28 +0,0 @@
[Unit]
Description=JMRI VNC virtual display (:{{ jmri_vnc_display }})
After=network.target
# Start before jmri.service so the display is ready when JMRI launches
Before=jmri.service
[Service]
Type=simple
User={{ jmri_user }}
Group={{ jmri_group }}
ExecStart=/usr/bin/Xtigervnc \
:{{ jmri_vnc_display }} \
-rfbport {{ jmri_vnc_port }} \
-geometry {{ jmri_vnc_geometry }} \
-depth {{ jmri_vnc_depth }} \
-SecurityTypes VncAuth \
-PasswordFile {{ jmri_home }}/.vnc/passwd \
-localhost no \
-AlwaysShared \
-NeverShared no \
-AcceptKeyEvents \
-AcceptPointerEvents \
-desktop "JMRI"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,26 @@
[Unit]
Description=Xpra virtual display for JMRI (:{{ jmri_xpra_display }})
After=network.target
# Start before jmri.service so the display is ready when JMRI launches
Before=jmri.service
[Service]
Type=simple
User={{ jmri_user }}
Group={{ jmri_group }}
ExecStart=/usr/bin/xpra start \
:{{ jmri_xpra_display }} \
--daemon=no \
--mdns=no \
--notifications=no \
--systemd-run=no \
--pulseaudio=no \
--speaker=off \
--microphone=off \
--video-encoders=none \
--start-via-proxy=no
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target