aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md46
1 files changed, 42 insertions, 4 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 1483a6d..2a9bdb9 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -42,7 +42,8 @@ UI thread Worker thread
MainWindow NotmuchWorker
├ query row: QComboBox, QLineEdit, └ owns the only notmuch_database_t*
│ saved-query QPushButtons
- ├ QTableView ── ThreadListModel (SubjectDelegate)
+ ├ ThreadListView ── ThreadListModel
+ │ (RowStyleDelegate every column, SubjectDelegate on Subject)
└ MessageView (header QLabel, QWebEngineView, attachment bar, TagStrip)
Config (INI) KeyMap MailSync (QProcess) MimeParser (GMime)
@@ -53,9 +54,21 @@ The query row and the message-pane header are **built inline in `MainWindow` and
`MessageView`**, not as named widget classes. Earlier revisions of this diagram
listed `QueryBar`, `SavedQueryBar`, `HeaderWidget` and `AttachmentBar`; none of
those types have ever existed, and looking for them wastes a search. The widget
-classes that do exist are `MessageView`, `TagStrip`, `TagDialog` and
-`SubjectDelegate`; `TagChip` is a namespace of painting helpers, not a widget,
-and `ThreadCidMap` is a struct.
+classes that do exist are `MessageView`, `ThreadListView`, `TagStrip`,
+`TagDialog`, `RowStyleDelegate` and `SubjectDelegate`; `TagChip` is a namespace
+of painting helpers, not a widget, and `ThreadCidMap` is a struct.
+
+**`ThreadListView` exists because a delegate cannot paint outside its column.**
+The tag chips under each row are one strip spanning the whole width, so they
+are drawn in the view's `paintEvent` after the cells. Consequences that are
+easy to undo by accident: `SubjectDelegate` reads `AccountLabelRole`, which
+belongs to the ROW, so installing it view-wide draws the account chip into
+every column (a `Q_ASSERT` catches this); row height must be set on the
+vertical header, since a table takes one height per row and a column's
+`sizeHint` only applies if the view happens to ask that column; and because
+alternating colours, the selection and the model's `BackgroundRole` are all
+painted per cell, the view has to fill the strip's band itself, honouring all
+three or a deleted row is cut in half and every other row shows a bare stripe.
**No `notmuch_*` pointer ever crosses the thread boundary.** Data crosses as the plain
value structs in `src/types.h` (`ThreadSummary`, `MessageRef`, `TagChange`), over queued
@@ -157,6 +170,31 @@ it. Verify against a real keyboard before changing a default on reachability gro
separate, real trap `normalizeSequence()` handles is a **bare capital** (`N` parses to
unshifted Key_N, which no keystroke emits).
+**Rendering probes lie in specific, repeatable ways.** A whole session was spent chasing
+a defect that did not exist because of these; each was believed until it was contradicted.
+
+- **Counting lit pixels cannot tell bold from regular.** Antialiasing lights a similar
+ number either way, so an "ink count" reads identical whichever is true, in both
+ directions. It measures nothing. **Text width** distinguishes weights (277px against
+ 306px for one string at 12pt), and a **strict pixel diff** distinguishes renders.
+- **`viewport()->render()` returns a blank image** in several ordinary situations: before
+ the widget is exposed, when the content sits outside a viewport narrower than the
+ columns, and sometimes with no discernible cause. A probe that reports "no ink anywhere"
+ is far more likely broken than the code it is testing. Check that it finds the thing it
+ expects to find *before* trusting it to report the thing it expects to miss.
+- **A "saturated pixel" threshold catches antialiased edges of the selection highlight**,
+ hundreds of distinct near-background colours, and will pass whatever the code does. Match
+ the exact colours the model supplies instead. Two versions of one test passed under
+ mutation before this was noticed.
+- Every rendering test needs a **mutation check** and a guard proving it *can* fail: assert
+ the geometry it depends on (a column is on screen, a row has non-zero height) rather than
+ assuming it.
+
+The bug that started all this was not in the code at all: the desktop's Qt font was
+configured **Bold** in qt6ct, so every row rendered bold and `setBold(true)` changed
+nothing. Before concluding a Qt facility is broken, check the desktop's own font and theme
+configuration.
+
## Web view security
The most security-sensitive area: a browser engine pointed at input from strangers. Do not