Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

quickshell/nuguland/niri.js

Raw
// Niri 26.04: niri-ipc/src/{lib,state}.rs at
// https://github.com/niri-wm/niri/tree/8ed0da44d974c32c6877d2f4630c314da0717ecb
// Pure patches keep protocol validation/replays independent of QML process timing.
function object(value) {
    return value !== null && typeof value === "object" && !Array.isArray(value);
}

function id(value) {
    return Number.isSafeInteger(value) && value >= 0;
}

function optionalId(value) {
    return value === null || id(value);
}

function optionalString(value) {
    return value === null || typeof value === "string";
}

function pair(value) {
    return Array.isArray(value) && value.length === 2 && value.every(Number.isFinite);
}

function timestamp(value) {
    return value === null || object(value) && id(value.secs) && id(value.nanos) && value.nanos < 1000000000;
}

function layout(value) {
    return object(value)
        && (value.pos_in_scrolling_layout === null || pair(value.pos_in_scrolling_layout) && value.pos_in_scrolling_layout.every(id))
        && pair(value.tile_size) && pair(value.window_size)
        && (value.tile_pos_in_workspace_view === null || pair(value.tile_pos_in_workspace_view))
        && pair(value.window_offset_in_tile);
}

function windowRecord(value) {
    return object(value) && id(value.id) && optionalString(value.title) && optionalString(value.app_id)
        && (value.pid === null || Number.isInteger(value.pid)) && optionalId(value.workspace_id) && typeof value.is_focused === "boolean"
        && typeof value.is_floating === "boolean" && typeof value.is_urgent === "boolean"
        && layout(value.layout) && timestamp(value.focus_timestamp);
}

function workspaceRecord(value) {
    return object(value) && id(value.id) && id(value.idx) && value.idx <= 255
        && optionalString(value.name) && optionalString(value.output)
        && typeof value.is_urgent === "boolean" && typeof value.is_active === "boolean"
        && typeof value.is_focused === "boolean" && optionalId(value.active_window_id);
}

function castRecord(value) {
    if (!object(value) || !object(value.target) || Object.keys(value.target).length !== 1)
        return false;
    const name = Object.keys(value.target)[0];
    const target = value.target[name];
    return id(value.stream_id) && id(value.session_id) && ["PipeWire", "WlrScreencopy"].includes(value.kind)
        && typeof value.is_dynamic_target === "boolean" && typeof value.is_active === "boolean"
        && (value.pid === null || Number.isInteger(value.pid)) && optionalId(value.pw_node_id)
        && object(target) && (name === "Nothing" || name === "Output" && typeof target.name === "string"
            || name === "Window" && id(target.id));
}

function records(value, valid) {
    return Array.isArray(value) && value.every(valid) && new Set(value.map(row => row.id)).size === value.length;
}

function requireValid(valid, name) {
    if (!valid)
        throw new Error("malformed niri " + name);
}

function replace(items, target, fields) {
    return items.map(row => row.id === target ? Object.assign({}, row, fields) : row);
}

function windowPatch(windows) {
    const focused = windows.find(row => row.is_focused);
    return { windows: windows, focusedWindow: focused ? focused.id : null };
}

