quickshell: boot bloom overlay + native pipewire audio
The C splash now plays only Acts I-III and hands off at ~6.8s; a new BootBloom layershell overlay (modules/souveraine/boot) resumes Acts IV-V (Souvie + bloom flower) over the live compositor, clock-aligned to the boot epoch so the animation is continuous across the process swap. It maps as Hyprland's first surface (top-level in ShellRoot, before Config.ready), pokes splash-signal on its first frame to release the GPU, and LockScreen clears bootBloomActive on secure to fade it out and reveal the lock. Bloom shader is qsb-compiled from BootBloom.frag at deploy time. Drop services/Audio.qml from the manifest: it was a pactl mirror written for native PulseAudio and only tracked the default sink/source. The phone runs PipeWire now, so ii's native Pipewire Audio service (full graph, WirePlumber-owned volume) takes over.
This commit is contained in:
parent
a2320641a3
commit
e3cf50bf75
9 changed files with 341 additions and 17 deletions
|
|
@ -45,6 +45,10 @@ Singleton {
|
|||
property real superLastReleaseTime: 0
|
||||
property bool wallpaperSelectorOpen: false
|
||||
property bool workspaceShowNumbers: false
|
||||
// Boot bloom overlay: true from shell start until the lockscreen surface is
|
||||
// secure. It covers all of Hyprland's boot render, continuing the C splash's
|
||||
// bloom animation. LockScreen.onSecureChanged clears it to reveal the lock.
|
||||
property bool bootBloomActive: true
|
||||
// In fullscreen this is the only way the dock becomes visible:
|
||||
// the navigation rail swipe sets/clears it. It deliberately has no timer
|
||||
// or secondary state.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ GlobalStates.qml souveraine/GlobalStates.qml
|
|||
settings-phone.qml souveraine/settings-phone.qml
|
||||
panelFamilies/SouveraineFamily.qml souveraine/panelFamilies/SouveraineFamily.qml
|
||||
services/Souveraine.qml souveraine/services/Souveraine.qml
|
||||
services/Audio.qml souveraine/services/Audio.qml
|
||||
services/Ai.qml souveraine/services/Ai.qml
|
||||
services/TaskbarApps.qml souveraine/services/TaskbarApps.qml
|
||||
services/GlobalFocusGrab.qml souveraine/services/GlobalFocusGrab.qml
|
||||
|
|
@ -80,6 +79,10 @@ modules/souveraine/lock/LockSurfaceHost.qml souveraine/modules/souveraine/lock/L
|
|||
modules/souveraine/lock/qmldir souveraine/modules/souveraine/lock/qmldir
|
||||
modules/souveraine/navigation/SystemGestureRail.qml souveraine/modules/souveraine/navigation/SystemGestureRail.qml
|
||||
modules/souveraine/navigation/qmldir souveraine/modules/souveraine/navigation/qmldir
|
||||
modules/souveraine/boot/BootBloom.qml souveraine/modules/souveraine/boot/BootBloom.qml
|
||||
modules/souveraine/boot/BootBloom.frag.qsb souveraine/modules/souveraine/boot/BootBloom.frag.qsb
|
||||
modules/souveraine/boot/souvie.png souveraine/modules/souveraine/boot/souvie.png
|
||||
modules/souveraine/boot/qmldir souveraine/modules/souveraine/boot/qmldir
|
||||
modules/ii/sessionScreen/SessionScreen.qml souveraine/modules/ii/sessionScreen/SessionScreen.qml
|
||||
"
|
||||
|
||||
|
|
@ -88,6 +91,28 @@ PHONE_DEST="souveraine-surfaces/quickshell"
|
|||
|
||||
manifest_lines() { printf '%s\n' "$MANIFEST" | sed '/^[[:space:]]*$/d'; }
|
||||
|
||||
# Compile the boot bloom shader to .qsb (Qt RHI) if the source is newer. The
|
||||
# .qsb is architecture-independent (SPIR-V + reflection), so we build it once
|
||||
# here and the manifest symlink / phone rsync carries it — no qsb on the phone.
|
||||
compile_shaders() {
|
||||
local frag="$SRC/modules/souveraine/boot/BootBloom.frag"
|
||||
local qsb_out="$SRC/modules/souveraine/boot/BootBloom.frag.qsb"
|
||||
[[ -f "$frag" ]] || return 0
|
||||
if [[ ! -f "$qsb_out" || "$frag" -nt "$qsb_out" ]]; then
|
||||
local qsb
|
||||
qsb="$(command -v qsb || echo /usr/lib/qt6/bin/qsb)"
|
||||
if [[ ! -x "$qsb" ]]; then
|
||||
echo "ERROR: qsb not found (need qt6-shadertools) to build BootBloom.frag.qsb" >&2
|
||||
exit 1
|
||||
fi
|
||||
# --glsl 100es,120,150 + --hlsl/--msl targets so it runs on the Adreno
|
||||
# GLES backend the phone uses; -O optimizes.
|
||||
"$qsb" --glsl "100es,120,150" --hlsl 50 --msl 12 -O -o "$qsb_out" "$frag"
|
||||
echo "compiled BootBloom.frag -> BootBloom.frag.qsb"
|
||||
fi
|
||||
}
|
||||
compile_shaders
|
||||
|
||||
if [[ "${1:-}" == "--manifest" ]]; then
|
||||
manifest_lines
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -44,13 +44,10 @@ Scope {
|
|||
KeyringStorage.fetchKeyringData();
|
||||
}
|
||||
}
|
||||
// Poke the boot splash to fade out + hand DRM master to Hyprland.
|
||||
// Fires once, the first time the lock surface goes up after boot.
|
||||
// splash-signal no-ops if the splash isn't running, so re-locks are safe.
|
||||
Process {
|
||||
id: splashSignalProc
|
||||
}
|
||||
property bool splashPoked: false
|
||||
// Set once, the first time the lock surface goes secure after boot, to
|
||||
// dismiss the BootBloom overlay. The C splash is already gone by now (it
|
||||
// released at the Act III handoff); nothing to poke here anymore.
|
||||
property bool bootDismissed: false
|
||||
function unlockKeyring() {
|
||||
unlockKeyringProc.exec({
|
||||
environment: ({
|
||||
|
|
@ -114,18 +111,19 @@ Scope {
|
|||
// separate so an IPC caller cannot mistake a queued lock for a secure
|
||||
// surface when it is deciding whether personal content may be exposed.
|
||||
// It is also the true "lockscreen is ready" event: the one moment we
|
||||
// end the boot splash. The bloom has covered all of Hyprland's startup
|
||||
// and now our own lock surface is mapped and on screen, so fade it
|
||||
// here. Firing on the request edge (screenLocked) was too early —
|
||||
// Hyprland's boot render leaked through the gap. splashPoked keeps it
|
||||
// once-only so re-locks after unlock never re-fade a splash that
|
||||
// isn't there.
|
||||
// dismiss the boot bloom. The C splash released DRM master back at the
|
||||
// Act III→IV handoff (~6.8s); the quickshell BootBloom overlay has
|
||||
// covered all of Hyprland's startup since. Now our own lock surface is
|
||||
// mapped and secure, so fade the bloom out to reveal it. Firing on the
|
||||
// request edge (screenLocked) was too early — the lock surface wasn't
|
||||
// on screen yet. bootDismissed keeps it once-only so re-locks after
|
||||
// unlock never re-hide a bloom that's already gone.
|
||||
onSecureChanged: {
|
||||
GlobalStates.screenLockSecure = secure;
|
||||
console.log("[lock] session lock secure=" + secure);
|
||||
if (secure && !root.splashPoked) {
|
||||
root.splashPoked = true;
|
||||
splashSignalProc.exec({ command: ["splash-signal"] });
|
||||
if (secure && !root.bootDismissed) {
|
||||
root.bootDismissed = true;
|
||||
GlobalStates.bootBloomActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
140
surfaces/quickshell/modules/souveraine/boot/BootBloom.frag
Normal file
140
surfaces/quickshell/modules/souveraine/boot/BootBloom.frag
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
// Souveraine boot bloom — Act IV+V, the quickshell half of the boot animation.
|
||||
//
|
||||
// The C splash (bootsplash/shader.frag) plays Act I-III on bare GPU: cursor
|
||||
// blink, slide, and types "Hello There..." / "I'm Souveraine...", fading the
|
||||
// lines out at ~6.8s. It then releases DRM master. Hyprland takes over and
|
||||
// this ShaderEffect resumes the animation seamlessly — Souvie fades in and the
|
||||
// bloom flower grows — over the live compositor, until the lockscreen is ready.
|
||||
//
|
||||
// This is the SAME flower as the C shader's flowerLayer/textLayer Souvie half,
|
||||
// ported to Qt RHI (std140 UBO, qsb-compiled). The intro timeline is shifted so
|
||||
// t=0 here corresponds to the C shader's t=CURSOR_SLIDE_END (3.0s): the caller
|
||||
// feeds u_time already offset by the boot epoch so phase is continuous across
|
||||
// the process swap. Everything is additive light on black.
|
||||
//
|
||||
// Qt RHI conventions vs raw GLES2:
|
||||
// - qt_TexCoord0 in [0,1], origin top-left; we build the same centered,
|
||||
// aspect-corrected uv the C shader derived from gl_FragCoord.
|
||||
// - uniforms live in a std140 ubuf block matching ShaderEffect properties.
|
||||
// - output is fragColor, premultiplied-alpha not needed (opaque black bg).
|
||||
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec2 qt_TexCoord0;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 qt_Matrix;
|
||||
float qt_Opacity;
|
||||
float u_time; // seconds since FLOWER epoch start (boot-aligned)
|
||||
vec2 u_resolution; // px
|
||||
float u_fade; // 1.0 = full, 0.0 = black (dismiss fade)
|
||||
};
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
// The C shader's absolute timeline (seconds from boot t0). We keep the SAME
|
||||
// numbers so the phase matches: the caller passes u_time in that same clock.
|
||||
#define SOUVIE_FADE vec2(7.4, 8.6)
|
||||
#define FLOWER_START 8.0
|
||||
#define BLOOM_DURATION 7.0
|
||||
|
||||
float easeOutBack(float t) { // overshoots past 1 on purpose
|
||||
float c = 1.70158;
|
||||
float u = t - 1.0;
|
||||
return 1.0 + (c + 1.0) * u * u * u + c * u * u;
|
||||
}
|
||||
|
||||
// Layered radial bloom on black — outer petals open first, inner follow.
|
||||
// Verbatim port of flowerLayer() from bootsplash/shader.frag.
|
||||
vec3 flowerLayer(vec2 p, float tF) {
|
||||
vec2 c = vec2(0.0, 0.08);
|
||||
vec2 q = p - c;
|
||||
q.y /= 0.82;
|
||||
float rho = length(q);
|
||||
float th = atan(q.y, q.x);
|
||||
|
||||
float prog = clamp(tF / BLOOM_DURATION, 0.0, 1.0);
|
||||
float bloom = easeOutBack(prog);
|
||||
float gate = smoothstep(0.9, 1.0, prog);
|
||||
float breathe = 1.0 + gate * 0.02 * sin(tF * 0.8);
|
||||
|
||||
vec3 acc = vec3(0.0);
|
||||
float maxR = 0.30 * breathe;
|
||||
|
||||
for (int l = 0; l < 6; l++) {
|
||||
float lr = (float(l) + 0.5) / 6.0;
|
||||
float delay = (1.0 - lr) * 0.25;
|
||||
float lb = clamp((bloom - delay) / (1.0 - delay), 0.0, 1.0);
|
||||
if (lb < 0.01) continue;
|
||||
|
||||
float n = 7.0 + float(l) * 2.0;
|
||||
float rotl = float(l) * 0.37 + gate * 0.06 * sin(tF * 0.5 + float(l));
|
||||
float lobe = pow(abs(cos(n * (th - rotl) * 0.5)), 3.0 - lr * 1.5);
|
||||
|
||||
float d0 = maxR * max(lr, 0.12) * lb * 0.35;
|
||||
float plen = maxR * max(lr, 0.12) * lb * (0.9 - lr * 0.25);
|
||||
float reach = d0 + plen * (0.30 + 0.70 * lobe);
|
||||
|
||||
float body = smoothstep(reach, reach * 0.55, rho)
|
||||
* smoothstep(d0 * 0.6, d0 + 0.01, rho);
|
||||
float rim = exp(-abs(rho - reach) * 55.0) * lobe;
|
||||
|
||||
float shimmer = 0.88 + 0.12 * sin(tF * 2.0 + sin(th * 13.0) * 5.0
|
||||
+ rho * 40.0 + float(l) * 1.7);
|
||||
|
||||
vec3 colL = mix(vec3(0.78, 0.12, 0.31), vec3(1.00, 0.51, 0.78), lr);
|
||||
colL = mix(colL, vec3(0.71, 0.40, 0.94), 0.35 * lr);
|
||||
|
||||
acc += colL * (body * 0.22 + rim * 0.85) * lb * shimmer;
|
||||
}
|
||||
|
||||
// starburst core
|
||||
float coreIn = smoothstep(0.25, 0.65, bloom);
|
||||
float rays = pow(abs(cos(4.0 * th + tF * 0.3)), 10.0);
|
||||
float core = exp(-rho * 20.0) * 1.3 + rays * exp(-rho * 8.0) * 0.45;
|
||||
acc += vec3(0.95, 0.86, 0.98) * core * coreIn;
|
||||
|
||||
// ring glints
|
||||
if (bloom > 0.5) {
|
||||
float sb = min((bloom - 0.5) / 0.4, 1.0);
|
||||
float ring = exp(-abs(rho - maxR * 0.85 * sb) * 60.0);
|
||||
float glint = pow(abs(cos(8.0 * th + sin(tF * 0.5) * 0.4)), 24.0);
|
||||
acc += vec3(0.78, 0.24, 0.39) * ring * glint * sb * 0.8;
|
||||
}
|
||||
|
||||
// stem
|
||||
float stemIn = clamp((bloom - 0.05) / 0.5, 0.0, 1.0);
|
||||
float stemTop = c.y - maxR * 0.15;
|
||||
float stemLen = 0.55 * stemIn;
|
||||
if (p.y < stemTop && p.y > stemTop - stemLen) {
|
||||
float st = (stemTop - p.y) / 0.55;
|
||||
float curveX = sin(st * PI * 0.3) * 0.045 + sin(st * PI * 0.8) * 0.015;
|
||||
float d = abs(p.x - (c.x + curveX));
|
||||
float shade = 0.55 + (1.0 - st) * 0.45;
|
||||
acc += vec3(0.16, 0.30, 0.10) * exp(-d * 220.0) * shade;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float tt = u_time;
|
||||
|
||||
// Rebuild the C shader's centered, y-normalized uv from qt_TexCoord0.
|
||||
// C: uv = (2*fragCoord - res) / res.y, origin bottom-left.
|
||||
// Qt: qt_TexCoord0 origin top-left, so flip y.
|
||||
vec2 frag = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * u_resolution;
|
||||
vec2 uv = (2.0 * frag - u_resolution) / u_resolution.y;
|
||||
|
||||
vec3 col = vec3(0.0);
|
||||
|
||||
float fadeT = smoothstep(FLOWER_START, FLOWER_START + 0.8, tt);
|
||||
if (fadeT > 0.001)
|
||||
col += flowerLayer(uv, tt - FLOWER_START) * fadeT;
|
||||
|
||||
// Souvie is drawn as a real PNG Image in the QML layer above this shader
|
||||
// (BootBloom.qml), not baked into the atlas — so the shader is bloom-only.
|
||||
|
||||
fragColor = vec4(col * u_fade, 1.0);
|
||||
}
|
||||
BIN
surfaces/quickshell/modules/souveraine/boot/BootBloom.frag.qsb
Normal file
BIN
surfaces/quickshell/modules/souveraine/boot/BootBloom.frag.qsb
Normal file
Binary file not shown.
147
surfaces/quickshell/modules/souveraine/boot/BootBloom.qml
Normal file
147
surfaces/quickshell/modules/souveraine/boot/BootBloom.qml
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Souveraine boot bloom overlay — the quickshell half of the boot animation.
|
||||
//
|
||||
// The C splash (souveraine-splash) owns DRM master at boot and plays Act I-III
|
||||
// (cursor blink/slide, types the two lines) on bare GPU, then holds. This
|
||||
// overlay is Hyprland's first surface: a fullscreen layershell Overlay that
|
||||
// resumes the animation (Act IV+V — Souvie + bloom flower) seamlessly, over the
|
||||
// live compositor, covering ALL of Hyprland's own boot render. It:
|
||||
//
|
||||
// 1. maps as early as possible (top-level in ShellRoot, NOT behind the
|
||||
// Config.ready LazyLoader) so nothing of Hyprland's default output shows;
|
||||
// 2. on its first painted frame, pokes `splash-signal` — telling the C splash
|
||||
// "I'm up, you may release DRM master now." The splash fades and exits;
|
||||
// Hyprland (already waiting) grabs the CRTC; this overlay is already
|
||||
// painting black+bloom over the swap, so the handoff is invisible;
|
||||
// 3. drives u_time from the boot monotonic clock so the bloom phase continues
|
||||
// exactly where the splash left off (no visible seam / restart);
|
||||
// 4. is dismissed by LockScreen.onSecureChanged (fade out) once the real lock
|
||||
// surface is up.
|
||||
//
|
||||
// Clock continuity: the C shader's t is CLOCK_MONOTONIC seconds since its own
|
||||
// start (≈ boot). We read /proc/uptime once at map time to recover that same
|
||||
// clock, so u_time here matches the splash's u_time. FLOWER_START (8.0s) is
|
||||
// absolute in that clock; the bloom begins on its own regardless of when this
|
||||
// overlay happens to map.
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
// Held true from boot until the lockscreen is secure. LockScreen flips it
|
||||
// off (onSecureChanged) to fade the overlay out and reveal the lock.
|
||||
property bool active: GlobalStates.bootBloomActive
|
||||
// Monotonic seconds at the moment we captured the boot clock. u_time =
|
||||
// bootBase + (now - captureWall). Filled from /proc/uptime once.
|
||||
property real bootBase: 0
|
||||
property bool clockReady: false
|
||||
property bool splashPoked: false
|
||||
|
||||
// Read the boot monotonic clock once, as early as possible.
|
||||
Process {
|
||||
id: uptimeProc
|
||||
command: ["cat", "/proc/uptime"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
// /proc/uptime: "<seconds-since-boot> <idle>"
|
||||
const secs = parseFloat(text.trim().split(/\s+/)[0]);
|
||||
if (!isNaN(secs)) {
|
||||
root.bootBase = secs;
|
||||
root.clockReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pokes the C splash to release DRM master. Fires once, on first frame.
|
||||
Process { id: splashSignalProc }
|
||||
|
||||
// Wall-clock reference captured when the /proc/uptime read completed, so
|
||||
// elapsed = frameClock.currentTime-based delta. We drive u_time off an
|
||||
// Animator-free FrameAnimation for a monotonic per-frame tick.
|
||||
FrameAnimation {
|
||||
id: frameClock
|
||||
running: root.active
|
||||
// elapsedTime is seconds since this animation started running.
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: root.active ? Quickshell.screens : []
|
||||
|
||||
PanelWindow {
|
||||
id: win
|
||||
required property var modelData
|
||||
screen: modelData
|
||||
|
||||
WlrLayershell.namespace: "quickshell:bootbloom"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
// No keyboard grab — we're purely visual; the lock takes input.
|
||||
color: "black"
|
||||
|
||||
anchors { top: true; left: true; right: true; bottom: true }
|
||||
|
||||
// u_time in the splash's boot clock: base + seconds elapsed since
|
||||
// we captured the base. Continuous with the C shader.
|
||||
property real bootTime: root.bootBase + frameClock.elapsedTime
|
||||
|
||||
ShaderEffect {
|
||||
id: bloom
|
||||
anchors.fill: parent
|
||||
// qsb-compiled at deploy time from BootBloom.frag
|
||||
fragmentShader: Qt.resolvedUrl("BootBloom.frag.qsb")
|
||||
|
||||
property real u_time: win.bootTime
|
||||
property vector2d u_resolution: Qt.vector2d(width, height)
|
||||
property real u_fade: 1.0
|
||||
|
||||
// Fade out on dismiss.
|
||||
Behavior on u_fade {
|
||||
NumberAnimation { duration: 450; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
}
|
||||
|
||||
// ShaderEffect has no per-frame signal; poke the splash once the
|
||||
// shader is compiled AND the boot clock is read, one tick later, so
|
||||
// the C splash only releases DRM master after we're actually able to
|
||||
// paint. window.frameSwapped would be ideal but doesn't surface
|
||||
// through PanelWindow — a single-shot armed Timer is the reliable
|
||||
// "we're up" edge (a frame or two of overlap with the splash is
|
||||
// harmless; both draw the same continuous bloom).
|
||||
Timer {
|
||||
interval: 32 // ~2 frames at 60Hz
|
||||
repeat: false
|
||||
running: bloom.status === ShaderEffect.Compiled
|
||||
&& root.clockReady && !root.splashPoked
|
||||
onTriggered: {
|
||||
root.splashPoked = true;
|
||||
splashSignalProc.exec({ command: ["splash-signal"] });
|
||||
}
|
||||
}
|
||||
|
||||
// Souvie — real PNG logo, drawn above the bloom, fading in on the
|
||||
// same SOUVIE_FADE window (7.4-8.6s) the shader used for the atlas
|
||||
// text. Falls back to invisible if the asset is missing.
|
||||
Image {
|
||||
id: souvie
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: parent.height * 0.14
|
||||
width: Math.min(parent.width * 0.42, sourceSize.width)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: Qt.resolvedUrl("souvie.png")
|
||||
smooth: true
|
||||
// fade in over 7.4-8.6s in boot clock
|
||||
opacity: bloom.u_fade * Math.max(0, Math.min(1,
|
||||
(win.bootTime - 7.4) / 1.2))
|
||||
visible: status === Image.Ready
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
surfaces/quickshell/modules/souveraine/boot/qmldir
Normal file
2
surfaces/quickshell/modules/souveraine/boot/qmldir
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
module qs.modules.souveraine.boot
|
||||
BootBloom 1.0 BootBloom.qml
|
||||
BIN
surfaces/quickshell/modules/souveraine/boot/souvie.png
Normal file
BIN
surfaces/quickshell/modules/souveraine/boot/souvie.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
|
|
@ -12,6 +12,7 @@
|
|||
// is owned outright.
|
||||
|
||||
import "modules/common"
|
||||
import "modules/souveraine/boot"
|
||||
import "services"
|
||||
import "panelFamilies"
|
||||
|
||||
|
|
@ -28,6 +29,13 @@ ShellRoot {
|
|||
// predates it, and version-dependent types don't belong in the entry file.
|
||||
ReloadPopup {}
|
||||
|
||||
// Boot bloom overlay. Top-level (NOT inside the Config.ready LazyLoader) so
|
||||
// it maps as Hyprland's first surface, before the rest of the shell loads —
|
||||
// covering all of Hyprland's boot render and continuing the C splash's
|
||||
// bloom until the lockscreen is secure. Signals the splash to release DRM
|
||||
// master on its first frame; LockScreen clears GlobalStates.bootBloomActive.
|
||||
BootBloom {}
|
||||
|
||||
Component.onCompleted: {
|
||||
MaterialThemeLoader.reapplyTheme()
|
||||
SessiondBridge.load()
|
||||
|
|
|
|||
Loading…
Reference in a new issue