1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00
Files
DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml
2025-11-17 10:08:06 -05:00

274 lines
8.4 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
id: root
property bool extWorkspaceAvailable: false
property var groups: []
property var _cachedWorkspaces: ({})
signal stateChanged()
Connections {
target: DMSService
function onCapabilitiesReceived() {
checkCapabilities()
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
checkCapabilities()
} else {
extWorkspaceAvailable = false
}
}
function onExtWorkspaceStateUpdate(data) {
if (extWorkspaceAvailable) {
handleStateUpdate(data)
}
}
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
checkCapabilities()
}
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
extWorkspaceAvailable = false
return
}
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace")
if (hasExtWorkspace && !extWorkspaceAvailable) {
if (typeof CompositorService !== "undefined") {
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway)
if (!useExtWorkspace) {
console.info("ExtWorkspaceService: ext-workspace available but compositor has native support")
extWorkspaceAvailable = false
return
}
}
extWorkspaceAvailable = true
console.info("ExtWorkspaceService: ext-workspace capability detected")
DMSService.addSubscription("extworkspace")
requestState()
} else if (!hasExtWorkspace) {
extWorkspaceAvailable = false
}
}
function requestState() {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.getState", null, response => {
if (response.result) {
handleStateUpdate(response.result)
}
})
}
function handleStateUpdate(state) {
groups = state.groups || []
if (groups.length === 0) {
console.warn("ExtWorkspaceService: Received empty workspace groups from backend")
} else {
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups")
}
stateChanged()
}
function activateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.activateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error)
}
})
}
function deactivateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.deactivateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error)
}
})
}
function removeWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.removeWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error)
}
})
}
function createWorkspace(groupID, name) {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.createWorkspace", {
"groupID": groupID,
"name": name
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: createWorkspace error:", response.error)
}
})
}
function getGroupForOutput(outputName) {
for (const group of groups) {
if (group.outputs && group.outputs.includes(outputName)) {
return group
}
}
return null
}
function getWorkspacesForOutput(outputName) {
const group = getGroupForOutput(outputName)
return group ? (group.workspaces || []) : []
}
function getActiveWorkspaces() {
const active = []
for (const group of groups) {
if (!group.workspaces) continue
for (const ws of group.workspaces) {
if (ws.active) {
active.push({
workspace: ws,
group: group,
outputs: group.outputs || []
})
}
}
}
return active
}
function getActiveWorkspaceForOutput(outputName) {
const group = getGroupForOutput(outputName)
if (!group || !group.workspaces) return null
for (const ws of group.workspaces) {
if (ws.active) {
return ws
}
}
return null
}
function getVisibleWorkspaces(outputName) {
const workspaces = getWorkspacesForOutput(outputName)
let visible = workspaces.filter(ws => !ws.hidden)
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0)
if (hasValidCoordinates) {
visible = visible.sort((a, b) => {
const coordsA = a.coordinates || [0, 0]
const coordsB = b.coordinates || [0, 0]
if (coordsA[0] !== coordsB[0]) return coordsA[0] - coordsB[0]
return coordsA[1] - coordsB[1]
})
}
const cacheKey = outputName
if (!_cachedWorkspaces[cacheKey]) {
_cachedWorkspaces[cacheKey] = {
workspaces: [],
lastNames: []
}
}
const cache = _cachedWorkspaces[cacheKey]
const currentNames = visible.map(ws => ws.name || ws.id)
const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames)
if (namesChanged || cache.workspaces.length !== visible.length) {
cache.workspaces = visible.map(ws => ({
id: ws.id,
name: ws.name,
coordinates: ws.coordinates,
state: ws.state,
active: ws.active,
urgent: ws.urgent,
hidden: ws.hidden
}))
cache.lastNames = currentNames
return cache.workspaces
}
for (let i = 0; i < visible.length; i++) {
const src = visible[i]
const dst = cache.workspaces[i]
dst.id = src.id
dst.name = src.name
dst.coordinates = src.coordinates
dst.state = src.state
dst.active = src.active
dst.urgent = src.urgent
dst.hidden = src.hidden
}
return cache.workspaces
}
function getUrgentWorkspaces() {
const urgent = []
for (const group of groups) {
if (!group.workspaces) continue
for (const ws of group.workspaces) {
if (ws.urgent) {
urgent.push({
workspace: ws,
group: group,
outputs: group.outputs || []
})
}
}
}
return urgent
}
function switchToWorkspace(outputName, workspaceName) {
const workspaces = getWorkspacesForOutput(outputName)
for (const ws of workspaces) {
if (ws.name === workspaceName || ws.id === workspaceName) {
activateWorkspace(ws.name || ws.id)
return
}
}
console.warn("ExtWorkspaceService: workspace not found:", workspaceName)
}
}