summaryrefslogtreecommitdiff
path: root/widget
diff options
context:
space:
mode:
Diffstat (limited to 'widget')
-rw-r--r--widget/Bar.tsx124
1 files changed, 93 insertions, 31 deletions
diff --git a/widget/Bar.tsx b/widget/Bar.tsx
index c2db8c5..02aa3ba 100644
--- a/widget/Bar.tsx
+++ b/widget/Bar.tsx
@@ -1,36 +1,98 @@
import { App, Astal, Gtk, Gdk } from "astal/gtk4"
-import { Variable } from "astal"
+import { exec, GLib, Variable } from "astal"
+
+type NiriWorkspace = {
+ id: number,
+ idx: number,
+ name: string | null,
+ output: string,
+ is_active: boolean,
+ is_focused: boolean,
+ active_window_id: number | null,
+};
+
+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,
+ isActive: boolean,
+ isFocused: boolean,
+};
+
+function WorkspaceButton(args: WorkspaceButtonArguments) {
+ const classes: string[] = [];
+ args.isActive && classes.push("active");
+ args.isFocused && classes.push("focused");
+ return <button cssClasses={classes} onClicked={() => focusWorkspace(args.idx)} />
+}
+
+type WorkspacesArguments = {
+ connector: string,
+};
+
+function Workspaces(args: WorkspacesArguments) {
+ // NOTE: it is pretty inefficient and not so much responsive
+ // TODO: it would be better to use Niri socket in the future
+ const workspaces: Variable<NiriWorkspace[]> = Variable(getWorkspacesByOutput(args.connector))
+ .poll(1000, () => getWorkspacesByOutput(args.connector));
+
+ // BUG: on workspace change there's no CSS transition
+ // I guess it is due to rerender here
+ return <box cssClasses={["Workspaces"]}>
+ {workspaces(v => v.map(workspace => <WorkspaceButton idx={workspace.idx} isActive={workspace.is_active} isFocused={workspace.is_focused} />))}
+ </box>
+}
+
+
+type TimeArguments = {
+ format: string,
+};
+
+function Time(args: TimeArguments) {
+ const time = Variable<GLib.DateTime>(GLib.DateTime.new_now_local()).poll(1000, () => GLib.DateTime.new_now_local())
+
+ return <box>
+ {time(v => v.format(args.format))}
+ </box>
+}
-const time = Variable("").poll(1000, "date")
export default function Bar(gdkmonitor: Gdk.Monitor) {
- const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
-
- return <window
- visible
- cssClasses={["Bar"]}
- gdkmonitor={gdkmonitor}
- exclusivity={Astal.Exclusivity.EXCLUSIVE}
- anchor={TOP | LEFT | RIGHT}
- application={App}>
- <centerbox cssName="centerbox">
- <button
- onClicked="echo hello"
- hexpand
- halign={Gtk.Align.CENTER}
- >
- Welcome to AGS!
- </button>
- <box />
- <menubutton
- hexpand
- halign={Gtk.Align.CENTER}
- >
- <label label={time()} />
- <popover>
- <Gtk.Calendar />
- </popover>
- </menubutton>
- </centerbox>
- </window>
+ const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
+
+ return <window
+ visible
+ name={"Bar"}
+ cssClasses={["Bar"]}
+ gdkmonitor={gdkmonitor}
+ exclusivity={Astal.Exclusivity.EXCLUSIVE}
+ anchor={TOP | LEFT | RIGHT}
+ application={App}>
+ <centerbox cssClasses={["bar-container"]}>
+ <box halign={Gtk.Align.START}>
+ <Workspaces connector={gdkmonitor.get_connector()!} />
+ </box>
+
+ <box halign={Gtk.Align.CENTER}>
+ </box>
+
+ <box halign={Gtk.Align.END}>
+ <Time format="%I:%M:%S %p %Z" />
+ </box>
+ </centerbox>
+ </window>
}