import Quickshell import Quickshell.Bluetooth import Quickshell.Wayland import Quickshell.Hyprland import QtQuick import QtMultimedia PanelWindow { id: overlay anchors { top: true left: true right: true bottom: true } WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.focusable: true WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive WlrLayershell.namespace: "deltarune-startup-overlay" color: "#000000" exclusionMode: ExclusionMode.Ignore aboveWindows: true focusable: true property string bluetoothTargetName: "JBL Tune 525BT" property int bluetoothTimeoutMs: 5000 property bool waitingForBluetooth: true property bool animationLaunchScheduled: false property bool animationStarted: false property bool bluetoothConnectRequested: false function bluetoothModelCount() { if (bluetoothDeviceRepeater) return bluetoothDeviceRepeater.count; return 0; } function bluetoothDeviceAt(index) { const item = bluetoothDeviceRepeater.itemAt(index); if (!item) return null; return item.device || null; } function bluetoothDeviceName(device) { if (!device) return ""; if (device.name && device.name.length > 0) return String(device.name); if (device.deviceName && device.deviceName.length > 0) return String(device.deviceName); return ""; } function findTargetBluetoothDevice() { for (var i = 0; i < bluetoothModelCount(); i++) { var device = bluetoothDeviceAt(i); var deviceName = bluetoothDeviceName(device); console.log("Startup BT: candidate", i, deviceName, device ? Boolean(device.connected) : false); if (deviceName === bluetoothTargetName) return device; } console.log("Startup BT: target not found", bluetoothTargetName, "count", bluetoothModelCount()); return null; } function maybeStartBluetoothOrSkip() { console.log("Startup BT: maybeStartBluetoothOrSkip", "waiting", waitingForBluetooth, "requested", bluetoothConnectRequested); if (!waitingForBluetooth) return; const device = findTargetBluetoothDevice(); if (!device) { console.log("Startup BT: no matching device yet"); return; } console.log("Startup BT: matched device", bluetoothDeviceName(device), "connected", Boolean(device.connected)); if (device.connected) { console.log("Startup BT: already connected, starting animation"); beginAnimation(); return; } if (!bluetoothConnectRequested) { bluetoothConnectRequested = true; console.log("Startup BT: requesting connect", bluetoothDeviceName(device)); device.connect(); } else { console.log("Startup BT: connect already requested, waiting"); } } function beginAnimation() { console.log("Startup: beginAnimation", "started", animationStarted, "scheduled", animationLaunchScheduled); if (animationStarted || animationLaunchScheduled) return; waitingForBluetooth = false; bluetoothRetryTimer.stop(); bluetoothTimeoutTimer.stop(); animationLaunchScheduled = true; startupDelayTimer.restart(); } function handlePrimaryAction() { console.log("Startup: handlePrimaryAction", "animationStarted", animationStarted, "waitingForBluetooth", waitingForBluetooth); if (!animationStarted) beginAnimation(); else finishStartup(); } function finishStartup() { console.log("Startup: finishStartup", "playbackState", player.playbackState); if (player.playbackState !== MediaPlayer.StoppedState) player.stop(); else Qt.quit(); } HyprlandFocusGrab { active: true windows: [overlay] } Component.onCompleted: { console.log("Startup: overlay completed", "btCount", bluetoothModelCount(), "target", bluetoothTargetName); maybeStartBluetoothOrSkip(); } FocusScope { id: overlayFocus anchors.fill: parent focus: true Component.onCompleted: overlayFocus.forceActiveFocus() onVisibleChanged: if (visible) overlayFocus.forceActiveFocus() onFocusChanged: if (focus) overlayFocus.forceActiveFocus() Keys.onReleased: function (event) { switch (event.key) { case Qt.Key_Z: case Qt.Key_Return: case Qt.Key_Enter: event.accepted = true; overlay.handlePrimaryAction(); return; } } } Connections { target: Bluetooth.devices ignoreUnknownSignals: true function onCountChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices count changed", overlay.bluetoothModelCount(), "repeater", bluetoothDeviceRepeater.count); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } function onModelReset() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices model reset"); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } function onRowsInserted() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows inserted"); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } function onRowsRemoved() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows removed"); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } } Repeater { id: bluetoothDeviceRepeater model: Bluetooth.devices delegate: Item { property var device: modelData Component.onCompleted: { console.log("Startup BT: delegate ready", index, overlay.bluetoothDeviceName(device), Boolean(device ? device.connected : false), "repeaterCount", bluetoothDeviceRepeater.count); overlay.maybeStartBluetoothOrSkip(); } Connections { target: device ignoreUnknownSignals: true function onConnectedChanged() { console.log("Startup BT: connected changed", overlay.bluetoothDeviceName(device), Boolean(device ? device.connected : false)); if (overlay.waitingForBluetooth) overlay.maybeStartBluetoothOrSkip(); } function onNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: name changed", overlay.bluetoothDeviceName(device)); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } function onDeviceNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: deviceName changed", overlay.bluetoothDeviceName(device)); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } } } } MediaPlayer { id: player source: "deltarune.webm" // Local file or URL autoPlay: false videoOutput: videoOutput playbackRate: 1 audioOutput: AudioOutput {} onPlaybackStateChanged: a => { console.log("Startup: playback state changed", player.playbackState); if (player.playbackState === MediaPlayer.StoppedState) overlay.finishStartup(); } } Timer { id: startupDelayTimer interval: 1000 repeat: false onTriggered: { console.log("Startup: startup delay elapsed, playing video"); overlay.animationLaunchScheduled = false; overlay.animationStarted = true; player.play(); } } Timer { id: bluetoothRetryTimer interval: 250 running: true repeat: true onTriggered: { if (!overlay.waitingForBluetooth) { console.log("Startup BT: retry timer stopping"); stop(); return; } console.log("Startup BT: retry timer fired"); overlay.bluetoothConnectRequested = false; overlay.maybeStartBluetoothOrSkip(); } } Timer { id: bluetoothTimeoutTimer interval: overlay.bluetoothTimeoutMs running: true repeat: false onTriggered: { console.log("Startup BT: timeout reached", overlay.bluetoothTimeoutMs); overlay.beginAnimation(); } } VideoOutput { id: videoOutput anchors.fill: parent } // Text { // visible: overlay.waitingForBluetooth // anchors.horizontalCenter: parent.horizontalCenter // anchors.verticalCenter: parent.verticalCenter // color: "#ffffff" // font.family: "Determination Mono" // font.pixelSize: 28 // text: "CONNECTING TO " + overlay.bluetoothTargetName.toUpperCase() // z: 1 // } MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton hoverEnabled: true cursorShape: Qt.BlankCursor } }