From 695a75ea099ee76af284e7956f002c7963a06d9c Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 11 Nov 2025 17:19:45 -0500 Subject: [PATCH] wayland: add wlr-output-management-unstable-v1 service + labwc info --- Modules/DankBar/Widgets/LauncherButton.qml | 4 +- Modules/Settings/AboutTab.qml | 51 +++- README.md | 4 +- Services/CompositorService.qml | 32 ++- Services/CupsService.qml | 2 +- Services/DMSService.qml | 5 +- Services/WlrOutputService.qml | 275 +++++++++++++++++++++ assets/labwc.png | Bin 0 -> 5211 bytes translations/en.json | 24 +- 9 files changed, 374 insertions(+), 23 deletions(-) create mode 100644 Services/WlrOutputService.qml create mode 100644 assets/labwc.png diff --git a/Modules/DankBar/Widgets/LauncherButton.qml b/Modules/DankBar/Widgets/LauncherButton.qml index 1880f7e0..6b147005 100644 --- a/Modules/DankBar/Widgets/LauncherButton.qml +++ b/Modules/DankBar/Widgets/LauncherButton.qml @@ -56,7 +56,7 @@ BasePill { } IconImage { - visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway) + visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isLabwc) anchors.centerIn: parent width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset) height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset) @@ -71,6 +71,8 @@ BasePill { return "file://" + Theme.shellDir + "/assets/mango.png" } else if (CompositorService.isSway) { return "file://" + Theme.shellDir + "/assets/sway.svg" + } else if (CompositorService.isLabwc) { + return "file://" + Theme.shellDir + "/assets/labwc.png" } return "" } diff --git a/Modules/Settings/AboutTab.qml b/Modules/Settings/AboutTab.qml index 25c61c6c..971d2327 100644 --- a/Modules/Settings/AboutTab.qml +++ b/Modules/Settings/AboutTab.qml @@ -13,11 +13,13 @@ Item { property bool isNiri: CompositorService.isNiri property bool isSway: CompositorService.isSway property bool isDwl: CompositorService.isDwl + property bool isLabwc: CompositorService.isLabwc property string compositorName: { if (isHyprland) return "hyprland" if (isSway) return "sway" if (isDwl) return "mangowc" + if (isLabwc) return "labwc" return "niri" } @@ -25,6 +27,7 @@ Item { if (isHyprland) return "/assets/hyprland.svg" if (isSway) return "/assets/sway.svg" if (isDwl) return "/assets/mango.png" + if (isLabwc) return "/assets/labwc.png" return "/assets/niri.svg" } @@ -32,6 +35,7 @@ Item { if (isHyprland) return "https://hypr.land" if (isSway) return "https://swaywm.org" if (isDwl) return "https://github.com/DreamMaoMao/mangowc" + if (isLabwc) return "https://labwc.github.io/" return "https://github.com/YaLTeR/niri" } @@ -39,6 +43,7 @@ Item { if (isHyprland) return "Hyprland Website" if (isSway) return "Sway Website" if (isDwl) return "mangowc GitHub" + if (isLabwc) return "LabWC Website" return "niri GitHub" } @@ -60,9 +65,13 @@ Item { property string redditUrl: "https://reddit.com/r/niri" property string redditTooltip: "r/niri Subreddit" - property bool showMatrix: isNiri && !isHyprland && !isSway && !isDwl + property string ircUrl: "https://web.libera.chat/gamja/?channels=#labwc" + property string ircTooltip: "LabWC IRC Channel" + + property bool showMatrix: isNiri && !isHyprland && !isSway && !isDwl && !isLabwc property bool showCompositorDiscord: isHyprland || isDwl - property bool showReddit: isNiri && !isHyprland && !isSway && !isDwl + property bool showReddit: isNiri && !isHyprland && !isSway && !isDwl && !isLabwc + property bool showIrc: isLabwc DankFlickable { anchors.fill: parent @@ -153,6 +162,9 @@ Item { if (showMatrix) { baseWidth += matrixButton.width + 4 } + if (showIrc) { + baseWidth += ircButton.width + Theme.spacingM + } if (showCompositorDiscord) { baseWidth += compositorDiscordButton.width + Theme.spacingM } @@ -232,11 +244,43 @@ Item { } } + Item { + id: ircButton + width: 24 + height: 24 + x: compositorButton.x + compositorButton.width + Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + visible: showIrc + + property bool hovered: false + property string tooltipText: ircTooltip + + DankIcon { + anchors.centerIn: parent + name: "forum" + size: 20 + color: Theme.surfaceText + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onEntered: parent.hovered = true + onExited: parent.hovered = false + onClicked: Qt.openUrlExternally(ircUrl) + } + } + Item { id: dmsDiscordButton width: 20 height: 20 - x: showMatrix ? matrixButton.x + matrixButton.width + Theme.spacingM : compositorButton.x + compositorButton.width + Theme.spacingM + x: { + if (showMatrix) return matrixButton.x + matrixButton.width + Theme.spacingM + if (showIrc) return ircButton.x + ircButton.width + Theme.spacingM + return compositorButton.x + compositorButton.width + Theme.spacingM + } anchors.verticalCenter: parent.verticalCenter property bool hovered: false @@ -618,6 +662,7 @@ Item { property var hoveredButton: { if (compositorButton.hovered) return compositorButton if (matrixButton.visible && matrixButton.hovered) return matrixButton + if (ircButton.visible && ircButton.hovered) return ircButton if (dmsDiscordButton.hovered) return dmsDiscordButton if (compositorDiscordButton.visible && compositorDiscordButton.hovered) return compositorDiscordButton if (redditButton.visible && redditButton.hovered) return redditButton diff --git a/README.md b/README.md index bb2253d8..767c8962 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ -DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hypr.land), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop - all in one cohesive package with a gorgeous interface. +DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hypr.land), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), [labwc](https://labwc.github.io/), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop - all in one cohesive package with a gorgeous interface. ## Components @@ -100,7 +100,7 @@ Endless customization with the [plugin registry](https://plugins.danklinux.com). ## Supported Compositors -DankMaterialShell works best with **[niri](https://github.com/YaLTeR/niri)**, **[Hyprland](https://hyprland.org/)**, **[sway](https://swaywm.org/)**, and **[dwl/MangoWC](https://github.com/DreamMaoMao/mangowc)** - with full workspace switching, overview integration, and monitor management. +DankMaterialShell works best with **[niri](https://github.com/YaLTeR/niri)**, **[Hyprland](https://hyprland.org/)**, **[sway](https://swaywm.org/)**, **[dwl/MangoWC](https://github.com/DreamMaoMao/mangowc)**, and **[labwc](https://labwc.github.io/)** - with full workspace switching, overview integration, and monitor management. Other Wayland compositors work too, just with a reduced feature set. diff --git a/Services/CompositorService.qml b/Services/CompositorService.qml index 90b8eb99..a3d1bf85 100644 --- a/Services/CompositorService.qml +++ b/Services/CompositorService.qml @@ -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") } diff --git a/Services/CupsService.qml b/Services/CupsService.qml index 83db99df..5e358d3c 100644 --- a/Services/CupsService.qml +++ b/Services/CupsService.qml @@ -1,6 +1,6 @@ pragma Singleton -pragma ComponentBehavior +pragma ComponentBehavior: Bound import QtQuick import Quickshell diff --git a/Services/DMSService.qml b/Services/DMSService.qml index 785ea311..6c74377d 100644 --- a/Services/DMSService.qml +++ b/Services/DMSService.qml @@ -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) } } diff --git a/Services/WlrOutputService.qml b/Services/WlrOutputService.qml new file mode 100644 index 00000000..2810e629 --- /dev/null +++ b/Services/WlrOutputService.qml @@ -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) + } +} diff --git a/assets/labwc.png b/assets/labwc.png new file mode 100644 index 0000000000000000000000000000000000000000..e60bec3bd2466c3751b7ec354f11662278b8db40 GIT binary patch literal 5211 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 SaJUN%0ngN4sMe}jNBjq6F3)QK literal 0 HcmV?d00001 diff --git a/translations/en.json b/translations/en.json index d9985033..417c93df 100644 --- a/translations/en.json +++ b/translations/en.json @@ -14,13 +14,13 @@ { "term": "- Stateless System Monitoring", "context": "- Stateless System Monitoring", - "reference": "Modules/Settings/AboutTab.qml:544", + "reference": "Modules/Settings/AboutTab.qml:588", "comment": "" }, { "term": "- Support Us With a Star ⭐", "context": "- Support Us With a Star ⭐", - "reference": "Modules/Settings/AboutTab.qml:509", + "reference": "Modules/Settings/AboutTab.qml:553", "comment": "" }, { @@ -62,7 +62,7 @@ { "term": "About", "context": "About", - "reference": "Modals/Settings/SettingsSidebar.qml:44, Modules/Settings/AboutTab.qml:363", + "reference": "Modals/Settings/SettingsSidebar.qml:44, Modules/Settings/AboutTab.qml:407", "comment": "" }, { @@ -1010,7 +1010,7 @@ { "term": "DMS out of date", "context": "DMS out of date", - "reference": "Services/DMSService.qml:300", + "reference": "Services/DMSService.qml:301", "comment": "" }, { @@ -1262,7 +1262,7 @@ { "term": "Donate on Ko-fi", "context": "Donate on Ko-fi", - "reference": "Modules/Settings/AboutTab.qml:598", + "reference": "Modules/Settings/AboutTab.qml:642", "comment": "" }, { @@ -1688,7 +1688,7 @@ { "term": "Github:", "context": "Github:", - "reference": "Modules/Settings/AboutTab.qml:482", + "reference": "Modules/Settings/AboutTab.qml:526", "comment": "" }, { @@ -2798,7 +2798,7 @@ { "term": "Plugins:", "context": "Plugins:", - "reference": "Modules/Settings/AboutTab.qml:459", + "reference": "Modules/Settings/AboutTab.qml:503", "comment": "" }, { @@ -3026,7 +3026,7 @@ { "term": "Resources", "context": "Resources", - "reference": "Modules/Settings/AboutTab.qml:421", + "reference": "Modules/Settings/AboutTab.qml:465", "comment": "" }, { @@ -3500,7 +3500,7 @@ { "term": "Support Development", "context": "Support Development", - "reference": "Modules/Settings/AboutTab.qml:583", + "reference": "Modules/Settings/AboutTab.qml:627", "comment": "" }, { @@ -3578,7 +3578,7 @@ { "term": "System Monitoring:", "context": "System Monitoring:", - "reference": "Modules/Settings/AboutTab.qml:517", + "reference": "Modules/Settings/AboutTab.qml:561", "comment": "" }, { @@ -3728,7 +3728,7 @@ { "term": "To update, run the following command:", "context": "To update, run the following command:", - "reference": "Services/DMSService.qml:300", + "reference": "Services/DMSService.qml:301", "comment": "" }, { @@ -4052,7 +4052,7 @@ { "term": "Website:", "context": "Website:", - "reference": "Modules/Settings/AboutTab.qml:436", + "reference": "Modules/Settings/AboutTab.qml:480", "comment": "" }, {