fix: Wonder Ink prints without crashing, and prints worksheets at all
Little Waders, 0.2.2: SIGSEGV in QPrinter::resolution() every time a teacher confirmed a print job. QWebEngineView.print() keeps the raw QPrinter pointer and returns; Qt's didPrintPage() reads printer->resolution() once Chromium has rendered the page, and by then PyQt had deleted the printer, which print_view() held only as a local. Reproduced in the lab with the 0.2.2 code, same backtrace, no job. Keeping the printer alive fixed the crash and was measured, and Qt's path was still not a print path: a worksheet PDF tab printed as one blank page, a lesson went as 24.6 MB of 300 dpi pictures with no text, and a queue refusing jobs was reported as printed. Print is now: make a PDF (a worksheet already is one; a lesson page is printToPdf'd onto the printer's own paper; an inline PDF is downloaded and opened as a worksheet), show it in a preview with printer, pages, copies and colour, and hand it to CUPS with lp — Chrome's route in the same rooms. Nothing asynchronous holds a printer. Black and white uses the driver's ColorModel=Grayscale, because Elmer's generic PCL 6 driver ignores print-color-mode. An exception escaping any slot no longer aborts Wonder Ink: PyQt6's default is to kill the process, and it is now logged instead. tests/test-classroom-printing.sh: 50 checks. tools/lab/wonderink-print- check: 39 checks over 13 scenarios in the lab, against a queue built from Elmer's PPD, judged by what CUPS received. Not yet on paper. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
690ef95aff
commit
10433b850d
+80
-3
@@ -140,9 +140,8 @@ Alongside it, two Qt defaults are turned off rather than left implicit:
|
||||
`LocalContentCanAccessFileUrls` (on by default, and would let a local
|
||||
document read other local documents) and `LocalContentCanAccessRemoteUrls`.
|
||||
|
||||
The print dialog's **Print to File** option is also removed. Choosing it
|
||||
enables an output path with a "..." button, which is a file chooser, in a
|
||||
room whose whole design is that there is no file chooser.
|
||||
Printing has no **Print to File** and no file chooser of any kind: the
|
||||
preview (below) offers the room's CUPS printers and nothing else.
|
||||
|
||||
### What a teacher still cannot reach
|
||||
|
||||
@@ -182,6 +181,84 @@ is Chrome's business and stays that way.
|
||||
Downloads folder. That is partly tidiness and mostly the security
|
||||
argument: it is the only place a worksheet can come from.
|
||||
|
||||
## Printing
|
||||
|
||||
### The crash (0.2.2, Little Waders)
|
||||
|
||||
Wonder Ink closed completely every time a teacher confirmed a print job:
|
||||
`SIGSEGV in QPrinter::resolution()`, twice, both through QtWebEngine's
|
||||
print-completion path.
|
||||
|
||||
`QWebEngineView.print(printer)` is asynchronous. In Qt 6.8.2
|
||||
(`qwebengineview.cpp`) it stores the raw `QPrinter*` and returns; when
|
||||
Chromium has rendered the page, `didPrintPage()` calls
|
||||
`currentPrinter->resolution()` and hands the printer to a worker thread.
|
||||
0.2.2 made the printer a local variable in `print_view()`, so PyQt deleted
|
||||
it when the function returned and Qt read freed memory. Reproduced in the
|
||||
lab with the 0.2.2 code: `QPrinter::resolution()` ←
|
||||
`QWebEnginePagePrivate::didPrintPage` ← `WebContentsAdapter::didPrintPage`,
|
||||
the Little Waders backtrace, and no job in CUPS.
|
||||
|
||||
Keeping the printer alive until `printFinished` stops the crash — that was
|
||||
built and measured first — and it is still not a working print path:
|
||||
|
||||
| Measured, QtWebEngine 6.8.2, lab queue built from Elmer's PPD | Qt `view.print()` | `printToPdf()` + `lp` |
|
||||
| --- | --- | --- |
|
||||
| A three-page lesson | 24.6 MB of 300 dpi pictures, no text, A4 on a test queue | 18 KB vector PDF with its text, on Letter, 0.43 s through Elmer's filters |
|
||||
| A worksheet PDF tab | **one blank page** | the worksheet file itself |
|
||||
| A PDF a site shows inline | — | `printToPdf` never answers (`CreatePreviewDocument got 0 page count`) — so it is downloaded and printed as a file |
|
||||
| A queue refusing jobs | reported as **printed** | "Refusing did not take the job: Destination … is not accepting jobs." |
|
||||
| Black and white on Elmer | — | IPP `print-color-mode` is **ignored** by the generic PCL 6 driver ("Unknown option", prints colour); `ColorModel=Grayscale` gives `pxlmono` |
|
||||
|
||||
Qt's path also mishandles three things its own source makes plain: a
|
||||
second `print()` on a page that is still printing is refused with no
|
||||
`printFinished`, the worker keeps the printer after the tab has gone, and
|
||||
quitting destroys the printer under that worker.
|
||||
|
||||
So 0.2.6.1 does not use Qt printing at all. **Print** makes a PDF — a
|
||||
worksheet already is one; a lesson page is rendered by the engine onto the
|
||||
printer's own paper with Chrome-like 10 mm margins — shows it, and hands it
|
||||
to CUPS with `lp`, which is how Chrome prints in the same rooms. Nothing
|
||||
asynchronous ever holds a printer, so closing a tab or Wonder Ink cannot
|
||||
break a job: once `lp` returns, the job is CUPS's.
|
||||
|
||||
### The preview
|
||||
|
||||
One dialog, for lessons and worksheets alike:
|
||||
|
||||
* the document as it will print, a whole page at a time, ‹ › to turn;
|
||||
* **Printer** — the CUPS destinations, the system default preselected
|
||||
(Elmer, in every room);
|
||||
* **Pages** — all, or some: `2`, `1-3`, `1, 3, 5-6`, checked against the
|
||||
document with the reason given if wrong;
|
||||
* **Copies** — 1 to 50;
|
||||
* **Colour** — colour or black and white, only where the printer's driver
|
||||
has a grey mode, and asked for in that driver's own terms;
|
||||
* **Cancel** sends nothing; **Print** returns to the lesson once CUPS has
|
||||
the job, and a notification says where it went. A refused job keeps the
|
||||
preview open with CUPS's reason.
|
||||
|
||||
Choosing a printer with different paper lays a lesson page out again. A
|
||||
page that closes its own tab while the preview is open is reported, not
|
||||
printed. Print pressed again while a preview is open does nothing, and so
|
||||
does a page calling `window.print()` meanwhile. The PDF viewer's own print
|
||||
button opens the same preview.
|
||||
|
||||
Temporary PDFs live in the teacher's `$XDG_RUNTIME_DIR` and are removed
|
||||
when the preview closes.
|
||||
|
||||
`tools/lab/wonderink-print-check` runs all of this against the installed
|
||||
command in the lab, and judges every scenario by what CUPS actually
|
||||
received. `tests/test-classroom-printing.sh` covers the CUPS side at every
|
||||
build. **Neither is paper.** The first print through the real Elmer is a
|
||||
job for somebody standing next to it.
|
||||
|
||||
### Any other error
|
||||
|
||||
An exception escaping any Qt handler makes PyQt6 abort the whole process —
|
||||
measured: a mistake in one slot and the window vanishes. Wonder Ink now
|
||||
logs it to the journal and carries on.
|
||||
|
||||
## What stayed the same
|
||||
|
||||
* **A separate profile from the ordinary browser.** A teacher's Wonder Ink
|
||||
|
||||
Reference in New Issue
Block a user