229 lines
10 KiB
Markdown
229 lines
10 KiB
Markdown
# Presentations
|
|
|
|
Optional per device, off by default. `PRESENTATIONS_ENABLED=true` in
|
|
`/etc/ekklesia-classroom/device.conf` puts a **Presentations** button on
|
|
the bar and starts the importer; nothing else in the room changes.
|
|
|
|
It depends on nothing else. A machine may have Presentations with no
|
|
Wonder Ink, no drive, no Parent Call, on Wi-Fi or a cable, as a laptop or
|
|
a tower. The Bible study laptop is the first installation.
|
|
|
|
## What was measured before any of this was designed
|
|
|
|
The brief was to use existing presentation software. So the existing
|
|
presentation software was tried first, on Debian 13 in the Plasma lab,
|
|
against a ten-slide deck in both PPTX and PDF. **The critical
|
|
requirement is that a teacher who ends or cancels a slideshow lands back
|
|
in the library and never in an editor.**
|
|
|
|
| Tried | What it actually did |
|
|
| --- | --- |
|
|
| `soffice --show deck.pptx` | Starts a real fullscreen slideshow — `app_id=libreoffice-impress`, `"Presenting: session7"`, `fullscreen=1`. But it needs `XDG_SESSION_TYPE=wayland` **and** `libreoffice-gtk3`/`-qt6`, or it dies with *"Failed to open display"*; it shows the LibreOffice splash on the way up; and a **"Tip of the Day: 1/225"** dialog opened on top of the slideshow on first run. Ending the show leaves the Impress editor. |
|
|
| `okular --presentation deck.pdf` | Opens **three** windows: the presentation, the ordinary Okular document window behind it, and an **"Information — Okular"** dialog. The full viewer UI — File, Open, Settings — sits behind the slides. |
|
|
| `zathura deck.pdf` | Opens windowed, not fullscreen. A document reader, not a presenter. |
|
|
| `pdfpc deck.pdf` | Single fullscreen window, the closest of the four. With `--single-screen` it came up windowed, and in the lab it did not respond to Right, Escape or `q`. A presenter-console tool with notes and a timer, and another dependency. |
|
|
|
|
None of them returns a teacher to a library, because none of them knows
|
|
there is one. Every one of them leaves an application on the screen that
|
|
can open any file on the machine.
|
|
|
|
### What was chosen instead
|
|
|
|
**LibreOffice converts once, headless, at import. Poppler renders the
|
|
pages. The classroom shows the pictures.**
|
|
|
|
```
|
|
Session 7.pptx --soffice --headless --convert-to pdf--> slides.pdf
|
|
slides.pdf --pdftoppm -png -scale-to-x 1920--------> page-001.png ...
|
|
```
|
|
|
|
Measured on the same deck:
|
|
|
|
| Step | Time |
|
|
| --- | --- |
|
|
| PPTX → PDF, ten slides | 0.34 s |
|
|
| All ten pages → PNG | 0.03 s |
|
|
| One page at 1920px | 0.10 s |
|
|
|
|
Fonts embed correctly (`BAAAAA+LiberationSans`, subset, embedded) and the
|
|
text survives, which is where a title comes from when the filename is a
|
|
hash.
|
|
|
|
This is not a new renderer. LibreOffice does exactly the rendering
|
|
Impress would have done live — it is the same engine — and poppler does
|
|
what every PDF viewer does. The classroom's own code displays a PNG.
|
|
Because playback is made from static page images, PowerPoint animations,
|
|
video, audio and other interactive content are not supported.
|
|
What it buys:
|
|
|
|
* **A teacher can never reach an editor**, because no editor ever runs
|
|
interactively. `soffice` runs once, with no window, at import.
|
|
* **Escape is ours.** The presenter is a window of the library's own
|
|
process, so ending a slideshow is the library raising itself, not a
|
|
second program being asked to exit.
|
|
* **Presenting is instant.** The pictures already exist; there is no
|
|
LibreOffice to start in front of a room.
|
|
* **PDF is first class.** A session exported from Google Slides as PDF
|
|
skips the conversion entirely and keeps exactly the appearance Google
|
|
gave it. PPT and PPTX join that path rather than having one of their
|
|
own.
|
|
* **Offline by construction.** Nothing after the download touches the
|
|
network.
|
|
|
|
`libreoffice-gtk3` is deliberately *not* a dependency: nothing
|
|
interactive runs, so no UI integration package is needed.
|
|
|
|
## Where things are
|
|
|
|
```
|
|
~/Downloads/ completed presentations move from here
|
|
~/Downloads/Wonder Ink/ Wonder Ink's worksheets. NEVER touched.
|
|
|
|
~/.local/share/ekklesia-classroom/presentations/
|
|
imported.json which downloads have been dealt with
|
|
<id>/
|
|
presentation.json title, pages, thumbnail slide, timers
|
|
original/
|
|
Session 7 - Romans.pptx the one original, name kept
|
|
slides.pdf what everything is rendered from
|
|
pages/page-001.png ... one per slide, 1920px wide
|
|
thumbnail.png the card picture, from the chosen slide
|
|
```
|
|
|
|
## Importing
|
|
|
|
`ekklesia-classroom-presentations.service` (user) runs
|
|
`classroom-presentation-import`, which looks at `~/Downloads` every four
|
|
seconds. Polling, not inotify: a teacher waits the same few seconds
|
|
either way, and this cannot miss an event across a restart.
|
|
|
|
A file is imported when **all** of these hold:
|
|
|
|
* its extension is `.pdf`, `.pptx` or `.ppt`;
|
|
* it is not inside the `Wonder Ink` directory;
|
|
* there is no `.crdownload`, `.part`, `.partial`, `.download` or `.tmp`
|
|
sibling — Chrome writes `Session 7.pptx.crdownload` and renames it when
|
|
the transfer finishes, so that sibling is the authoritative "still
|
|
arriving";
|
|
* it has not changed for six seconds, which catches a copy from a USB
|
|
stick that has no `.crdownload` to go by;
|
|
* it is not empty; and
|
|
* its fingerprint — path, size, modification time — is not already in
|
|
`imported.json`.
|
|
|
|
Two downloads of the same name are two presentations in separate id
|
|
directories. The second gets `(2)` after its title; neither overwrites the
|
|
other.
|
|
|
|
**Move and crash safety.** On one filesystem the completed download is
|
|
renamed atomically. Across filesystems it is copied to a hidden temporary,
|
|
flushed, published atomically, and only then removed from Downloads. The
|
|
metadata and transaction fingerprint are written first. On startup, an
|
|
interruption before the source was removed discards the partial destination
|
|
and retries; an interruption after the move resumes conversion from the
|
|
managed original. A presentation becomes ready only once every derived file
|
|
it needs is on disk.
|
|
|
|
A file that cannot be converted gets a card saying so, offering only
|
|
**Remove**. Its managed original remains recoverable even when PDF or page
|
|
generation fails.
|
|
|
|
## The three things kept apart
|
|
|
|
This is the part most worth not breaking.
|
|
|
|
| | Changed by | Never changed by |
|
|
| --- | --- | --- |
|
|
| **Library cover** | *Use as cover* in Quick Look | presenting, importing |
|
|
| **Starting slide** | nothing — always slide 1 | choosing a thumbnail |
|
|
| **Retention** | a slide actually reaching the screen | Quick Look, opening the library, choosing a thumbnail, preview generation, a viewer that failed to start |
|
|
|
|
The first slide of a Bible study session is a generic opening shared by
|
|
every session; the one that names the session is usually the second. So
|
|
the thumbnail defaults to slide 1 and Quick Look exists to change it, and
|
|
changing it must not be mistaken for having presented anything.
|
|
|
|
`Presenter.show_page` calls `mark_presented()` at the moment the first
|
|
slide is drawn, and not before. Pressing **Present** is an intention; a
|
|
picture on the screen is a presentation.
|
|
|
|
## Retention
|
|
|
|
| State | Kept |
|
|
| --- | --- |
|
|
| Never presented | 180 days from import |
|
|
| Presented | 30 days from the **last** presentation |
|
|
|
|
Every presentation restarts the thirty days. No teacher-facing setting.
|
|
|
|
The cleanup runs hourly in the importer and:
|
|
|
|
* never removes a presentation whose id is in
|
|
`$XDG_RUNTIME_DIR/ekklesia-classroom-presenting` — the lock the
|
|
presenter holds while a slide is on the screen. In the runtime
|
|
directory so a crash cannot make a presentation permanently
|
|
un-removable;
|
|
* only ever removes a directory under the library root;
|
|
* removes the managed original and all derived assets together;
|
|
* never touches unrelated files in `~/Downloads`, and therefore never a
|
|
Wonder Ink worksheet;
|
|
* tolerates a directory that is already half gone.
|
|
|
|
## The presenter
|
|
|
|
A fullscreen `Gtk.Window` in the library's own process showing one
|
|
pre-rendered page at a time, letterboxed — never cropped, never
|
|
stretched.
|
|
|
|
| Key | Does |
|
|
| --- | --- |
|
|
| Space, →, ↓, Page Down, Return, `n` | Next slide |
|
|
| ←, ↑, Page Up, Backspace, `p` | Previous slide |
|
|
| Home / End | First / last slide |
|
|
| Escape, `q`, F5 | Finish, back to the library |
|
|
|
|
Page Up and Page Down are what the clicker in the cupboard sends.
|
|
|
|
Going past the last slide finishes, rather than showing a black "click to
|
|
exit" slide.
|
|
|
|
**Fullscreen is re-asserted, not assumed.** The presenter requests
|
|
fullscreen after its Wayland surface is mapped, and its stable `Presenting`
|
|
title lets a presenter-only KWin rule apply fullscreen and remove the border
|
|
without affecting the library or Quick Look. `window-state-event` reasserts
|
|
the state for as long as the presentation is running and stops the moment
|
|
Escape is pressed. The library is hidden during playback and restored on
|
|
exit; the Plasma panel itself is never hidden or reconfigured.
|
|
|
|
## Fonts
|
|
|
|
The pastor's material comes from Google Slides. These are all in Debian
|
|
main and install without a question:
|
|
|
|
| Package | Covers |
|
|
| --- | --- |
|
|
| `fonts-liberation2` | Arial, Times New Roman, Courier New — metric compatible |
|
|
| `fonts-crosextra-carlito` | Calibri |
|
|
| `fonts-crosextra-caladea` | Cambria |
|
|
| `fonts-croscore` | the same three under their Chrome OS names |
|
|
| `fonts-liberation-sans-narrow` | Arial Narrow |
|
|
| `fonts-roboto`, `fonts-open-sans`, `fonts-lato`, `fonts-montserrat` | the web fonts Google Slides offers |
|
|
| `fonts-urw-base35` | the PostScript standard 35 |
|
|
|
|
`ttf-mscorefonts-installer` is deliberately **absent**. It is in contrib,
|
|
it downloads from a third party at install time, and it shows an EULA
|
|
prompt — which an unattended classroom upgrade cannot answer.
|
|
|
|
## Checking a machine
|
|
|
|
```
|
|
classroom-presentation-import --status what the library holds
|
|
classroom-presentation-import --once one pass, then stop
|
|
classroom-presentation-import --cleanup apply retention now
|
|
classroom-manual --features which manual pages this device shows
|
|
```
|
|
|
|
`--status` prints titles, slide counts, the chosen thumbnail slide, both
|
|
timers and the expiry date. It is the fastest way to answer "why has this
|
|
gone" and "why has this not appeared".
|