From 255072ac949127fda7595da6ac0fb0b52d40a90e Mon Sep 17 00:00:00 2001 From: ekklesia Date: Sat, 5 Sep 2026 00:21:02 -0500 Subject: [PATCH] feat: settle Chrome's window, crash bubble and password prompts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things a volunteer should never have to see. Sway was drawing its own title bar above Chrome's tab strip, which already carries the window controls. Verified on a real session: Chrome is an xdg_shell client with app_id "google-chrome" and sway was giving it border "normal". A scoped rule removes the compositor decoration only — Chrome keeps its tabs and address bar, stays a normal window, and still maximises and minimises. A class rule covers an XWayland fallback. Nothing else changes: the only other window in this classroom is VLC, which is already borderless, so no broader rule is warranted. "Restore pages? Chrome didn't shut down correctly" is suppressed with --hide-crash-restore-bubble. Note the name. The switch this was going to use, --disable-session-crashed-bubble, is not present in Chrome 152 at all — checked against the strings of the installed binary — so it would have silently done nothing. That hides the prompt; the profile was still being marked as crashed, which is the untidy half. Chrome's browser process shuts down cleanly on SIGTERM, so a shutdown unit now gives it one and waits up to eight seconds before the session is torn out from under it. Best effort by construction: a shutdown that will not finish is far worse than a crash flag. Password prompts go off with the PasswordManagerEnabled policy, on the path the classroom already manages. Existing profile and session data are untouched, and website logins are unaffected: Wonder Ink and YouTube stay signed in. Co-Authored-By: Claude Opus 5 --- .../policies/managed/ekklesia-classroom.json | 1 + config/sway/config | 12 ++++ packaging/debian/postinst | 6 ++ scripts/classroom-browser | 7 +++ scripts/classroom-shutdown | 61 +++++++++++++++++++ .../ekklesia-classroom-shutdown.service | 14 +++++ tools/build-release.sh | 8 +++ 7 files changed, 109 insertions(+) create mode 100755 scripts/classroom-shutdown create mode 100644 systemd/shutdown/ekklesia-classroom-shutdown.service diff --git a/config/chrome/policies/managed/ekklesia-classroom.json b/config/chrome/policies/managed/ekklesia-classroom.json index eaa83e7..2efd01b 100644 --- a/config/chrome/policies/managed/ekklesia-classroom.json +++ b/config/chrome/policies/managed/ekklesia-classroom.json @@ -8,6 +8,7 @@ "BrowserAddPersonEnabled": false, "ProfilePickerOnStartupAvailability": 1, + "PasswordManagerEnabled": false, "PasswordLeakDetectionEnabled": false, "BackgroundModeEnabled": false, diff --git a/config/sway/config b/config/sway/config index 5c695a2..0e58998 100644 --- a/config/sway/config +++ b/config/sway/config @@ -24,6 +24,18 @@ exec --no-startup-id /usr/local/bin/classroom-dock include /etc/sway/config.d/* +# Chrome draws its own tab strip with window controls in it, so sway's +# title bar above that is a second, redundant one. Verified on the +# endpoint: Chrome is an xdg_shell client with app_id "google-chrome", +# and sway was giving it border "normal". The class rule covers the case +# where Chrome falls back to XWayland. +# +# This removes the compositor's decoration only. Chrome keeps its tabs +# and address bar, stays a normal window, and still maximises and +# minimises exactly as before. +for_window [app_id="google-chrome"] border none +for_window [class="(?i)google-chrome"] border none + # The DVD player is an appliance screen, not a desktop window. VLC takes # the whole display itself; this removes the title bar sway would # otherwise draw above the video. classroom-dvd-session covers the diff --git a/packaging/debian/postinst b/packaging/debian/postinst index 84a6d10..b6d478e 100755 --- a/packaging/debian/postinst +++ b/packaging/debian/postinst @@ -25,6 +25,7 @@ chmod 0755 /usr/local/bin/classroom-dvd-css-setup chmod 0755 /usr/local/bin/classroom-notify-test chmod 0755 /usr/local/bin/classroom-notifications chmod 0755 /usr/local/bin/classroom-scale +chmod 0755 /usr/local/bin/classroom-shutdown chmod 0755 /usr/local/bin/classroom-chrome-setup chmod 0755 /usr/local/bin/classroom-provision @@ -90,4 +91,9 @@ systemctl start ekklesia-classroom-update.timer || true # A failure there must never fail this installation. systemctl enable ekklesia-classroom-provision.service || true +# Gives Chrome a chance to close properly on reboot, so its profile is +# not marked as crashed. Best effort: it must never hold a shutdown up. +systemctl enable ekklesia-classroom-shutdown.service || true +systemctl start ekklesia-classroom-shutdown.service || true + exit 0 diff --git a/scripts/classroom-browser b/scripts/classroom-browser index 80cd4b4..015325d 100755 --- a/scripts/classroom-browser +++ b/scripts/classroom-browser @@ -7,6 +7,12 @@ set -euo pipefail # Chrome stays a full browser: Wonder Ink is only the starting page, and # the profile in ~/.config/google-chrome is never touched here so logins # and cookies survive reboots and updates. +# +# --hide-crash-restore-bubble is what suppresses "Restore pages? Chrome +# didn't shut down correctly" after a reboot. Note the switch name: the +# older --disable-session-crashed-bubble is not present in Chrome 152 at +# all, so it would have silently done nothing. Verified against the +# strings of the installed binary. HOME_PAGE='https://app.wonderink.org/' @@ -22,4 +28,5 @@ exec /usr/local/bin/classroom-window toggle \ --no-first-run \ --no-default-browser-check \ --password-store=basic \ + --hide-crash-restore-bubble \ "$HOME_PAGE" diff --git a/scripts/classroom-shutdown b/scripts/classroom-shutdown new file mode 100755 index 0000000..f22cadb --- /dev/null +++ b/scripts/classroom-shutdown @@ -0,0 +1,61 @@ +#!/bin/bash +set -uo pipefail + +# Closes Chrome properly before the machine goes down. +# +# Chrome marks a profile as crashed when it does not get to run its own +# shutdown, which is what produces "Restore pages? Chrome didn't shut +# down correctly" on the next boot. The browser process handles SIGTERM +# by shutting down cleanly, so it is worth giving it one and waiting a +# moment before the session is torn out from under it. +# +# --hide-crash-restore-bubble already hides the prompt. This stops the +# profile being marked crashed at all, which is the tidier half of the +# same problem. +# +# Run from ekklesia-classroom-shutdown.service. Never fails: a shutdown +# that will not finish is far worse than a crash flag. + +CLASSROOM_USER=classroom +WAIT_SECONDS=8 + +log() { + echo "[classroom-shutdown] $1" +} + +browser_processes() { + # Only the browser process, not its renderers: those carry --type= + # and are Chrome's own business to reap. + local pid + for pid in $(pgrep -u "$CLASSROOM_USER" -x chrome 2>/dev/null); do + # Braces so a process exiting between pgrep and this read is + # silent: bash reports a failed redirection itself, before the + # command's own stderr redirect can catch it. + if ! { tr '\0' '\n' < "/proc/$pid/cmdline"; } 2>/dev/null | + grep -q '^--type='; then + echo "$pid" + fi + done +} + +pids="$(browser_processes)" + +if [[ -z "$pids" ]]; then + exit 0 +fi + +log "asking Chrome to close" + +# shellcheck disable=SC2086 +kill -TERM $pids 2>/dev/null || true + +for _ in $(seq 1 $((WAIT_SECONDS * 5))); do + if [[ -z "$(browser_processes)" ]]; then + log "Chrome closed cleanly" + exit 0 + fi + sleep 0.2 +done + +log "Chrome did not close in time; leaving it to systemd" +exit 0 diff --git a/systemd/shutdown/ekklesia-classroom-shutdown.service b/systemd/shutdown/ekklesia-classroom-shutdown.service new file mode 100644 index 0000000..727c419 --- /dev/null +++ b/systemd/shutdown/ekklesia-classroom-shutdown.service @@ -0,0 +1,14 @@ +[Unit] +Description=Ekklesia Classroom clean shutdown +Documentation=file:///usr/local/bin/classroom-shutdown +Before=shutdown.target reboot.target halt.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/true +ExecStop=/usr/local/bin/classroom-shutdown +TimeoutStopSec=20 + +[Install] +WantedBy=multi-user.target diff --git a/tools/build-release.sh b/tools/build-release.sh index b82776e..ad5ed3b 100755 --- a/tools/build-release.sh +++ b/tools/build-release.sh @@ -125,6 +125,10 @@ install -Dm755 \ "$ROOT/scripts/classroom-scale" \ "$STAGE/usr/local/bin/classroom-scale" +install -Dm755 \ + "$ROOT/scripts/classroom-shutdown" \ + "$STAGE/usr/local/bin/classroom-shutdown" + install -Dm755 \ "$ROOT/scripts/classroom-chrome-setup" \ "$STAGE/usr/local/bin/classroom-chrome-setup" @@ -203,6 +207,10 @@ install -Dm644 \ "$ROOT/systemd/provision/ekklesia-classroom-provision.service" \ "$STAGE/etc/systemd/system/ekklesia-classroom-provision.service" +install -Dm644 \ + "$ROOT/systemd/shutdown/ekklesia-classroom-shutdown.service" \ + "$STAGE/etc/systemd/system/ekklesia-classroom-shutdown.service" + install -Dm644 \ "$ROOT/config/icons/dvd.svg" \ "$STAGE/etc/ekklesia-classroom/icons/dvd.svg"