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>
}
|