[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
This commit is contained in:
2025-04-22 15:30:41 +02:00
parent 8b70f80e60
commit 8a2180e120
19 changed files with 678 additions and 200 deletions

View File

@@ -1,14 +1,16 @@
import { GLib, Variable } from "astal"
import { Gtk } from "astal/gtk4"
const Time = ({ format = "%a, %e.%m %H:%M:%S" }) => {
const time = Variable<string>("").poll(1000, () =>
GLib.DateTime.new_now_local().format(format)!)
return <label
className="Time"
onDestroy={() => time.drop()}
label={time()}
/>
return <menubutton cssClasses={["Time"]} hexpand halign={Gtk.Align.CENTER}>
<label onDestroy={() => time.drop()} label={time()}></label>
<popover>
<Gtk.Calendar />
</popover>
</menubutton>
}
const Calendar = () => {

View File

@@ -1,38 +1,62 @@
import AstalTray from "gi://AstalTray";
import { bind, Variable } from "astal";
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();
return <box className="SysTray">
{bind(tray, "items").as( items => items.map( item => (
<button
tooltipMarkup={bind(item, "tooltipMarkup")}
usePopover={false}
actionGroup={bind(item, "actionGroup").as(ag => ["dbusmenu", ag])}
menuModel={bind(item, "menuModel")}>
<icon gicon={bind(item, "gicon")} />
</button>
) ) ) }
</box>
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 className={"HyprlandWorkspaces"}>
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
className={bind(hypr, "focusedWorkspace").as(fw =>
ws === fw ? "HyprlandFocusedWorkspace" : "")}
onClicked={() => ws.focus()}>
{ws.id}
cssClasses={bind(hypr, "focusedWorkspace").as(fw =>
ws === fw ? ["HyprlandFocusedWorkspace"] : [""])}
onButtonPressed={() => ws.focus()} child={<label label={String(ws.id)}></label>}>
</button>
))
)}
@@ -40,24 +64,88 @@ const Workspace = () => {
}
/**
* 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" );
let visible = Variable( false );
const toggleOverlay = () => {
visible.set( !visible.get() );
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)}>
<Gtk.Button onClicked={toggleOverlay}>
<button onClicked={() => windowPopover.popup()}>
{focused.as( client => (
client && <label label={bind( client, "title" ).as( String )} />
))}
</Gtk.Button>
<eventbox visible={bind(visible).as( v => v )} name="popover-container">
<label label="This is a test"></label>
</eventbox>
</button>
{ windowPopover }
</box>
}

View File

@@ -1,10 +1,10 @@
import { bind } from "astal";
import AstalBattery from "gi://AstalBattery?version=0.1";
import AstalBluetooth from "gi://AstalBluetooth?version=0.1";
import AstalNetwork from "gi://AstalNetwork?version=0.1"
import AstalWp from "gi://AstalWp?version=0.1";
import AstalBattery from "gi://AstalBattery";
import AstalBluetooth from "gi://AstalBluetooth";
import AstalNetwork from "gi://AstalNetwork"
import AstalWp from "gi://AstalWp";
import Brightness from "../../util/brightness";
import { Gtk } from "astal/gtk3";
import { Gtk } from "astal/gtk4";
const QuickView = () => {
return <box>

View File

@@ -18,7 +18,6 @@ const featureTest = () => {
printerr( '[ SysInfo ] Feature Test for CPU info failed. mpstat from the sysstat package missing!' );
}
// Screen brightness... CTL might be available, but no screen controllable
// Battery... acpi might be present, but potentially no bat
}
@@ -28,8 +27,6 @@ const availableFeatures = {
cpu: true,
ram: true,
bat: true,
net: false,
brightness: true,
}
const sysInfoFetcher = () => {
@@ -44,17 +41,10 @@ const sysInfoFetcher = () => {
const acpi = exec( `acpi -i | grep 'Battery'` );
// TODO: Parse acpi output
}
// if ( availableFeatures.net ) {
// // Using ifstat or vnstat probably, get current network de
// }
if ( availableFeatures.brightness ) {
}
}
}
const SystemInfo = () => {
return <box></box>
}