Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

quickshell/nuguland/SurfaceManager.qml

Raw
import QtQuick
import "popoutCatalog.js" as PopoutCatalog
import "diagnostics.js" as DiagnosticData

Item {
    id: root

    property int operationId: 0
    property bool popoutOpen: false
    property bool popoutClosing: false
    property string popoutPhase: "closed"
    property string popoutName: ""
    property string popoutOutput: ""
    property string activeLoaderName: ""
    property string pendingLoaderName: ""
    property string removingLoaderName: ""
    property var previousContent: ({})
    property string lastInteraction: ""
    property string lastCloseReason: ""
    property rect popoutAnchor: Qt.rect(0, 0, 0, 0)
    property real popoutProgress: 0
    property int screenWidth: 0
    property int screenHeight: 0
    property int barHeight: 34
    property string orientation: "horizontal"
    property var powerService
    property var mediaService
    property var trayService
    property Niri niriService
    property var returnWindowId: null
    readonly property bool vertical: orientation === "vertical"
    property var anchorRegistry: ({})
    // Ordinary view state lives for the shell session, never on disk.
    property var panelStates: ({
            "clock": {
                "scrollY": 0
            },
            "system": {
                "scrollY": 0
            },
            "notifications": {
                "scrollY": 0
            },
            "noko": {
                "scrollY": 0
            },
            "connectivity": {
                "scrollY": 0,
                "expandedSsid": ""
            },
            "launcher": {
                "query": "",
                "selectedId": "",
                "scrollY": 0
            },
            "clipboard": {
                "query": "",
                "selectedId": "",
                "scrollY": 0
            },
            "audio": {
                "scrollY": 0,
                "expandedSink": "",
                "expandedSource": ""
            },
            "brightness": {
                "scrollY": 0
            },
            "media": {
                "scrollY": 0
            },
            "tray": {
                "scrollY": 0
            },
            "power": {
                "scrollY": 0
            }
        })
    signal dismissing(string name)

    readonly property int closeRetentionMs: 0

    function parseRect(text) {
        const parts = String(text).split(/[, x]+/).filter(p => {
            return p.length > 0;
        }).map(Number);
        if (parts.length !== 4 || parts.some(n => {
            return !Number.isFinite(n);
        }))
            return Qt.rect(0, 0, 0, 0);

        return Qt.rect(parts[0], parts[1], parts[2], parts[3]);
    }

    function dismissTask() {
        dismissing(popoutName);
        if (popoutName === "power" && powerService)
            powerService.cancelAction();
    }

    function rectObject(rect) {
        return {
            "x": Math.round(rect.x),
            "y": Math.round(rect.y),
            "width": Math.round(rect.width),
            "height": Math.round(rect.height)
        };
    }

    function emptyPanel(name) {
        const service = name === "media" ? root.mediaService : (name === "tray" ? root.trayService : null);
        if (!service)
            return false;
        const state = JSON.parse(service.stateJson());
        return (name === "media" ? (state.players || []) : (state.items || [])).length === 0;
    }

    function popoutWidth(name) {
        const entry = Object.prototype.hasOwnProperty.call(PopoutCatalog.entries, String(name)) ? PopoutCatalog.entries[String(name)] : null;
        const wanted = emptyPanel(name) ? 368 : (entry ? entry.width : 520);
        const along = vertical ? screenWidth - barHeight : screenWidth;
        return along > 0 ? Math.min(wanted, Math.max(1, along - 16)) : wanted;
    }

    function heightBudget(wanted, minimum = 220) {
        const reserve = vertical ? 48 : barHeight + 48;
        const maxHeight = screenHeight > 0 ? Math.max(260, screenHeight - reserve) : 680;
        return Math.min(maxHeight, Math.max(minimum, Number(wanted)));
    }

    function powerContentSize() {
        const width = popoutWidth("power");
        const state = powerService ? JSON.parse(powerService.stateJson()) : ({
                "battery": {},
                "externalDevices": []
            });
        const hasBattery = !!(state.battery && state.battery.present);
        const deviceCount = (state.externalDevices || []).length;
        const entry = PopoutCatalog.entries.power;
        const deviceHeight = deviceCount > 0 ? Math.ceil(deviceCount / 2) * 40 + 4 : 0;
        const confirmationHeight = state.pendingConfirmation ? 116 : 0;
        return {
            "width": width,
            "height": heightBudget((hasBattery ? entry.batteryHeight : entry.height) + deviceHeight + confirmationHeight, entry.height)
        };
    }

    function popoutContentSize(name) {
        const key = String(name);
        if (key === "power")
            return powerContentSize();

        const entry = Object.prototype.hasOwnProperty.call(PopoutCatalog.entries, key) ? PopoutCatalog.entries[key] : null;
        return {
            "width": popoutWidth(key),
            "height": emptyPanel(key) ? heightBudget(104, 104) : heightBudget(entry ? entry.height : PopoutCatalog.fallbackHeight)
        };
    }

    function popupWindowAnchorRect() {
        if (vertical)
            return {
                "x": Math.max(1, Math.round(barHeight)),
                "y": 0,
                "width": 1,
                "height": screenHeight > 0 ? screenHeight : popoutContentSize(popoutName).height
            };

        return {
            "x": 0,
            "y": Math.max(1, Math.round(barHeight)),
            "width": screenWidth > 0 ? screenWidth : popoutContentSize(popoutName).width,
            "height": 1
        };
    }

    function popupCardFrame(progress) {
        const t = Math.max(0, Math.min(1, Number(progress)));
        const contentSize = popoutContentSize(popoutName);
        if (vertical) {
            const surfaceHeight = screenHeight > 0 ? screenHeight : contentSize.height;
            return {
                "source": "left-bar-slide-fade",
                "progress": t,
                "currentRect": {
                    "x": Math.round(barHeight - 18 + 26 * t),
                    "y": Math.max(8, Math.round((surfaceHeight - contentSize.height) / 2) + 8),
                    "width": Math.max(1, Math.round(contentSize.width - 16)),
                    "height": Math.max(1, Math.round(contentSize.height - 16))
                },
                "opacity": t
            };
        }
        const surfaceWidth = screenWidth > 0 ? screenWidth : contentSize.width;
        return {
            "source": "simple-center-slide-fade",
            "progress": t,
            "currentRect": {
                "x": Math.max(8, Math.round((surfaceWidth - contentSize.width) / 2) + 8),
                "y": Math.round(barHeight - 18 + 26 * t),
                "width": Math.max(1, Math.round(contentSize.width - 16)),
                "height": Math.max(1, Math.round(contentSize.height - 16))
            },
            "opacity": t
        };
    }

    function popoutContentCatalog() {
        return PopoutCatalog.catalogJson();
    }

    function registerAnchor(name, anchorText) {
        const next = Object.assign({}, anchorRegistry);
        next[String(name)] = rectObject(parseRect(anchorText));
        anchorRegistry = next;
        return registeredAnchors();
    }

    function registeredAnchors() {
        return JSON.stringify(anchorRegistry);
    }

    function setPopoutScreen(width, height, topBarThickness, orient) {
        screenWidth = Math.max(0, Number(width));
        screenHeight = Math.max(0, Number(height));
        barHeight = Math.max(1, Number(topBarThickness || barHeight));
        if (orient === "horizontal" || orient === "vertical")
            orientation = orient;

        return popoutState();
    }

    function clampedTarget(origin, contentSize) {
        const edges = [];
        if (vertical) {
            let y = Math.round(origin.y - contentSize.height / 2);
            if (y < 0) {
                y = 0;
                edges.push("top");
            }
            if (screenHeight > 0 && y + contentSize.height > screenHeight) {
                y = Math.max(0, screenHeight - contentSize.height);
                edges.length = 0;
                edges.push("bottom");
            }
            return {
                "rect": {
                    "x": Math.max(0, Math.round(barHeight)),
                    "y": y,
                    "width": contentSize.width,
                    "height": contentSize.height
                },
                "edges": edges
            };
        }
        let x = Math.round(origin.x - contentSize.width / 2);
        if (x < 0) {
            x = 0;
            edges.push("left");
        }
        if (screenWidth > 0 && x + contentSize.width > screenWidth) {
            x = Math.max(0, screenWidth - contentSize.width);
            edges.length = 0;
            edges.push("right");
        }
        return {
            "rect": {
                "x": x,
                "y": origin.y,
                "width": contentSize.width,
                "height": contentSize.height
            },
            "edges": edges
        };
    }

    function openPopout(name, anchorText, outputName) {
        const nextName = String(name);
        const wasOpen = popoutOpen && !popoutClosing;
        if (wasOpen && popoutName !== nextName)
            dismissTask();
        if (!wasOpen)
            returnWindowId = niriService ? niriService.focusedWindow : null;
        operationId = DiagnosticData.nextOperationId(operationId);
        unloadTimer.stop();
        openTimer.stop();
        popoutClosing = false;
        lastInteraction = "";
        lastCloseReason = "";
        popoutName = nextName;
        popoutOutput = String(outputName || "");
        activeLoaderName = nextName;
        pendingLoaderName = "";
        removingLoaderName = "";
        previousContent = ({});
        popoutAnchor = parseRect(anchorText);
        popoutOpen = true;
        if (wasOpen) {
            popoutProgress = 1;
            popoutPhase = "open";
        } else {
            popoutPhase = "opening";
            popoutProgress = 0;
            openTimer.restart();
        }
        console.info(JSON.stringify(DiagnosticData.transition(wasOpen ? "switched" : "opening", root)));
        return popoutState();
    }

    function openRegisteredPopout(name, outputName) {
        const anchor = anchorRegistry[String(name)] || {
            "x": 0,
            "y": 0,
            "width": 0,
            "height": 0
        };
        return openPopout(name, `${anchor.x},${anchor.y},${anchor.width},${anchor.height}`, outputName);
    }

    function hoverRegisteredPopout(name) {
        // Hover is discovery, never navigation away from an active task.
        return popoutState();
    }

    function closePopout(reason) {
        if (!popoutOpen && !popoutClosing)
            return popoutState();

        dismissTask();
        operationId = DiagnosticData.nextOperationId(operationId);
        openTimer.stop();
        if (reason && String(reason).length > 0)
            lastCloseReason = String(reason);

        popoutOpen = false;
        popoutClosing = false;
        popoutProgress = 0;
        popoutPhase = "closed";
        popoutName = "";
        popoutOutput = "";
        activeLoaderName = "";
        pendingLoaderName = "";
        removingLoaderName = "";
        previousContent = ({});
        console.info(JSON.stringify(DiagnosticData.transition("closed", root)));
        return popoutState();
    }

    function popoutInteraction(kind) {
        lastInteraction = String(kind);
        if (lastInteraction === "inside")
            return popoutState();

        if (lastInteraction === "outside" || lastInteraction === "escape" || lastInteraction === "focus-grab-outside" || lastInteraction === "escape-key")
            return closePopout(lastInteraction);

        return popoutState();
    }

    function popoutState() {
        const contentSize = popoutContentSize(popoutName);
        const origin = vertical ? {
            "x": Math.round(popoutAnchor.x + popoutAnchor.width),
            "y": Math.round(popoutAnchor.y + popoutAnchor.height / 2)
        } : {
            "x": Math.round(popoutAnchor.x + popoutAnchor.width / 2),
            "y": Math.round(popoutAnchor.y + popoutAnchor.height)
        };
        const target = clampedTarget(origin, contentSize);
        return JSON.stringify({
            "open": popoutOpen,
            "closing": popoutClosing,
            "phase": popoutPhase,
            "name": popoutName,
            "output": popoutOutput,
            "lastInteraction": lastInteraction,
            "lastCloseReason": lastCloseReason,
            "anchor": rectObject(popoutAnchor),
            "origin": origin,
            "contentSize": contentSize,
            "popupAnchorRect": popupWindowAnchorRect(),
            "popupCardFrame": popupCardFrame(popoutProgress),
            "activeLoaderName": activeLoaderName,
            "pendingLoaderName": pendingLoaderName,
            "removingLoaderName": removingLoaderName,
            "previousContent": previousContent,
            "screen": {
                "width": screenWidth,
                "height": screenHeight,
                "barHeight": barHeight
            },
            "progress": popoutProgress,
            "transition": {
                "host": "bar",
                "animation": vertical ? "left-bar-slide-fade" : "simple-center-slide-fade",
                "direction": vertical ? (popoutClosing ? "left-out" : "right-in") : (popoutClosing ? "up-out" : "down-in"),
                "loaderActive": popoutOpen,
                "targetRect": popupWindowAnchorRect()
            }
        });
    }

    function completeOpen() {
        if (!popoutOpen || popoutClosing || popoutPhase !== "opening")
            return;

        popoutProgress = 1;
        popoutPhase = "open";
        console.info(JSON.stringify(DiagnosticData.transition("opened", root)));
    }

    Timer {
        id: openTimer

        interval: root.closeRetentionMs
        repeat: false
        onTriggered: root.completeOpen()
    }

    Timer {
        id: unloadTimer

        interval: root.closeRetentionMs
        repeat: false
        onTriggered: {
            root.popoutClosing = false;
            root.popoutPhase = "closed";
            root.popoutName = "";
            root.popoutOutput = "";
            root.activeLoaderName = "";
            root.pendingLoaderName = "";
            root.removingLoaderName = "";
            root.previousContent = ({});
        }
    }
}