Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccf73d41bd | ||
|
|
10c4c22f44 | ||
|
|
6f6d34512e | ||
|
|
f01781de41 | ||
|
|
68a7345f5b | ||
|
|
b5d37fa646 | ||
|
|
de9c97aa06 | ||
|
|
ca00674e4c | ||
|
|
0c809d7e53 | ||
|
|
29b5783052 | ||
|
|
de197f77d3 | ||
|
|
8116fdf258 | ||
|
|
35350d9908 | ||
|
|
6621f9221b |
@@ -59,6 +59,38 @@ The installer will guide you through configuration during setup.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Offline / Air-Gapped Download
|
||||||
|
|
||||||
|
If the kiosk machine can't reach GitHub directly (no browser, restrictive proxy, or you just prefer to grab the script on another computer and carry it over via USB), download it ahead of time instead of using the `curl`/`wget` one-liner above.
|
||||||
|
|
||||||
|
> **Note:** This only avoids needing internet access *to fetch the script*. The installer itself still requires the kiosk machine to have internet access while it runs — it uses `apt` to install packages, pulls Node.js from NodeSource, and runs `npm install` to fetch Electron (~120MB). There is currently no fully air-gapped/offline package bundle.
|
||||||
|
|
||||||
|
**On a machine with internet access:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Option A: download just the latest installer script
|
||||||
|
LATEST=$(curl -fsSL https://api.github.com/repos/outis1one/ubuntu-based-kiosk/contents \
|
||||||
|
| grep -oP 'ubuntu-based-kiosk-v[0-9.]+\.sh' \
|
||||||
|
| grep -v beta | sort -V | tail -1)
|
||||||
|
wget "https://github.com/outis1one/ubuntu-based-kiosk/raw/main/$LATEST"
|
||||||
|
|
||||||
|
# Option B: download the whole repo as a ZIP (includes all installer versions and addon scripts)
|
||||||
|
wget https://github.com/outis1one/ubuntu-based-kiosk/archive/refs/heads/main.zip
|
||||||
|
unzip main.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the downloaded `.sh` file (or the extracted ZIP contents) to a USB drive, then on the kiosk machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mount the USB drive and copy the script over, then:
|
||||||
|
chmod +x ubuntu-based-kiosk-v*.sh
|
||||||
|
./ubuntu-based-kiosk-v*.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The kiosk machine still needs a working internet connection (ethernet, or WiFi configured during Ubuntu install) for the script to complete.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Core Features
|
## Core Features
|
||||||
|
|
||||||
### Multi-Site Management
|
### Multi-Site Management
|
||||||
@@ -285,6 +317,9 @@ Both can be used at the same time — they serve different purposes:
|
|||||||
- **build-essential** - GCC, make, etc.
|
- **build-essential** - GCC, make, etc.
|
||||||
- **Python 3** with evdev for PTT
|
- **Python 3** with evdev for PTT
|
||||||
- **jq** - JSON processing
|
- **jq** - JSON processing
|
||||||
|
- **curl / git** - Downloading and version control
|
||||||
|
- **net-tools** - Legacy networking utilities (ifconfig, netstat, etc.)
|
||||||
|
- **ncdu** - Disk usage analyzer for troubleshooting
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -343,6 +378,57 @@ id kiosk
|
|||||||
sudo -u kiosk DISPLAY=:0 xdpyinfo
|
sudo -u kiosk DISPLAY=:0 xdpyinfo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**External monitor/TV (HDMI) shows nothing, or shows a cropped/scaled picture:**
|
||||||
|
|
||||||
|
Any connected display beyond the primary is mirrored automatically at the **primary's exact resolution** (not the external display's own native resolution) — both at kiosk login/boot (via Openbox autostart) and live when plugged/unplugged afterward (via a udev rule that triggers `kiosk-hotplug.service`). Both paths call the same `/usr/local/bin/kiosk-mirror-display.sh`. If the external display doesn't natively list the primary's resolution (e.g. a 1366x768 laptop panel mirrored to a 1920x1080-native TV), a matching mode is generated on the fly with `cvt` and forced onto the output — most monitors/TVs accept a close, non-native CVT timing without issue, but a few strict ones may reject it (see below).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List outputs and check if the external display is detected
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr
|
||||||
|
|
||||||
|
# Look for your output (e.g. HDMI1/HDMI2/HDMI-1) as "connected" with a mode list.
|
||||||
|
|
||||||
|
# Check what the mirroring logic actually did (native mode vs. forced CVT mode, or failures)
|
||||||
|
journalctl | grep "KIOSK:" | tail -20
|
||||||
|
|
||||||
|
# Check whether the hotplug handler fired
|
||||||
|
sudo journalctl -u kiosk-hotplug.service -n 20
|
||||||
|
|
||||||
|
# Manually re-trigger it
|
||||||
|
sudo systemctl start kiosk-hotplug.service
|
||||||
|
|
||||||
|
# Run the mirroring logic by hand for more verbose output
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority bash -x /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
```
|
||||||
|
If the output shows `disconnected`, it's a cabling/port/EDID issue, not software — try a different cable/port or a monitor known to work.
|
||||||
|
|
||||||
|
If a forced CVT mode is rejected by the display (blank screen only after mirroring runs, works fine before), that display's EDID doesn't accept out-of-spec timings — you'll need to manually pick one of its natively listed modes instead:
|
||||||
|
```bash
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr --output HDMI2 --mode 1360x768 --same-as eDP1
|
||||||
|
```
|
||||||
|
|
||||||
|
**No sound over HDMI (audio only from laptop/built-in speakers):**
|
||||||
|
|
||||||
|
Whenever an external display is connected/mirrored, `kiosk-audio-route.sh` switches PipeWire's default sink to whichever sink's name contains `hdmi`, and moves any already-playing audio stream onto it. It's called at kiosk login (after PipeWire is confirmed ready) and by `kiosk-hotplug.service` on every plug/unplug — see `/usr/local/bin/kiosk-mirror-display.sh` above for the display side of the same hotplug event.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List sinks and confirm an HDMI one exists (name will contain "hdmi")
|
||||||
|
sudo -u kiosk pactl list sinks short
|
||||||
|
|
||||||
|
# Check what the routing logic actually did
|
||||||
|
journalctl | grep "KIOSK: audio routed\|KIOSK: failed to route" | tail -10
|
||||||
|
|
||||||
|
# Check current default sink
|
||||||
|
sudo -u kiosk pactl get-default-sink
|
||||||
|
|
||||||
|
# Manually re-trigger routing
|
||||||
|
sudo systemctl start kiosk-hotplug.service
|
||||||
|
|
||||||
|
# Force it by hand if needed (replace with your sink name from the list above)
|
||||||
|
sudo -u kiosk pactl set-default-sink alsa_output.pci-0000_00_1f.3.hdmi-stereo
|
||||||
|
```
|
||||||
|
If no sink name contains `hdmi`, the audio codec on that HDMI port either isn't exposed by ALSA/PipeWire on this hardware, or the monitor/TV doesn't report HDMI audio support in its EDID (common on monitors that only do video) — in that case there's no PipeWire-side fix, audio has to come from the laptop speakers or a separate cable.
|
||||||
|
|
||||||
**Audio not working:**
|
**Audio not working:**
|
||||||
```bash
|
```bash
|
||||||
# Check PipeWire (use menu: Advanced → Audio Diagnostics)
|
# Check PipeWire (use menu: Advanced → Audio Diagnostics)
|
||||||
@@ -1087,6 +1173,9 @@ See the LICENSE file in the repository for full terms.
|
|||||||
**Current Version:** 1.0.3
|
**Current Version:** 1.0.3
|
||||||
|
|
||||||
**Recent Updates (v1.0.3):**
|
**Recent Updates (v1.0.3):**
|
||||||
|
- **HDMI/external display mirroring:** any connected display beyond the primary (e.g. HDMI-out to a monitor/TV) is now mirrored automatically at the primary's exact resolution — generating a custom `cvt` mode if the external display doesn't natively list it — both at kiosk login/boot and live on plug/unplug via a new udev-triggered `kiosk-hotplug.service`. Previously the external output was left inactive even when detected by X, and would otherwise mirror at its own native resolution instead of matching the kiosk panel
|
||||||
|
- **HDMI audio routing:** audio now follows the same hotplug event — the default PipeWire sink automatically switches to the HDMI audio output when an external display is connected/mirrored, and back to the built-in sink when it's disconnected (`kiosk-audio-route.sh`)
|
||||||
|
- **Package install:** installer now also installs `net-tools` and `ncdu` (alongside the already-installed `curl` and `git`)
|
||||||
- **Touch input fix (keyring):** added `--password-store=basic` to the Electron launch. Under LightDM autologin the GNOME keyring stays locked; when Chromium accessed it, the keyring unlock dialog grabbed all keyboard/touch input — the kiosk rendered fine but ignored every tap and keypress. This flag stops Electron from using the keyring, so the dialog never appears.
|
- **Touch input fix (keyring):** added `--password-store=basic` to the Electron launch. Under LightDM autologin the GNOME keyring stays locked; when Chromium accessed it, the keyring unlock dialog grabbed all keyboard/touch input — the kiosk rendered fine but ignored every tap and keypress. This flag stops Electron from using the keyring, so the dialog never appears.
|
||||||
- **Touch gesture fix (libinput):** any touch screen is now forced to the `libinput` driver via `/etc/X11/xorg.conf.d/99-finger-libinput.conf` (matched by hardware capability, so it works on any brand and never affects keyboards, mice, or the pen/stylus). Some drivers — notably `wacom` — only do single-touch pointer emulation and never pass real multitouch to Chromium, so 1-finger and 2-finger swipe gestures could not fire. libinput delivers proper multitouch.
|
- **Touch gesture fix (libinput):** any touch screen is now forced to the `libinput` driver via `/etc/X11/xorg.conf.d/99-finger-libinput.conf` (matched by hardware capability, so it works on any brand and never affects keyboards, mice, or the pen/stylus). Some drivers — notably `wacom` — only do single-touch pointer emulation and never pass real multitouch to Chromium, so 1-finger and 2-finger swipe gestures could not fire. libinput delivers proper multitouch.
|
||||||
- **Upgrade reliability:** `start.sh` is now refreshed on every upgrade alongside `main.js` and `preload.js`
|
- **Upgrade reliability:** `start.sh` is now refreshed on every upgrade alongside `main.js` and `preload.js`
|
||||||
@@ -1128,7 +1217,7 @@ See the LICENSE file in the repository for full terms.
|
|||||||
**Known Limitations:**
|
**Known Limitations:**
|
||||||
- Raspberry Pi support untested in production
|
- Raspberry Pi support untested in production
|
||||||
- No web-based configuration (CLI menu only)
|
- No web-based configuration (CLI menu only)
|
||||||
- Single display only (extended desktop not supported)
|
- Extended desktop not supported — additional connected displays (e.g. HDMI-out to a monitor/TV) are automatically **mirrored**, not extended
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+178
-19
@@ -3844,6 +3844,8 @@ complete_uninstall() {
|
|||||||
echo "[5/13] Removing scripts..."
|
echo "[5/13] Removing scripts..."
|
||||||
sudo rm -f /usr/local/bin/kiosk-*
|
sudo rm -f /usr/local/bin/kiosk-*
|
||||||
sudo rm -f /usr/local/bin/rtc-wake.sh
|
sudo rm -f /usr/local/bin/rtc-wake.sh
|
||||||
|
sudo rm -f /etc/udev/rules.d/99-kiosk-hotplug.rules
|
||||||
|
sudo udevadm control --reload-rules 2>/dev/null || true
|
||||||
|
|
||||||
# Remove CUPS
|
# Remove CUPS
|
||||||
echo "[6/13] Removing CUPS..."
|
echo "[6/13] Removing CUPS..."
|
||||||
@@ -3953,7 +3955,8 @@ first_time_install() {
|
|||||||
libegl-mesa0 libegl1-mesa-dev libgles2-mesa-dev \
|
libegl-mesa0 libegl1-mesa-dev libgles2-mesa-dev \
|
||||||
pipewire pipewire-pulse pipewire-alsa wireplumber pipewire-audio-client-libraries alsa-utils libnotify-bin \
|
pipewire pipewire-pulse pipewire-alsa wireplumber pipewire-audio-client-libraries alsa-utils libnotify-bin \
|
||||||
gstreamer1.0-pipewire libspa-0.2-bluetooth \
|
gstreamer1.0-pipewire libspa-0.2-bluetooth \
|
||||||
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip
|
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip \
|
||||||
|
net-tools ncdu
|
||||||
|
|
||||||
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
||||||
sudo apt install -y intel-gpu-tools xserver-xorg-video-intel \
|
sudo apt install -y intel-gpu-tools xserver-xorg-video-intel \
|
||||||
@@ -7388,9 +7391,118 @@ TOUCHCFG
|
|||||||
# Create empty xbindkeysrc to prevent errors
|
# Create empty xbindkeysrc to prevent errors
|
||||||
sudo -u "$KIOSK_USER" touch "$KIOSK_HOME/.xbindkeysrc"
|
sudo -u "$KIOSK_USER" touch "$KIOSK_HOME/.xbindkeysrc"
|
||||||
|
|
||||||
|
# Shared logic for mirroring any connected display beyond the primary at
|
||||||
|
# the primary's exact resolution (forcing a custom CVT mode if the
|
||||||
|
# external output doesn't natively list it). Called from both the
|
||||||
|
# Openbox autostart below (already running as kiosk user in the X
|
||||||
|
# session) and kiosk-hotplug.sh (root, via systemd/udev — wraps the call
|
||||||
|
# with sudo -u kiosk DISPLAY=:0 XAUTHORITY=...).
|
||||||
|
sudo tee /usr/local/bin/kiosk-mirror-display.sh > /dev/null <<'MIRRORSCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Assumes it's run with DISPLAY/XAUTHORITY already set for the kiosk user's
|
||||||
|
# X session (either inherited, as from Openbox autostart, or exported by the
|
||||||
|
# caller). Mirrors every connected non-primary output at the primary's exact
|
||||||
|
# current resolution so kiosk content isn't cropped/letterboxed/blank on a
|
||||||
|
# TV/monitor with a different native resolution than the kiosk panel.
|
||||||
|
|
||||||
|
QUERY=$(xrandr --query 2>/dev/null)
|
||||||
|
[ -z "$QUERY" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
|
||||||
|
[ -z "$PRIMARY_OUTPUT" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_RES=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '$1==p{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+x[0-9]+\+/){split($i,a,"+"); print a[1]; exit}}')
|
||||||
|
[ -z "$PRIMARY_RES" ] && exit 0
|
||||||
|
|
||||||
|
for OUT in $(echo "$QUERY" | awk '/ connected/{print $1}'); do
|
||||||
|
[ "$OUT" = "$PRIMARY_OUTPUT" ] && continue
|
||||||
|
|
||||||
|
HAS_NATIVE=$(echo "$QUERY" | awk -v out="$OUT" -v res="$PRIMARY_RES" '
|
||||||
|
$0 ~ "^"out" " {infound=1; next}
|
||||||
|
/^[^ \t]/ {infound=0}
|
||||||
|
infound && $1==res {print "yes"; exit}
|
||||||
|
')
|
||||||
|
|
||||||
|
if [ "$HAS_NATIVE" = "yes" ]; then
|
||||||
|
xrandr --output "$OUT" --mode "$PRIMARY_RES" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: mirrored $OUT at native $PRIMARY_RES" \
|
||||||
|
|| logger "KIOSK: mirror of $OUT at $PRIMARY_RES failed"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# $OUT doesn't natively list the primary's resolution - force a matching mode
|
||||||
|
CVT_LINE=$(cvt "${PRIMARY_RES%x*}" "${PRIMARY_RES#*x}" 2>/dev/null | grep Modeline)
|
||||||
|
MODENAME=$(echo "$CVT_LINE" | sed -n 's/^Modeline "\([^"]*\)".*/\1/p')
|
||||||
|
TIMINGS=$(echo "$CVT_LINE" | sed -n 's/^Modeline "[^"]*" *//p')
|
||||||
|
|
||||||
|
if [ -z "$MODENAME" ] || [ -z "$TIMINGS" ]; then
|
||||||
|
logger "KIOSK: could not generate a $PRIMARY_RES mode for $OUT (cvt failed or missing)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
xrandr --newmode "$MODENAME" $TIMINGS 2>/dev/null
|
||||||
|
xrandr --addmode "$OUT" "$MODENAME" 2>/dev/null
|
||||||
|
xrandr --output "$OUT" --mode "$MODENAME" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: mirrored $OUT at forced $PRIMARY_RES ($MODENAME)" \
|
||||||
|
|| logger "KIOSK: mirror of $OUT at forced $PRIMARY_RES failed"
|
||||||
|
done
|
||||||
|
MIRRORSCRIPT
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
|
# Shared logic for routing audio to an HDMI audio sink whenever an
|
||||||
|
# external (non-primary) display is connected/mirrored, and back to the
|
||||||
|
# built-in sink when it isn't. Requires PipeWire/pipewire-pulse to
|
||||||
|
# already be running (pactl needs a live socket), so unlike
|
||||||
|
# kiosk-mirror-display.sh this is called later in autostart, after the
|
||||||
|
# "wait for PipeWire/ALSA" steps below — and from kiosk-hotplug.sh, where
|
||||||
|
# the system is already fully booted by the time it fires.
|
||||||
|
sudo tee /usr/local/bin/kiosk-audio-route.sh > /dev/null <<'AUDIOSCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Assumes DISPLAY/XAUTHORITY are set (for xrandr) and pactl already has a
|
||||||
|
# working PipeWire/pulse socket for the invoking context.
|
||||||
|
|
||||||
|
QUERY=$(xrandr --query 2>/dev/null)
|
||||||
|
[ -z "$QUERY" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
|
||||||
|
[ -z "$PRIMARY_OUTPUT" ] && exit 0
|
||||||
|
|
||||||
|
EXTERNAL_CONNECTED=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '/ connected/ && $1!=p{f=1} END{print (f==1)?"yes":"no"}')
|
||||||
|
|
||||||
|
HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) ~ /hdmi/{print $2; exit}')
|
||||||
|
NON_HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) !~ /hdmi/{print $2; exit}')
|
||||||
|
|
||||||
|
route_to() {
|
||||||
|
local sink="$1" label="$2"
|
||||||
|
if [ -z "$sink" ]; then
|
||||||
|
logger "KIOSK: no $label audio sink found, leaving routing unchanged"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
pactl set-default-sink "$sink" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: audio routed to $label sink ($sink)" \
|
||||||
|
|| logger "KIOSK: failed to route audio to $label sink ($sink)"
|
||||||
|
pactl list sink-inputs short 2>/dev/null | awk '{print $1}' | while read -r sid; do
|
||||||
|
pactl move-sink-input "$sid" "$sink" 2>/dev/null
|
||||||
|
done
|
||||||
|
pactl set-sink-volume "$sink" 100% 2>/dev/null
|
||||||
|
pactl set-sink-mute "$sink" 0 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$EXTERNAL_CONNECTED" = "yes" ]; then
|
||||||
|
route_to "$HDMI_SINK" "HDMI"
|
||||||
|
else
|
||||||
|
route_to "$NON_HDMI_SINK" "built-in"
|
||||||
|
fi
|
||||||
|
AUDIOSCRIPT
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-audio-route.sh
|
||||||
|
|
||||||
sudo -u "$KIOSK_USER" tee "$KIOSK_HOME/.config/openbox/autostart" > /dev/null <<'AUTOSTART'
|
sudo -u "$KIOSK_USER" tee "$KIOSK_HOME/.config/openbox/autostart" > /dev/null <<'AUTOSTART'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Mirror any connected external display (e.g. HDMI-out to a monitor/TV) onto
|
||||||
|
# the primary display, forcing it to the primary's exact resolution.
|
||||||
|
/usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
# AGGRESSIVE DPMS disable - multiple methods
|
# AGGRESSIVE DPMS disable - multiple methods
|
||||||
xset s off
|
xset s off
|
||||||
xset s noblank
|
xset s noblank
|
||||||
@@ -7460,6 +7572,9 @@ for i in {1..10}; do
|
|||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Route audio to HDMI if an external display is connected/mirrored, else built-in
|
||||||
|
/usr/local/bin/kiosk-audio-route.sh
|
||||||
|
|
||||||
# Set audio levels (speakers 100%, mic 100%, mic unmuted)
|
# Set audio levels (speakers 100%, mic 100%, mic unmuted)
|
||||||
pactl set-sink-volume @DEFAULT_SINK@ 100%
|
pactl set-sink-volume @DEFAULT_SINK@ 100%
|
||||||
pactl set-source-volume @DEFAULT_SOURCE@ 100%
|
pactl set-source-volume @DEFAULT_SOURCE@ 100%
|
||||||
@@ -7527,7 +7642,41 @@ sleep 2
|
|||||||
/home/kiosk/kiosk-app/start.sh &
|
/home/kiosk/kiosk-app/start.sh &
|
||||||
AUTOSTART
|
AUTOSTART
|
||||||
sudo chmod 750 "$KIOSK_HOME/.config/openbox/autostart"
|
sudo chmod 750 "$KIOSK_HOME/.config/openbox/autostart"
|
||||||
|
|
||||||
|
# HDMI/display hotplug: re-mirror any newly connected external display
|
||||||
|
# without waiting for the next login. Triggered by udev on DRM "change"
|
||||||
|
# events (monitor plugged/unplugged), which starts a oneshot systemd
|
||||||
|
# service that re-runs the same kiosk-mirror-display.sh logic used at
|
||||||
|
# Openbox autostart, as root, so it wraps the call with sudo -u kiosk.
|
||||||
|
sudo tee /usr/local/bin/kiosk-hotplug.sh > /dev/null <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Give X a moment to finish enumerating the output after the hotplug event
|
||||||
|
sleep 2
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
|
kiosk_uid=$(id -u kiosk)
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority XDG_RUNTIME_DIR="/run/user/${kiosk_uid}" /usr/local/bin/kiosk-audio-route.sh
|
||||||
|
EOF
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-hotplug.sh
|
||||||
|
|
||||||
|
sudo tee /etc/systemd/system/kiosk-hotplug.service > /dev/null <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Kiosk Display Hotplug Handler
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/kiosk-hotplug.sh
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo tee /etc/udev/rules.d/99-kiosk-hotplug.rules > /dev/null <<'EOF'
|
||||||
|
SUBSYSTEM=="drm", ACTION=="change", TAG+="systemd", ENV{SYSTEMD_WANTS}="kiosk-hotplug.service"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
|
||||||
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
||||||
sudo mkdir -p /etc/X11/xorg.conf.d/
|
sudo mkdir -p /etc/X11/xorg.conf.d/
|
||||||
sudo tee /etc/X11/xorg.conf.d/20-intel.conf > /dev/null <<'EOF'
|
sudo tee /etc/X11/xorg.conf.d/20-intel.conf > /dev/null <<'EOF'
|
||||||
@@ -7557,23 +7706,7 @@ EndSection
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "[19/27] Configuring autologin..."
|
echo "[19/27] Configuring autologin..."
|
||||||
sudo mkdir -p /etc/lightdm/lightdm.conf.d
|
configure_lightdm_autologin
|
||||||
# [Seat:*] is required on Ubuntu 22.04+ ([SeatDefaults] is ignored on newer LightDM)
|
|
||||||
# Also add kiosk user to the autologin group required by newer Ubuntu
|
|
||||||
sudo groupadd -f autologin
|
|
||||||
sudo usermod -aG autologin "$KIOSK_USER"
|
|
||||||
sudo tee /etc/lightdm/lightdm.conf.d/10-kiosk.conf > /dev/null <<EOF
|
|
||||||
[Seat:*]
|
|
||||||
autologin-user=$KIOSK_USER
|
|
||||||
autologin-user-timeout=0
|
|
||||||
user-session=openbox
|
|
||||||
autologin-session=openbox
|
|
||||||
|
|
||||||
# SECURITY: Greeter security settings
|
|
||||||
greeter-hide-users=true
|
|
||||||
greeter-show-manual-login=false
|
|
||||||
allow-guest=false
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "[20/27] Configuring firewall..."
|
echo "[20/27] Configuring firewall..."
|
||||||
sudo ufw --force enable
|
sudo ufw --force enable
|
||||||
@@ -11081,6 +11214,27 @@ import_settings() {
|
|||||||
pause
|
pause
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Shared helper: write LightDM autologin config and add kiosk user to required groups.
|
||||||
|
# Called from both fresh install (step 19/27) and upgrade (step 5/6).
|
||||||
|
configure_lightdm_autologin() {
|
||||||
|
sudo mkdir -p /etc/lightdm/lightdm.conf.d
|
||||||
|
# nopasswdlogin is checked by PAM on Ubuntu 24.04; autologin group for older versions
|
||||||
|
sudo groupadd -f nopasswdlogin
|
||||||
|
sudo groupadd -f autologin
|
||||||
|
sudo usermod -aG nopasswdlogin,autologin "$KIOSK_USER"
|
||||||
|
# [Seat:*] works on all LightDM versions; [SeatDefaults] is ignored on newer Ubuntu
|
||||||
|
sudo tee /etc/lightdm/lightdm.conf.d/10-kiosk.conf > /dev/null <<EOF
|
||||||
|
[Seat:*]
|
||||||
|
autologin-user=$KIOSK_USER
|
||||||
|
autologin-user-timeout=0
|
||||||
|
user-session=openbox
|
||||||
|
autologin-session=openbox
|
||||||
|
greeter-hide-users=true
|
||||||
|
greeter-show-manual-login=false
|
||||||
|
allow-guest=false
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
# Shared helper: verify Electron binary exists, download if missing, fix sandbox perms.
|
# Shared helper: verify Electron binary exists, download if missing, fix sandbox perms.
|
||||||
# Called from both fresh install (step 17/27) and upgrade (step 5/6).
|
# Called from both fresh install (step 17/27) and upgrade (step 5/6).
|
||||||
install_electron_binary() {
|
install_electron_binary() {
|
||||||
@@ -11322,6 +11476,11 @@ upgrade_kiosk() {
|
|||||||
sudo rm -f "$config_backup"
|
sudo rm -f "$config_backup"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure LightDM autologin config exists and groups are correct.
|
||||||
|
# The upgrade preserves node_modules but does not re-run the full install,
|
||||||
|
# so this may be the first time the config is written on new hardware.
|
||||||
|
configure_lightdm_autologin
|
||||||
|
|
||||||
# Force any touch screen to use libinput (proper multitouch for Chromium).
|
# Force any touch screen to use libinput (proper multitouch for Chromium).
|
||||||
# Remove the old wacom-touch override from earlier versions — it sorts after
|
# Remove the old wacom-touch override from earlier versions — it sorts after
|
||||||
# this file and would otherwise win and re-bind the device to the wacom driver.
|
# this file and would otherwise win and re-bind the device to the wacom driver.
|
||||||
|
|||||||
Reference in New Issue
Block a user