[AGS] Bar: Done (WiFi still missing, will be added at some later point)
This commit is contained in:
211
config/astal/components/bar/modules/SystemInfo.tsx
Normal file
211
config/astal/components/bar/modules/SystemInfo.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import { exec, execAsync, GLib, interval, Variable } from "astal";
|
||||
import { Gtk } from "astal/gtk4";
|
||||
import AstalBattery from "gi://AstalBattery?version=0.1";
|
||||
|
||||
const FETCH_INTERVAL = 2000;
|
||||
|
||||
const cpuUtil = Variable("0%");
|
||||
const ramUtil = Variable("0%");
|
||||
const ramUsed = Variable("0MiB");
|
||||
const gpuUtil = Variable("0%");
|
||||
let gpuName = "card1";
|
||||
let enabled = false;
|
||||
|
||||
const refreshStats = (): Stats => {
|
||||
gpuName = exec(`/bin/bash -c "ls /sys/class/drm/ | grep '^card[0-9]*$'"`);
|
||||
const cpuNameInSensors = "CPUTIN";
|
||||
const stats = {
|
||||
kernel: exec("uname -sr"),
|
||||
netSpeed: exec(
|
||||
`/bin/bash -c "interface=$(ip route get 8.8.8.8 | awk '{print $5; exit}') && cat \"/sys/class/net/$interface/speed\""`,
|
||||
),
|
||||
cpuTemp: exec(
|
||||
`/bin/bash -c "sensors | grep -m1 ${cpuNameInSensors} | awk '{print $2}'"`,
|
||||
),
|
||||
cpuClk: exec(
|
||||
`awk '/cpu MHz/ {sum+=$4; ++n} END {print sum/n " MHz"}' /proc/cpuinfo`,
|
||||
),
|
||||
gpuTemp: exec(
|
||||
`/bin/bash -c "sensors | grep -E 'edge' | awk '{print $2}'"`,
|
||||
),
|
||||
gpuClk: exec(
|
||||
`/bin/bash -c "cat /sys/class/drm/${gpuName}/device/pp_dpm_sclk | grep '\\*' | awk '{print $2 $3}'"`,
|
||||
),
|
||||
vram:
|
||||
Math.round(
|
||||
parseInt(
|
||||
exec(
|
||||
`cat /sys/class/drm/${gpuName}/device/mem_info_vram_used`,
|
||||
),
|
||||
) /
|
||||
1024 /
|
||||
1024,
|
||||
) + "MiB",
|
||||
availableVRAM:
|
||||
Math.round(
|
||||
parseInt(
|
||||
exec(
|
||||
`cat /sys/class/drm/${gpuName}/device/mem_info_vram_total`,
|
||||
),
|
||||
) /
|
||||
1024 /
|
||||
1024,
|
||||
) + "MiB",
|
||||
};
|
||||
|
||||
return stats;
|
||||
};
|
||||
|
||||
const systemStats: Variable<Stats> = Variable(refreshStats());
|
||||
|
||||
const availableFeatures = {
|
||||
cpu: true,
|
||||
ram: true,
|
||||
};
|
||||
|
||||
const featureTest = () => {
|
||||
// Check if awk & sed are available
|
||||
try {
|
||||
exec("awk -V");
|
||||
exec("sed --version");
|
||||
enabled = true;
|
||||
} catch (e) {
|
||||
printerr(
|
||||
"[ SysInfo ] AWK or SED missing! No system info will be available",
|
||||
);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if mpstat is available
|
||||
try {
|
||||
exec("mpstat -V");
|
||||
} catch (e) {
|
||||
availableFeatures.cpu = false;
|
||||
printerr(
|
||||
"[ SysInfo ] Feature Test for CPU info failed. mpstat from the sysstat package missing!",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const info = () => {
|
||||
return (
|
||||
<box vertical>
|
||||
<label
|
||||
label={"System Information"}
|
||||
cssClasses={["title-2"]}
|
||||
></label>
|
||||
<Gtk.Separator marginTop={5} marginBottom={10}></Gtk.Separator>
|
||||
<label
|
||||
vexpand
|
||||
halign={Gtk.Align.START}
|
||||
hexpand
|
||||
label={ramUsed(used => {
|
||||
return "RAM: " + used + ` (${ramUtil.get()}%)`;
|
||||
})}
|
||||
></label>
|
||||
<label
|
||||
label={systemStats(stats => {
|
||||
return `CPU: ${stats.cpuTemp}, ${stats.cpuClk}
|
||||
GPU: ${stats.gpuTemp}, ${stats.gpuClk} (${stats.vram} / ${stats.availableVRAM})
|
||||
Network: ${stats.netSpeed} mb/s
|
||||
Kernel: ${stats.kernel}`;
|
||||
})}
|
||||
></label>
|
||||
<Gtk.Separator marginTop={10}></Gtk.Separator>
|
||||
<button
|
||||
onClicked={() => exec( `/bin/sh -c "kitty --hold fish -c 'fastfetch'"` )}
|
||||
child={
|
||||
<label label={"View FastFetch"}></label>
|
||||
}></button>
|
||||
</box>
|
||||
);
|
||||
};
|
||||
|
||||
const SystemInformationPanel = () => {
|
||||
const popover = new Gtk.Popover();
|
||||
|
||||
popover.set_child(info());
|
||||
|
||||
return popover;
|
||||
};
|
||||
|
||||
const sysInfoFetcher = () => {
|
||||
if (enabled) {
|
||||
if (availableFeatures.cpu) {
|
||||
cpuUtil.set(
|
||||
"" +
|
||||
Math.round(
|
||||
parseFloat(exec(`/bin/fish -c cpu-utilization`)),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (availableFeatures.ram) {
|
||||
ramUtil.set(
|
||||
"" +
|
||||
Math.round(
|
||||
parseFloat(
|
||||
exec(
|
||||
`/bin/bash -c "free | awk '/Mem/ { printf(\\"%.2f\\\\n\\", ($3/$2)*100) }'"`,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
ramUsed.set(
|
||||
exec(
|
||||
`/bin/bash -c \"free -h | awk '/^Mem:/ {print $3 \\" used of \\" $2}'\"`,
|
||||
)
|
||||
.replaceAll("Gi", "GiB")
|
||||
.replaceAll("Mi", "MiB"),
|
||||
);
|
||||
}
|
||||
gpuUtil.set(exec("cat /sys/class/drm/card1/device/gpu_busy_percent"));
|
||||
}
|
||||
};
|
||||
|
||||
const panel = SystemInformationPanel();
|
||||
|
||||
const SystemInfo = () => {
|
||||
featureTest();
|
||||
|
||||
const openSysInfo = async () => {
|
||||
panel.popup();
|
||||
systemStats.set(refreshStats());
|
||||
};
|
||||
|
||||
if (enabled) {
|
||||
sysInfoFetcher();
|
||||
interval(FETCH_INTERVAL, sysInfoFetcher);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClicked={() => openSysInfo()}
|
||||
child={
|
||||
<box tooltipText={ramUsed(v => v)}>
|
||||
<image
|
||||
iconName={"power-profile-performance-symbolic"}
|
||||
marginEnd={1}
|
||||
></image>
|
||||
<label
|
||||
label={cpuUtil(util => util)}
|
||||
marginEnd={5}
|
||||
></label>
|
||||
<image iconName={"histogram-symbolic"}></image>
|
||||
<label label={ramUtil(util => util)}></label>
|
||||
<image iconName={"show-gpu-effects-symbolic"}></image>
|
||||
<label label={gpuUtil(util => util)}></label>
|
||||
{panel}
|
||||
</box>
|
||||
}
|
||||
cssClasses={["bar-button"]}
|
||||
></button>
|
||||
);
|
||||
} else {
|
||||
return <image iconName={"action-unavailable-symbolic"}></image>;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
SystemInfo,
|
||||
panel,
|
||||
};
|
Reference in New Issue
Block a user