Files
claude-code-gnome-extension/lib/glyph.js
T
av 839c6f6b52 Drop colour from the panel, and the message that said nothing
Two changes that turned out to be related.

The chips painted their own red, amber and green. An indicator that picks
its own colours competes with the shell's accents and stops following the
theme, so the panel now draws everything in the panel's text colour and
lets shape carry the state. Only alpha still varies, to push idle sessions
back.

That put real weight on the four shapes being distinguishable at 14 px,
which is not something to guess at, so the drawing moved to lib/glyph.js
-- free of St, Clutter and shell imports precisely so the glyphs can be
rendered to a file and looked at. They were, and the first attempt was
wrong twice: a disc filled to the ring's centreline reads smaller than the
ring beside it, and the inner disc of "blocked" was too small to tell from
a plain "working" ring. Radii are now matched at the outer edge and the
inner disc sits at 0.55, both settled by comparing renders.

Separately, hooking a live session showed the Notification that accompanies
a permission prompt carries only "Claude needs your permission" -- no tool,
no command -- and arrives identically when the session is putting a question
to the user rather than asking to run something. The menu was giving that
string the line, pushing out the tab and the path: strictly less information
in more space. It is gone, and the comment claiming it "says what is about
to run" is corrected. Recovering the real command means reading the tail of
the transcript when the prompt fires; it is not in the event.

The same finding settles how far the states can split. "Blocked" cannot be
divided into "asking permission" and "asking a question" from this data.
2026-08-09 19:02:43 +03:00

56 lines
2.2 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:
// Idle: same ring as "working", but dashed and dimmed. Reading as a
// fainter version of a state you already know is the point -- nobody
// is waiting on it.
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;
}
}