// null means ignored, never a successful state update. Unknown variants/fields
// are allowed by the IPC contract; known payloads must validate before mutation.
function reduce(state, event) {
    requireValid(object(event) && Object.keys(event).length === 1, "event envelope");
    const name = Object.keys(event)[0];
    const data = event[name];
    switch (name) {
    case "WorkspacesChanged":
        requireValid(object(data) && records(data.workspaces, workspaceRecord), name);
        return { workspaces: data.workspaces, workspacesInitialized: true };
    case "WorkspaceActivated": {
        requireValid(object(data) && id(data.id) && typeof data.focused === "boolean", name);
        const active = state.workspaces.find(row => row.id === data.id);
        requireValid(!!active, name + " workspace");
        return { workspaces: state.workspaces.map(row => Object.assign({}, row, {
            is_active: row.output === active.output ? row.id === data.id : row.is_active,
            is_focused: data.focused ? row.id === data.id : row.is_focused
        })) };
    }
    case "WorkspaceActiveWindowChanged":
        requireValid(object(data) && id(data.workspace_id) && optionalId(data.active_window_id), name);
        requireValid(state.workspaces.some(row => row.id === data.workspace_id), name + " workspace");
        // The window may not have arrived yet. Upstream does not require it here.
        return { workspaces: replace(state.workspaces, data.workspace_id, { active_window_id: data.active_window_id }) };
    case "WorkspaceUrgencyChanged":
        requireValid(object(data) && id(data.id) && typeof data.urgent === "boolean", name);
        return { workspaces: replace(state.workspaces, data.id, { is_urgent: data.urgent }) };
    case "WindowsChanged":
        requireValid(object(data) && records(data.windows, windowRecord), name);
        return Object.assign(windowPatch(data.windows), { windowsInitialized: true });
    case "WindowOpenedOrChanged": {
        requireValid(object(data) && windowRecord(data.window), name);
        const win = data.window;
        const windows = state.windows.filter(row => row.id !== win.id).map(row =>
            win.is_focused ? Object.assign({}, row, { is_focused: false }) : row);
        windows.push(win);
        return windowPatch(windows);
    }
    case "WindowClosed":
        requireValid(object(data) && id(data.id), name);
        requireValid(state.windows.some(row => row.id === data.id), name + " window");
        return windowPatch(state.windows.filter(row => row.id !== data.id));
    case "WindowFocusChanged":
        requireValid(object(data) && optionalId(data.id), name);
        return windowPatch(state.windows.map(row => Object.assign({}, row, { is_focused: row.id === data.id })));
    case "WindowFocusTimestampChanged":
        requireValid(object(data) && id(data.id) && timestamp(data.focus_timestamp), name);
        return { windows: replace(state.windows, data.id, { focus_timestamp: data.focus_timestamp }) };
    case "WindowUrgencyChanged":
        requireValid(object(data) && id(data.id) && typeof data.urgent === "boolean", name);
        return { windows: replace(state.windows, data.id, { is_urgent: data.urgent }) };
    case "WindowLayoutsChanged": {
        requireValid(object(data) && Array.isArray(data.changes) && data.changes.every(change =>
            Array.isArray(change) && change.length === 2 && id(change[0]) && layout(change[1])
            && state.windows.some(row => row.id === change[0])), name);
        let windows = state.windows;
        for (const change of data.changes)
            windows = replace(windows, change[0], { layout: change[1] });
        return { windows: windows };
    }
    case "OverviewOpenedOrClosed":
        requireValid(object(data) && typeof data.is_open === "boolean", name);
        return { overviewState: data.is_open ? "open" : "closed" };
    case "ScreenshotCaptured":
        requireValid(object(data) && optionalString(data.path), name);
        return { screenshotPath: data.path };
    // These installed variants are not owned by Nuguland. Validate them without
    // treating them as initialization or adding unused service state.
    case "KeyboardLayoutsChanged":
        requireValid(object(data) && object(data.keyboard_layouts)
            && Array.isArray(data.keyboard_layouts.names) && data.keyboard_layouts.names.every(value => typeof value === "string")
            && id(data.keyboard_layouts.current_idx) && data.keyboard_layouts.current_idx <= 255, name);
        return null;
    case "KeyboardLayoutSwitched":
        requireValid(object(data) && id(data.idx) && data.idx <= 255, name);
        return null;
    case "ConfigLoaded":
        requireValid(object(data) && typeof data.failed === "boolean", name);
        return null;
    case "CastsChanged":
        requireValid(object(data) && Array.isArray(data.casts) && data.casts.every(castRecord), name);
        return null;
    case "CastStartedOrChanged":
        requireValid(object(data) && castRecord(data.cast), name);
        return null;
    case "CastStopped":
        requireValid(object(data) && id(data.stream_id), name);
        return null;
    default:
        return null;
    }
}

// Outputs are a separate request, never stream state. A failed/partial query
// must not replace the last inventory, including when stdout happens to be {}.
function parseOutputs(text, exitCode, exitStatus) {
    requireValid(exitCode === 0 && exitStatus === 0, "outputs query exit");
    const outputs = JSON.parse(text);
    requireValid(object(outputs) && Object.keys(outputs).every(name => {
        const row = outputs[name];
        const logical = row && row.logical;
        return object(row) && row.name === name && typeof row.make === "string" && typeof row.model === "string"
            && optionalString(row.serial) && Array.isArray(row.modes) && optionalId(row.current_mode)
            && (logical === null || object(logical) && [logical.x, logical.y, logical.width, logical.height, logical.scale].every(Number.isFinite));
    }), "outputs inventory");
    return outputs;
}