// The Dock's pinned applications: reorder, remove, and add. // // The list was a sixteen-entry literal in Settings.qml, so changing what sits // in the Dock meant editing a QML file and reloading the shell. It is a plain // ordered list of desktop entry ids, stored in the shared settings file, which // means it is covered by Restore defaults like everything else. // // Move up / move down rather than drag-and-drop. Dragging inside a Flickable // that is itself inside a scrolling page is a genuinely hard interaction to get // right, and it fails in a way the user reads as the app being broken; two // buttons are unambiguous and keyboard-reachable. import QtQuick import Quickshell import qs.config import qs.services import qs.widgets Column { id: root spacing: 0 readonly property var pinned: { const stored = DesktopPreferences.get("dockPinned"); return Array.isArray(stored) ? stored : []; } // DesktopEntries populates asynchronously, so this must be read as a // binding rather than looked up inside one -- byId() called during // evaluation registers no dependency and answers from an empty list. readonly property var entriesById: { const index = {}; for (const entry of DesktopEntries.applications.values) index[entry.id] = entry; return index; } function nameFor(id: string): string { const entry = root.entriesById[id]; return entry ? entry.name : id; } function commit(next: var): void { DesktopPreferences.set("dockPinned", next); } function move(from: int, to: int): void { if (to < 0 || to >= root.pinned.length) return; const next = root.pinned.slice(); const moved = next.splice(from, 1)[0]; next.splice(to, 0, moved); root.commit(next); } function remove(index: int): void { const next = root.pinned.slice(); next.splice(index, 1); root.commit(next); } function add(id: string): void { if (root.pinned.indexOf(id) >= 0) return; root.commit(root.pinned.concat([id])); } Repeater { model: root.pinned SettingRow { id: pin required property var modelData required property int index label: root.nameFor(pin.modelData) detail: pin.modelData divider: pin.index < root.pinned.length - 1 controlWidth: 132 Row { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter spacing: 4 SettingsButton { text: "↑" enabled: pin.index > 0 onClicked: root.move(pin.index, pin.index - 1) } SettingsButton { text: "↓" enabled: pin.index < root.pinned.length - 1 onClicked: root.move(pin.index, pin.index + 1) } SettingsButton { text: "Unpin" onClicked: root.remove(pin.index) } } } } SettingRow { visible: root.pinned.length === 0 label: "Nothing is pinned" detail: "The Dock will only show running applications" divider: false } }