Files
Classroom_Desktop/config/plasma/lookandfeel/contents/layouts/org.kde.plasma.desktop-layout.js
T
ekklesiaandClaude Opus 5 7f4a122900 feat: one setting per application, and never the shape of the machine
A laptop is going in for the women's Bible study, and the obvious way to
build that — a laptop profile that turns off the children's church
applications — is the wrong way. A laptop may well take children's church,
and a tower may well be a Bible study. Hardware cannot be allowed to
decide purpose, so every optional application gets a setting of its own:

    WONDERINK_ENABLED       already existed; behaviour unchanged
    DVD_ENABLED             new
    PARENT_CALL_ENABLED     new

and DEVICE_TYPE says only what the hardware IS. classroom-desktop-layout
never reads it, and there is a test that says so, because this is the rule
that will be under pressure the first time somebody adds a device.

All three default to true, so an existing classroom that has never heard
of any of them comes up exactly as it did before. The settings are
appended to device.conf by the same mechanism every other setting has
used, so an upgrade gains them without losing a byte an administrator
wrote.

The disc player is the one place hardware still votes, and it is a veto:
DVD_ENABLED can take the player away from a machine that has a drive,
nothing can put it on a machine that has none. A button that cannot work
is worse than no button.

The layout's launcher markers are replaced by a feature block of three
plain booleans. The old mechanism commented a line out of an array, which
worked for launchers and could not express Parent Call, because that is a
whole widget rather than one entry. Three booleans express both, and the
launcher list is now built from them in one fixed order, so a disabled
application closes the row up rather than leaving a gap, and the same
enabled set produces the same bar on every machine in the church.

Also here, because it is the bar and not a feature: sortingStrategy=0.
Plasma's default is 1, "manually", and the task manager accepts a
reordering drop only in that mode — MouseHandler.qml tests
tasksModel.sortMode === SortManual before it will move anything. The
classroom never wrote the key, so it had the default, and any teacher
could drag the launchers into a different order. This is the applet's own
lever refusing the drop rather than something of ours putting the bar back
afterwards.

The test now runs the layout the package actually ships, in node, with
Plasma's API stubbed, and asserts the launcher string that comes out.
Asserting against a copy of the file's text in the test was how the old
one worked, and a copy is a thing that drifts.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 20:55:09 -05:00

216 lines
9.4 KiB
JavaScript

