"Idle" was set by SessionStart and by nothing else, and there was no path back into it. So it never meant "sitting unused" -- it meant "opened and never asked anything yet", a state a few seconds long that you would almost never catch. Meanwhile a session that finished an hour ago and was forgotten showed as waiting, which is correct but leaves the fourth state with nothing to describe. A session that has just opened is waiting for your first prompt exactly as one that finished a turn is waiting for your next. They are the same thing, and now they are the same state. Three glyphs instead of four, which also gives the remaining three more room to be told apart in a monochrome panel. Files written by the previous hook still say "idle", and a session open across the upgrade must not disappear, so unrecognised states now read as waiting rather than being treated as unknown. Covered by a test that feeds an "idle" file to the store and asserts it comes back as waiting, sorted by age among the others. The "hide when nothing is running" setting goes with it. Its condition was "no sessions, or all of them idle"; with idle gone the second half is unreachable and the first was already unconditional, so the switch could no longer change anything. A control that does nothing is worse than no control. The compaction test also got stronger in passing: it now checks that a mid-turn SessionStart leaves a *busy* session alone, which is the case that matters. It used to assert from waiting, where the state it was guarding against happened to be the state already stored.
57 lines
2.3 KiB
JavaScript
57 lines
2.3 KiB
JavaScript
// State glyphs, drawn with cairo alone.
|
|
//
|
|
// The panel is monochrome, so shape is the only channel left and these four
|
|
// have to stay apart at 14 px. Kept free of St/Clutter/GNOME imports so the
|
|
// shapes can be rendered to a file and looked at, rather than guessed about.
|
|
|
|
/** Draw `state` filling the given box, in the colour passed as {r,g,b,a} 0..1. */
|
|
export function drawState(cr, state, width, height, color) {
|
|
const { r, g, b, a } = color;
|
|
const LINE = 1.75;
|
|
const cx = width / 2;
|
|
const cy = height / 2;
|
|
// Centreline of the ring. A stroke straddles it, so a disc filled to this
|
|
// radius reads visibly smaller than a ring drawn at it -- the filled states
|
|
// below use `outer` instead, which keeps every glyph the same size.
|
|
const radius = Math.min(width, height) / 2 - LINE;
|
|
const outer = radius + LINE / 2;
|
|
|
|
cr.setLineWidth(LINE);
|
|
cr.setSourceRGBA(r, g, b, a);
|
|
|
|
switch (state) {
|
|
case 'blocked':
|
|
// Disc inside a ring: the most ink of the four, for the only state
|
|
// where a session is stuck until you act. The inner disc has to be
|
|
// big enough to register at 14 px, or this reads as plain "working".
|
|
cr.arc(cx, cy, radius, 0, 2 * Math.PI);
|
|
cr.stroke();
|
|
// 0.55 of the ring radius: below that the centre stops registering at
|
|
// 14 px and this collapses into the "working" ring; above it the gap
|
|
// closes and it collapses into the "waiting" disc. Checked by
|
|
// rendering, not guessed.
|
|
cr.arc(cx, cy, radius * 0.55, 0, 2 * Math.PI);
|
|
cr.fill();
|
|
break;
|
|
case 'waiting':
|
|
cr.arc(cx, cy, outer, 0, 2 * Math.PI);
|
|
cr.fill();
|
|
break;
|
|
case 'busy':
|
|
cr.arc(cx, cy, radius, 0, 2 * Math.PI);
|
|
cr.stroke();
|
|
break;
|
|
default:
|
|
// Fallback for a state this build does not know, which should not
|
|
// happen: sessions.js normalises anything unrecognised to "waiting".
|
|
// Drawn dashed and dim so an unknown state looks uncertain rather than
|
|
// impersonating one of the three real ones.
|
|
cr.setDash([2, 2], 0);
|
|
cr.setSourceRGBA(r, g, b, a * 0.5);
|
|
cr.arc(cx, cy, radius, 0, 2 * Math.PI);
|
|
cr.stroke();
|
|
cr.setDash([], 0);
|
|
break;
|
|
}
|
|
}
|