The fourth panel this desktop handed to GNOME Settings, and the last one worth owning. Driverless only, deliberately. Adding a printer that describes its own capabilities over IPP is supported; choosing a PPD or fetching a vendor driver is not, and the page says so rather than pretending. That restraint is the whole design: a wrong driver produces a printer that accepts jobs, reports success, and prints nothing, which is the worst failure this page could ship because it looks like it worked. A printer old enough to need a PPD stays a job for the system printer tool. Printers and the queue are separate cards because they answer separate questions. Which printers exist is one; where a document went is the other, and it is the one that actually brings someone here -- so the queue is a single list across every printer. Device URIs are validated by scheme before reaching CUPS, whose backends run as root. file: and pipe: do not lead to a printer and are refused here rather than further down. This machine has no printer, so the page was built against a temporary CUPS queue that was created, exercised through the service, and removed; the service was confirmed to observe the removal rather than merely perform it. Discovery and the driverless add path are verified by their refusals rather than against hardware. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
193 lines
7.0 KiB
QML
193 lines
7.0 KiB
QML
import QtQuick
|
||
import qs.config
|
||
import qs.services
|
||
|
||
Rectangle {
|
||
id: root
|
||
|
||
property var hostWindow: null
|
||
readonly property var homePhoneDiagnostics: pageLoader.status === Loader.Ready
|
||
&& pageLoader.item
|
||
&& pageLoader.item.objectName === "home-phone-page"
|
||
? pageLoader.item.pageDiagnostics
|
||
: ({})
|
||
readonly property var healthDiagnostics: pageLoader.status === Loader.Ready
|
||
&& pageLoader.item
|
||
&& pageLoader.item.objectName === "system-health-page"
|
||
? pageLoader.item.uiDiagnostics()
|
||
: ({})
|
||
|
||
function requestHealthAction(id: string): bool {
|
||
if (pageLoader.status !== Loader.Ready
|
||
|| !pageLoader.item
|
||
|| pageLoader.item.objectName !== "system-health-page")
|
||
return false;
|
||
return pageLoader.item.activateRenderedAction(id);
|
||
}
|
||
|
||
color: Theme.bg
|
||
radius: 18
|
||
border.width: 1
|
||
border.color: Theme.alpha(Theme.fg, 0.08)
|
||
clip: true
|
||
|
||
SettingsSidebar {
|
||
id: sidebar
|
||
anchors.left: parent.left
|
||
anchors.top: titlebar.bottom
|
||
anchors.bottom: parent.bottom
|
||
selectedPage: ShellState.settingsPage
|
||
onPageRequested: page => ShellState.openSettings(page)
|
||
}
|
||
|
||
Rectangle {
|
||
id: titlebar
|
||
anchors.left: parent.left
|
||
anchors.right: parent.right
|
||
anchors.top: parent.top
|
||
height: 48
|
||
color: Theme.alpha(Theme.bgDark, 0.97)
|
||
border.width: 0
|
||
|
||
Text {
|
||
anchors.left: parent.left
|
||
anchors.leftMargin: 18
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
text: "Settings"
|
||
color: Theme.fg
|
||
font.family: Theme.fontFamily
|
||
font.pixelSize: Theme.fontSize
|
||
font.weight: Font.DemiBold
|
||
}
|
||
|
||
Row {
|
||
anchors.right: parent.right
|
||
anchors.rightMargin: 12
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
spacing: 7
|
||
|
||
Rectangle {
|
||
width: 28; height: 28; radius: 9
|
||
color: minMouse.containsMouse ? Theme.alpha(Theme.fg, 0.12) : Theme.alpha(Theme.fg, 0)
|
||
Text { anchors.centerIn: parent; text: "—"; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
|
||
MouseArea { id: minMouse; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: if (root.hostWindow) root.hostWindow.minimized = true }
|
||
}
|
||
|
||
Rectangle {
|
||
width: 28; height: 28; radius: 9
|
||
color: closeMouse.containsMouse ? Theme.alpha(Theme.danger, 0.17) : Theme.alpha(Theme.fg, 0)
|
||
Text { anchors.centerIn: parent; text: "×"; color: closeMouse.containsMouse ? Theme.danger : Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: 18 }
|
||
MouseArea { id: closeMouse; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: ShellState.closeSettings() }
|
||
}
|
||
}
|
||
|
||
DragHandler {
|
||
target: null
|
||
onActiveChanged: if (active && root.hostWindow) root.hostWindow.startSystemMove()
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
anchors.left: sidebar.right
|
||
anchors.top: titlebar.bottom
|
||
anchors.bottom: parent.bottom
|
||
width: 1
|
||
color: Theme.alpha(Theme.fg, 0.06)
|
||
}
|
||
|
||
Loader {
|
||
id: pageLoader
|
||
anchors.left: sidebar.right
|
||
anchors.right: parent.right
|
||
anchors.top: titlebar.bottom
|
||
anchors.bottom: parent.bottom
|
||
sourceComponent: {
|
||
switch (ShellState.settingsPage) {
|
||
case "appearance": return appearancePage;
|
||
case "displays": return displaysPage;
|
||
case "connectivity": return connectivityPage;
|
||
case "home-phone": return homePhonePage;
|
||
case "desktop": return desktopPage;
|
||
case "sound": return soundPage;
|
||
case "notifications": return notificationsPage;
|
||
case "screen-intelligence": return screenIntelligencePage;
|
||
case "shortcuts": return shortcutsPage;
|
||
case "mouse": return mousePage;
|
||
case "privacy": return privacyPage;
|
||
case "region": return regionPage;
|
||
case "accounts": return onlineAccountsPage;
|
||
case "accessibility": return accessibilityPage;
|
||
case "power": return powerPage;
|
||
case "datetime": return dateTimePage;
|
||
case "applications": return applicationsPage;
|
||
case "storage": return storagePage;
|
||
case "users": return usersPage;
|
||
case "sharing": return sharingPage;
|
||
case "printers": return printersPage;
|
||
case "services": return healthPage;
|
||
case "about": return aboutPage;
|
||
default: return homePage;
|
||
}
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
anchors.right: parent.right
|
||
anchors.rightMargin: 22
|
||
anchors.bottom: parent.bottom
|
||
anchors.bottomMargin: 20
|
||
width: Math.min(460, errorCopy.implicitWidth + 34)
|
||
height: 42
|
||
radius: 12
|
||
visible: SystemSettings.lastError !== ""
|
||
color: Theme.mix(Theme.bgPopover, Theme.danger, 0.1)
|
||
border.width: 1
|
||
border.color: Theme.alpha(Theme.danger, 0.28)
|
||
|
||
Text {
|
||
id: errorCopy
|
||
anchors.centerIn: parent
|
||
text: SystemSettings.lastError
|
||
color: Theme.fg
|
||
font.family: Theme.fontFamily
|
||
font.pixelSize: Theme.fontSizeSmall
|
||
}
|
||
|
||
MouseArea {
|
||
anchors.fill: parent
|
||
cursorShape: Qt.PointingHandCursor
|
||
onClicked: SystemSettings.lastError = ""
|
||
}
|
||
}
|
||
|
||
Component { id: homePage; HomePage {} }
|
||
Component { id: applicationsPage; ApplicationsPage {} }
|
||
Component { id: storagePage; StoragePage {} }
|
||
Component { id: usersPage; UsersPage {} }
|
||
Component { id: sharingPage; SharingPage {} }
|
||
Component { id: printersPage; PrintersPage {} }
|
||
Component { id: accessibilityPage; AccessibilityPage {} }
|
||
Component { id: powerPage; PowerPage {} }
|
||
Component { id: dateTimePage; DateTimePage {} }
|
||
Component { id: appearancePage; AppearancePage {} }
|
||
Component { id: displaysPage; DisplaysPage {} }
|
||
Component { id: connectivityPage; ConnectivityPage {} }
|
||
Component { id: homePhonePage; HomePhonePage {} }
|
||
Component { id: desktopPage; DesktopPage {} }
|
||
Component { id: soundPage; SoundPage {} }
|
||
Component { id: notificationsPage; NotificationsPage {} }
|
||
Component { id: screenIntelligencePage; ScreenIntelligencePage {} }
|
||
Component { id: shortcutsPage; ShortcutsPage {} }
|
||
Component { id: mousePage; MousePage {} }
|
||
Component { id: privacyPage; PrivacyPage {} }
|
||
Component { id: regionPage; RegionPage {} }
|
||
Component { id: onlineAccountsPage; OnlineAccountsPage {} }
|
||
Component { id: healthPage; HealthPage {} }
|
||
Component { id: aboutPage; AboutPage {} }
|
||
|
||
Shortcut {
|
||
sequence: "Escape"
|
||
onActivated: ShellState.closeSettings()
|
||
}
|
||
}
|