Improve Raspberry Pi startup and Chromium transitions
This commit is contained in:
+75
-46
@@ -1307,60 +1307,59 @@ class SignagePlayer(Widget):
|
||||
|
||||
Logger.info(f"SignagePlayer: Playing item {self.current_index + 1}/{len(self.playlist)}: {file_name} ({duration}s)")
|
||||
|
||||
# ── Weblink → media transition (Wayland-safe) ──────────────────
|
||||
# On Wayland (Labwc) Window.raise_window() is a no-op, so we must
|
||||
# ensure Chromium's fullscreen window is fully gone BEFORE we try
|
||||
# to render Kivy content. We:
|
||||
# 1. Stop watchdog + preload immediately
|
||||
# 2. Terminate Chromium (non-blocking)
|
||||
# 3. Hide the Kivy content_area so nothing stale is visible
|
||||
# 4. Wait 200 ms for the compositor to remove Chromium's window
|
||||
# 5. Show content_area + re-call play_current_media to render
|
||||
# ── Weblink → media transition (desktop-flash safe) ──────────────
|
||||
# For web→media transitions, render the next Kivy widget first,
|
||||
# then close Chromium on the next frame. This prevents a brief
|
||||
# desktop exposure while the compositor removes Chromium.
|
||||
if not _after_weblink:
|
||||
proc = getattr(self, '_weblink_proc', None)
|
||||
if proc is not None:
|
||||
self._stop_inactivity_watchdog()
|
||||
self._kill_weblink_preload()
|
||||
self._weblink_proc = None
|
||||
next_is_weblink = media_item.get('type') == 'weblink'
|
||||
if next_is_weblink:
|
||||
# Weblink -> weblink: close current Chromium first.
|
||||
self._stop_inactivity_watchdog()
|
||||
self._kill_weblink_preload()
|
||||
self._weblink_proc = None
|
||||
|
||||
# Hide content while Chromium is still closing
|
||||
try:
|
||||
self.ids.content_area.opacity = 0
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Terminate Chromium
|
||||
if proc.poll() is None:
|
||||
try:
|
||||
proc.terminate()
|
||||
except Exception as exc:
|
||||
Logger.warning(f"SignagePlayer: weblink terminate: {exc}")
|
||||
|
||||
def _resume(dt):
|
||||
# Force-kill if still alive after the delay
|
||||
if proc.poll() is None:
|
||||
try:
|
||||
proc.kill()
|
||||
proc.terminate()
|
||||
except Exception as exc:
|
||||
Logger.warning(f"SignagePlayer: weblink terminate: {exc}")
|
||||
|
||||
def _resume(dt):
|
||||
if proc.poll() is None:
|
||||
try:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
Window.show()
|
||||
Window.raise_window()
|
||||
except Exception:
|
||||
pass
|
||||
# Restore content area and show Kivy window
|
||||
try:
|
||||
self.ids.content_area.opacity = 1
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
Window.show()
|
||||
Window.raise_window()
|
||||
except Exception:
|
||||
pass
|
||||
# Now render the actual media
|
||||
self.play_current_media(
|
||||
force_reload=force_reload, _after_weblink=True
|
||||
)
|
||||
self.play_current_media(
|
||||
force_reload=force_reload, _after_weblink=True
|
||||
)
|
||||
|
||||
# 200 ms gives Labwc time to remove the fullscreen surface
|
||||
Clock.schedule_once(_resume, 0.2)
|
||||
return
|
||||
Clock.schedule_once(_resume, 0.2)
|
||||
return
|
||||
|
||||
# Weblink -> non-weblink: keep Chromium visible while we
|
||||
# prepare next Kivy frame, then close Chromium deferred.
|
||||
self._stop_inactivity_watchdog()
|
||||
self._kill_weblink_preload()
|
||||
self._weblink_proc = proc
|
||||
try:
|
||||
self.ids.content_area.opacity = 1
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
Window.show()
|
||||
Window.raise_window()
|
||||
except Exception:
|
||||
pass
|
||||
Logger.debug("SignagePlayer: Deferred Chromium close after next frame render")
|
||||
# ────────────────────────────────────────────────────────────────
|
||||
|
||||
# Handle web links before any file/path handling (no local file exists)
|
||||
@@ -1440,6 +1439,11 @@ class SignagePlayer(Widget):
|
||||
# Reset error counter on successful playback
|
||||
self.consecutive_errors = 0
|
||||
Logger.debug(f"SignagePlayer: Media started successfully")
|
||||
|
||||
# If we arrived here from a weblink item, close Chromium after the
|
||||
# next Kivy frame so the new widget is already visible underneath.
|
||||
if media_item.get('type') != 'weblink' and getattr(self, '_weblink_proc', None) is not None:
|
||||
self._kill_weblink_after_frame()
|
||||
|
||||
except Exception as e:
|
||||
Logger.error(f"SignagePlayer: Error playing media: {e}")
|
||||
@@ -1602,9 +1606,12 @@ class SignagePlayer(Widget):
|
||||
self._skip_to_next_media()
|
||||
return False
|
||||
|
||||
target_width, target_height = self._get_browser_target_size()
|
||||
|
||||
try:
|
||||
Logger.info(f"SignagePlayer: Opening weblink in kiosk browser: {url}")
|
||||
Logger.info(f"SignagePlayer: Inactivity timeout set to {duration}s (touch resets the countdown)")
|
||||
Logger.info(f"SignagePlayer: Chromium target launch size: {target_width}x{target_height}")
|
||||
# Kill the hidden pre-warm instance first; its work (binary in RAM,
|
||||
# page in disk cache) makes the kiosk relaunch below near-instant.
|
||||
self._kill_weblink_preload()
|
||||
@@ -1616,6 +1623,7 @@ class SignagePlayer(Widget):
|
||||
# --start-fullscreen is a normal maximised window that the
|
||||
# compositor can un-stack without issues.
|
||||
'--start-fullscreen',
|
||||
'--start-maximized',
|
||||
'--app=' + url,
|
||||
'--noerrdialogs',
|
||||
'--disable-infobars',
|
||||
@@ -1631,6 +1639,8 @@ class SignagePlayer(Widget):
|
||||
'--disable-background-networking',
|
||||
'--no-default-browser-check',
|
||||
'--window-position=0,0',
|
||||
f'--window-size={target_width},{target_height}',
|
||||
'--force-device-scale-factor=1',
|
||||
])
|
||||
|
||||
# Unschedule any previous fixed timer — the watchdog thread takes
|
||||
@@ -1653,6 +1663,23 @@ class SignagePlayer(Widget):
|
||||
self._skip_to_next_media()
|
||||
return False
|
||||
|
||||
def _get_browser_target_size(self):
|
||||
"""Return a stable browser launch size to avoid 800x600 first-paint flash."""
|
||||
default_width, default_height = 1920, 1080
|
||||
try:
|
||||
width, height = Window.size
|
||||
width = int(width)
|
||||
height = int(height)
|
||||
except Exception:
|
||||
return default_width, default_height
|
||||
|
||||
# Chromium sometimes first-paints at 800x600 before fullscreen;
|
||||
# force at least Full HD when reported dimensions are too small.
|
||||
if width < 1280 or height < 720:
|
||||
return default_width, default_height
|
||||
|
||||
return width, height
|
||||
|
||||
def _start_inactivity_watchdog(self, duration):
|
||||
"""Start a background thread that monitors /dev/input/* for touch/key
|
||||
activity. The thread resets the idle counter on every event; when the
|
||||
@@ -1893,6 +1920,8 @@ class SignagePlayer(Widget):
|
||||
if not browser:
|
||||
return
|
||||
|
||||
target_width, target_height = self._get_browser_target_size()
|
||||
|
||||
# Kill any stale preload first.
|
||||
self._kill_weblink_preload()
|
||||
|
||||
@@ -1903,7 +1932,7 @@ class SignagePlayer(Widget):
|
||||
'--app=' + url,
|
||||
# Place window completely outside the visible display area.
|
||||
'--window-position=-9999,-9999',
|
||||
'--window-size=1920,1080', # pre-render at full resolution
|
||||
f'--window-size={target_width},{target_height}', # pre-render at target resolution
|
||||
'--noerrdialogs',
|
||||
'--disable-infobars',
|
||||
'--incognito',
|
||||
|
||||
Reference in New Issue
Block a user