fix(hyprdrive/station-bar): wall-clock safety net so the holo intro can't stall
The materialise intro was driven only by the frame-clock tick, which stops advancing when the compositor withholds frame callbacks (e.g. the bar restarted into an idle compositor) — freezing it at t=0 with content stuck at opacity 0, i.e. permanent static. Arm a GLib.timeout alongside start_intro() that force-resolves the intro regardless, so content always appears. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>main
parent
e1126e9613
commit
837bc2823a
|
|
@ -19,7 +19,7 @@ import cairo
|
|||
import gi
|
||||
|
||||
gi.require_version("Gtk", "4.0")
|
||||
from gi.repository import Gtk # noqa: E402
|
||||
from gi.repository import GLib, Gtk # noqa: E402
|
||||
|
||||
# Same CyberQueer violet/magenta/red combo as the rest of the suite's hologram.
|
||||
_VIOLET = (0x50 / 255, 0x18 / 255, 0xDD / 255)
|
||||
|
|
@ -58,6 +58,13 @@ class HologramOverlay:
|
|||
self._intro_t: float | None = None # >=0 while the materialise intro plays
|
||||
self._outro_t: float | None = None # >=0 while the closing dissolve plays
|
||||
self._outro_done = None # callback fired when the dissolve finishes
|
||||
# Wall-clock safety net for the intro: the frame-clock tick that normally
|
||||
# advances the intro only fires while the compositor sends frame callbacks.
|
||||
# When the bar is (re)started into an otherwise-idle compositor those can
|
||||
# stall, freezing the intro at t=0 — i.e. the bar sits in permanent static
|
||||
# with content stuck at opacity 0. This timeout force-resolves the intro on
|
||||
# real time regardless, so content always appears.
|
||||
self._intro_deadline_id: int | None = None
|
||||
self._mask_cache: tuple | None = None # (w, h, pattern) edge-fade mask
|
||||
|
||||
self.widget = Gtk.DrawingArea()
|
||||
|
|
@ -76,9 +83,7 @@ class HologramOverlay:
|
|||
if self._intro_t is not None:
|
||||
self._intro_t += dt
|
||||
if self._intro_t >= self.INTRO_DURATION:
|
||||
self._intro_t = None
|
||||
if self._fade_widget is not None:
|
||||
self._fade_widget.set_opacity(1.0)
|
||||
self._finish_intro()
|
||||
elif self._fade_widget is not None:
|
||||
p = self._intro_t / self.INTRO_DURATION
|
||||
self._fade_widget.set_opacity(p * p * (3 - 2 * p)) # smooth ramp 0->1
|
||||
|
|
@ -95,6 +100,17 @@ class HologramOverlay:
|
|||
done()
|
||||
self.widget.queue_draw()
|
||||
|
||||
def _finish_intro(self) -> None:
|
||||
"""End the intro: clear its state, cancel the safety timeout, and make the
|
||||
content fully opaque. Safe to call from either the tick or the timeout."""
|
||||
self._intro_t = None
|
||||
if self._intro_deadline_id is not None:
|
||||
GLib.source_remove(self._intro_deadline_id)
|
||||
self._intro_deadline_id = None
|
||||
if self._fade_widget is not None:
|
||||
self._fade_widget.set_opacity(1.0)
|
||||
self.widget.queue_draw() # in case the frame clock has stalled
|
||||
|
||||
def start_intro(self) -> None:
|
||||
"""Kick off the 'hologram materialising out of static' opening effect."""
|
||||
if self.enabled:
|
||||
|
|
@ -103,6 +119,18 @@ class HologramOverlay:
|
|||
self._intro_t = 0.0
|
||||
if self._fade_widget is not None:
|
||||
self._fade_widget.set_opacity(0.0) # start hidden; tick() ramps it up
|
||||
# Wall-clock backstop: if frame callbacks stall, force the intro done a
|
||||
# little past its nominal length so content can never get stuck hidden.
|
||||
if self._intro_deadline_id is not None:
|
||||
GLib.source_remove(self._intro_deadline_id)
|
||||
self._intro_deadline_id = GLib.timeout_add(
|
||||
int(self.INTRO_DURATION * 1000) + 150, self._on_intro_deadline)
|
||||
|
||||
def _on_intro_deadline(self) -> bool:
|
||||
self._intro_deadline_id = None
|
||||
if self._intro_t is not None:
|
||||
self._finish_intro()
|
||||
return False # one-shot
|
||||
|
||||
def start_outro(self, on_done) -> None:
|
||||
"""Play a quick reverse of the intro (content dissolving back into static),
|
||||
|
|
@ -111,6 +139,9 @@ class HologramOverlay:
|
|||
on_done()
|
||||
return
|
||||
self._intro_t = None # cancel any in-flight opening intro
|
||||
if self._intro_deadline_id is not None:
|
||||
GLib.source_remove(self._intro_deadline_id)
|
||||
self._intro_deadline_id = None
|
||||
self._outro_t = 0.0
|
||||
self._outro_done = on_done
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue