mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
241 lines
8.9 KiB
QML
241 lines
8.9 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property var contextMenu: null
|
|
property bool requestDockShow: false
|
|
property int pinnedAppCount: 0
|
|
property bool groupByApp: false
|
|
|
|
implicitWidth: row.width
|
|
implicitHeight: row.height
|
|
|
|
function movePinnedApp(fromIndex, toIndex) {
|
|
if (fromIndex === toIndex) {
|
|
return
|
|
}
|
|
|
|
const currentPinned = [...(SessionData.pinnedApps || [])]
|
|
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) {
|
|
return
|
|
}
|
|
|
|
const movedApp = currentPinned.splice(fromIndex, 1)[0]
|
|
currentPinned.splice(toIndex, 0, movedApp)
|
|
|
|
SessionData.setPinnedApps(currentPinned)
|
|
}
|
|
|
|
Row {
|
|
id: row
|
|
spacing: 2
|
|
anchors.centerIn: parent
|
|
height: 40
|
|
|
|
Repeater {
|
|
id: repeater
|
|
model: ListModel {
|
|
id: dockModel
|
|
|
|
Component.onCompleted: updateModel()
|
|
|
|
function updateModel() {
|
|
clear()
|
|
|
|
const items = []
|
|
const pinnedApps = [...(SessionData.pinnedApps || [])]
|
|
const sortedToplevels = CompositorService.sortedToplevels
|
|
|
|
if (root.groupByApp) {
|
|
// Group windows by appId
|
|
const appGroups = new Map()
|
|
|
|
// Add pinned apps first (even if they have no windows)
|
|
pinnedApps.forEach(appId => {
|
|
appGroups.set(appId, {
|
|
appId: appId,
|
|
isPinned: true,
|
|
windows: []
|
|
})
|
|
})
|
|
|
|
// Group all running windows by appId
|
|
sortedToplevels.forEach((toplevel, index) => {
|
|
const appId = toplevel.appId || "unknown"
|
|
if (!appGroups.has(appId)) {
|
|
appGroups.set(appId, {
|
|
appId: appId,
|
|
isPinned: false,
|
|
windows: []
|
|
})
|
|
}
|
|
const title = toplevel.title || "(Unnamed)"
|
|
const truncatedTitle = title.length > 50 ? title.substring(0, 47) + "..." : title
|
|
const uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
|
|
|
|
appGroups.get(appId).windows.push({
|
|
windowId: index,
|
|
windowTitle: truncatedTitle,
|
|
uniqueId: uniqueId
|
|
})
|
|
})
|
|
|
|
// Sort groups: pinned first, then unpinned
|
|
const pinnedGroups = []
|
|
const unpinnedGroups = []
|
|
|
|
Array.from(appGroups.entries()).forEach(([appId, group]) => {
|
|
// For grouped apps, just show the first window info but track all windows
|
|
const firstWindow = group.windows.length > 0 ? group.windows[0] : null
|
|
|
|
const item = {
|
|
"type": "grouped",
|
|
"appId": appId,
|
|
"windowId": firstWindow ? firstWindow.windowId : -1,
|
|
"windowTitle": firstWindow ? firstWindow.windowTitle : "",
|
|
"workspaceId": -1,
|
|
"isPinned": group.isPinned,
|
|
"isRunning": group.windows.length > 0,
|
|
"windowCount": group.windows.length,
|
|
"uniqueId": firstWindow ? firstWindow.uniqueId : "",
|
|
"allWindows": group.windows
|
|
}
|
|
|
|
if (group.isPinned) {
|
|
pinnedGroups.push(item)
|
|
} else {
|
|
unpinnedGroups.push(item)
|
|
}
|
|
})
|
|
|
|
// Add items in order
|
|
pinnedGroups.forEach(item => items.push(item))
|
|
|
|
// Add separator if needed
|
|
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
|
|
items.push({
|
|
"type": "separator",
|
|
"appId": "__SEPARATOR__",
|
|
"windowId": -1,
|
|
"windowTitle": "",
|
|
"workspaceId": -1,
|
|
"isPinned": false,
|
|
"isRunning": false
|
|
})
|
|
}
|
|
|
|
unpinnedGroups.forEach(item => items.push(item))
|
|
root.pinnedAppCount = pinnedGroups.length
|
|
} else {
|
|
pinnedApps.forEach(appId => {
|
|
items.push({
|
|
"type": "pinned",
|
|
"appId": appId,
|
|
"windowId": -1,
|
|
"windowTitle": "",
|
|
"workspaceId": -1,
|
|
"isPinned": true,
|
|
"isRunning": false
|
|
})
|
|
})
|
|
|
|
root.pinnedAppCount = pinnedApps.length
|
|
|
|
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
|
|
items.push({
|
|
"type": "separator",
|
|
"appId": "__SEPARATOR__",
|
|
"windowId": -1,
|
|
"windowTitle": "",
|
|
"workspaceId": -1,
|
|
"isPinned": false,
|
|
"isRunning": false,
|
|
"isFocused": false
|
|
})
|
|
}
|
|
|
|
sortedToplevels.forEach((toplevel, index) => {
|
|
const title = toplevel.title || "(Unnamed)"
|
|
const truncatedTitle = title.length > 50 ? title.substring(0, 47) + "..." : title
|
|
const uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
|
|
|
|
items.push({
|
|
"type": "window",
|
|
"appId": toplevel.appId,
|
|
"windowId": index,
|
|
"windowTitle": truncatedTitle,
|
|
"workspaceId": -1,
|
|
"isPinned": false,
|
|
"isRunning": true,
|
|
"uniqueId": uniqueId
|
|
})
|
|
})
|
|
}
|
|
|
|
items.forEach(item => append(item))
|
|
}
|
|
}
|
|
|
|
delegate: Item {
|
|
id: delegateItem
|
|
property alias dockButton: button
|
|
|
|
width: model.type === "separator" ? 16 : 40
|
|
height: 40
|
|
|
|
Rectangle {
|
|
visible: model.type === "separator"
|
|
width: 2
|
|
height: 20
|
|
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
|
radius: 1
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
DockAppButton {
|
|
id: button
|
|
visible: model.type !== "separator"
|
|
anchors.centerIn: parent
|
|
|
|
width: 40
|
|
height: 40
|
|
|
|
appData: model
|
|
contextMenu: root.contextMenu
|
|
dockApps: root
|
|
index: model.index
|
|
|
|
// Override tooltip for windows to show window title
|
|
showWindowTitle: model.type === "window" || model.type === "grouped"
|
|
windowTitle: model.windowTitle || ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: CompositorService
|
|
function onSortedToplevelsChanged() {
|
|
dockModel.updateModel()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SessionData
|
|
function onPinnedAppsChanged() {
|
|
dockModel.updateModel()
|
|
}
|
|
}
|
|
|
|
onGroupByAppChanged: {
|
|
dockModel.updateModel()
|
|
}
|
|
}
|