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:
@@ -62,6 +62,18 @@ ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
|
|||||||
&& rm -rf \"${REMOTE_TMP}\"
|
&& rm -rf \"${REMOTE_TMP}\"
|
||||||
'" 2>&1 | tail -3
|
'" 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..."
|
echo "Restarting bbctrl service..."
|
||||||
ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
|
ssh -o ConnectTimeout=5 "${REMOTE_USER}@${HOST}" \
|
||||||
"echo '${PASSWORD}' | sudo -S systemctl restart bbctrl" 2>&1 | tail -3
|
"echo '${PASSWORD}' | sudo -S systemctl restart bbctrl" 2>&1 | tail -3
|
||||||
|
|||||||
102
scripts/deploy/patch_font_mime.py
Normal file
102
scripts/deploy/patch_font_mime.py
Normal 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())
|
||||||
@@ -2570,3 +2570,51 @@ html.kiosk-mode
|
|||||||
.control-page .jog-head > * + *
|
.control-page .jog-head > * + *
|
||||||
margin-left 8px
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user