// 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 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. // // The first three are true here, which is what an existing classroom must // come up as. PRESENTATIONS is false, which is what an existing classroom // must come up as too: no room has ever had it, and an upgrade may not // put a button on a bar nobody asked for. /* CLASSROOM-FEATURES-BEGIN */ var WONDERINK = true; var DVD = true; var PARENT_CALL = true; var PRESENTATIONS = false; /* 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); } // HELP, beside Parent Call and not in the row with the applications. // // Every room gets it: the manual is the one thing that is never optional, // because a teacher who needs it is by definition a teacher who does not // know where to look. It shows only the pages for the features THIS // device has — see classroom-manual — so the button means the same thing // in every room while what it opens does not. // // On the left, with Parent Call, for the same reason Parent Call is // there: it is not one of the room's applications, and putting it in the // middle row would move buttons teachers reach for without looking. var help = panel.addWidget("org.kde.plasma.quicklaunch"); help.currentConfigGroup = ["General"]; help.writeConfig( "launcherUrls", "file:///usr/share/applications/ekklesia-manual.desktop" ); help.writeConfig("showLauncherNames", false); help.writeConfig("enablePopup", false); help.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"); } // LAST, AND THAT IS THE WHOLE REASON IT IS HERE. // // Every existing room has Wonder Ink, the browser and the disc player in // that order, and teachers have been pressing them in that order for // months. Appending keeps all three exactly where they are on every // machine that upgrades; putting Presentations anywhere else in the row // would move a button somebody reaches for without looking. if (PRESENTATIONS) { launchers.push("applications:ekklesia-presentations.desktop"); } tasks.writeConfig("launchers", launchers.join(",")); // THE ORDER STAYS PUT WHEN AN APPLICATION OPENS. // // 1 is "manually", and it has to be 1. This is not a preference; it is // the only value at which the Icons-Only Task Manager keeps a running // application in its pinned position. // // 0.2.4 set this to 0 to stop teachers dragging the launchers about, and // that worked — and broke the order instead, which is the bug this // replaces. Two lines of the stock applet explain the whole thing: // // main.qml:153 hideActivatedLaunchers: tasks.iconsOnly || ... // main.qml:155 launchInPlace: tasks.iconsOnly && sortingStrategy === 1 // // For an icons-only bar the first is ALWAYS true: the moment an // application starts, its launcher is hidden. The second is what puts the // running window back in the launcher's place — and only at 1. At 0 the // launcher vanished and the window was appended after the others, so // opening the browser moved it behind the disc player. Reproduced in the // lab with a real Chrome window, and fixed by this line; both measured. // // The cost is that manual sorting is also the only mode in which // MouseHandler.qml accepts a reordering drop, so a teacher can drag the // launchers again within a session. There is no value that gives both, // and no Kiosk key that separates them. classroom-desktop-reset rebuilds // this bar from the package at every login, so a drag never outlives the // session, and docs/testing.md records the trade rather than hiding it. tasks.writeConfig("sortingStrategy", 1); // 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);