import GLib from "gi://GLib"; import Astal from "gi://Astal"; import AstalHyprland from "gi://AstalHyprland"; import Gio from "gi://Gio"; import Gtk from "gi://Gtk"; import Gdk from "gi://Gdk"; import { exec } from "gi://GLib"; function getSystemStats() { const cpu = exec("sh -c 'top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk \"{print 100 - $1}\"'"); const memory = exec("free | grep Mem | awk '{print $3/$2 * 100.0}'"); const brightness = exec("brightnessctl g"); const battery = exec("cat /sys/class/power_supply/BAT0/capacity"); return { cpu, memory, brightness, battery }; } function getWorkspaceNumber() { return AstalHyprland.get_default().get_active_workspace().get_id(); } function getWindowTitle() { return exec("xdotool getactivewindow getwindowname"); } function getDateTime() { return GLib.DateTime.new_now_local().format("%a %b %d, %Y %H:%M:%S"); } function createQuickActionMenu() { const menu = new Gtk.Menu(); const volumeItem = new Gtk.MenuItem({ label: "🔊 Volume" }); const micItem = new Gtk.MenuItem({ label: "🎙️ Microphone" }); const wifiItem = new Gtk.MenuItem({ label: "📶 WiFi" }); const powerItem = new Gtk.MenuItem({ label: "🔌 Power" }); menu.append(volumeItem); menu.append(micItem); menu.append(wifiItem); menu.append(powerItem); volumeItem.show(); micItem.show(); wifiItem.show(); powerItem.show(); return menu; } function Bar(gdkmonitor) { const { cpu, memory, brightness, battery } = getSystemStats(); const workspaceNumber = getWorkspaceNumber(); const windowTitle = getWindowTitle(); const dateTime = getDateTime(); const quickActionMenu = createQuickActionMenu(); return ( ); } function createQuickActionsMenu() { const wifi = AstalNetwork.get_default().get_wifi(); const bt = AstalBluetooth.get_default().get_adapter(); const wifiSub = new Gtk.Menu(); const btSub = new Gtk.Menu(); function refreshWifiMenu() { wifiSub.foreach(c => wifiSub.remove(c)); for (const ap of wifi.get_access_points()) { const item = new Gtk.MenuItem({ label: `${ap.get_ssid()} (${ap.get_strength()}%)` }); item.connect("activate", () => wifi.connect_access_point(ap)); item.show(); wifiSub.append(item); } } function refreshBtMenu() { btSub.foreach(c => btSub.remove(c)); for (const dev of AstalBluetooth.get_default().get_devices()) { const name = dev.get_name(); const label = dev.get_connected() ? `✔ ${name}` : name; const item = new Gtk.MenuItem({ label }); item.connect("activate", () => { dev.get_connected() ? dev.disconnect_device() : dev.connect_device(); }); item.show(); btSub.append(item); } } return ( {createToggleRow({ label: "📶 WiFi", active: wifi.get_state() !== AstalNetwork.WifiState.DISCONNECTED, onToggle: () => { wifi.get_state() === AstalNetwork.WifiState.DISCONNECTED ? wifi.connect() : wifi.disconnect(); }, onExpand: () => { refreshWifiMenu(); wifiSub.popup(); } })} {createToggleRow({ label: "🔵 Bluetooth", active: bt.get_powered(), onToggle: () => bt.set_powered(!bt.get_powered()), onExpand: () => { refreshBtMenu(); btSub.popup(); } })} exec("pavucontrol")} /> exec("pavucontrol")} /> exec("power-menu")} /> ); } export { createQuickActionsMenu }; @import "colors"; .toggle-row { background-color: $bg; border-radius: 12px; margin: 6px 0; overflow: hidden; border: 1px solid $border; button { padding: 10px 16px; font-size: 14px; transition: background 0.2s ease; border: none; background: transparent; &:hover { background-color: $hover; } } .toggle { flex: 1; background-color: transparent; text-align: left; &.active { background-color: $accent; color: white; } } .arrow { width: 40px; background-color: transparent; text-align: center; } } .audio-control { display: flex; align-items: center; padding: 8px 12px; gap: 8px; label { min-width: 60px; color: $fg; } scale { flex: 1; } button { background-color: transparent; padding: 6px; border-radius: 6px; &:hover { background-color: $hover; } } } .media-control { padding: 12px; text-align: center; label { display: block; margin-bottom: 6px; } button { margin: 0 4px; padding: 6px 10px; border-radius: 6px; &:hover { background-color: $hover; } } } import Gtk from "gi://Gtk"; import AstalNetwork from "gi://AstalNetwork"; import AstalBluetooth from "gi://AstalBluetooth"; import AstalAudio from "gi://AstalAudio"; import AstalMedia from "gi://AstalMedia"; import { exec } from "gi://GLib"; // Helpers function createToggleRow({ label, active, onToggle, onExpand }) { return ( ); } function createPowerRow({ onExpand }) { return ( ); } function createQuickActionsMenu() { const wifi = AstalNetwork.get_default().get_wifi(); const bt = AstalBluetooth.get_default().get_adapter(); const audio = AstalAudio.get_default(); const media = AstalMedia.get_default(); // Submenus const wifiSub = new Gtk.Menu(); const btSub = new Gtk.Menu(); const powerSub = new Gtk.Menu(); const outputSub = new Gtk.Menu(); const inputSub = new Gtk.Menu(); function refreshWifiMenu() { wifiSub.foreach(c => wifiSub.remove(c)); for (const ap of wifi.get_access_points()) { const item = new Gtk.MenuItem({ label: `${ap.get_ssid()} (${ap.get_strength()}%)` }); item.connect("activate", () => wifi.connect_access_point(ap)); item.show(); wifiSub.append(item); } } function refreshBtMenu() { btSub.foreach(c => btSub.remove(c)); for (const dev of AstalBluetooth.get_default().get_devices()) { const label = dev.get_connected() ? `✔ ${dev.get_name()}` : dev.get_name(); const item = new Gtk.MenuItem({ label }); item.connect("activate", () => dev.get_connected() ? dev.disconnect_device() : dev.connect_device() ); item.show(); btSub.append(item); } } function refreshPowerMenu() { const entries = [ { label: "⏻ Shutdown", cmd: "systemctl poweroff" }, { label: "🔁 Reboot", cmd: "systemctl reboot" }, { label: "🔒 Lock", cmd: "loginctl lock-session" }, { label: "🚪 Logout", cmd: "hyprctl dispatch exit" }, ]; powerSub.foreach(c => powerSub.remove(c)); for (const entry of entries) { const item = new Gtk.MenuItem({ label: entry.label }); item.connect("activate", () => exec(entry.cmd)); item.show(); powerSub.append(item); } } function refreshOutputDevices() { outputSub.foreach(c => outputSub.remove(c)); for (const device of audio.get_outputs()) { const label = device.is_default() ? `✔ ${device.get_description()}` : device.get_description(); const item = new Gtk.MenuItem({ label }); item.connect("activate", () => audio.set_default_output(device)); item.show(); outputSub.append(item); } } function refreshInputDevices() { inputSub.foreach(c => inputSub.remove(c)); for (const device of audio.get_inputs()) { const label = device.is_default() ? `✔ ${device.get_description()}` : device.get_description(); const item = new Gtk.MenuItem({ label }); item.connect("activate", () => audio.set_default_input(device)); item.show(); inputSub.append(item); } } return ( {/* WiFi */} {createToggleRow({ label: "📶 WiFi", active: wifi.get_state() !== AstalNetwork.WifiState.DISCONNECTED, onToggle: () => wifi.get_state() === AstalNetwork.WifiState.DISCONNECTED ? wifi.connect() : wifi.disconnect(), onExpand: () => { refreshWifiMenu(); wifiSub.popup(); }, })} {/* Bluetooth */} {createToggleRow({ label: "🔵 Bluetooth", active: bt.get_powered(), onToggle: () => bt.set_powered(!bt.get_powered()), onExpand: () => { refreshBtMenu(); btSub.popup(); }, })} {/* Output Volume */} audio.set_output_volume(v)} drawValue={false} min={0} max={100} /> {/* Input Volume */} audio.set_input_volume(v)} drawValue={false} min={0} max={100} /> {/* Media Controls */} {media && ( )} {/* Power */} {createPowerRow({ onExpand: () => { refreshPowerMenu(); powerSub.popup(); }, })} ); } export { createQuickActionsMenu };