583f9b180938575590e1d9a255f20ac4ec9ecf79
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9fc86f9d4c |
test: the wallpaper repair, on Tiny Pebbles' own file, in the lab and on a real install
Unit: Tiny Pebbles' file (desktop 10, panel 1), a healthy River Kids file left byte for byte, a late desktop beside a good one, idempotence, the refusal under a running shell. Lab: Plasma makes a bare desktop itself through a new activity, and the screen is read, not the file. Container gate: the installed package's fallback is the package, and its repair fixes the room's file and leaves the panel alone. Co-Authored-By: Claude Opus 5.5 <[email protected]> |
||
|
|
cd798a33a1 |
fix: a notification's Configure button no longer opens system settings
The kernel memory killer's "Memory Shortage Avoided" notice carried a Configure button that ran kcmshell6 and opened KDE's whole Notifications settings under the teacher's account. Reproduced in the lab. Plasma draws that button without consulting the Kiosk policy, but kcmshell6 and System Settings do: every settings module Debian 13's Plasma 6.3 installs (90) is now refused in the classroom's immutable kdeglobals, so the same click shows only "disabled by the system administrator". The clock's Configure Digital Clock goes with plasma/allow_configure_when_locked=false; Configure Audio Devices disappears on its own; the disabled window's Help button opened KDE Help Center, which the package now conflicts with (plasma-desktop only recommends it). The maintenance terminal runs outside the classroom's configuration and still opens every module, verified. converged-check fails if any module on a machine is ever left unrestricted: 126 passed in the lab. Co-Authored-By: Claude Opus 5.5 <[email protected]> |
||
|
|
1cb9fd35d2 |
feat: Wonder Ink looks like the classroom, and its preview shows the page
The tab strip is drawn from the classroom's own palette, the one the panel, Parent Call and Presentations read: larger titles, an accent under the active tab, worksheets marked with a document icon. Its one corner widget is the lesson's size and Print — not a new-tab button. With one tab the strip stays hidden, as before; a change of size shows a moment's badge instead, and the right-click menu and keys still work. The window is named "Lesson — Wonder Ink" and carries its own icon. The print preview showed "Page 1 could not be shown" in the real session while printing correctly: poppler 25.03 does not write to stdout when asked for "-" — it writes a file called "-.png" into the current directory, which for Wonder Ink is the teacher's home. Pages are now rendered into a directory of their own, and the lab print check fails any preview that does not draw its page. The teacher's manual has lesson size and printing. Co-Authored-By: Claude Opus 5.5 <[email protected]> |
||
|
|
48b3097c43 |
feat: a lesson in Wonder Ink is the size the browser shows it, and zooms
Teachers found lessons in Wonder Ink too small next to the ordinary browser. Measured by asking each page for devicePixelRatio: Wonder Ink follows the display scale exactly (dpr 1.5 at 150%), and Chrome is scaled TWICE (dpr 2.25) — under Plasma it follows the compositor itself and classroom-browser also forces UI_SCALE, a flag from the sway session. The browser is left as it is. Wonder Ink's pages start at zoom = UI_SCALE, the room's own number (1.0 at 100%), and measured afterwards match the browser: dpr 2.25 and 853 px against 2.25 and 854. The window is not zoomed; Qt scales it once, correctly. Ctrl+Plus/=/keypad, Ctrl+Minus, Ctrl+0, Ctrl+wheel and the right-click menu set one level for every tab, remembered as LEVEL= in its own file, relative to the room. Two actions on one key are ambiguous to Qt and it then does neither — Ctrl+Minus did nothing until each command became one action with all its keys, which also fixes Ctrl+Shift+Tab. The engine profile is built by one function, which the lab's checks now use: a check with its own profile showed every worksheet blank. The lab fences 10.10.0.0/16 as well: the development host reaches the real Elmer over Tailscale, and the lab provisions a queue pointing at it. Four lab checks written for older code are corrected; one had failed on every run since 0.2.3. tools/lab/wonderink-zoom-check: 18 checks. Lab: converged 120, print 39, worksheets 24, all passing. Co-Authored-By: Claude Opus 5.5 <[email protected]> |
||
|
|
5f2a9098c1 |
fix: a worksheet a lesson downloads comes back as a tab
Some Wonder Ink lesson links are a download rather than a page: the server sends the PDF as an attachment, so there is nothing for a tab to show and the file lands on disk. In this room that is the same as it not arriving. There is no file manager, no application launcher and no downloads bar, on purpose, and a teacher is not going to open a maintenance terminal to print a Christmas tree. 0.2.1 downloaded the worksheet, said so in a notification, and left it somewhere unreachable. Found on the canary machine with a real lesson. So a download that completes, and really is a PDF, opens as another tab. Rendering is the engine's own viewer — the same PDFium Chrome uses — so there is no second rendering library and no separate application. That was verified against a completed local file rather than assumed from the remote case: PdfViewerEnabled was already on, and a local file: URL is a different question. WHAT IS REFUSED. A completed download is not a usable worksheet. HTML that a server called .pdf, an empty file, an unreadable one: all refused on the first five bytes rather than on the name, because the alternative is a blank tab that says nothing. An interrupted download says it did not finish and to try again — and that needed stateChanged rather than isFinishedChanged, which is not emitted for an interrupted download at all. Connected to the obvious signal, this said nothing whatsoever about a worksheet that failed to arrive, which is the one case a teacher most needs told about. Measured. WHICH LOCAL FILES. Exactly the ones the window opened itself. Opening a worksheet adds one resolved path to a list, and the page's acceptNavigationRequest refuses every file: URL that is not on it. Chromium already refuses to let a remote page reach file: — verified with a link, a location.href, and a link to a worksheet that had been downloaded but not opened by the shell, all refused — so this is the second lock rather than the only one. It is here because the first one is somebody else's. Two Qt defaults are turned off beside it: LocalContentCanAccessFileUrls, which is on by default and would let a local document read other local documents, and its remote counterpart. Print to File is removed from the print dialog, because choosing it enables a path with a "..." button, which is a file chooser, in a room whose whole design is that there is no file chooser. The PDF viewer's own menus were audited: two-page view, annotations, present, properties, and nothing that opens or saves anywhere a teacher chooses. AND THE BROWSER IS NOT INVOLVED. The handler is connected to Wonder Ink's own profile, so it only ever sees downloads that started in a Wonder Ink tab. Nothing inspects a filename, nothing watches a directory, and Chrome — a separate application with a separate profile — is untouched: classroom-browser and the Chrome policies are byte-identical to stable 0.2.0. Worksheets go to ~/Downloads/Wonder Ink, which is tidiness and mostly the security argument: it is the only place one can come from. Only PDFs. Anything else downloads, says so, and is still unreachable; that limitation and two small follow-ups are written down rather than built, and nothing downloaded is ever executed. Measured from the package on a rebooted machine, and again on one upgraded from the published 0.2.1: the click-to-tab workflow end to end, a name with spaces and brackets, multi-page navigation, printing to Elmer, closing the worksheet without closing the lesson, and the four refusals. 120 convergence checks and 24 worksheet checks pass on both. Cookies are still session-only, the Present-view autoplay fix still works, fullscreen still comes back maximised, and there is still no address bar and no new-tab button. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
de5025ad22 |
feat: give Wonder Ink tabs, and let a device say it has no Wonder Ink
Teachers prepare a lesson across several tabs — the lesson, its video,
the activity — and app mode is the one thing that cannot give them that.
Chrome cannot be asked for "tabs but no omnibox". App mode has no tabs; a
normal window has an address bar and no policy, flag or extension removes
it; tabbed web apps need a manifest on a site that is not ours and push
off-origin links out into a normal browser window, which is the whole of
what this design exists to prevent. So the tab strip is ours, and the
engine is Chromium either way.
QtWebEngine, from Debian, measured before it was chosen rather than
after. The usual and correct objection is codecs: on Debian 13 it reports
H.264, AAC, MP3, VP8 and VP9 all playable, MediaSource supports avc1,
mp4a and vp9, and a 720p H.264 file decoded and played to the end in the
lab. app.wonderink.org loads, and its sign-in is an ordinary email and
password form rather than a Google flow that would mind an embedded
browser. The user agent has the QtWebEngine token stripped so a site
gating on it sees the Chromium this actually is, and Widevine is handed
over from Chrome's own bundle when the machine has Chrome, which a
classroom always does.
[ Lesson ] [ Video ] [ Activity ]
The strip appears only above one tab, so an ordinary lesson looks exactly
like the application it replaces. A tab can only come from the lesson —
target=_blank, window.open, a middle click, a Ctrl+click — and there is
no address bar, no search and no button that makes a blank tab. No
allowlist of domains either, on purpose: a list would have to be right
about every video service a lesson might ever embed.
Three bugs the lab caught and this fixes. A lesson calling window.print()
did nothing at all, which is worse than no print button because a teacher
concludes the printer is broken; printRequested is now bound to the page
that asked. Leaving fullscreen left the window 200 pixels wide in the
corner — a window that has only ever been maximised has no ordinary
geometry to return to — so the fullscreen bit is cleared rather than
maximised being re-requested. And the Present view video failure written
up in docs/wonder-ink.md is acted on at last: that investigation named
the autoplay gesture chain as the likeliest cause and declined to fix it,
because in Chrome the only lever governed the ordinary browser as well.
Here it does not — this profile is Wonder Ink and nothing else — so a
lesson may start its own video and no other page in the room may.
Reproduced both ways in the lab with an unmuted video started by a script
with no gesture: NotAllowedError at Chrome's default, playing as shipped.
That is not proof Present view is fixed; the lab has no Wonder Ink
account, and candidates 2 and 3 in that document are still open.
Measured on a rebooted machine, from the package: tabs open from a link
and from window.open, switch, and close; closing one leaves the others;
closing the last closes Wonder Ink; H.264 video plays and fills the
display in fullscreen and comes back maximised with its tabs; the print
dialog offers the room's own Elmer queue; a download lands in ~/Downloads;
back and forward work from a right-click menu that is built rather than
filtered; pressing the panel button twice raises one window rather than
starting a second on the same profile; KWin reports the window as
ekklesia-wonderink, which is one panel button and not two.
Separate from the browser as before, in its own profile, with cookies
that live only as long as the window — what the Chrome policy did for
wonderink.org, and the reason closing Wonder Ink ends a teacher's
session. Chrome's old profile directory is left untouched beside it, and
the browser's own policy is not edited by any of this.
Wonder Ink is now optional per device, through WONDERINK_ENABLED in
device.conf, because one future device is a laptop that will not have it.
It rides the mechanism the disc player already uses: one marked line in
the packaged layout, edited by classroom-desktop-layout. False takes the
launcher off the panel and makes the command refuse to start; the
browser, Parent Call and the disc player are untouched and the panel
stays balanced. Absent means yes, so every existing room is unchanged.
One scale, still. Chrome has to be handed UI_SCALE because it was
measured not to follow the compositor; Qt does follow it — devicePixelRatio
2.0 at UI_SCALE=2.0, measured — so Wonder Ink is deliberately not told,
or the room would get it twice.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
23dff0b7b4 |
feat: close the chord that let a teacher hibernate the room
Ctrl+Alt+Delete opened Plasma's session screen and a teacher hibernated a classroom computer from it. A hibernated room cannot be recovered by anybody standing in front of it, which on a Sunday morning is everybody. logout=false was already set and did not stop it. That restriction governs Plasma's own actions — what plasmashell draws in a menu or an applet. The chord is a KGlobalAccel shortcut registered by ksmserver and it asks D-Bus for the greeter without consulting a Plasma action at all. A restriction on a menu cannot see a key. Three layers, because each one alone has a way past it. The key. kglobalshortcutsrc unbinds every ksmserver session action and PowerDevil's Sleep, Hibernate, PowerDown and PowerOff, each entry marked immutable. It is deliberately not in the xdg directory with the other settings: kglobalacceld opens that file as a SimpleConfig, so it reads one file in the teacher's home and no system directory at all. Measured — with it in the cascade, kreadconfig6 reported the chord unbound while the shortcut server went on answering Ctrl+Alt+Del. classroom-desktop-reset copies the package's copy into place before the shortcut server starts, the same way the panel is copied out of the package at every login. The policy. A polkit rule refuses login1.suspend* and .hibernate* for the classroom user and for nobody else. This is the layer that matters: a key can be unbound and anything reaching logind can still ask. Refusing here rather than masking sleep.target keeps a technician's own account working, and is also what tells Plasma to stop drawing the button — CanSuspend and CanHibernate come back no. Hybrid sleep and suspend-then-hibernate have no action of their own in systemd 257; both are authorised through hibernate, so denying it denies all three. The greeter. Its D-Bus activation is shadowed with /bin/false, the same mechanism already used for the old notification daemon. Layer one removes the caller, this removes the callee. Measured in the lab, from the package, after a reboot: the escape reproduced first with the shadow removed — the greeter really does start — and then refused, exited 1, with it back. The chord reports nothing bound. systemctl suspend as the classroom user is denied. The maintenance chord and the display chord both still answer, by key code, after the shortcut file is replaced wholesale. A root process may still suspend, hibernate, reboot and power off. 182 checks pass across a logout and back. Screen locking stays disabled, the power button still does nothing, and reboot and shut down are not newly denied to anybody. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
926668dc9b |
fix: make an existing classroom converge into the Plasma appliance
A real room upgraded to 0.1.45 and came up as stock Debian Plasma with the old Waybar across the top, mako still catching notifications, and a lock screen on an account that has no password. The cause was one line, and it was in the lab: the harness handed the session under test XDG_CONFIG_DIRS by hand, so every result it had ever produced was a result about a machine somebody had already configured. On a machine SDDM starts the session through PAM, PAM does not read /etc/environment.d, and Debian's own plasma-workspace env.sh then set the variable from scratch — so the classroom's settings directory was not in the cascade at all. No layout, no lock policy, no Kiosk restrictions. The settings now arrive the way Plasma delivers them, through a file in /etc/xdg/plasma-workspace/env. Around that: the look and feel is immutable on its own key so a stale profile cannot answer for it; the palette is composed into the package, because naming a colour scheme does not produce one and the dark bar had been coming from a technician's hand; the desktop reset converges another desktop's appearance state and keeps the room's own; and classroom-migrate stops, deactivates and masks the old shell, including the D-Bus activation that brought mako back while the panel was down — found only by killing the panel on a migrated machine. device.conf loses COMPOSITOR and comes off the hyprland channel, which would otherwise have handed the room the experiment back. The lab stops flattering the package: it restarts the machine, lets SDDM actually autologin, and asks a fresh install and a machine upgraded from the Hyprland package the same sixty questions. Both answer identically, twice, and the panel still comes back from eight SIGKILLs. Co-Authored-By: Claude Opus 5 <[email protected]> |