Give the kiosk a window manager, and a debug mode to go with it
The role ran no window manager on the theory that Firefox is the only X client and --kiosk makes it full-screen by itself. It doesn't: --kiosk *asks* to be full-screen over EWMH, and with no WM running nobody answers. Firefox kept its default window size in the top-left corner - on musicdolphin's 1920x1080 monitor, a 1280x972 window with black bands down the right edge and along the bottom, which looks exactly like an overscan problem and isn't one. Openbox answers the request and does nothing else. pi_kiosk_mode=debug then turns the attached screen into something workable: Firefox as an ordinary window that is not relaunched when you close it, a visible pointer, Openbox as the session leader with a root menu offering a terminal, and xterm, x11-utils and mesa-utils installed. musicdolphin is set to debug for now. The templates notify the getty handler, so a mode switch restarts the session on its own - Xorg lives in that unit's cgroup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,56 @@
|
||||
# pi_kiosk
|
||||
|
||||
Turns a Pi with a monitor attached into a full-screen Firefox kiosk display, with no
|
||||
window manager: an autologin console user runs `startx`, whose `.xinitrc` launches
|
||||
Firefox in `--kiosk` mode pointed at `pi_kiosk_url` and relaunches it if it ever exits.
|
||||
If X itself crashes, `.bash_profile` restarts it.
|
||||
Turns a Pi with a monitor attached into a full-screen Firefox display: an autologin
|
||||
console user runs `startx`, whose `.xinitrc` starts Openbox and then Firefox pointed at
|
||||
`pi_kiosk_url`, relaunching it if it ever exits. If X itself crashes, `.bash_profile`
|
||||
restarts it.
|
||||
|
||||
Vars:
|
||||
|
||||
- `pi_kiosk_user` (default `kiosk`) - the account that autologs into tty1.
|
||||
- `pi_kiosk_url` (default `http://localhost:8080`) - what Firefox shows.
|
||||
- `pi_kiosk_mode` (default `kiosk`) - `kiosk` or `debug`, see below.
|
||||
|
||||
Meant to run alongside `pi_musicmouse` on the same host when it's serving the page
|
||||
locally (the default `pi_kiosk_url`), gated in `mediapis.yml` by `mediapi_has_monitor`.
|
||||
|
||||
niri was considered instead of plain X/no-WM, but isn't packaged for Debian Bookworm
|
||||
yet (no official apt package, only third-party `.deb`s or a from-source Rust build) -
|
||||
revisit once it is.
|
||||
## Why there is a window manager
|
||||
|
||||
This role used to run no WM at all, on the theory that Firefox is the only X client and
|
||||
`--kiosk` makes it full-screen by itself. It doesn't. `--kiosk` *asks* to be
|
||||
full-screen, over EWMH, and with no window manager running there is nobody to answer:
|
||||
Firefox falls back to its default window size in the top-left corner. On the 1920x1080
|
||||
monitor on musicdolphin that came out as a 1280x972 window with black bands down the
|
||||
right edge and along the bottom - looking for all the world like an overscan problem,
|
||||
which it is not. Openbox answers the request and otherwise stays out of the way.
|
||||
|
||||
## Debug mode
|
||||
|
||||
`pi_kiosk_mode: debug` turns the device's own screen into something you can work on:
|
||||
|
||||
- Firefox runs as an ordinary window with its chrome, so the URL bar and devtools are
|
||||
reachable, and it is **not** relaunched when you close it.
|
||||
- The pointer is visible (no `-nocursor`, no `unclutter`).
|
||||
- Openbox is the session leader. Right-click the desktop for a menu with a terminal,
|
||||
both ways of opening the page again, and "End this X session", which drops back to
|
||||
the autologin loop and starts a fresh one.
|
||||
- `xterm`, `x11-utils` and `mesa-utils` get installed, so `xwininfo`, `xprop`,
|
||||
`glxinfo` and `glxgears` are on the device. (The menu's Terminal entry runs
|
||||
`x-terminal-emulator`, which on the Pi OS image is `zutty`, not the xterm we
|
||||
install - both work; xterm is the fallback if the alternatives link ever points
|
||||
somewhere that doesn't.)
|
||||
|
||||
Switch a host over in `host_vars`, or for one run:
|
||||
|
||||
```sh
|
||||
just run mediapis.yml musicdolphin -e pi_kiosk_mode=debug
|
||||
just run mediapis.yml musicdolphin -e pi_kiosk_mode=kiosk
|
||||
```
|
||||
|
||||
Either way the session restarts itself: the templates notify the getty handler, and
|
||||
restarting `getty@tty1` takes X down with it because Xorg lives in that unit's cgroup.
|
||||
Going back to `kiosk` does not uninstall the debug packages; they are small and inert.
|
||||
|
||||
niri was considered instead of Openbox, but isn't packaged for Debian Bookworm yet (no
|
||||
official apt package, only third-party `.deb`s or a from-source Rust build) - revisit
|
||||
once it is.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
pi_kiosk_user: "kiosk"
|
||||
pi_kiosk_url: "http://localhost:8080"
|
||||
|
||||
# "kiosk" - the page full-screen with no browser chrome and no pointer. The normal mode.
|
||||
# "debug" - the same page in an ordinary Firefox window, pointer visible, with an
|
||||
# Openbox root menu (right-click the desktop) offering a terminal, so the
|
||||
# device can be poked at on its own screen. Switch back with
|
||||
# `just run mediapis.yml musicdolphin -e pi_kiosk_mode=kiosk`, or by editing
|
||||
# host_vars.
|
||||
pi_kiosk_mode: "kiosk"
|
||||
|
||||
@@ -5,10 +5,25 @@
|
||||
- xserver-xorg
|
||||
- xinit
|
||||
- x11-xserver-utils
|
||||
# Without a window manager, Firefox's request to go full-screen (which is all
|
||||
# --kiosk does) has nobody to answer it, and it settles for its default window
|
||||
# size in the corner of the screen. Openbox answers it, and nothing else.
|
||||
- openbox
|
||||
- firefox-esr
|
||||
- unclutter
|
||||
cache_valid_time: 7200
|
||||
|
||||
- name: Debugging tools for the attached screen
|
||||
# Only pulled in for pi_kiosk_mode=debug; apt does not take them away again when the
|
||||
# host goes back to kiosk mode, which is fine - they are inert and small.
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- xterm # a terminal that is ours, whatever x-terminal-emulator points at
|
||||
- x11-utils # xwininfo, xprop: is the window actually the size of the screen?
|
||||
- mesa-utils # glxinfo, glxgears: is anything accelerated, or is this llvmpipe?
|
||||
cache_valid_time: 7200
|
||||
when: pi_kiosk_mode == 'debug'
|
||||
|
||||
- name: Create kiosk user
|
||||
ansible.builtin.user:
|
||||
name: "{{ pi_kiosk_user }}"
|
||||
@@ -64,14 +79,16 @@
|
||||
owner: "{{ pi_kiosk_user }}"
|
||||
group: "{{ pi_kiosk_user }}"
|
||||
mode: "0644"
|
||||
notify: Reload systemd and restart getty
|
||||
|
||||
- name: Install .xinitrc (launches Firefox kiosk, no window manager)
|
||||
- name: Install .xinitrc (starts Openbox, then Firefox)
|
||||
ansible.builtin.template:
|
||||
src: xinitrc.j2
|
||||
dest: "/home/{{ pi_kiosk_user }}/.xinitrc"
|
||||
owner: "{{ pi_kiosk_user }}"
|
||||
group: "{{ pi_kiosk_user }}"
|
||||
mode: "0755"
|
||||
notify: Reload systemd and restart getty
|
||||
|
||||
- name: Ensure firefox-esr policy directory exists
|
||||
ansible.builtin.file:
|
||||
@@ -85,3 +102,26 @@
|
||||
src: policies.json
|
||||
dest: /etc/firefox-esr/policies.json
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure the Openbox config directories exist
|
||||
# Both levels explicitly, and owned by the user: a file: task creates missing parents
|
||||
# as root, and a root-owned ~/.config is the same trap that broke the Firefox profile
|
||||
# above.
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ pi_kiosk_user }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ pi_kiosk_user }}"
|
||||
group: "{{ pi_kiosk_user }}"
|
||||
mode: "0755"
|
||||
loop:
|
||||
- .config
|
||||
- .config/openbox
|
||||
|
||||
- name: Install the Openbox root menu
|
||||
ansible.builtin.template:
|
||||
src: openbox-menu.xml.j2
|
||||
dest: "/home/{{ pi_kiosk_user }}/.config/openbox/menu.xml"
|
||||
owner: "{{ pi_kiosk_user }}"
|
||||
group: "{{ pi_kiosk_user }}"
|
||||
mode: "0644"
|
||||
notify: Reload systemd and restart getty
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
# this account autologs into - not meant for interactive use.
|
||||
if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then
|
||||
while true; do
|
||||
{% if pi_kiosk_mode == 'debug' %}
|
||||
# No -nocursor: debugging on the device's own screen needs a pointer.
|
||||
startx
|
||||
{% else %}
|
||||
startx -- -nocursor
|
||||
{% endif %}
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
|
||||
32
roles/pi_kiosk/templates/openbox-menu.xml.j2
Normal file
32
roles/pi_kiosk/templates/openbox-menu.xml.j2
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Managed by ansible (pi_kiosk role). Replaces Debian's default Openbox menu, which
|
||||
points at a desktop's worth of applications that are not installed here. Right-click
|
||||
the desktop to open it; in kiosk mode there is no pointer to do that with, which is
|
||||
the point.
|
||||
-->
|
||||
<openbox_menu xmlns="http://openbox.org/3.4/menu">
|
||||
<menu id="root-menu" label="{{ inventory_hostname }}">
|
||||
<item label="Terminal">
|
||||
<action name="Execute"><command>x-terminal-emulator</command></action>
|
||||
</item>
|
||||
<separator/>
|
||||
<item label="Open the MusicMouse page">
|
||||
<action name="Execute">
|
||||
<command>firefox {{ pi_kiosk_url }}</command>
|
||||
</action>
|
||||
</item>
|
||||
<item label="Open it full-screen (kiosk)">
|
||||
<action name="Execute">
|
||||
<command>firefox --kiosk {{ pi_kiosk_url }}</command>
|
||||
</action>
|
||||
</item>
|
||||
<separator/>
|
||||
<item label="Restart Openbox">
|
||||
<action name="Restart"/>
|
||||
</item>
|
||||
<item label="End this X session (it restarts)">
|
||||
<action name="Exit"/>
|
||||
</item>
|
||||
</menu>
|
||||
</openbox_menu>
|
||||
@@ -1,15 +1,34 @@
|
||||
#!/bin/sh
|
||||
# Managed by ansible (pi_kiosk role). No window manager on purpose - Firefox is the
|
||||
# only X client, launched full-screen in kiosk mode; the loop is what takes the place
|
||||
# of a WM's "keep something on screen" job if it crashes.
|
||||
# Managed by ansible (pi_kiosk role).
|
||||
#
|
||||
# Openbox is here for one concrete reason: a browser asks to be full-screen over EWMH,
|
||||
# and only a window manager answers that request. With no WM running, --kiosk was
|
||||
# silently ignored and Firefox fell back to its default 1280x972 window on a 1920x1080
|
||||
# screen - the page in the top-left corner with black bands down the right edge and
|
||||
# along the bottom. Openbox costs a couple of MB and does nothing else here.
|
||||
|
||||
xset s off
|
||||
xset -dpms
|
||||
xset s noblank
|
||||
|
||||
{% if pi_kiosk_mode == 'debug' %}
|
||||
# Debug session. Firefox is an ordinary window with its chrome (so devtools and the URL
|
||||
# bar are reachable) and is *not* relaunched when it exits - quitting it should leave a
|
||||
# usable desktop, not fight you for the screen. Openbox is the session leader instead:
|
||||
# when it exits (root menu -> Exit) the X session ends and .bash_profile starts a fresh
|
||||
# one. Right-click the desktop for a terminal.
|
||||
firefox "{{ pi_kiosk_url }}" &
|
||||
|
||||
exec openbox
|
||||
{% else %}
|
||||
openbox &
|
||||
|
||||
unclutter -idle 0.5 -root &
|
||||
|
||||
# The loop is what takes the place of a WM's "keep something on screen" job: Openbox
|
||||
# manages the window, but nothing else would bring Firefox back if it died.
|
||||
while true; do
|
||||
firefox --kiosk "{{ pi_kiosk_url }}"
|
||||
sleep 2
|
||||
done
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user