From 0253f9daa5ca479876516169dd22bda052a9aa98 Mon Sep 17 00:00:00 2001 From: fluxwrk <296322568+fluxwrk@users.noreply.github.com> Date: Thu, 20 Aug 2026 12:06:42 -0500 Subject: [PATCH] fix: update mango named scratchpad keybind (#3118) --- quickshell/Common/KeybindActions.js | 50 ++++-- quickshell/Modules/Settings/KeybindItem.qml | 163 +++++++++++++++----- 2 files changed, 165 insertions(+), 48 deletions(-) diff --git a/quickshell/Common/KeybindActions.js b/quickshell/Common/KeybindActions.js index 857c1b783..24bdab256 100644 --- a/quickshell/Common/KeybindActions.js +++ b/quickshell/Common/KeybindActions.js @@ -294,7 +294,7 @@ const MANGOWC_ACTIONS = { ], "Scratchpad": [ { id: "toggle_scratchpad", label: "Toggle Scratchpad" }, - { id: "toggle_name_scratchpad", label: "Toggle Named Scratchpad" } + { id: "toggle_named_scratchpad", label: "Toggle Named Scratchpad" } ], "Overview": [ { id: "toggleoverview", label: "Toggle Overview" } @@ -549,8 +549,12 @@ const MANGOWC_ACTION_ARGS = { "setoption": { args: [{ name: "option", type: "text", label: "Option", placeholder: "option_name value" }] }, - "toggle_name_scratchpad": { - args: [{ name: "name", type: "text", label: "Name", placeholder: "scratchpad name" }] + "toggle_named_scratchpad": { + args: [ + { name: "appid", type: "text", label: "App ID", placeholder: "Optional", emptyValue: "none" }, + { name: "title", type: "text", label: "Title", placeholder: "Optional", emptyValue: "none" }, + { name: "command", type: "text", label: "Command", placeholder: "Command" } + ] }, "incnmaster": { args: [{ name: "value", type: "number", label: "Amount", placeholder: "+1, -1" }] @@ -1070,9 +1074,24 @@ function parseCompositorActionArgs(compositor, action) { case "mangowc": if (argConfig.args && argConfig.args.length > 0 && argParts.length > 0) { var paramStr = argParts.join(" "); - var paramValues = paramStr.split(","); - for (var m = 0; m < argConfig.args.length && m < paramValues.length; m++) { - args[argConfig.args[m].name] = paramValues[m]; + var remaining = paramStr; + + for (var m = 0; m < argConfig.args.length; m++) { + var argDef = argConfig.args[m]; + + if (m === argConfig.args.length - 1) { + args[argDef.name] = remaining; + break; + } + + var commaIdx = remaining.indexOf(","); + if (commaIdx === -1) { + args[argDef.name] = remaining; + break; + } + + args[argDef.name] = remaining.substring(0, commaIdx); + remaining = remaining.substring(commaIdx + 1); } } break; @@ -1215,15 +1234,26 @@ function buildCompositorAction(compositor, base, args) { if (compositorArgs && compositorArgs[base] && compositorArgs[base].args) { var argConfig = compositorArgs[base].args; var argValues = []; + for (var i = 0; i < argConfig.length; i++) { var argDef = argConfig[i]; var val = args[argDef.name]; - if (val === undefined || val === "") - val = argDef.default || ""; - if (val === "" && argValues.length === 0) - continue; + + if (val === undefined || val === "") { + if (argDef.emptyValue !== undefined) + val = argDef.emptyValue; + else if (argDef.default !== undefined) + val = argDef.default; + else + val = ""; + } + argValues.push(val); } + + while (argValues.length > 0 && argValues[argValues.length - 1] === "") + argValues.pop(); + if (argValues.length > 0) parts.push(argValues.join(",")); } else if (args.value) { diff --git a/quickshell/Modules/Settings/KeybindItem.qml b/quickshell/Modules/Settings/KeybindItem.qml index 027462a86..e026933e0 100644 --- a/quickshell/Modules/Settings/KeybindItem.qml +++ b/quickshell/Modules/Settings/KeybindItem.qml @@ -1254,6 +1254,66 @@ Item { readonly property var argConfig: Actions.getActionArgConfig(KeybindsService.currentProvider, root.editAction) readonly property var parsedArgs: Actions.parseCompositorActionArgs(KeybindsService.currentProvider, root.editAction) + readonly property int argCount: argConfig?.config?.args?.length || 0 + + readonly property int argEditorCount: { + const defs = argConfig?.config?.args || []; + let count = 0; + + for (let i = 0; i < defs.length; i++) { + if (shouldShowArgEditor(i, defs[i])) + count++; + } + + return count; + } + + function shouldShowArgEditor(index, argDef) { + if (!argDef) + return false; + + if (argDef.type !== "text" && argDef.type !== "number") + return false; + + if (KeybindsService.currentProvider === "mangowc") + return true; + + return index === 0; + } + + function displayArgValue(argDef) { + if (!argDef || !parsedArgs?.args) + return ""; + + const value = parsedArgs.args[argDef.name]; + + if (value === undefined || value === null) + return ""; + + if (argDef.emptyValue !== undefined && value === argDef.emptyValue) + return ""; + + return String(value); + } + + function commitArgValue(argDef, textValue) { + if (!argDef || !argConfig) + return; + + const parsed = parsedArgs; + const args = Object.assign({}, parsed?.args || {}); + + args[argDef.name] = textValue; + + root.updateEdit({ + "action": Actions.buildCompositorAction( + KeybindsService.currentProvider, + parsed?.base || argConfig.base, + args + ) + }); + } + StyledText { text: I18n.tr("Options") font.pixelSize: Theme.fontSizeSmall @@ -1266,51 +1326,78 @@ Item { Layout.fillWidth: true spacing: Theme.spacingS - DankTextField { - id: argValueField - Layout.fillWidth: true - Layout.preferredHeight: root._inputHeight + Repeater { + model: optionsRow.argCount - readonly property string _argName: optionsRow.argConfig?.config?.args[0]?.name || "value" + delegate: ColumnLayout { + id: argEditor - visible: { - const cfg = optionsRow.argConfig; - if (!cfg?.config?.args) - return false; - const firstArg = cfg.config.args[0]; - return firstArg && (firstArg.type === "text" || firstArg.type === "number"); - } - placeholderText: optionsRow.argConfig?.config?.args[0]?.placeholder || "" + required property int index - function commitValue(textValue) { - const cfg = optionsRow.argConfig; - if (!cfg) - return; - const parsed = optionsRow.parsedArgs; - const args = Object.assign({}, parsed?.args || {}); - args[_argName] = textValue; - root.updateEdit({ - "action": Actions.buildCompositorAction(KeybindsService.currentProvider, parsed?.base || cfg.base, args) - }); - } + readonly property var argDef: optionsRow.argConfig?.config?.args[index] || null + readonly property bool editorVisible: optionsRow.shouldShowArgEditor(index, argDef) - Connections { - target: optionsRow - function onParsedArgsChanged() { - const argName = argValueField._argName; - const newText = optionsRow.parsedArgs?.args[argName] || ""; - if (argValueField.text !== newText) - argValueField.text = newText; + Layout.fillWidth: editorVisible + spacing: Theme.spacingXS + visible: editorVisible + + StyledText { + text: I18n.tr(argEditor.argDef?.label || "", "keybind option label") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + Layout.fillWidth: true + Layout.leftMargin: 6 + horizontalAlignment: Text.AlignLeft + visible: optionsRow.argEditorCount > 1 + } + + DankTextField { + id: argField + + Layout.fillWidth: true + Layout.preferredHeight: root._inputHeight + placeholderText: I18n.tr(argEditor.argDef?.placeholder || "", "keybind option placeholder") + + property bool _syncing: false + + function syncFromAction() { + const newText = optionsRow.displayArgValue(argEditor.argDef); + + if (text === newText) + return; + + _syncing = true; + text = newText; + _syncing = false; + } + + Connections { + target: optionsRow + + function onParsedArgsChanged() { + argField.syncFromAction(); + } + } + + Connections { + target: argEditor + + function onArgDefChanged() { + argField.syncFromAction(); + } + } + + Component.onCompleted: { + syncFromAction(); + } + + onTextChanged: { + if (!_syncing) + optionsRow.commitArgValue(argEditor.argDef, text); + } } } - - Component.onCompleted: { - text = optionsRow.parsedArgs?.args[_argName] || ""; - } - - onTextChanged: commitValue(text) } - RowLayout { visible: { const cfg = optionsRow.argConfig;