import { bind, execAsync, Binding, Variable } from "astal"; import { App, Astal, Gdk, Gtk } from "astal/gtk4"; import Bluetooth from "gi://AstalBluetooth"; import Hyprland from "gi://AstalHyprland"; import Network from "gi://AstalNetwork"; import { SHELL, IDLE_INHIBIT_SCRIPT, SWITCH_THEME_SCRIPT } from "@/settings.json"; import { hideWindow, openOnButton } from "@lib/utils"; type ButtonProps = { icon: string | Binding<string>, command?: string, label: string | Binding<string>, binding?: Binding<boolean>, bindingMethod?: (binding: boolean) => void } const isIdleInhibitorEnabled = async () => { try { await execAsync([SHELL, "-c", `pgrep -f ${IDLE_INHIBIT_SCRIPT}`]); return true; } catch { return false; } }; function Preference(props: ButtonProps & JSX.IntrinsicElements["button"]) { const onClicked = () => { if (props.command) execAsync([ SHELL, "-c", props.command ]); else if (typeof props.binding !== 'undefined' && props.bindingMethod) props.bindingMethod(!props.binding.get()) } return <button {...props} label={undefined} onClicked={onClicked} cssClasses={props.binding?.as(active => active ? ["active"] : [])} > <box orientation={Gtk.Orientation.HORIZONTAL} spacing={4}> <image iconName={props.icon} /> <label>{props.label}</label> </box> </button> } async function toggleIdleInhibitor(state: Variable<boolean>, enable: boolean) { try { if (enable) { execAsync([SHELL, "-c", IDLE_INHIBIT_SCRIPT]); } else { const pids = await execAsync([SHELL, "-c", `pgrep -f ${IDLE_INHIBIT_SCRIPT}`]); if (pids) { const pidList = pids.trim().split("\n"); for (const pid of pidList) { await execAsync(["kill", "-9", pid]); } } } state.set(!state.get()); } catch { console.error("Failed to change state of idle inhibitor"); } } export default async function QuickSettings(_monitor_id: number) { const { BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor const CENTER = Gtk.Align.CENTER; const hypr = Hyprland.get_default(); const bt = Bluetooth.get_default(); const net = Network.get_default(); const connectedBtDevice = bind(bt, "devices").as(devices => devices.find(device => device.connected)); const idleInhibitorEnabled = Variable(await isIdleInhibitorEnabled()); return <window visible={false} name={"quick_settings"} monitor={bind(hypr, "focusedMonitor").as(monitor => monitor.id)} cssClasses={["quick_settings"]} keymode={Astal.Keymode.EXCLUSIVE} exclusivity={Astal.Exclusivity.IGNORE} anchor={BOTTOM | LEFT | RIGHT} onKeyPressed={hideWindow} application={App}> <box halign={CENTER} cssClasses={["inner"]} vertical> <box orientation={Gtk.Orientation.HORIZONTAL} halign={CENTER}> <Preference icon={"network-wireless-symbolic"} label={bind(Variable.derive([ bind(net.wifi, "enabled"), bind(net.wifi, "ssid") ], (enabled, ssid) => enabled && ssid ? ssid : "Wi-Fi"))} binding={bind(net.wifi, "enabled")} bindingMethod={enabled => net.wifi.set_enabled(enabled)} /> <Preference icon={bind(bt, "isConnected").as(c => c ? "bluetooth-active-symbolic" : "bluetooth-disabled-symbolic" )} label={connectedBtDevice.as(device => bt.isPowered && device ? device.alias : "Bluetooth")} binding={bind(bt, "isPowered")} bindingMethod={() => bt.toggle()} onButtonPressed={(_self, event) => openOnButton(event, Gdk.BUTTON_SECONDARY) (() => App.toggle_window("qs_bluetooth")) } /> <Preference icon={"uninterruptible-power-supply-symbolic"} label={"Idle inhibitor"} binding={bind(idleInhibitorEnabled)} bindingMethod={toggleIdleInhibitor.bind(null, idleInhibitorEnabled)} /> <Preference icon="applications-graphics-symbolic" command={SWITCH_THEME_SCRIPT} label="Switch theme" /> </box> <box orientation={Gtk.Orientation.HORIZONTAL} halign={CENTER}> <Preference icon="system-shutdown-symbolic" command="systemctl poweroff" label="Shutdown" /> <Preference icon="system-reboot-symbolic" command="systemctl reboot" label="Reboot" /> <Preference icon="preferences-system-privacy-symbolic" command="systemctl suspend" label="Suspend" /> <Preference icon="application-exit-symbolic" command="systemctl exit" label="Exit session" /> </box> <box orientation={Gtk.Orientation.HORIZONTAL} halign={CENTER}> <Preference icon="system-lock-screen-symbolic" command="loginctl lock-session" label="Lock Screen" /> <Preference icon="system-log-out-symbolic" command="loginctl terminate-user $(whoami)" label="Log out" /> <Preference icon="system-reboot-symbolic" command="systemctl reboot --boot-loader-entry=menu" label="Reboot to bootloader" /> </box> </box> </window> }