diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-13 11:35:00 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-13 11:35:00 +0200 |
| commit | 3943e08dabe684b409a3ac99c9371fbeb5df5cdb (patch) | |
| tree | 7dcedbb2d64a04e59ab239a8c40c04f0f0cf29aa /widgets/system.lua | |
| parent | b2fe3f493efc12dd300f0e2b2ede5660ee70c193 (diff) | |
| download | conky-theme-udt-3943e08dabe684b409a3ac99c9371fbeb5df5cdb.tar.gz conky-theme-udt-3943e08dabe684b409a3ac99c9371fbeb5df5cdb.zip | |
The quickshell island's performance panel now shows CPU, RAM,
temperatures, the GPU, disks and network, and warns from the status
pill when something runs hot, fills up, or the public IP drifts from
the pinned one. Two dashboards drawing the same numbers would drift
apart, so the four widgets go, with the disks and public IP samplers.
The island keeps writing ~/.cache/udt/pubip.txt in the same format.
The freed space is left empty for the user to rearrange.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Diffstat (limited to 'widgets/system.lua')
| -rw-r--r-- | widgets/system.lua | 198 |
1 files changed, 0 insertions, 198 deletions
diff --git a/widgets/system.lua b/widgets/system.lua deleted file mode 100644 index c1cdf67..0000000 --- a/widgets/system.lua +++ /dev/null @@ -1,198 +0,0 @@ --- System: CPU load as a per-core equaliser, memory, and every temperature. --- --- The hwmon bindings and temperature ceilings below are host-specific, which --- is why they live here rather than in lib/data.lua: that file is the part --- that ports to another machine, this is the part that does not. - -local card = require 'lib.card' -local data = require 'lib.data' - -local M = {} - --- chip, file, label, warn, crit. --- --- Ceilings are per sensor because a single pair cannot serve both: 70C is --- unremarkable on a CPU package and alarming on an NVMe. Starting values, --- easy to retune once real numbers under load are known. -local TEMPS = { - { 'k10temp', 'temp1_input', 'CPU', 75, 90 }, - { 'k10temp', 'temp3_input', 'CCD1', 75, 90 }, - { 'nvme', 'temp1_input', 'NVME', 60, 70 }, - { 'gigabyte_wmi', 'temp2_input', 'BOARD', 60, 70 }, - { 'gigabyte_wmi', 'temp3_input', 'BOARD', 60, 70 }, -} - --- One counter per core, created on first draw and kept for the process's life: --- load is a delta between samples, so the state has to outlive the frame. -local counters = {} -local total_counter = data.new_cpu_counter() - --- Sampled every ~2s whatever the draw rate; the values between samples are --- the last ones read. 1.9 not 2: draws jitter by a few ms either way. -local gate = data.new_gate(1.9) -local load, pcts = nil, {} - --- Read once, not per frame. Neither can change without a reboot, and --- re-reading /proc/cpuinfo every two seconds for a constant is waste: the file --- repeats its model-name line once per thread. --- --- `false` is the cached miss, distinct from nil meaning "not looked up yet", --- so an absent DMI table is not re-read on every draw. -local cpu_name, board = nil, nil - -local function hardware() - if cpu_name == nil then - cpu_name = data.cpu_model(data.slurp('/proc/cpuinfo') or '') or false - end - if board == nil then - local dmi = '/sys/devices/virtual/dmi/id/' - board = data.board_name(data.slurp(dmi .. 'board_vendor'), - data.slurp(dmi .. 'board_name')) or false - end - return cpu_name or nil, board or nil -end - -function M.draw(cr, rect, colors) - local inner = card.card(cr, rect, colors) - local function clamp(v, lo, hi) return math.max(lo, math.min(hi, v)) end - - if gate() then - local stat = data.slurp('/proc/stat') or '' - load = total_counter:sample(data.cpu_times(stat)) - for i, c in ipairs(data.per_cpu_times(stat)) do - counters[i] = counters[i] or data.new_cpu_counter() - pcts[i] = counters[i]:sample(c.total, c.idle) or 0 - end - end - local load_txt = load and string.format('%d%%', math.floor(load + 0.5)) or '--' - local temp_n = #TEMPS - local cpu_txt, board_txt = hardware() - - -- Fluid type. One base size S drives the label, headline, RAM and every - -- temperature row; the equaliser then absorbs the vertical room left over, - -- so the card fills its cell and S shrinks only where a row would overrun - -- the width. card.fit_unit supplies the width side of that. - local LABEL_F, BIG_F, ROW_F = 0.30, 1.0, 0.32 - local groups = { - { { card.title_str(card.ICON.system, 'CPU'), card.FONT_MONO, LABEL_F }, - { load_txt, card.FONT_HEAVY, BIG_F } }, - { { cpu_txt or '', card.FONT_MONO, ROW_F } }, - { { board_txt or '', card.FONT_MONO, ROW_F } }, - { { 'RAM', card.FONT_MONO, ROW_F }, { '999.9G / 999.9G', card.FONT_MONO, ROW_F } }, - } - for _, t in ipairs(TEMPS) do - groups[#groups + 1] = { { t[3], card.FONT_MONO, ROW_F }, - { '888\u{00B0}', card.FONT_MONO, ROW_F } } - end - -- Height the non-equaliser content needs, in units of S, plus a reserve for - -- the equaliser band. The smaller of that budget and the width fit is S. - -- The two identification rows come out of the equaliser's budget: it is the - -- card's designated slack absorber, so it is what gives up the height. - local id_rows = (cpu_txt and 1 or 0) + (board_txt and 1 or 0) - local fixed_units = 1.00 + 1.13 + temp_n * ROW_F * 1.8 + 0.10 - + id_rows * ROW_F * 1.5 - local S = clamp(math.min(inner.h * 0.96 / (fixed_units + 1.7), - card.fit_unit(cr, inner.w * 0.96, groups, 100)), 10, 72) - local label_size = S * LABEL_F - local big_size = S * BIG_F - local row_size = S * ROW_F - - local y = inner.y - - -- Aggregate load, the headline number. It takes the header line, right - -- aligned like the big value on every other card, with the label top-left. - card.font(cr, card.FONT_HEAVY, big_size, false) - card.rgba(cr, load and card.threshold(load, 25, 75, colors) or colors.label) - card.text_right(cr, inner.x + inner.w, y + big_size, load_txt) - - card.font(cr, card.FONT_MONO, label_size, false) - card.title(cr, inner.x, y + label_size, card.ICON.system, 'CPU', colors) - - -- The hardware this card is about, under the header. Truncated by character, - -- never by byte: a model string can carry a multi-byte character and half of - -- one draws as a replacement box. - -- Two accents rather than one label colour: the rows name two different - -- pieces of hardware, and giving each its own hue separates them at a glance - -- without a prefix like 'CPU:' eating the width. `heading` and `highlight` - -- are the two roles that carry no state meaning, so they can stand for an - -- identity; ok/warning/critical could not, since those say how something is - -- doing and these strings never change. - local id_y = y + big_size + row_size * 0.2 - if cpu_txt or board_txt then - card.font(cr, card.FONT_MONO, row_size, false) - local id_limit = math.max(8, math.floor(inner.w / (row_size * 0.55))) - if cpu_txt then - card.rgba(cr, colors.heading) - card.text(cr, inner.x, id_y, card.truncate(cpu_txt, id_limit)) - id_y = id_y + row_size * 1.5 - end - if board_txt then - card.rgba(cr, colors.highlight) - card.text(cr, inner.x, id_y, card.truncate(board_txt, id_limit)) - id_y = id_y + row_size * 1.5 - end - end - - -- The equaliser: one bar per core, rising from a common baseline. It takes - -- the room left between the header and the RAM/temperature block, so it is - -- the card's slack absorber. - -- Below the identification rows when there are any, otherwise where it was. - local eq_top = (cpu_txt or board_txt) and (id_y + S * 0.10) or (y + big_size + S * 0.30) - local bar_h = S * 0.18 - local step = row_size * 1.8 - -- The floor was a flat 18px. With the identification rows above it the - -- equaliser can genuinely run out of room, and a fixed floor means it keeps - -- height it does not have and the temperature rows draw over it. Zero is a - -- legitimate outcome: the guard below skips the band when it has no height. - local eh = clamp((inner.y + inner.h) - eq_top - (S * 1.13 + temp_n * step), - 0, math.huge) - local n = #pcts - if n > 0 and eh >= 8 then - local gap = math.max(2, inner.w * 0.006) - local bw = (inner.w - gap * (n - 1)) / n - -- Below about 3px a row of sixteen bars is an illegible smear; drop to the - -- aggregate bar instead of drawing one. - if bw >= 3 then - for i, pct in ipairs(pcts) do - card.vbar(cr, inner.x + (i - 1) * (bw + gap), eq_top + eh, bw, eh, - pct / 100, card.threshold(pct, 25, 75, colors), colors) - end - else - card.bar(cr, inner.x, eq_top + eh - bar_h, inner.w, bar_h, (load or 0) / 100, - card.threshold(load or 0, 25, 75, colors), colors) - end - end - local ey = eq_top + eh + S * 0.30 - - -- Memory. MemAvailable, not free: it already excludes reclaimable cache, so - -- it is the figure a person recognises as "used". - local mem = data.mem_info(data.slurp('/proc/meminfo') or '') - if mem then - local frac = mem.used / mem.total - card.font(cr, card.FONT_MONO, row_size, false) - card.rgba(cr, colors.label) - card.text(cr, inner.x, ey, 'RAM') - card.rgba(cr, colors.value) - card.text_right(cr, inner.x + inner.w, ey, - string.format('%s / %s', card.human(mem.used * 1024), card.human(mem.total * 1024))) - ey = ey + S * 0.30 - card.bar(cr, inner.x, ey, inner.w, bar_h, frac, - card.threshold(frac * 100, 25, 75, colors), colors) - ey = ey + bar_h + S * 0.35 - end - - -- Temperatures, each against its own ceiling. - card.font(cr, card.FONT_MONO, row_size, false) - for _, t in ipairs(TEMPS) do - if ey + step > inner.y + inner.h then break end -- out of room: stop - local v = data.sensor(t[1], t[2]) - card.rgba(cr, colors.label) - card.text(cr, inner.x, ey, t[3]) - card.rgba(cr, v and card.threshold(v, t[4], t[5], colors) or colors.label) - card.text_right(cr, inner.x + inner.w, ey, - v and string.format('%d\u{00B0}', v) or '--') - ey = ey + step - end -end - -return M |
