mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-27 15:02:50 -05:00
wayland: add wlr-output-management-unstable-v1 service + labwc info
This commit is contained in:
@@ -14,11 +14,13 @@ Singleton {
|
||||
property bool isNiri: false
|
||||
property bool isDwl: false
|
||||
property bool isSway: false
|
||||
property bool isLabwc: false
|
||||
property string compositor: "unknown"
|
||||
|
||||
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
||||
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
|
||||
readonly property string labwcPid: Quickshell.env("LABWC_PID")
|
||||
property bool useNiriSorting: isNiri && NiriService
|
||||
|
||||
property var sortedToplevels: []
|
||||
@@ -33,6 +35,13 @@ Singleton {
|
||||
return screen.devicePixelRatio || 1
|
||||
}
|
||||
|
||||
if (WlrOutputService.wlrOutputAvailable && screen) {
|
||||
const wlrOutput = WlrOutputService.getOutput(screen.name)
|
||||
if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
|
||||
return wlrOutput.scale
|
||||
}
|
||||
}
|
||||
|
||||
if (isNiri && screen) {
|
||||
const niriScale = NiriService.displayScales[screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
@@ -343,6 +352,7 @@ Singleton {
|
||||
isNiri = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
isLabwc = false
|
||||
compositor = "hyprland"
|
||||
console.info("CompositorService: Detected Hyprland")
|
||||
return
|
||||
@@ -355,6 +365,7 @@ Singleton {
|
||||
isHyprland = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
isLabwc = false
|
||||
compositor = "niri"
|
||||
console.info("CompositorService: Detected Niri with socket:", niriSocket)
|
||||
NiriService.generateNiriBinds()
|
||||
@@ -371,13 +382,25 @@ Singleton {
|
||||
isHyprland = false
|
||||
isDwl = false
|
||||
isSway = true
|
||||
isLabwc = false
|
||||
compositor = "sway"
|
||||
console.info("CompositorService: Detected Sway with socket:", swaySocket)
|
||||
}
|
||||
}, 0)
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (labwcPid && labwcPid.length > 0) {
|
||||
isHyprland = false
|
||||
isNiri = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
isLabwc = true
|
||||
compositor = "labwc"
|
||||
console.info("CompositorService: Detected LabWC with PID:", labwcPid)
|
||||
return
|
||||
}
|
||||
|
||||
if (DMSService.dmsAvailable) {
|
||||
Qt.callLater(checkForDwl)
|
||||
} else {
|
||||
@@ -385,6 +408,7 @@ Singleton {
|
||||
isNiri = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
isLabwc = false
|
||||
compositor = "unknown"
|
||||
console.warn("CompositorService: No compositor detected")
|
||||
}
|
||||
@@ -393,7 +417,7 @@ Singleton {
|
||||
Connections {
|
||||
target: DMSService
|
||||
function onCapabilitiesReceived() {
|
||||
if (!isHyprland && !isNiri && !isDwl) {
|
||||
if (!isHyprland && !isNiri && !isDwl && !isLabwc) {
|
||||
checkForDwl()
|
||||
}
|
||||
}
|
||||
@@ -404,6 +428,8 @@ Singleton {
|
||||
isHyprland = false
|
||||
isNiri = false
|
||||
isDwl = true
|
||||
isSway = false
|
||||
isLabwc = false
|
||||
compositor = "dwl"
|
||||
console.info("CompositorService: Detected DWL via DMS capability")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
@@ -48,8 +48,9 @@ Singleton {
|
||||
signal brightnessStateUpdate(var data)
|
||||
signal brightnessDeviceUpdate(var device)
|
||||
signal extWorkspaceStateUpdate(var data)
|
||||
signal wlrOutputStateUpdate(var data)
|
||||
|
||||
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "gamma", "bluetooth", "bluetooth.pairing", "dwl", "brightness"]
|
||||
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "gamma", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput"]
|
||||
|
||||
Component.onCompleted: {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
@@ -346,6 +347,8 @@ Singleton {
|
||||
}
|
||||
} else if (service === "extworkspace") {
|
||||
extWorkspaceStateUpdate(data)
|
||||
} else if (service === "wlroutput") {
|
||||
wlrOutputStateUpdate(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
275
Services/WlrOutputService.qml
Normal file
275
Services/WlrOutputService.qml
Normal file
@@ -0,0 +1,275 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool wlrOutputAvailable: false
|
||||
property var outputs: []
|
||||
property int serial: 0
|
||||
|
||||
signal stateChanged
|
||||
signal configurationApplied(bool success, string message)
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function onCapabilitiesReceived() {
|
||||
checkCapabilities()
|
||||
}
|
||||
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkCapabilities()
|
||||
return
|
||||
}
|
||||
wlrOutputAvailable = false
|
||||
}
|
||||
|
||||
function onWlrOutputStateUpdate(data) {
|
||||
if (!wlrOutputAvailable) {
|
||||
return
|
||||
}
|
||||
handleStateUpdate(data)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!DMSService.dmsAvailable) {
|
||||
return
|
||||
}
|
||||
checkCapabilities()
|
||||
}
|
||||
|
||||
function checkCapabilities() {
|
||||
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
|
||||
wlrOutputAvailable = false
|
||||
return
|
||||
}
|
||||
|
||||
const hasWlrOutput = DMSService.capabilities.includes("wlroutput")
|
||||
if (hasWlrOutput && !wlrOutputAvailable) {
|
||||
wlrOutputAvailable = true
|
||||
console.info("WlrOutputService: wlr-output-management capability detected")
|
||||
requestState()
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasWlrOutput) {
|
||||
wlrOutputAvailable = false
|
||||
}
|
||||
}
|
||||
|
||||
function requestState() {
|
||||
if (!DMSService.isConnected || !wlrOutputAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
DMSService.sendRequest("wlroutput.getState", null, response => {
|
||||
if (!response.result) {
|
||||
return
|
||||
}
|
||||
handleStateUpdate(response.result)
|
||||
})
|
||||
}
|
||||
|
||||
function handleStateUpdate(state) {
|
||||
outputs = state.outputs || []
|
||||
serial = state.serial || 0
|
||||
|
||||
if (outputs.length === 0) {
|
||||
console.warn("WlrOutputService: Received empty outputs list")
|
||||
} else {
|
||||
console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial)
|
||||
outputs.forEach((output, index) => {
|
||||
console.log("WlrOutputService: Output", index, "-", output.name,
|
||||
"enabled:", output.enabled,
|
||||
"mode:", output.currentMode ?
|
||||
output.currentMode.width + "x" + output.currentMode.height + "@" +
|
||||
(output.currentMode.refresh / 1000) + "Hz" : "none")
|
||||
})
|
||||
}
|
||||
stateChanged()
|
||||
}
|
||||
|
||||
function getOutput(name) {
|
||||
for (const output of outputs) {
|
||||
if (output.name === name) {
|
||||
return output
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function getEnabledOutputs() {
|
||||
return outputs.filter(output => output.enabled)
|
||||
}
|
||||
|
||||
function applyConfiguration(heads, callback) {
|
||||
if (!DMSService.isConnected || !wlrOutputAvailable) {
|
||||
if (callback) {
|
||||
callback(false, "Not connected")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
console.log("WlrOutputService: Applying configuration for", heads.length, "outputs")
|
||||
heads.forEach((head, index) => {
|
||||
console.log("WlrOutputService: Head", index, "- name:", head.name,
|
||||
"enabled:", head.enabled,
|
||||
"modeId:", head.modeId,
|
||||
"customMode:", JSON.stringify(head.customMode),
|
||||
"position:", JSON.stringify(head.position),
|
||||
"scale:", head.scale,
|
||||
"transform:", head.transform,
|
||||
"adaptiveSync:", head.adaptiveSync)
|
||||
})
|
||||
|
||||
DMSService.sendRequest("wlroutput.applyConfiguration", {
|
||||
"heads": heads
|
||||
}, response => {
|
||||
const success = !response.error
|
||||
const message = response.error || response.result?.message || ""
|
||||
|
||||
if (response.error) {
|
||||
console.warn("WlrOutputService: applyConfiguration error:", response.error)
|
||||
} else {
|
||||
console.log("WlrOutputService: Configuration applied successfully")
|
||||
}
|
||||
|
||||
configurationApplied(success, message)
|
||||
if (callback) {
|
||||
callback(success, message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function testConfiguration(heads, callback) {
|
||||
if (!DMSService.isConnected || !wlrOutputAvailable) {
|
||||
if (callback) {
|
||||
callback(false, "Not connected")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
console.log("WlrOutputService: Testing configuration for", heads.length, "outputs")
|
||||
|
||||
DMSService.sendRequest("wlroutput.testConfiguration", {
|
||||
"heads": heads
|
||||
}, response => {
|
||||
const success = !response.error
|
||||
const message = response.error || response.result?.message || ""
|
||||
|
||||
if (response.error) {
|
||||
console.warn("WlrOutputService: testConfiguration error:", response.error)
|
||||
} else {
|
||||
console.log("WlrOutputService: Configuration test passed")
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(success, message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setOutputEnabled(outputName, enabled, callback) {
|
||||
const output = getOutput(outputName)
|
||||
if (!output) {
|
||||
console.warn("WlrOutputService: Output not found:", outputName)
|
||||
if (callback) {
|
||||
callback(false, "Output not found")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": enabled
|
||||
}]
|
||||
|
||||
if (enabled && output.currentMode) {
|
||||
heads[0].modeId = output.currentMode.id
|
||||
}
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputMode(outputName, modeId, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"modeId": modeId
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputCustomMode(outputName, width, height, refresh, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"customMode": {
|
||||
"width": width,
|
||||
"height": height,
|
||||
"refresh": refresh
|
||||
}
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputPosition(outputName, x, y, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"position": {
|
||||
"x": x,
|
||||
"y": y
|
||||
}
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputScale(outputName, scale, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"scale": scale
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputTransform(outputName, transform, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"transform": transform
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function setOutputAdaptiveSync(outputName, state, callback) {
|
||||
const heads = [{
|
||||
"name": outputName,
|
||||
"enabled": true,
|
||||
"adaptiveSync": state
|
||||
}]
|
||||
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function configureOutput(config, callback) {
|
||||
const heads = [config]
|
||||
applyConfiguration(heads, callback)
|
||||
}
|
||||
|
||||
function configureMultipleOutputs(configs, callback) {
|
||||
applyConfiguration(configs, callback)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user