Janis Hutz 8a2180e120 [AGS] GTK 4 Migration: Done, Start adding QuickActions
Probably gonna abandon the QuickActions, as that is just way too much
effort for what it does. Will be providing keybinds for doing what I
wanted to do there in Hyprland
2025-04-22 15:30:41 +02:00

158 lines
5.2 KiB
TypeScript

import AstalTray from "gi://AstalTray";
import { bind, GObject } from "astal";
import AstalHyprland from "gi://AstalHyprland";
import { Gtk } from "astal/gtk4";
const SYNC = GObject.BindingFlags.SYNC_CREATE;
const SysTray = () => {
const trayBox = new Gtk.Box();
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 });
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 = () => {
const hypr = AstalHyprland.get_default()
return <box cssClasses={["HyprlandWorkspaces"]}>
{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 ? ["HyprlandFocusedWorkspace"] : [""])}
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 hypr = AstalHyprland.get_default();
const focused = bind( hypr, "focusedClient" );
const WindowPopover = (): Gtk.Popover => {
// Set up boxes + Popover
const clients = new Map<string, Gtk.Box>();
const popover = new Gtk.Popover();
const popoverBox = new Gtk.Box( { orientation: Gtk.Orientation.VERTICAL } );
const addClient = ( client: AstalHyprland.Client ) => {
const clientBox = new Gtk.Box();
// Workspace description
const descWS = new Gtk.Label( { label: '(WS ' } );
// Workpsace information
const workspace = new Gtk.Label();
client.workspace.bind_property( 'name', workspace, 'label', SYNC );
const windowClassDesc = new Gtk.Label( { label: ') [' } );
const windowClass = new Gtk.Label();
windowClass.label = client.get_initial_class();
const titleDesc = new Gtk.Label( { label: '] ' } );
titleDesc.set_margin_end( 2 );
const title = new Gtk.Label();
client.bind_property( 'title', title, 'label', SYNC );
clientBox.append( descWS );
clientBox.append( workspace );
clientBox.append( windowClassDesc );
clientBox.append( windowClass );
clientBox.append( titleDesc );
clientBox.append( title );
popoverBox.append( clientBox );
clients.set( client.get_address(), clientBox );
}
// Populate with already added clients
const c = hypr.get_clients();
for ( let index = 0; index < c.length; index++ ) {
addClient( c[ index ] );
}
hypr.connect( 'client-added', ( _, client ) => {
addClient( client );
} );
hypr.connect( 'client-removed', ( _, client ) => {
const c = clients.get( client );
if ( c ) {
popoverBox.remove( c );
c.run_dispose();
clients.delete( client );
}
} );
popover.set_child( popoverBox );
return popover;
}
const windowPopover = WindowPopover();
// ───────────────────────────────────────────────────────────────────
// Return fully assembled HyprlandFocusedClient box
// ───────────────────────────────────────────────────────────────────
return <box cssName={"HyprlandFocusedClients"} visible={focused.as(Boolean)}>
<button onClicked={() => windowPopover.popup()}>
{focused.as( client => (
client && <label label={bind( client, "title" ).as( String )} />
))}
</button>
{ windowPopover }
</box>
}
export default {
Workspace,
ActiveWindow,
SysTray
}