// About. // // The landing page of the System category, and the answer to "what am I // running". Every line here is read from the machine rather than written down: // the versions block used to carry a hardcoded Quickshell version that had been // wrong for two releases, and a Design principles card restating opinions the // manual argues properly. // // Rows come from MachineInfo, except graphics, which is joined from // GraphicsDevices rather than read a second time -- two readouts of the same // hardware are two things that can disagree. Facts the cards below do not claim // by name are still shown, in Software, so a row the helper learns to report // cannot go missing here. import Quickshell import Quickshell.Io import QtQuick import qs.config import qs.services SettingsPage { id: root objectName: "about" title: "About" lede: "This machine, plainly." Component.onCompleted: { if (!MachineInfo.scanned) MachineInfo.refresh(); if (GraphicsDevices.devices.length === 0) GraphicsDevices.refresh(); } // ── Reading the machine ────────────────────────────────────────────────── function fact(label: string): string { const row = (MachineInfo.facts ?? []).find(entry => entry.label === label); return row ? String(row.value ?? "") : ""; } // Joined with a middle dot, skipping whatever is absent. Firmware and // Secure Boot are both absent-tolerant on the helper's side, so either half // of that row can be missing on a given machine. function joined(parts: var): string { return parts.filter(part => String(part ?? "") !== "").join(" · "); } readonly property string hostname: root.fact("Hostname") // "Fedora Linux 44 (Workstation Edition)" says the edition twice for the // one line where brevity matters most. readonly property string operatingSystem: root.fact("Operating system").replace(/\s*\(.*\)\s*$/, "") readonly property string uptime: root.fact("Uptime").split(",")[0].trim() readonly property string identity: root.joined([ root.operatingSystem === "" ? "" : "Panama on " + root.operatingSystem, SystemSettings.hyprlandVersion === "" ? "" : "Hyprland " + SystemSettings.hyprlandVersion, root.uptime === "" ? "" : "up " + root.uptime ]) readonly property var graphicsRows: { const gpus = GraphicsDevices.devices ?? []; return gpus.map((device, index) => ({ label: gpus.length > 1 ? "Graphics " + (index + 1) : "Graphics", value: String(device.name ?? "") })); } readonly property string displayValue: root.joined([ SystemSettings.monitorName, root.fact("Resolution") ]) // Everything the three cards below name explicitly. Whatever the helper // reports that is not in here lands in Software rather than nowhere. readonly property var claimedFacts: [ "Hostname", "Operating system", "Uptime", "Panama", "Kernel", "Firmware", "Secure Boot", "Model", "Processor", "Memory", "Swap", "Disk", "Resolution" ] readonly property var otherFacts: (MachineInfo.facts ?? []) .filter(entry => root.claimedFacts.indexOf(String(entry.label ?? "")) < 0) // ── Copying it ─────────────────────────────────────────────────────────── // The same facts, as plain text, for a bug report or a message to somebody // trying to help. Built from what is on screen so the two cannot disagree. function systemInfoText(): string { const lines = []; if (root.hostname !== "") lines.push(root.hostname); if (root.identity !== "") lines.push(root.identity); lines.push(""); for (const row of root.versionRows.concat(root.hardwareRows, root.otherFacts)) { if (String(row.value ?? "") !== "") lines.push(row.label + ": " + row.value); } return lines.join("\n") + "\n"; } property string copyResult: "" Process { id: copyRun property string payload: "" command: ["wl-copy"] stdinEnabled: true onStarted: { copyRun.write(copyRun.payload); // wl-copy reads stdin until EOF before it exits; leaving the // channel open would hang it forever waiting for more. Same // stdinEnabled close that Health.copyReport uses. copyRun.stdinEnabled = false; } onExited: exitCode => { root.copyResult = exitCode === 0 ? "Copied." : "Could not reach the clipboard."; copyRun.payload = ""; } } function copySystemInfo(): void { if (copyRun.running) return; root.copyResult = ""; copyRun.payload = root.systemInfoText(); copyRun.stdinEnabled = true; copyRun.running = true; } // ── The hero ───────────────────────────────────────────────────────────── readonly property var versionRows: [ { label: "Panama", value: root.fact("Panama") }, { label: "Quickshell", value: SystemSettings.quickshellVersion }, { label: "Kernel", value: root.fact("Kernel") }, { label: "Firmware", value: root.joined([ root.fact("Firmware"), root.fact("Secure Boot") === "" ? "" : "Secure Boot " + root.fact("Secure Boot") ]) } ].filter(row => String(row.value ?? "") !== "") SettingsCard { Item { width: parent.width implicitHeight: Math.max(96, heroCopy.implicitHeight + 16) // The house tile: a rounded plate carrying the System glyph the // sidebar uses, in the accent, drawn rather than shipped as an // image so it follows the theme like everything else. Rectangle { id: heroArt anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter width: 84 height: 84 radius: 24 color: Theme.alpha(Theme.accent, 0.13) border.width: 1 border.color: Theme.alpha(Theme.accent, 0.3) Rectangle { anchors.fill: parent radius: parent.radius color: "transparent" gradient: Gradient { orientation: Gradient.Vertical GradientStop { position: 0; color: Theme.alpha(Theme.accentSecondary, 0.14) } GradientStop { position: 1; color: Theme.alpha(Theme.accent, 0.02) } } } Text { anchors.centerIn: parent text: "\u{F02FD}" color: Theme.accent font.family: Theme.fontMono font.pixelSize: 38 } } Column { id: heroCopy anchors.left: heroArt.right anchors.leftMargin: 20 anchors.right: copyButton.left anchors.rightMargin: 18 anchors.verticalCenter: parent.verticalCenter spacing: 5 Text { width: parent.width text: root.hostname === "" ? "This machine" : root.hostname color: Theme.fg font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeTitle font.weight: Font.Bold elide: Text.ElideRight } Text { width: parent.width visible: root.identity !== "" text: root.identity color: Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall wrapMode: Text.WordWrap } Text { width: parent.width visible: root.copyResult !== "" text: root.copyResult color: Theme.fgMuted font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } } SettingsButton { id: copyButton objectName: "about-copy-button" anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter text: "Copy system info" enabled: !copyRun.running activeFocusOnTab: enabled border.width: activeFocus ? 2 : 1 border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08) onClicked: root.copySystemInfo() Accessible.role: Accessible.Button Accessible.name: "Copy system info" Keys.onReturnPressed: root.copySystemInfo() Keys.onSpacePressed: root.copySystemInfo() } } Repeater { model: root.versionRows TextRow { required property var modelData required property int index label: modelData.label value: modelData.value divider: index < root.versionRows.length - 1 } } } // ── Hardware ───────────────────────────────────────────────────────────── readonly property var hardwareRows: [ { label: "Model", value: root.fact("Model") }, { label: "Processor", value: root.fact("Processor") } ].concat(root.graphicsRows, [ { label: "Memory", value: root.joined([ root.fact("Memory"), root.fact("Swap") === "" ? "" : root.fact("Swap") + " swap" ]) }, { label: "Disk", value: root.fact("Disk") }, { label: "Display", value: root.displayValue } ]).filter(row => String(row.value ?? "") !== "") SettingsCard { title: "Hardware" Repeater { model: root.hardwareRows TextRow { required property var modelData label: modelData.label value: modelData.value } } TextRow { visible: MachineInfo.scanned && root.hardwareRows.length === 0 label: "Hardware" detail: "The system did not report anything readable" value: "Unavailable" } // The machine's name is a network-facing setting rather than a fact // about the hardware, and Sharing is the page that owns it. Saying so // here is cheaper than a second field that writes the same hostname. ActionRow { label: "Device name" detail: root.hostname === "" ? "What this machine calls itself on the network" : root.hostname + " — what this machine calls itself on the network" action: "Open Sharing" divider: false onTriggered: ShellState.openSettings("sharing") } } // ── Software ───────────────────────────────────────────────────────────── SettingsCard { title: "Software" Repeater { model: root.otherFacts TextRow { required property var modelData label: String(modelData.label ?? "") value: String(modelData.value ?? "") } } TextRow { label: "Configuration" detail: Quickshell.shellDir value: "Local" divider: false } } // ── Manual ─────────────────────────────────────────────────────────────── ManualChapters { id: contents } SettingsCard { title: "Manual" subtitle: "How this desktop works, written for the person using it. Links inside a chapter open the settings page they name." Repeater { id: chapterRows model: contents.titled ActionRow { required property var modelData required property int index label: modelData.title action: "Read" onTriggered: ShellState.openSettingsSection("manual", modelData.file) } } ActionRow { label: "Open the manual" detail: "Starts at the beginning" action: "Open" divider: false onTriggered: ShellState.openSettings("manual") } } }