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 var bluetoothTargetNames: ["JBL Tune 525BT", "JBL GO"] property int bluetoothConnectAttemptMs: 3000 property bool waitingForBluetooth: true property bool animationLaunchScheduled: false property bool animationStarted: false property bool bluetoothConnectRequested: false property int bluetoothTargetAttemptIndex: 0 property string bluetoothActiveTargetName: "" 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 findBluetoothDeviceByName(targetName) { 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 === targetName) return device; } console.log("Startup BT: target not found", targetName, "count", bluetoothModelCount()); return null; } function findConnectedPreferredBluetoothDevice() { for (var i = 0; i < bluetoothTargetNames.length; i++) { var device = findBluetoothDeviceByName(bluetoothTargetNames[i]); if (device && device.connected) return device; } return null; } function resetBluetoothAttemptState() { bluetoothConnectRequested = false; bluetoothTargetAttemptIndex = 0; bluetoothActiveTargetName = ""; bluetoothConnectAttemptTimer.stop(); } function maybeStartBluetoothOrSkip() { console.log("Startup BT: maybeStartBluetoothOrSkip", "waiting", waitingForBluetooth, "requested", bluetoothConnectRequested, "active", bluetoothActiveTargetName, "attemptIndex", bluetoothTargetAttemptIndex); if (!waitingForBluetooth) return; const connectedDevice = findConnectedPreferredBluetoothDevice(); if (connectedDevice) { console.log("Startup BT: preferred device connected, starting animation", bluetoothDeviceName(connectedDevice)); beginAnimation(); return; } if (bluetoothConnectRequested) { console.log("Startup BT: connect already requested, waiting on", bluetoothActiveTargetName); return; } for (var i = bluetoothTargetAttemptIndex; i < bluetoothTargetNames.length; i++) { var targetName = bluetoothTargetNames[i]; var targetDevice = findBluetoothDeviceByName(targetName); if (!targetDevice) continue; bluetoothConnectRequested = true; bluetoothTargetAttemptIndex = i; bluetoothActiveTargetName = targetName; bluetoothConnectAttemptTimer.restart(); console.log("Startup BT: requesting connect", targetName); targetDevice.connect(); return; } console.log("Startup BT: no preferred devices available yet"); } function beginAnimation() { console.log("Startup: beginAnimation", "started", animationStarted, "scheduled", animationLaunchScheduled); if (animationStarted || animationLaunchScheduled) return; waitingForBluetooth = false; bluetoothRetryTimer.stop(); bluetoothConnectAttemptTimer.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(), "targets", JSON.stringify(bluetoothTargetNames)); 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.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onModelReset() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices model reset"); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onRowsInserted() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows inserted"); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onRowsRemoved() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows removed"); overlay.resetBluetoothAttemptState(); 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) { if (Boolean(device ? device.connected : false)) overlay.bluetoothConnectAttemptTimer.stop(); overlay.maybeStartBluetoothOrSkip(); } } function onNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: name changed", overlay.bluetoothDeviceName(device)); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onDeviceNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: deviceName changed", overlay.bluetoothDeviceName(device)); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } } } } MediaPlayer { id: player source: "deltarune.webm" // Local file or URL autoPlay: false videoOutput: videoOutput playbackRate: 1 audioOutput: startupAudioOutput onPlaybackStateChanged: a => { console.log("Startup: playback state changed", player.playbackState); if (player.playbackState === MediaPlayer.StoppedState) overlay.finishStartup(); } } Timer { id: startupDelayTimer interval: 1500 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.maybeStartBluetoothOrSkip(); } } Timer { id: bluetoothConnectAttemptTimer interval: overlay.bluetoothConnectAttemptMs running: false repeat: false onTriggered: { console.log("Startup BT: connect attempt timed out", overlay.bluetoothActiveTargetName); overlay.bluetoothConnectRequested = false; overlay.bluetoothActiveTargetName = ""; overlay.bluetoothTargetAttemptIndex = Math.min(overlay.bluetoothTargetAttemptIndex + 1, overlay.bluetoothTargetNames.length); overlay.maybeStartBluetoothOrSkip(); } } MediaDevices { id: mediaDevices onDefaultAudioOutputChanged: { console.log("Startup Audio: default output changed", mediaDevices.defaultAudioOutput.description); startupAudioOutput.device = mediaDevices.defaultAudioOutput; } } AudioOutput { id: startupAudioOutput device: mediaDevices.defaultAudioOutput } 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 } }