2025-04-25 18:14:42 +02:00

140 lines
4.7 KiB
TypeScript

import AstalTray from "gi://AstalTray";
import { bind, GObject } from "astal";
import AstalHyprland from "gi://AstalHyprland";
import { Gtk } from "astal/gtk4";
const hypr = AstalHyprland.get_default();
const SYNC = GObject.BindingFlags.SYNC_CREATE;
const SysTray = () => {
const trayBox = new Gtk.Box({ cssClasses: ["bar-button"] });
const tray = AstalTray.get_default();
const trayItems = new Map<string, Gtk.MenuButton>();
const trayAddedHandler = tray.connect("item-added", (_, id) => {
const item = tray.get_item(id);
const popover = Gtk.PopoverMenu.new_from_model(item.menu_model);
const icon = new Gtk.Image();
const button = new Gtk.MenuButton({
popover,
child: icon,
cssClasses: ["tray-item"],
});
item.bind_property("gicon", icon, "gicon", SYNC);
popover.insert_action_group("dbusmenu", item.action_group);
item.connect("notify::action-group", () => {
popover.insert_action_group("dbusmenu", item.action_group);
});
trayItems.set(id, button);
trayBox.append(button);
});
const trayRemovedHandler = tray.connect("item-removed", (_, id) => {
const button = trayItems.get(id);
if (button) {
trayBox.remove(button);
button.run_dispose();
trayItems.delete(id);
}
});
trayBox.connect("destroy", () => {
tray.disconnect(trayAddedHandler);
tray.disconnect(trayRemovedHandler);
});
return trayBox;
};
const Workspace = () => {
return (
<box>
{bind(hypr, "workspaces").as(wss =>
wss
.filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces
.sort((a, b) => a.id - b.id)
.map(ws => (
<button
cssClasses={bind(hypr, "focusedWorkspace").as(fw =>
ws === fw
? [
"focused-workspace-button",
"workspace-button",
]
: ["workspace-button"],
)}
onButtonPressed={() => ws.focus()}
child={<label label={String(ws.id)}></label>}
></button>
)),
)}
</box>
);
};
/**
* Displays the name of the currently active window and provides a popover for
* displaying all available clients
*/
const ActiveWindow = () => {
const focused = bind(hypr, "focusedClient");
const WindowPopover = (): Gtk.Popover => {
// Set up boxes + Popover
const popover = new Gtk.Popover();
const popoverBox = WindowPopoverBox();
popover.set_child(popoverBox);
return popover;
};
const windowPopover = WindowPopover();
// ───────────────────────────────────────────────────────────────────
// Return fully assembled HyprlandFocusedClient box
// ───────────────────────────────────────────────────────────────────
return (
<box visible={focused.as(Boolean)}>
<button
onClicked={() => windowPopover.popup()}
cssClasses={["bar-button"]}
child={
focused.as(
client =>
client && (
<label label={bind(client, "title").as(String)} />
),
)
}></button>
{windowPopover}
</box >
);
};
const WindowPopoverBox = () => {
return <box vertical>
<label label={"Available Windows"} cssClasses={['title-2']}></label>
<Gtk.Separator marginTop={5} marginBottom={5}></Gtk.Separator>
<box vertical>
{bind(hypr, 'clients').as(clients => {
return clients.map(client => {
return <box>
<label label={bind(client, 'workspace').as(w => `(WS ${w})`)}></label>
<label label={bind(client, 'initialClass').as(c => `[${c}]`)}></label>
<label label={bind(client, 'title')}></label>
</box>
})
})}
</box>
</box>
}
export default {
Workspace,
ActiveWindow,
SysTray,
};