summaryrefslogtreecommitdiff
path: root/widget/Bar.tsx
blob: ccbd4960f42819ad41f2c3c55a01c4a2bf9741d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { App, Astal, Gtk, Gdk } from "astal/gtk3"
import { exec, monitorFile, Variable } from "astal"
import { Button, Label } from "astal/gtk3/widget";
import Pango from "gi://Pango?version=1.0";

const time = Variable("").poll(1000, "date")

type Id = number
interface SwayNodeCommon {
    id: Id,
    orientation: 'horizontal' | 'vertical' | 'none',
    name: string,
    focus: Id[],
    rect: Rect,
    deco_rect: Rect,
    window_rect: Rect,
    geometry: Rect,
}
type SwayNode = SwayOutput | SwayRoot | SwayCon | SwayWorkspace;
type Rect = { x: number, y: number, width: number, height: number }
interface SwayWorkspace extends SwayNodeCommon {
    type: 'workspace',
    nodes: SwayCon[]
}
interface SwayCon extends SwayNodeCommon {
    type: 'con',
    window_properties?: {
        class: string,
        instance: string,
        title: string,
        window_role: string,
        window_type: string,
    },
}
interface SwayOutput extends SwayNodeCommon {
    type: 'output',
    nodes: SwayWorkspace[],
    focused: boolean,
}
interface SwayRoot extends SwayNodeCommon {
    type: 'root',
    nodes: SwayOutput[]
}
const swayTree = Variable({} as SwayRoot | { type: undefined }).poll(1000, "swaymsg -t get_tree",
    text => JSON.parse(text) as SwayRoot
)
function omit<T extends object, K extends keyof T>(obj: T, ...ks: K[]): Omit<T, K> {
    return Object.fromEntries(Object.entries(obj).filter(it => !ks.includes(it[0] as K))) as any
}
function Monitor(props: { monitor: SwayOutput }) {
    return <>
        <Label halign={Gtk.Align.START} className={"monitor"}>
            {`${props.monitor.name} (${props.monitor.nodes.length})`}
        </Label>
        {props.monitor.nodes.map(ws =>
            <Workspace ws={ws} focused={props.monitor.focus.includes(ws.id)}></Workspace>
        )}
    </>
}
function Workspace(props: { ws: SwayWorkspace, focused: boolean }) {
    return <>
        <Button
            halign={Gtk.Align.START}
            onClickRelease={() => exec(['swaymsg', `workspace ${JSON.stringify(props.ws.name)}`])}
            className={"workspace linky-button " + (props.focused ? 'active-ws ' : '')} relief={Gtk.ReliefStyle.NONE}>
            {`Workspace ${props.ws.name}`}
        </Button>
        {props.ws.nodes.map(window =>
            <Label
                ellipsize={Pango.EllipsizeMode.MIDDLE}
                maxWidthChars={30}
                halign={Gtk.Align.START}
                className={"window"}>{window.window_properties?.title ?? window.name}</Label>
        )}
    </>
}
export default function Bar(gdkmonitor: Gdk.Monitor) {
    const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor
    return <window
        className="Bar"
        gdkmonitor={gdkmonitor}
        exclusivity={Astal.Exclusivity.EXCLUSIVE}
        anchor={TOP | LEFT | BOTTOM}
        application={App}>
        <box vertical className={"output-list"}>
            {swayTree(root => !root.type ? null
                : root.nodes
                    .map(monitor => monitor.name.startsWith("_") ? null : <Monitor monitor={monitor}></Monitor>)
                    .filter(it => it)
            )}
        </box>
    </window>
}