1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00
Files
DankMaterialShell/quickshell/Services/DwlService.qml
2025-11-12 17:18:45 -05:00

260 lines
7.2 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property bool dwlAvailable: false
property var outputs: ({})
property var tagCount: 9
property var layouts: []
property string activeOutput: ""
property var outputScales: ({})
signal stateChanged()
Connections {
target: DMSService
function onCapabilitiesReceived() {
checkCapabilities()
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
checkCapabilities()
} else {
dwlAvailable = false
}
}
function onDwlStateUpdate(data) {
if (dwlAvailable) {
handleStateUpdate(data)
}
}
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
checkCapabilities()
}
if (dwlAvailable) {
refreshOutputScales()
}
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
dwlAvailable = false
return
}
const hasDwl = DMSService.capabilities.includes("dwl")
if (hasDwl && !dwlAvailable) {
dwlAvailable = true
console.info("DwlService: DWL capability detected")
requestState()
refreshOutputScales()
} else if (!hasDwl) {
dwlAvailable = false
}
}
function requestState() {
if (!DMSService.isConnected || !dwlAvailable) {
return
}
DMSService.sendRequest("dwl.getState", null, response => {
if (response.result) {
handleStateUpdate(response.result)
}
})
}
function handleStateUpdate(state) {
outputs = state.outputs || {}
tagCount = state.tagCount || 9
layouts = state.layouts || []
activeOutput = state.activeOutput || ""
stateChanged()
}
function setTags(outputName, tagmask, toggleTagset) {
if (!DMSService.isConnected || !dwlAvailable) {
return
}
DMSService.sendRequest("dwl.setTags", {
"output": outputName,
"tagmask": tagmask,
"toggleTagset": toggleTagset
}, response => {
if (response.error) {
console.warn("DwlService: setTags error:", response.error)
}
})
}
function setClientTags(outputName, andTags, xorTags) {
if (!DMSService.isConnected || !dwlAvailable) {
return
}
DMSService.sendRequest("dwl.setClientTags", {
"output": outputName,
"andTags": andTags,
"xorTags": xorTags
}, response => {
if (response.error) {
console.warn("DwlService: setClientTags error:", response.error)
}
})
}
function setLayout(outputName, index) {
if (!DMSService.isConnected || !dwlAvailable) {
return
}
DMSService.sendRequest("dwl.setLayout", {
"output": outputName,
"index": index
}, response => {
if (response.error) {
console.warn("DwlService: setLayout error:", response.error)
}
})
}
function getOutputState(outputName) {
if (!outputs || !outputs[outputName]) {
return null
}
return outputs[outputName]
}
function getActiveTags(outputName) {
const output = getOutputState(outputName)
if (!output || !output.tags) {
return []
}
return output.tags.filter(tag => tag.state === 1).map(tag => tag.tag)
}
function getTagsWithClients(outputName) {
const output = getOutputState(outputName)
if (!output || !output.tags) {
return []
}
return output.tags.filter(tag => tag.clients > 0).map(tag => tag.tag)
}
function getUrgentTags(outputName) {
const output = getOutputState(outputName)
if (!output || !output.tags) {
return []
}
return output.tags.filter(tag => tag.state === 2).map(tag => tag.tag)
}
function switchToTag(outputName, tagIndex) {
const tagmask = 1 << tagIndex
setTags(outputName, tagmask, 0)
}
function toggleTag(outputName, tagIndex) {
const output = getOutputState(outputName)
if (!output || !output.tags) {
console.log("toggleTag: no output or tags for", outputName)
return
}
let currentMask = 0
output.tags.forEach(tag => {
if (tag.state === 1) {
currentMask |= (1 << tag.tag)
}
})
const clickedMask = 1 << tagIndex
const newMask = currentMask ^ clickedMask
console.log("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2))
if (newMask === 0) {
console.log("toggleTag: newMask is 0, switching to tag", tagIndex)
setTags(outputName, 1 << tagIndex, 0)
} else {
console.log("toggleTag: setting combined mask", newMask)
setTags(outputName, newMask, 0)
}
}
function quit() {
Quickshell.execDetached(["mmsg", "-d", "quit"])
}
Process {
id: scaleQueryProcess
command: ["mmsg", "-A"]
running: false
stdout: StdioCollector {
onStreamFinished: {
try {
const newScales = {}
const lines = text.trim().split('\n')
for (const line of lines) {
const parts = line.trim().split(/\s+/)
if (parts.length >= 3 && parts[1] === "scale_factor") {
const outputName = parts[0]
const scale = parseFloat(parts[2])
if (!isNaN(scale)) {
newScales[outputName] = scale
}
}
}
outputScales = newScales
} catch (e) {
console.warn("DwlService: Failed to parse mmsg output:", e)
}
}
}
onExited: exitCode => {
if (exitCode !== 0) {
console.warn("DwlService: mmsg failed with exit code:", exitCode)
}
}
}
function refreshOutputScales() {
if (!dwlAvailable) return
scaleQueryProcess.running = true
}
function getOutputScale(outputName) {
return outputScales[outputName]
}
function getVisibleTags(outputName) {
const output = getOutputState(outputName)
if (!output || !output.tags) {
return []
}
const visibleTags = new Set()
output.tags.forEach(tag => {
if (tag.state === 1 || tag.clients > 0) {
visibleTags.add(tag.tag)
}
})
return Array.from(visibleTags).sort((a, b) => a - b)
}
}