Desktop & Dock becomes Shell — Bar, Dock, Control Center, Tiling, Workspaces — the home for everything Quickshell draws. The settings- management cluster moves to System as Sync & Backup, Appearance's Shell tab dissolves, and 24-hour time finally lives on Date & Time, which always owned it. The bar gets what it never had: a way to survive the wallpaper. A second neutral text family (follow theme, or forced light or dark), a one-layer shadow under every glyph, and a gradient scrim for wallpapers nothing else survives — all off by default, pixel-identical until asked. Widgets earn toggles (weather, media, clipboard, calendar countdown), the vitals cluster stops leaving a dead pill behind, and Control Center's sections learn to step aside. The dock graduates from MVP: a context menu with window rows, pin, unpin, quit and new-window; scroll an icon to cycle its windows; drag to reorder on the dock itself; hover previews with one-shot captures; and "Add App to Dock" in the launcher. Three real bugs died en route — menus that slid away with the autohide, a readonly-property crash on every menu open, and a drag that drifted half a slot per icon on side docks. The pinned-apps editor in Settings becomes a drag strip. 166 contracts; the full suite is green except two live display and switcher tests that cannot run behind a locked session — re-verified on unlock. Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
78 lines
2.1 KiB
QML
78 lines
2.1 KiB
QML
// Adds an installed application to the Dock.
|
|
//
|
|
// Filtered rather than a full list: there are several hundred desktop entries
|
|
// on a normal system, and rendering them all into a page that is already
|
|
// scrolling is both slow and useless. Typing narrows; nothing shows until you
|
|
// do, which also keeps the card short when you are not using it.
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.config
|
|
import qs.modules.clipboard
|
|
|
|
Column {
|
|
id: root
|
|
|
|
spacing: 0
|
|
|
|
required property var pinned
|
|
|
|
signal picked(string id)
|
|
|
|
// For surfaces that open straight into this picker instead of scrolling to
|
|
// it, so nothing has to be clicked before typing works.
|
|
function grab(): void {
|
|
search.grab();
|
|
}
|
|
|
|
readonly property var matches: {
|
|
const needle = search.text.trim().toLowerCase();
|
|
if (needle === "")
|
|
return [];
|
|
const out = [];
|
|
for (const entry of DesktopEntries.applications.values) {
|
|
if (entry.noDisplay)
|
|
continue;
|
|
if (root.pinned.indexOf(entry.id) >= 0)
|
|
continue;
|
|
if (String(entry.name).toLowerCase().indexOf(needle) >= 0)
|
|
out.push(entry);
|
|
if (out.length >= 8)
|
|
break;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
SearchField {
|
|
id: search
|
|
width: parent.width
|
|
placeholder: "Search installed applications"
|
|
}
|
|
|
|
Repeater {
|
|
model: root.matches
|
|
|
|
SettingRow {
|
|
id: candidate
|
|
|
|
required property var modelData
|
|
required property int index
|
|
|
|
label: candidate.modelData.name
|
|
detail: candidate.modelData.id
|
|
divider: candidate.index < root.matches.length - 1
|
|
controlWidth: 86
|
|
|
|
SettingsButton {
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "Pin"
|
|
onClicked: {
|
|
root.picked(candidate.modelData.id);
|
|
search.text = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|