Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

quickshell/nuguland/Tray.qml

Raw
import QtQuick
import Quickshell.Services.SystemTray

Item {
    id: root

    property string selectedItemId: ""
    property string expandedSubmenu: ""
    property bool closeRequested: false
    property string closeReason: ""
    property var closePropagation: ({
            "requested": false,
            "source": "",
            "reason": ""
        })
    property var lastAction: ({})
    readonly property var rowKinds: ["action", "separator", "submenu", "check", "radio", "disabled"]
    readonly property var nativeItems: SystemTray.items.values
    readonly property int attentionCount: itemsArray().filter(item => {
        return item.status === "NeedsAttention";
    }).length

    function activeRole() {
        return "ui.focus";
    }

    function attentionRole() {
        return "info";
    }

    function borderRole(attention, active) {
        if (attention)
            return attentionRole();

        if (active)
            return activeRole();

        return "ui.accent";
    }

    function fillRole(active) {
        return active ? activeRole() : "transparent";
    }

    function enumName(value, fallback) {
        const text = String(value === undefined || value === null ? "" : value);
        if (text.indexOf("NeedsAttention") >= 0)
            return "NeedsAttention";

        if (text.indexOf("Active") >= 0)
            return "Active";

        if (text.indexOf("Passive") >= 0)
            return "Passive";

        if (text.indexOf("Hardware") >= 0)
            return "Hardware";

        if (text.indexOf("SystemServices") >= 0)
            return "SystemServices";

        if (text.indexOf("Communications") >= 0)
            return "Communications";

        if (text.indexOf("ApplicationStatus") >= 0)
            return "ApplicationStatus";

        return fallback;
    }

    function itemKey(item, index) {
        const id = String(item && item.id ? item.id : "");
        const title = String(item && item.title ? item.title : (item && item.tooltipTitle ? item.tooltipTitle : ""));
        return id.length > 0 ? id : (title.length > 0 ? title : `tray-${index}`);
    }

    function shapeItem(item, index) {
        const id = itemKey(item, index);
        return {
            "id": id,
            "index": index,
            "title": String(item && item.title ? item.title : (item && item.tooltipTitle ? item.tooltipTitle : id)),
            "tooltipTitle": String(item && item.tooltipTitle ? item.tooltipTitle : ""),
            "tooltipDescription": String(item && item.tooltipDescription ? item.tooltipDescription : ""),
            "icon": String(item && item.icon ? item.icon : ""),
            "status": enumName(item ? item.status : null, "Passive"),
            "category": enumName(item ? item.category : null, "ApplicationStatus"),
            "hasMenu": !!(item && item.hasMenu),
            "onlyMenu": !!(item && item.onlyMenu),
            "nativeRoutes": ["activate", "secondaryActivate", "scroll", "display"],
            "backend": "SystemTrayItem"
        };
    }

    function itemsArray() {
        const result = [];
        for (let i = 0; i < nativeItems.length; i++)
            result.push(shapeItem(nativeItems[i], i));
        return result;
    }

    function nativeItemById(id) {
        const needle = String(id);
        for (let i = 0; i < nativeItems.length; i++)
            if (itemKey(nativeItems[i], i) === needle) {
                return nativeItems[i];
            }
        return null;
    }

    function menuFor(id) {
        const item = nativeItemById(id);
        return item && item.hasMenu ? item.menu : null;
    }

    function selectedItem() {
        const items = itemsArray();
        if (items.length === 0)
            return null;

        if (selectedItemId.length === 0)
            return items[0];

        for (let i = 0; i < items.length; i++)
            if (items[i].id === selectedItemId) {
                return items[i];
            }
        return items[0];
    }

    function menuRows() {
        const item = selectedItem();
        if (!item || !item.hasMenu)
            return [];

        return [
            {
                "id": `${item.id}:native-menu`,
                "kind": "submenu",
                "label": `${item.title} menu`,
                "enabled": true,
                "expanded": expandedSubmenu === `${item.id}:native-menu`,
                "native": true,
                "children": []
            }
        ];
    }

    function rowById(id) {
        const rows = menuRows();
        const needle = String(id);
        for (let i = 0; i < rows.length; i++)
            if (rows[i].id === needle) {
                return rows[i];
            }
        return ({
                "id": needle,
                "kind": "missing",
                "label": "",
                "enabled": false,
                "native": false
            });
    }

    function trayPanelContract() {
        return {
            "source": "Quickshell.Services.SystemTray SystemTray.items.values plus native StatusNotifierItem routes",
            "ownedBy": "PopoutHost.qml inline TrayPanel",
            "nativeTrayMenuPanel": true,
            "realSystemTray": true,
            "trayItemGrid": true,
            "dbusMenuRows": true,
            "noSyntheticDbusMenuRows": true,
            "submenuCollapsePolicy": true,
            "menuClosePropagation": true,
            "attentionStatus": true,
            "serviceActionsOnly": true,
            "nativeRoutes": ["activate", "secondaryActivate", "scroll", "display"],
            "rowKinds": rowKinds
        };
    }

    function stateObject() {
        const rows = menuRows();
        const items = itemsArray();
        return {
            "backend": "Tray.qml",
            "source": "Quickshell.Services.SystemTray",
            "usesNativeSystemTray": true,
            "usesDBusMenu": true,
            "helperProcesses": [],
            "fakeRows": false,
            "nativeMenuHost": "bar-popout-host",
            "nativeItemCount": items.length,
            "attentionCount": attentionCount,
            "selectedItemId": selectedItemId,
            "items": items,
            "trayPanelContract": trayPanelContract(),
            "oneExpandedSubmenu": true,
            "expandedSubmenu": expandedSubmenu,
            "siblingsCollapsed": rows.filter(row => {
                return row.kind === "submenu" && row.expanded;
            }).length <= 1,
            "rowKinds": rowKinds,
            "rows": rows,
            "closeRequested": closeRequested,
            "closeReason": closeReason,
            "closePropagation": closePropagation,
            "lastAction": lastAction
        };
    }

    function stateJson() {
        return JSON.stringify(stateObject());
    }

    function selectItem(id) {
        const item = nativeItemById(id);
        selectedItemId = item ? String(id) : "";
        expandedSubmenu = "";
        lastAction = {
            "kind": "select-item",
            "id": String(id),
            "accepted": !!item
        };
        return stateJson();
    }

    function expandSubmenu(id) {
        const row = rowById(id);
        if (row.kind !== "submenu" || !row.enabled) {
            lastAction = {
                "kind": "expand-submenu",
                "id": String(id),
                "accepted": false
            };
            return stateJson();
        }
        expandedSubmenu = row.id;
        closeRequested = false;
        closeReason = "";
        closePropagation = {
            "requested": false,
            "source": row.id,
            "reason": "submenu-expanded"
        };
        lastAction = {
            "kind": "expand-submenu",
            "id": row.id,
            "accepted": true,
            "native": true
        };
        return stateJson();
    }

    function displayMenu(id, parentWindow, x, y) {
        const item = nativeItemById(id);
        if (!item || !item.hasMenu || !parentWindow)
            return stateJson();
        item.display(parentWindow, Math.round(x), Math.round(y));
        lastAction = {
            "kind": "display-menu",
            "id": String(id),
            "accepted": true,
            "native": true
        };
        return stateJson();
    }

    function primaryActivate(id, parentWindow, x, y) {
        const item = nativeItemById(id);
        if (item && item.onlyMenu)
            return displayMenu(id, parentWindow, x, y);
        return activateRow(id);
    }

    function secondaryActivate(id) {
        const item = nativeItemById(id);
        if (item) {
            item.secondaryActivate();
            lastAction = {
                "kind": "secondary-activate",
                "id": String(id),
                "accepted": true,
                "native": true
            };
        }
        return stateJson();
    }

    function activateRow(id) {
        const item = nativeItemById(id);
        if (item) {
            item.activate();
            closeRequested = true;
            closeReason = "item-activated";
            closePropagation = {
                "requested": true,
                "source": String(id),
                "reason": closeReason
            };
            lastAction = {
                "kind": "activate-item",
                "id": String(id),
                "accepted": true,
                "native": true
            };
            return stateJson();
        }
        const row = rowById(id);
        if (row.kind === "submenu")
            return expandSubmenu(row.id);

        closeRequested = false;
        closePropagation = {
            "requested": false,
            "source": row.id,
            "reason": row.kind
        };
        lastAction = {
            "kind": "activate-row",
            "id": row.id,
            "rowKind": row.kind,
            "accepted": false,
            "native": false
        };
        return stateJson();
    }

    function closeMenu(reason) {
        expandedSubmenu = "";
        closeRequested = true;
        closeReason = String(reason || "explicit");
        closePropagation = {
            "requested": true,
            "source": "menu",
            "reason": closeReason
        };
        lastAction = {
            "kind": "close-menu",
            "reason": closeReason
        };
        return stateJson();
    }

    function widgetState(attention, active) {
        return JSON.stringify({
            "attention": attention,
            "active": active,
            "attentionRole": attentionRole(),
            "activeRole": activeRole(),
            "borderRole": borderRole(attention, active),
            "fillRole": fillRole(active),
            "menu": stateObject()
        });
    }
}