import { App, Astal, Gtk, Gdk } from "astal/gtk4" import { bind, exec, GLib, Variable } from "astal" import AstalTray from "gi://AstalTray?version=0.1"; import AstalWp from "gi://AstalWp?version=0.1"; type NiriWorkspace = { id: number, idx: number, name: string | null, output: string, is_active: boolean, is_focused: boolean, active_window_id: number | null, }; // Niri Event Stream // This is used to dynamically update variables that should not be polling and // reacting as fast as it can be possible // NOTE: this works only in non-systemd environment on NixOS // TODO: I should better write a module for Astal that communicate with socket const niri = Variable("").watch("niri msg event-stream", (out, _prev) => out); function getWorkspaces(): NiriWorkspace[] { // NOTE: this works only in non-systemd environment on NixOS // TODO: try to use Niri socket if it is documented return JSON.parse(exec("niri msg -j workspaces")); } function getWorkspacesByOutput(output: string): NiriWorkspace[] { return getWorkspaces().filter(workspace => workspace.output == output).sort((a, b) => a.idx - b.idx); } function focusWorkspace(idx: number) { // NOTE: this works only in non-systemd environment on NixOS // TODO: try to use Niri socket if it is documented exec(`niri msg action focus-workspace ${idx}`); } type WorkspaceButtonArguments = { idx: number, workspaces: Variable, }; function WorkspaceButton(args: WorkspaceButtonArguments) { const classes: Variable = Variable.derive([args.workspaces], workspaces => { const classes: string[] = []; const workspace = workspaces.find(v => v.idx == args.idx); workspace !== undefined && classes.push("used"); workspace?.is_active && classes.push("active"); workspace?.is_focused && classes.push("focused"); return classes; }); // TODO: this solution make me to have 9 workspace buttons no matter what // I'd like to dynamically hide/show some of them, but I guess this will cause rerenders // Maybe I just need to transform them in CSS return