kiosk: chromium 72 mime + flex-gap fixes

Pi's onboard chromium is 72 (Jan 2019). Two issues:

1. Python 3.5's mimetypes doesn't know woff/woff2/ttf, so Tornado
   serves them as application/octet-stream which chromium 72 refuses
   to use as web fonts -> all FA6 icons render as empty boxes. Add
   scripts/deploy/patch_font_mime.py that monkey-patches bbctrl
   Web.py's StaticFileHandler with correct content types. Run
   automatically by deploy-hardware.sh (idempotent).

2. flex-gap landed in chromium 84. Add '> * + *' margin fallbacks
   for the flex containers that show up on Program tab (action-bar,
   action-btn, file-bar, file-btn) and tighten the kiosk-mode
   settings rail so all 14 items fit in 768px height.
This commit is contained in:
muehe
2026-05-01 11:16:28 +02:00
parent 68a92bb297
commit 50839718e2
3 changed files with 162 additions and 0 deletions

View File

@@ -62,6 +62,18 @@ ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
&& rm -rf \"${REMOTE_TMP}\"
'" 2>&1 | tail -3
# Patch bbctrl Web.py so font files get the correct MIME type. The
# Pi ships Python 3.5, whose `mimetypes` module doesn't know about
# woff/woff2/ttf, so Tornado serves them as application/octet-stream
# which Chromium 72 (the Pi's onboard browser) refuses to use as a
# web font, leading to all FontAwesome icons rendering as empty
# boxes in the kiosk UI. The patch is idempotent.
echo "Patching bbctrl font MIME types (idempotent)..."
scp -o ConnectTimeout=5 "$SCRIPT_DIR/scripts/deploy/patch_font_mime.py" \
"${REMOTE_USER}@${HOST}:/tmp/patch_font_mime.py" >/dev/null
ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
"echo '${PASSWORD}' | sudo -S python3 /tmp/patch_font_mime.py" 2>&1 | tail -3
echo "Restarting bbctrl service..."
ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
"echo '${PASSWORD}' | sudo -S systemctl restart bbctrl" 2>&1 | tail -3

View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
Patch bbctrl Web.py so font files get the correct MIME type.
Background
----------
The Onefinity controller (Pi 3B running Raspbian stretch) ships Python
3.5, whose ``mimetypes`` module does not recognize ``.woff``, ``.woff2``
or ``.ttf``. Tornado's ``StaticFileHandler`` therefore falls back to
``application/octet-stream`` for those, and Chromium 72 (the Pi's
onboard kiosk browser) refuses to use such payloads as web fonts. The
result is that every FontAwesome icon renders as an empty box on the
kiosk display.
This patch monkey-patches ``StaticFileHandler.get_content_type`` to
emit the right MIME types. It is idempotent: running it twice is a
no-op. Run with ``sudo`` so it can rewrite the egg's Web.py.
Used by:
scripts/deploy/hardware.sh
"""
from __future__ import print_function
import os
import sys
def find_web_py():
"""Return the absolute path to the bbctrl Web.py shipped in the egg."""
base = "/usr/local/lib"
for entry in os.listdir(base):
if not entry.startswith("python"):
continue
candidate_dir = os.path.join(base, entry, "dist-packages")
if not os.path.isdir(candidate_dir):
continue
for sub in os.listdir(candidate_dir):
if sub.startswith("bbctrl-") and sub.endswith(".egg"):
p = os.path.join(candidate_dir, sub, "bbctrl", "Web.py")
if os.path.isfile(p):
return p
return None
OLD_BLOCK = (
"class StaticFileHandler(tornado.web.StaticFileHandler):\n"
" def set_extra_headers(self, path):\n"
" self.set_header('Cache-Control',\n"
" 'no-store, no-cache, must-revalidate, max-age=0')"
)
NEW_BLOCK = (
"class StaticFileHandler(tornado.web.StaticFileHandler):\n"
" # FONT_MIME_FIX: Python 3.5's mimetypes module does not know\n"
" # woff/woff2/ttf, so Tornado serves them as application/octet-\n"
" # stream which Chromium 72 (the Pi's onboard kiosk browser)\n"
" # refuses to use as web fonts. Set explicit types so the FA6\n"
" # icon set actually renders on the kiosk display.\n"
" def get_content_type(self):\n"
" path = self.absolute_path or ''\n"
" if path.endswith('.woff2'): return 'font/woff2'\n"
" if path.endswith('.woff'): return 'font/woff'\n"
" if path.endswith('.ttf'): return 'font/ttf'\n"
" if path.endswith('.otf'): return 'font/otf'\n"
" if path.endswith('.eot'): return 'application/vnd.ms-fontobject'\n"
" return super().get_content_type()\n"
"\n"
" def set_extra_headers(self, path):\n"
" self.set_header('Cache-Control',\n"
" 'no-store, no-cache, must-revalidate, max-age=0')"
)
def main():
target = find_web_py()
if target is None:
print("ERROR: could not locate bbctrl Web.py under /usr/local/lib",
file=sys.stderr)
return 1
with open(target) as f:
src = f.read()
if "FONT_MIME_FIX" in src:
print("font mime: already patched ({})".format(target))
return 0
if OLD_BLOCK not in src:
print("font mime: expected block not found in {} -- skipping".format(target),
file=sys.stderr)
# Don't fail the deploy; just log and continue.
return 0
new_src = src.replace(OLD_BLOCK, NEW_BLOCK, 1)
with open(target, "w") as f:
f.write(new_src)
print("font mime: patched {}".format(target))
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -2570,3 +2570,51 @@ html.kiosk-mode
.control-page .jog-head > * + *
margin-left 8px
// Settings rail must be scrollable in kiosk mode \u2014 the 14+
// item list overflows the 768px viewport at default heights.
.settings-shell
grid-template-columns 220px 1fr
gap 10px
.settings-rail
position static
align-self stretch
max-height 100%
overflow-y auto
.settings-rail .set-item
height 36px
font-size 0.85rem
padding 0 10px
.fa
width 14px
font-size 0.9rem
.settings-rail .set-section
margin 6px 4px 2px
font-size 0.62rem
.settings-rail .set-rail-foot
margin-top 4px
padding-top 6px
.sp-shutdown, .sp-save
height 32px
font-size 0.85rem
// Program tab flex-gap fallbacks for Chromium 72.
// Action bar (RUN/STOP/UPLOAD/.../DELETE) and the action buttons
// themselves (icon stacked over label).
.action-bar > * + *
margin-left 12px
.action-btn > * + *
margin-top 4px
// File bar (Create Folder / folder select / file select / sort).
.file-bar > * + *
margin-left 10px
.file-btn > * + *
margin-left 0.4rem