From 315becb78eb48be186f2370ae6c5efd3e967c12d Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 14 Sep 2026 12:32:19 +0200 Subject: feat(desktop): move vm-manager in as the vm module Virsh.qml is unchanged; VmPanel's body becomes the page and the stat row becomes a Flow, because four stats with 150px bars do not fit a 600px drawer as one row. The page starts and stops Virsh.sampling, so the 2s poll runs only while something is looking at it; the lifecycle event stream still runs always, which is what keeps the tile's dots current. --- vm-manager/README.md | 125 --------------------------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 vm-manager/README.md (limited to 'vm-manager/README.md') diff --git a/vm-manager/README.md b/vm-manager/README.md deleted file mode 100644 index bcf12ac..0000000 --- a/vm-manager/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# vm-manager - -A drawer for libvirt virtual machines: state, live statistics, the actions -that make sense in the current state, and the snapshot list. It replaces the -menu half of `rofi-qemu.sh`, which could only ever show a list of strings. - - ┌─ buildsystem ───────────────── ● running ─┐ - │ CPU 4% RAM 0.7/16 GB Disk 60/130 GB │ - │ 172.16.34.20 │ - │ [Shutdown] [Reboot] [Suspend] [Reset] │ - │ snapshots │ - │ working 2026-03-06 10:27 │ - └───────────────────────────────────────────┘ - -## Running it - - qs -p . - -`SUPER+v` toggles it, through an IPC call, so the shell has to be running -first. Both are wired in the Hyprland config: - - -- autostart.lua - hl.exec_cmd("qs -p ~/Programming/GIT/quickshell/vm-manager") - - -- keybindings.lua - hl.bind(mainMod .. " + v", hl.dsp.exec_cmd( - "qs -p ~/Programming/GIT/quickshell/vm-manager ipc call panel toggle")) - -Write those two paths out in full in the real config: `exec_cmd` runs the -command directly, with no shell to expand `~`. - -The drawer opens on the monitor named by the `monitor` property at the top of -`VmPanel.qml`, defaulting to `DP-3`, and falls back to the first screen when -that one is not connected. It dims the rest of that monitor, because the -secondary screen usually has a real window on it, and takes keyboard focus so -Escape closes it and a delete can be confirmed by typing. - -## Where the numbers come from - -Everything shells out to `virsh`, the same commands the rofi script used. No -libvirt bindings, no new dependency. - -| Row | Source | -| ---------- | ------------------------------------------------- | -| state | `virsh domstats --state` | -| CPU | `cpu.time` sampled twice, divided by vCPU count | -| RAM | `virsh dommemstat`: `actual - usable` | -| Disk | guest agent `guest-get-fsinfo`, the `/` mount | -| address | `virsh domifaddr --source agent` | -| snapshots | `virsh snapshot-list` | - -Three of those need **qemu-guest-agent running inside the guest**. It is not -up for the first few seconds after boot, and another VM might not have it at -all, so those rows show `—` and the header says `agent starting` rather than -substituting a host-side figure. That distinction matters: libvirt's own -`balloon.current` is memory *allocated* to the VM, which on a VM that has -booted reads as 100% forever, and `block.0.allocation` is qcow2 growth on the -host, not usage inside the guest. Showing either in place of the real number -would be quietly wrong, so they are not used as a fallback. - -## Live without polling - -`virsh event --all --loop` streams lifecycle changes, and that process runs -for the whole session, panel open or not. Starting a VM from `virsh` or -virt-manager updates the drawer, and opening it shows current state rather -than whatever was true last time. - -Statistics do need sampling, on a 2 second timer, but only while the drawer -is open: `Virsh.sampling` follows the panel's `open`. A closed panel costs one -idle process waiting on an event socket. - -## Two things that bite - -**A config with no visible window exits.** The drawer is closed most of the -time, so the shell holds itself open with a 1x1 transparent window with an -empty mask, which is click-through and draws nothing. Without it the shell -loads, reports no error and quits, and since `SUPER+v` reaches it over IPC, -the key then has nothing to talk to and silently does nothing. - -**Key events reach an item, not a window.** Setting `keyboardFocus` on the -layer shell is necessary but not sufficient: `Keys.onEscapePressed` on the -PanelWindow itself never fires, because no item inside holds focus. A filled -`Item` with `focus: true` catches it, and takes focus back when the TextInput -in a delete confirmation gives it up. - -## Destructive actions - -`Discard saved state` appears on a shut-off VM only when one actually exists, -and runs `virsh managedsave-remove`. A VM that was saved rather than shut down -restores that memory image on the next `start`, and when the image cannot be -restored the start fails every time with a QEMU `migrate-incoming` error while -the panel shows an ordinary `shut off`. Discarding it deletes the memory image -and nothing else, so the next start is a cold boot and the disk is untouched. -That is why it takes a confirmation but not a typed name. - -Detection is `virsh dominfo`, grepped for `Managed save: yes`, once per VM on -every list refresh. `domstats` does not carry it and `virsh list --name` drops -the column that would. - -`Reset`, `Force stop`, snapshot `Revert` and snapshot `Delete` each take one -confirmation click. `Delete VM` requires the machine's name to be typed, -because it runs `virsh undefine --remove-all-storage`, which erases the disk -image with no undo. The rofi script ran exactly that from a single menu -selection with no confirmation at all. - -Failures are reported with `notify-send`, since a `virsh` error otherwise has -nowhere to go: the process output is not attached to a terminal. - -## Theme - -`Theme.qml` carries only fallbacks. The palette comes from -`~/.cache/wal/udt-palette.qml`, generated by `udt-accent` from -unified-desktop-theme's `palette.rasi`, and is watched: editing the palette -there recolours a running drawer without restarting it. State dots use the -green, yellow and red from that palette. - -The frosting is Hyprland's, matched on this window's namespace: - - hl.layer_rule({ - name = "blur-vm-manager", - match = { namespace = "^(quickshell-vm-manager)$" }, - blur = true, - xray = false, - ignore_alpha = 0.1, - }) -- cgit v1.2.3