// The Ekklesia Classroom desktop.
//
// Plasma runs this once, when a session has no panel yet, and again on
// demand — `plasma-apply-lookandfeel -a org.ekklesia.classroom.desktop
// --resetLayout` rebuilds the whole desktop from this file. That is the
// classroom's recovery path for a damaged shell, and it is Plasma's own
// mechanism rather than something written here.
//
// One full-width bar along the bottom. Left is auxiliary, the middle is
// applications, the right is the small amount of status a teacher needs.
// Nothing else is on the screen.
// WHICH APPLICATIONS THIS DEVICE OFFERS.
//
// classroom-desktop-layout rewrites the three lines between the markers
// to match device.conf and this machine's hardware, and nothing else in
// this file. Each application is its own line because each is its own
// setting: a laptop taking children's church needs Wonder Ink and a tower
// used for Bible study does not, so the shape of the machine is never
// allowed to decide what it is for.
//
// All true here is the shipped default, which is what an existing
// classroom must come up as.
/* CLASSROOM-FEATURES-BEGIN */
var WONDERINK = true;
var DVD = true;
var PARENT_CALL = true;
/* CLASSROOM-FEATURES-END */
var WALLPAPER = "/usr/share/backgrounds/ekklesia/classroom-calm.png";
// Matches the 76px strip the classroom has always used, so muscle memory
// and the room's viewing distance both carry over.
var PANEL_HEIGHT = 76;
// The idle desktop: the wallpaper, and nothing on it.
var screens = desktops();
for (var i = 0; i < screens.length; i++) {
var desktop = screens[i];
desktop.wallpaperPlugin = "org.kde.image";
desktop.currentConfigGroup = ["Wallpaper", "org.kde.image", "General"];
desktop.writeConfig("Image", "file://" + WALLPAPER);
desktop.writeConfig("SlidePaths", "");
// 2 is "scaled and cropped": the landscape fills the display at any
// aspect ratio without being stretched out of shape.
desktop.writeConfig("FillMode", 2);
desktop.reloadConfig();
}
var panel = new Panel();
panel.location = "bottom";
panel.height = PANEL_HEIGHT;
panel.hiding = "none";
panel.floating = false;
panel.lengthMode = "fill";
panel.alignment = "center";
panel.opacity = "adaptive";
// LEFT — auxiliary. Parent Call is not one of the room's applications and
// is deliberately not in the row with them.
// Quick Launch: a launcher, and only a launcher.
//
// Two other widgets were tried on a real panel. The Icon widget copies
// the desktop entry into the user's home and uses the copy, so an update
// could never change the icon or the command — it kept showing a bell out
// of a package that no longer contained one. A task manager reads
// /usr/share/applications live, which fixes that, but a task manager also
// shows every running window, so the auxiliary corner filled up with the
// lesson's tasks.
//
// Quick Launch reads the entry live and shows nothing but the button.
if (PARENT_CALL) {
var parentCall = panel.addWidget("org.kde.plasma.quicklaunch");
parentCall.currentConfigGroup = ["General"];
// A file URL, not applications:. Quick Launch resolves the entry
// itself and does not copy it, so the path is a live reference to
// what the package installs.
parentCall.writeConfig(
"launcherUrls",
"file:///usr/share/applications/ekklesia-parent-call.desktop"
);
parentCall.writeConfig("showLauncherNames", false);
parentCall.writeConfig("enablePopup", false);
parentCall.writeConfig("maxSectionCount", 1);
}
var leftGap = panel.addWidget("org.kde.plasma.panelspacer");
leftGap.currentConfigGroup = ["General"];
leftGap.writeConfig("expanding", true);
// CENTRE — the applications, and the whole of the running/minimised/active
// story. This applet is the reason the classroom stops writing a dock.
var tasks = panel.addWidget("org.kde.plasma.icontasks");
tasks.currentConfigGroup = ["General"];
// THE LAUNCHERS, IN ONE FIXED ORDER.
//
// The order is written here and nowhere else, so the same set of enabled
// applications produces the same bar on every machine in the church.
// Anything switched off is left out of the list rather than blanked, so
// the remaining launchers close up and there is never a gap where a
// disabled application used to be.
//
// The browser is always present. Wonder Ink and the disc player are
// answered above.
var launchers = [];
if (WONDERINK) {
launchers.push("applications:ekklesia-wonderink.desktop");
}
launchers.push("applications:google-chrome.desktop");
if (DVD) {
launchers.push("applications:ekklesia-dvd.desktop");
}
tasks.writeConfig("launchers", launchers.join(","));
// THE ORDER STAYS PUT.
//
// 0 is "do not sort", and it is what stops a teacher dragging the
// launchers into a different order. Plasma's default is 1, "manually",
// and manual sorting is the only mode in which the task manager accepts a
// reordering drop at all — see MouseHandler.qml, which tests
// tasksModel.sortMode === SortManual before it will move anything. The
// classroom shipped without this line, so it had Plasma's default and the
// bar could be rearranged by anybody who dragged an icon.
//
// This is the supported lever rather than a patched task manager: the
// drop is refused by the applet's own code, not caught afterwards by
// something of ours putting the bar back.
tasks.writeConfig("sortingStrategy", 0);
// Launchers stay together at the start of the row and running windows
// appear after them, so opening or closing an application cannot move a
// pinned icon. This is Plasma's default; it is written down because the
// classroom depends on it.
tasks.writeConfig("separateLaunchers", true);
// Every window gets its own button. Teachers should never have to open a
// group to find out that a second window exists.
tasks.writeConfig("groupingStrategy", 0);
tasks.writeConfig("showOnlyCurrentDesktop", false);
tasks.writeConfig("showOnlyCurrentActivity", false);
tasks.writeConfig("showOnlyCurrentScreen", false);
// Clicking a button always means "show me this", and never "hide it".
//
// This was measured before it was decided. Plasma 6.3 draws a minimised
// task and a task that is merely behind another window identically: no
// indicator for closed, a grey indicator for running, a teal one for
// active — three marks for four states. Rather than write a task manager
// that draws a fourth, the classroom removes the state. There is nothing
// on the idle desktop for a teacher to want to see, so minimising an
// application in this room has no purpose and only ever loses it.
//
// A window minimised some other way is still shown as running and comes
// back with one click, so it can never be lost even then.
tasks.writeConfig("minimizeActiveTaskOnClick", false);
tasks.writeConfig("fill", false);
tasks.writeConfig("maxStripes", 1);
tasks.writeConfig("indicateAudioStreams", false);
tasks.writeConfig("wheelEnabled", false);
tasks.writeConfig("middleClickAction", "NewInstance");
tasks.writeConfig("showToolTips", true);
tasks.writeConfig("iconSpacing", 2);
var rightGap = panel.addWidget("org.kde.plasma.panelspacer");
rightGap.currentConfigGroup = ["General"];
rightGap.writeConfig("expanding", true);
// RIGHT — status.
//
// Three ordinary applets straight on the bar, and no system tray around
// them. A tray is a container that discovers whatever is installed and
// then hides most of it behind an arrow; measured in the lab it collected
// battery, brightness, clipboard, keyboard layout, camera, vaults and
// screen management on a machine that has none of those to say anything
// about. Naming the four the classroom actually uses is both smaller and
// deterministic, and it leaves nothing for a teacher to expand.
panel.addWidget("org.kde.plasma.networkmanagement");
var volume = panel.addWidget("org.kde.plasma.volume");
volume.currentConfigGroup = ["General"];
// No chime when the volume changes. A classroom is often listening to
// something when somebody adjusts it, and a beep over a lesson is worse
// than no feedback at all — the on-screen display is the feedback, and it
// is in the look and feel package where a television can read it.
//
// Plasma 6 moved this setting out of the applet and into a global one,
// and the applet migrates a false written here into it on first run. So
// this is both the setting and the instruction to carry it across.
volume.writeConfig("volumeFeedback", false);
volume.writeConfig("volumeOsd", true);
volume.writeConfig("muteOsd", true);
volume.writeConfig("outputChangeOsd", true);
// A teacher pressing the volume key expects a step they can hear.
volume.writeConfig("volumeStep", 5);
panel.addWidget("org.kde.plasma.notifications");
var clock = panel.addWidget("org.kde.plasma.digitalclock");
clock.currentConfigGroup = ["Appearance"];
clock.writeConfig("showDate", true);
clock.writeConfig("dateFormat", "custom");
clock.writeConfig("customDateFormat", "ddd d MMM");
clock.writeConfig("showSeconds", 0);
clock.writeConfig("dateDisplayFormat", "BelowTime");
// Sized by the bar, not by a number written here.
//
// It used to be pinned at 15 points to stop it becoming the largest text
// in the room. On a 4K television that was a clock a teacher could not
// read from the back of the room, and it was the one thing in the
// classroom that did not follow UI_SCALE, because a point size written
// into a layout is the same point size at every scale. Plasma's own
// sizing follows the bar, and the bar follows the scale.
clock.writeConfig("autoFontAndSize", true);
clock.writeConfig("fontWeight", 500);