From 19406e99b9c3b8cc17bb22017138af509b3f6f8c Mon Sep 17 00:00:00 2001 From: purian23 Date: Tue, 30 Jun 2026 14:48:09 -0400 Subject: [PATCH] refactor(include): Add missing layout include & normalize config banners - The Display config process ID now includes the output name in NiriService --- core/cmd/dms/commands_config.go | 2 + quickshell/Common/ConfigIncludeResolve.js | 22 +- .../Modules/Settings/CompositorLayoutTab.qml | 196 ++++++++++++++++++ .../DisplayConfig/DisplayConfigState.qml | 8 + .../DisplayConfig/IncludeWarningBox.qml | 23 +- quickshell/Modules/Settings/KeybindsTab.qml | 28 +-- .../Modules/Settings/ThemeColorsTab.qml | 45 ++-- .../Modules/Settings/WindowRulesTab.qml | 26 ++- quickshell/Services/NiriService.qml | 4 +- 9 files changed, 286 insertions(+), 68 deletions(-) diff --git a/core/cmd/dms/commands_config.go b/core/cmd/dms/commands_config.go index 2eace0d19..dc9505e5b 100644 --- a/core/cmd/dms/commands_config.go +++ b/core/cmd/dms/commands_config.go @@ -37,9 +37,11 @@ var resolveIncludeCmd = &cobra.Command{ "cursor.lua", "windowrules.lua", "cursor.kdl", + "layout.kdl", "outputs.kdl", "binds.kdl", "cursor.conf", + "layout.conf", "outputs.conf", "binds.conf", }, cobra.ShellCompDirectiveNoFileComp diff --git a/quickshell/Common/ConfigIncludeResolve.js b/quickshell/Common/ConfigIncludeResolve.js index 4ba5b2ce9..ce161de61 100644 --- a/quickshell/Common/ConfigIncludeResolve.js +++ b/quickshell/Common/ConfigIncludeResolve.js @@ -7,6 +7,24 @@ function dirname(path) { return idx > 0 ? path.substring(0, idx) : "."; } +function sectionHeaderFor(includeLine) { + const line = String(includeLine ?? "").trim(); + if (line.startsWith("require")) + return "-- DMS Include Configs"; + if (line.startsWith("source")) + return "# DMS Include Configs"; + return "// DMS Include Configs"; +} + +function managedIncludePatternFor(includeLine) { + const line = String(includeLine ?? "").trim(); + if (line.startsWith("require")) + return "require.*dms[.]"; + if (line.startsWith("source")) + return "source.*dms/"; + return "include.*dms/"; +} + function buildRepairScript(options) { const configFile = options.configFile; const backupFile = options.backupFile; @@ -31,7 +49,9 @@ function buildRepairScript(options) { for (const include of includes) { if (!include.grepPattern || !include.includeLine) continue; - commands.push(`if ! grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(include.grepPattern)}; then echo '' >> ${shQuote(configFile)} && printf '%s\\n' ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; fi`); + const sectionHeader = options.sectionHeader || sectionHeaderFor(include.includeLine); + const managedIncludePattern = managedIncludePatternFor(include.includeLine); + commands.push(`if ! grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(include.grepPattern)}; then if grep -Fqx ${shQuote(sectionHeader)} ${shQuote(configFile)} 2>/dev/null || grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(managedIncludePattern)}; then printf '%s\\n' ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; elif [ -s ${shQuote(configFile)} ]; then printf '\\n%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; else printf '%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; fi; fi`); } return commands.join("; "); diff --git a/quickshell/Modules/Settings/CompositorLayoutTab.qml b/quickshell/Modules/Settings/CompositorLayoutTab.qml index ed27c8ae9..e32919978 100644 --- a/quickshell/Modules/Settings/CompositorLayoutTab.qml +++ b/quickshell/Modules/Settings/CompositorLayoutTab.qml @@ -1,10 +1,130 @@ +import QtCore import QtQuick +import Quickshell import qs.Common import qs.Services import qs.Widgets import qs.Modules.Settings.Widgets +import "../../Common/ConfigIncludeResolve.js" as ConfigIncludeResolve Item { + id: root + + LayoutMirroring.enabled: I18n.isRtl + LayoutMirroring.childrenInherit: true + + property var layoutIncludeStatus: ({ + "exists": false, + "included": false, + "configFormat": "", + "readOnly": false + }) + readonly property bool readOnly: CompositorService.isHyprland && layoutIncludeStatus.readOnly === true + property bool checkingInclude: false + property bool fixingInclude: false + + function getLayoutConfigPaths() { + const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); + switch (CompositorService.compositor) { + case "niri": + return { + "configFile": configDir + "/niri/config.kdl", + "layoutFile": configDir + "/niri/dms/layout.kdl", + "grepPattern": 'include.*"dms/layout.kdl"', + "includeLine": 'include "dms/layout.kdl"' + }; + case "hyprland": + return { + "configFile": configDir + "/hypr/hyprland.lua", + "layoutFile": configDir + "/hypr/dms/layout.lua", + "grepPattern": "dms.layout", + "includeLine": "require(\"dms.layout\")" + }; + case "mango": + return { + "configFile": configDir + "/mango/config.conf", + "layoutFile": configDir + "/mango/dms/layout.conf", + "grepPattern": "source.*dms/layout.conf", + "includeLine": "source=./dms/layout.conf" + }; + default: + return null; + } + } + + function checkLayoutIncludeStatus() { + const compositor = CompositorService.compositor; + if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "mango") { + layoutIncludeStatus = { + "exists": false, + "included": false, + "configFormat": "", + "readOnly": false + }; + return; + } + + const filename = compositor === "niri" ? "layout.kdl" : (compositor === "hyprland" ? "layout.lua" : "layout.conf"); + const compositorArg = compositor === "mango" ? "mangowc" : compositor; + + checkingInclude = true; + Proc.runCommand("check-layout-include", ["dms", "config", "resolve-include", compositorArg, filename], (output, exitCode) => { + checkingInclude = false; + if (exitCode !== 0) { + layoutIncludeStatus = { + "exists": false, + "included": false, + "configFormat": "", + "readOnly": false + }; + return; + } + try { + layoutIncludeStatus = JSON.parse(output.trim()); + } catch (e) { + layoutIncludeStatus = { + "exists": false, + "included": false, + "configFormat": "", + "readOnly": false + }; + } + }); + } + + function fixLayoutInclude() { + if (readOnly) { + ToastService.showWarning(I18n.tr("Hyprland conf mode"), I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing layout settings."), "dms setup", "hyprland-migration"); + return; + } + const paths = getLayoutConfigPaths(); + if (!paths) + return; + + fixingInclude = true; + const unixTime = Math.floor(Date.now() / 1000); + const backupFile = paths.configFile + ".backup" + unixTime; + const script = ConfigIncludeResolve.buildRepairScript({ + configFile: paths.configFile, + backupFile: backupFile, + fragmentFile: paths.layoutFile, + grepPattern: paths.grepPattern, + includeLine: paths.includeLine + }); + Proc.runCommand("fix-layout-include", ["sh", "-c", script], (output, exitCode) => { + fixingInclude = false; + if (exitCode !== 0) + return; + checkLayoutIncludeStatus(); + SettingsData.updateCompositorLayout(); + }); + } + + Component.onCompleted: { + if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) + checkLayoutIncludeStatus(); + } + DankFlickable { anchors.fill: parent clip: true @@ -19,6 +139,82 @@ Item { anchors.horizontalCenter: parent.horizontalCenter spacing: Theme.spacingXL + StyledRect { + id: warningBox + width: parent.width + height: warningContent.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + + readonly property bool showLegacy: root.readOnly + readonly property bool showSetup: !showLegacy && !root.layoutIncludeStatus.included + + color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) + border.color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) + border.width: 1 + visible: (showLegacy || showSetup) && !root.checkingInclude && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) + + Row { + id: warningContent + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + DankIcon { + name: "warning" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: { + if (warningBox.showLegacy) + return I18n.tr("Hyprland conf mode"); + if (warningBox.showSetup) + return I18n.tr("First Time Setup"); + return ""; + } + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: Theme.primary + width: parent.width + horizontalAlignment: Text.AlignLeft + } + + StyledText { + text: { + if (warningBox.showLegacy) + return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing layout settings."); + if (warningBox.showSetup) + return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/layout"); + return ""; + } + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + wrapMode: Text.WordWrap + width: parent.width + horizontalAlignment: Text.AlignLeft + } + } + + DankButton { + id: fixButton + visible: !warningBox.showLegacy && warningBox.showSetup + text: root.fixingInclude ? I18n.tr("Setting up...") : I18n.tr("Setup") + backgroundColor: Theme.primary + textColor: Theme.primaryText + enabled: !root.fixingInclude + anchors.verticalCenter: parent.verticalCenter + onClicked: root.fixLayoutInclude() + } + } + } + SettingsCard { width: parent.width tags: ["niri", "layout", "gaps", "radius", "window", "border"] diff --git a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml index 5b8ac1664..7d5b40944 100644 --- a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml +++ b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml @@ -847,6 +847,14 @@ Singleton { } } + Connections { + target: NiriService + enabled: CompositorService.isNiri + function onConfigReloaded() { + root.checkIncludeStatus(); + } + } + Component.onCompleted: { outputs = buildOutputsMap(); reloadSavedOutputs(); diff --git a/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml b/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml index 2a57a152f..b249fac7c 100644 --- a/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml +++ b/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml @@ -13,13 +13,12 @@ StyledRect { radius: Theme.cornerRadius readonly property bool showLegacy: DisplayConfigState.readOnly - readonly property bool showError: !showLegacy && DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included - readonly property bool showSetup: !showLegacy && !DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included + readonly property bool showSetup: !showLegacy && !DisplayConfigState.includeStatus.included - color: (showLegacy || showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) - border.color: (showLegacy || showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) + color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) + border.color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) border.width: 1 - visible: (showLegacy || showError || showSetup) && DisplayConfigState.hasOutputBackend && !DisplayConfigState.checkingInclude + visible: (showLegacy || showSetup) && DisplayConfigState.hasOutputBackend && !DisplayConfigState.checkingInclude Column { id: warningContent @@ -49,8 +48,6 @@ StyledRect { return I18n.tr("Hyprland conf mode"); if (root.showSetup) return I18n.tr("First Time Setup"); - if (root.showError) - return I18n.tr("Outputs Include Missing"); return ""; } font.pixelSize: Theme.fontSizeMedium @@ -66,8 +63,6 @@ StyledRect { return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing display settings."); if (root.showSetup) return I18n.tr("Click 'Setup' to create the outputs config and add include to your compositor config."); - if (root.showError) - return I18n.tr("dms/outputs config exists but is not included in your compositor config. Display changes won't persist."); return ""; } font.pixelSize: Theme.fontSizeSmall @@ -80,14 +75,8 @@ StyledRect { DankButton { id: fixButton - visible: !root.showLegacy && (root.showError || root.showSetup) - text: { - if (DisplayConfigState.fixingInclude) - return I18n.tr("Fixing..."); - if (root.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } + visible: !root.showLegacy && root.showSetup + text: DisplayConfigState.fixingInclude ? I18n.tr("Setting up...") : I18n.tr("Setup") backgroundColor: Theme.primary textColor: Theme.primaryText enabled: !DisplayConfigState.fixingInclude diff --git a/quickshell/Modules/Settings/KeybindsTab.qml b/quickshell/Modules/Settings/KeybindsTab.qml index 9152231c0..a0c885a10 100644 --- a/quickshell/Modules/Settings/KeybindsTab.qml +++ b/quickshell/Modules/Settings/KeybindsTab.qml @@ -347,14 +347,13 @@ Item { readonly property var status: KeybindsService.dmsStatus readonly property bool showLegacy: KeybindsService.readOnly - readonly property bool showError: !showLegacy && !status.included && status.exists readonly property bool showWarning: !showLegacy && status.included && status.overriddenBy > 0 - readonly property bool showSetup: !showLegacy && !status.exists + readonly property bool showSetup: !showLegacy && !status.included - color: (showLegacy || showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) - border.color: (showLegacy || showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) + color: (showLegacy || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) + border.color: (showLegacy || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) border.width: 1 - visible: (showLegacy || showError || showWarning || showSetup) && !KeybindsService.loading + visible: (showLegacy || showWarning || showSetup) && !KeybindsService.loading Column { id: warningSection @@ -384,8 +383,6 @@ Item { return I18n.tr("Hyprland conf mode"); if (warningBox.showSetup) return I18n.tr("First Time Setup"); - if (warningBox.showError) - return I18n.tr("Binds Include Missing"); if (warningBox.showWarning) return I18n.tr("Possible Override Conflicts"); return ""; @@ -393,17 +390,16 @@ Item { font.pixelSize: Theme.fontSizeMedium font.weight: Font.Medium color: Theme.primary + width: parent.width + horizontalAlignment: Text.AlignLeft } StyledText { - readonly property string bindsFile: KeybindsService.currentProvider === "niri" ? "dms/binds.kdl" : KeybindsService.currentProvider === "hyprland" ? "dms/binds-user.lua" : "dms/binds.conf" text: { if (warningBox.showLegacy) return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing shortcuts in Settings."); if (warningBox.showSetup) - return I18n.tr("Click 'Setup' to create %1 and add include to config.").arg(bindsFile); - if (warningBox.showError) - return I18n.tr("%1 exists but is not included in config. Custom keybinds will not work until this is fixed.").arg(bindsFile); + return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/binds"); if (warningBox.showWarning) { const count = warningBox.status.overriddenBy; return I18n.ntr("%1 DMS bind may be overridden by config binds that come after the include.", "%1 DMS binds may be overridden by config binds that come after the include.", count).arg(count); @@ -420,14 +416,8 @@ Item { DankButton { id: fixButton - visible: !warningBox.showLegacy && (warningBox.showError || warningBox.showSetup) - text: { - if (KeybindsService.fixing) - return I18n.tr("Fixing..."); - if (warningBox.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } + visible: !warningBox.showLegacy && warningBox.showSetup + text: KeybindsService.fixing ? I18n.tr("Setting up...") : I18n.tr("Setup") backgroundColor: Theme.primary textColor: Theme.primaryText enabled: !KeybindsService.fixing diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 139ef22a0..f7f1c0fa0 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -2078,27 +2078,27 @@ Item { StyledRect { id: cursorWarningBox width: parent.width - height: cursorWarningContent.implicitHeight + Theme.spacingM * 2 + height: cursorWarningContent.implicitHeight + Theme.spacingL * 2 radius: Theme.cornerRadius - readonly property bool showError: themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included - readonly property bool showSetup: !themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included + readonly property bool showLegacy: themeColorsTab.cursorReadOnly + readonly property bool showSetup: !showLegacy && !themeColorsTab.cursorIncludeStatus.included - color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : Theme.withAlpha(Theme.warning, 0) - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : Theme.withAlpha(Theme.warning, 0) + color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) + border.color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) border.width: 1 - visible: (showError || showSetup) && !themeColorsTab.checkingCursorInclude + visible: (showLegacy || showSetup) && !themeColorsTab.checkingCursorInclude Row { id: cursorWarningContent anchors.fill: parent - anchors.margins: Theme.spacingM + anchors.margins: Theme.spacingL spacing: Theme.spacingM DankIcon { name: "warning" size: Theme.iconSize - color: Theme.warning + color: Theme.primary anchors.verticalCenter: parent.verticalCenter } @@ -2108,27 +2108,42 @@ Item { anchors.verticalCenter: parent.verticalCenter StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Cursor Config Not Configured") : I18n.tr("Cursor Include Missing") + text: { + if (cursorWarningBox.showLegacy) + return I18n.tr("Hyprland conf mode"); + if (cursorWarningBox.showSetup) + return I18n.tr("First Time Setup"); + return ""; + } font.pixelSize: Theme.fontSizeMedium font.weight: Font.Medium - color: Theme.warning + color: Theme.primary + width: parent.width + horizontalAlignment: Text.AlignLeft } StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Click 'Setup' to create cursor config and add include to your compositor config.") : I18n.tr("dms/cursor config exists but is not included. Cursor settings won't apply.") + text: { + if (cursorWarningBox.showLegacy) + return I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing cursor settings."); + if (cursorWarningBox.showSetup) + return I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/cursor"); + return ""; + } font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceVariantText wrapMode: Text.WordWrap width: parent.width + horizontalAlignment: Text.AlignLeft } } DankButton { id: cursorFixButton - visible: cursorWarningBox.showError || cursorWarningBox.showSetup - text: themeColorsTab.fixingCursorInclude ? I18n.tr("Fixing...") : (cursorWarningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background + visible: !cursorWarningBox.showLegacy && cursorWarningBox.showSetup + text: themeColorsTab.fixingCursorInclude ? I18n.tr("Setting up...") : I18n.tr("Setup") + backgroundColor: Theme.primary + textColor: Theme.primaryText enabled: !themeColorsTab.fixingCursorInclude anchors.verticalCenter: parent.verticalCenter onClicked: themeColorsTab.fixCursorInclude() diff --git a/quickshell/Modules/Settings/WindowRulesTab.qml b/quickshell/Modules/Settings/WindowRulesTab.qml index 9d61a2c9a..67b99bd43 100644 --- a/quickshell/Modules/Settings/WindowRulesTab.qml +++ b/quickshell/Modules/Settings/WindowRulesTab.qml @@ -472,13 +472,12 @@ Item { radius: Theme.cornerRadius readonly property bool showLegacy: root.readOnly - readonly property bool showError: !showLegacy && root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included - readonly property bool showSetup: !showLegacy && !root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included + readonly property bool showSetup: !showLegacy && !root.windowRulesIncludeStatus.included - color: (showLegacy || showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : Theme.withAlpha(Theme.warning, 0) - border.color: (showLegacy || showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : Theme.withAlpha(Theme.warning, 0) + color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : Theme.withAlpha(Theme.primary, 0) + border.color: (showLegacy || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.primary, 0) border.width: 1 - visible: (showLegacy || showError || showSetup) && !root.checkingInclude && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) + visible: (showLegacy || showSetup) && !root.checkingInclude && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) Row { id: warningSection @@ -489,7 +488,7 @@ Item { DankIcon { name: "warning" size: Theme.iconSize - color: Theme.warning + color: Theme.primary anchors.verticalCenter: parent.verticalCenter } @@ -499,17 +498,16 @@ Item { anchors.verticalCenter: parent.verticalCenter StyledText { - text: warningBox.showLegacy ? I18n.tr("Hyprland conf mode") : (warningBox.showSetup ? I18n.tr("Window Rules Not Configured") : I18n.tr("Window Rules Include Missing")) + text: warningBox.showLegacy ? I18n.tr("Hyprland conf mode") : I18n.tr("First Time Setup") font.pixelSize: Theme.fontSizeMedium font.weight: Font.Medium - color: Theme.warning + color: Theme.primary width: parent.width horizontalAlignment: Text.AlignLeft } StyledText { - readonly property string rulesFile: root.dmsRulesFileName - text: warningBox.showLegacy ? I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing window rules in Settings.") : (warningBox.showSetup ? I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg(rulesFile) : I18n.tr("%1 exists but is not included. Window rules won't apply.").arg(rulesFile)) + text: warningBox.showLegacy ? I18n.tr("This install is still using hyprland.conf. Run dms setup to migrate before editing window rules in Settings.") : I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg("dms/windowrules") font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceVariantText wrapMode: Text.WordWrap @@ -520,10 +518,10 @@ Item { DankButton { id: fixButton - visible: !warningBox.showLegacy && (warningBox.showError || warningBox.showSetup) - text: root.fixingInclude ? I18n.tr("Fixing...") : (warningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background + visible: !warningBox.showLegacy && warningBox.showSetup + text: root.fixingInclude ? I18n.tr("Setting up...") : I18n.tr("Setup") + backgroundColor: Theme.primary + textColor: Theme.primaryText enabled: !root.fixingInclude anchors.verticalCenter: parent.verticalCenter onClicked: root.fixWindowRulesInclude() diff --git a/quickshell/Services/NiriService.qml b/quickshell/Services/NiriService.qml index 7e3ef34a2..3696a39b8 100644 --- a/quickshell/Services/NiriService.qml +++ b/quickshell/Services/NiriService.qml @@ -1252,7 +1252,7 @@ Singleton { commands.push(`niri msg output "${outputName}" ${config.disabled ? "off" : "on"}`); if (config.disabled) { const fullDisableCommand = "{ " + commands.join(" && ") + "; } 2>&1"; - Proc.runCommand("niri-output-config", ["sh", "-c", fullDisableCommand], (output, exitCode) => { + Proc.runCommand("niri-output-config-" + outputName, ["sh", "-c", fullDisableCommand], (output, exitCode) => { if (exitCode !== 0) { log.warn("Failed to apply output config:", outputName, "exit:", exitCode, output); if (callback) @@ -1296,7 +1296,7 @@ Singleton { } const fullCommand = "{ " + commands.join(" && ") + "; } 2>&1"; - Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => { + Proc.runCommand("niri-output-config-" + outputName, ["sh", "-c", fullCommand], (output, exitCode) => { if (exitCode !== 0) { log.warn("Failed to apply output config:", outputName, "exit:", exitCode, output); if (callback)