summaryrefslogtreecommitdiff
path: root/widget/bar
diff options
context:
space:
mode:
authorLibravatar Mora Unie Youer <[email protected]>2025-03-02 17:56:12 +0300
committerLibravatar Mora Unie Youer <[email protected]>2025-03-02 17:57:55 +0300
commite79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9 (patch)
treeaca9f03423c6cd8566a0204aeda8b31e1f83b989 /widget/bar
parentfeat: basic topbar features (diff)
downloadags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.tar.gz
ags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.tar.bz2
ags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.tar.lz
ags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.tar.xz
ags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.tar.zst
ags-config-e79fa091cfbdbd9dfe2ed19a0a5f92604047b0a9.zip
feat: basic tray and improved workspaces buttons
Diffstat (limited to 'widget/bar')
-rw-r--r--widget/bar/Bar.tsx122
1 files changed, 122 insertions, 0 deletions
diff --git a/widget/bar/Bar.tsx b/widget/bar/Bar.tsx
new file mode 100644
index 0000000..b057cdb
--- /dev/null
+++ b/widget/bar/Bar.tsx
@@ -0,0 +1,122 @@
+import { App, Astal, Gtk, Gdk } from "astal/gtk4"
+import { bind, exec, GLib, Variable } from "astal"
+import AstalTray from "gi://AstalTray?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,
+};
+
+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>
+}
+
+
+function Tray() {
+ // BUG: personally I have one fantom icon being along other tray icons
+ // For now I don't have any ideas why this is happening
+ // TODO: rewrite this using more elements, as this is really restricted design
+ const tray = AstalTray.get_default();
+
+ return <box cssClasses={["Tray"]}>
+ {bind(tray, "items").as(items =>
+ items.map(item =>
+ <menubutton
+ setup={self => self.insert_action_group("dbusmenu", item.actionGroup)}
+ tooltipText={bind(item, "tooltipMarkup")}
+ >
+ <image gicon={bind(item, "gicon")} />
+ {Gtk.PopoverMenu.new_from_model(item.menuModel)}
+ </menubutton>
+ )
+ )}
+ </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>
+}
+
+
+export default function Bar(gdkmonitor: Gdk.Monitor) {
+ 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}>
+ <Tray />
+ <Time format="%I:%M:%S %p %Z" />
+ </box>
+ </centerbox>
+ </window>
+}