From 2e558f2489ac75df41e62fbe79286f950fb5cdbc Mon Sep 17 00:00:00 2001 From: bbedward Date: Wed, 5 Aug 2026 17:02:38 -0400 Subject: [PATCH] display config/niri: fix nested kdl blocks as being attributed to output state fixes #2966 port 1.5 (cherry picked from commit cffc33e14aa8c08de79aa1469fd5dcce3e9e533e) --- .../DisplayConfig/DisplayConfigState.qml | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml index b526f8d07..0c8945b39 100644 --- a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml +++ b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml @@ -1088,15 +1088,50 @@ Singleton { } } + function extractNiriOutputBlocks(content) { + const blocks = []; + const headerRegex = /output\s+"([^"]+)"\s*\{/g; + let match; + while ((match = headerRegex.exec(content)) !== null) { + const start = headerRegex.lastIndex; + let depth = 1; + let i = start; + while (i < content.length && depth > 0) { + const ch = content[i]; + if (ch === '{') + depth++; + else if (ch === '}') + depth--; + i++; + } + blocks.push({ + "name": match[1], + "body": content.slice(start, i - 1) + }); + headerRegex.lastIndex = i; + } + return blocks; + } + + function stripNestedBlocks(body) { + let stripped = body; + let prev; + do { + prev = stripped; + stripped = stripped.replace(/[\w-]+\s*\{[^{}]*\}/g, ""); + } while (stripped !== prev) + return stripped; + } + function parseNiriOutputs(content) { const result = {}; - const outputRegex = /output\s+"([^"]+)"\s*\{([^}]*)\}/g; - let match; - while ((match = outputRegex.exec(content)) !== null) { - const name = match[1]; - const body = match[2]; + for (const block of extractNiriOutputBlocks(content)) { + const name = block.name; + const body = block.body; - const disabled = /^\s*off\s*$/m.test(body); + // off marks the output disabled only at the top level of its block; + // nested sections like hot-corners { off } must not count (#2966) + const disabled = /^\s*off\s*$/m.test(stripNestedBlocks(body)); const modeMatch = body.match(/mode\s+"(\d+)x(\d+)@([\d.]+)"/); const posMatch = body.match(/position\s+x=(-?\d+)\s+y=(-?\d+)/); const scaleMatch = body.match(/scale\s+([\d.]+)/);