aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-17 19:25:01 +0200
committerDanilo M. <danix@danix.xyz>2026-09-17 19:25:01 +0200
commitf0790a43f2b7d94b3847135120bb92782eaa892d (patch)
treedcc61d836266b620e2c66b262e9061e4f72baca0
parentbff7023cd028b06a3e3d841b9769c3b46da06d0d (diff)
downloadconky-theme-udt-f0790a43f2b7d94b3847135120bb92782eaa892d.tar.gz
conky-theme-udt-f0790a43f2b7d94b3847135120bb92782eaa892d.zip
feat: name the CPU and motherboard on the system card
Both read once: neither changes without a reboot, and /proc/cpuinfo repeats its model-name line once per thread. The two rows come out of the equaliser's height budget, since it is the card's designated slack absorber. Its floor drops from 18px to zero: with rows above it the band can genuinely run out of room, and a fixed floor meant it kept height it did not have and the temperatures drew over it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--widgets/system.lua56
1 files changed, 53 insertions, 3 deletions
diff --git a/widgets/system.lua b/widgets/system.lua
index 1db3c45..03cd70a 100644
--- a/widgets/system.lua
+++ b/widgets/system.lua
@@ -27,6 +27,26 @@ local TEMPS = {
local counters = {}
local total_counter = data.new_cpu_counter()
+-- 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
@@ -37,6 +57,7 @@ function M.draw(cr, rect, colors)
local load_txt = load and string.format('%d%%', math.floor(load + 0.5)) or '--'
local cores = data.per_cpu_times(stat 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,
@@ -45,6 +66,8 @@ function M.draw(cr, rect, colors)
local LABEL_F, BIG_F, ROW_F = 0.30, 1.0, 0.32
local groups = {
{ { '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
@@ -53,7 +76,11 @@ function M.draw(cr, rect, colors)
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
@@ -72,16 +99,39 @@ function M.draw(cr, rect, colors)
card.rgba(cr, colors.label)
card.text(cr, inner.x, y + label_size, 'CPU')
+ -- 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.
+ 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)
+ card.rgba(cr, colors.label)
+ local id_limit = math.max(8, math.floor(inner.w / (row_size * 0.55)))
+ if cpu_txt then
+ 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.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.
- local eq_top = y + big_size + S * 0.30
+ -- 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),
- 18, math.huge)
+ 0, math.huge)
local n = #cores
- if n > 0 then
+ 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