feat(mango): native mouse/touchpad & keyboard input support

- Hide blur toggle options until mango support is added
This commit is contained in:
purian23 committed 2026-10-09 05:55:47 -04:00
1 parent ea68399ef3
commit e10102edc0
21 files changed
+199 -91

No files matched your search

+1
View File
@@ -44,6 +44,7 @@ var resolveIncludeCmd = &cobra.Command{
"binds.kdl",
"input.kdl",
"cursor.conf",
"input.conf",
"layout.conf",
"outputs.conf",
"binds.conf",
+6 -4
View File
@@ -145,10 +145,12 @@ var dmsConfigSpecs = map[string]dmsConfigSpec{
niriContent: func(_ string) string { return config.NiriAlttabConfig },
},
"input": {
niriFile: "input.kdl",
hyprFile: "input.lua",
niriContent: func(_ string) string { return config.NiriInputConfig },
hyprContent: func(_ string) string { return config.DMSInputLuaConfig },
niriFile: "input.kdl",
hyprFile: "input.lua",
mangoFile: "input.conf",
niriContent: func(_ string) string { return config.NiriInputConfig },
hyprContent: func(_ string) string { return config.DMSInputLuaConfig },
mangoContent: func(_ string) string { return "" },
},
"outputs": {
niriFile: "outputs.kdl",
+1
View File
@@ -12,6 +12,7 @@ exec-once=dms run
source=./dms/colors.conf
source=./dms/layout.conf
source=./dms/cursor.conf
source=./dms/input.conf
source=./dms/outputs.conf
source=./dms/windowrules.conf
source=./dms/binds.conf
+1
View File
@@ -174,6 +174,7 @@ func (cd *ConfigDeployer) deployMangoDmsConfigs(dmsDir, terminalCommand string,
{"layout.conf", MangoLayoutConfig},
{"outputs.conf", extractMangoLines(oldMain, mangoMonitorLine)},
{"cursor.conf", ""},
{"input.conf", ""},
{"windowrules.conf", extractMangoLines(oldMain, mangoWindowLine)},
}
for _, cfg := range configs {
@@ -51,6 +51,8 @@ func TestMangoDeployMovesUserRulesAndKeepsBindsByDefault(t *testing.T) {
assert.NotEmpty(t, result.BackupPath)
assert.Contains(t, readMango(t, home, "config.conf"), "exec-once=dms run")
assert.Contains(t, readMango(t, home, "config.conf"), "source=./dms/input.conf")
assert.Equal(t, "", readMango(t, home, "dms/input.conf"))
binds := readMango(t, home, "dms/binds.conf")
assert.Contains(t, binds, "bind=SUPER,Return,spawn,foot\nkeymode=resize\nbind=NONE,h,resizewin,-10,0")
assert.NotContains(t, binds, "{{TERMINAL_COMMAND}}")
+5 -1
View File
@@ -34,14 +34,18 @@ func TestMigrateLeavesUserConfigUnlessAsked(t *testing.T) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "dms"), 0o755))
main := filepath.Join(dir, "config.conf")
layout := filepath.Join(dir, "dms", "layout.conf")
input := filepath.Join(dir, "dms", "input.conf")
require.NoError(t, os.WriteFile(main, []byte("exec-once=dms run\n"), 0o644))
require.NoError(t, os.WriteFile(layout, []byte("borderpx=2\n"), 0o644))
require.NoError(t, os.WriteFile(input, []byte("numlockon=1\n"), 0o644))
changed, err := Snake.Migrate(dir, false)
require.NoError(t, err)
assert.Equal(t, []string{layout}, changed)
assert.Equal(t, []string{layout, input}, changed)
data, _ := os.ReadFile(main)
assert.Equal(t, "exec-once=dms run\n", string(data))
data, _ = os.ReadFile(input)
assert.Equal(t, "numlock_on=1\n", string(data))
changed, err = Snake.Migrate(dir, true)
require.NoError(t, err)
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// DMS-owned fragments under mango/dms; config.conf is the user's and only
// migrated on request.
var fragments = []string{"binds.conf", "colors.conf", "layout.conf", "cursor.conf", "outputs.conf", "windowrules.conf"}
var fragments = []string{"binds.conf", "colors.conf", "layout.conf", "cursor.conf", "input.conf", "outputs.conf", "windowrules.conf"}
// Migrate respells the dms fragments, and config.conf (after a backup) when includeMain is set.
// It returns the files rewritten; an unwritable file is reported without stopping the others.
+1 -2
View File
@@ -1,7 +1,6 @@
.pragma library
// One shell-wide blur reach in logical px, solved into each compositor's own knobs.
// Hyprland's stock 8/1 reaches 16px and reads as plain transparency, so DMS defaults it near niri.
// One shell-wide blur reach in logical px, per-compositor
var HYPRLAND_DEFAULT = 48;
var NIRI_DEFAULT = 42;
var AQUEOUS_DEFAULT = 40;
+2 -1
View File
@@ -105,7 +105,8 @@ const includeTable = {
},
input: {
niri: [kdlInclude("input")],
hyprland: [luaInclude("input")]
hyprland: [luaInclude("input")],
mango: [confInclude("input")]
},
windowrules: {
niri: [kdlInclude("windowrules")],
-1
View File
@@ -245,7 +245,6 @@ Singleton {
property int mangoLayoutGapsOutOverride: Spec.SPEC.mangoLayoutGapsOutOverride.def
property int mangoLayoutRadiusOverride: Spec.SPEC.mangoLayoutRadiusOverride.def
property int mangoLayoutBorderSize: Spec.SPEC.mangoLayoutBorderSize.def
property bool mangoTrackpadNaturalScrolling: Spec.SPEC.mangoTrackpadNaturalScrolling.def
property string mouseAccelProfile: Spec.SPEC.mouseAccelProfile.def
property real mouseAccelSpeed: Spec.SPEC.mouseAccelSpeed.def
property bool mouseLeftHanded: Spec.SPEC.mouseLeftHanded.def
@@ -315,10 +315,6 @@ var LOCAL_SPEC = {
def: -1,
onChange: "updateCompositorLayout"
},
mangoTrackpadNaturalScrolling: {
def: true,
onChange: "updateCompositorCursor"
},
mouseAccelProfile: {
def: "default",
onChange: "updateCompositorInput"
@@ -114,6 +114,7 @@ Item {
}
SettingsTextFieldRow {
visible: CompositorService.isNiri || CompositorService.isHyprland
resetKeys: ["keyboardKeymapFile"]
leftIconName: "description"
text: I18n.tr("Keymap file")
@@ -113,7 +113,7 @@ Item {
}
SettingsToggleRow {
visible: CompositorService.isNiri
visible: CompositorService.isNiri || CompositorService.isMango
tags: ["mouse", "middle", "click", "emulation"]
settingKey: "mouseMiddleEmulation"
text: I18n.tr("Middle click emulation")
@@ -122,23 +122,6 @@ Item {
}
}
SettingsCard {
width: parent.width
visible: CompositorService.isMango
tags: ["touchpad", "trackpad", "natural", "scrolling", "invert"]
title: I18n.tr("Touchpad")
settingKey: "mangoTouchpadSettings"
iconName: "trackpad_input_2"
SettingsToggleRow {
tags: ["touchpad", "trackpad", "natural", "scrolling", "invert"]
settingKey: "mangoTrackpadNaturalScrolling"
text: I18n.tr("Natural scrolling")
checked: SettingsData.mangoTrackpadNaturalScrolling
onToggled: checked => SettingsData.set("mangoTrackpadNaturalScrolling", checked)
}
}
SettingsCard {
width: parent.width
visible: CompositorService.supportsInputConfig
@@ -270,7 +253,7 @@ Item {
}
SettingsToggleRow {
visible: CompositorService.isNiri
visible: CompositorService.isNiri || CompositorService.isMango
tags: ["touchpad", "disable", "external", "mouse"]
settingKey: "touchpadDisableOnExternalMouse"
text: I18n.tr("Disable with external mouse")
@@ -192,9 +192,8 @@ Column {
settingKey: "blurEnabled"
valueKeys: ["blurStrength"]
text: I18n.tr("Background blur")
description: BlurService.available ? I18n.tr("Sets the compositor's blur for every window, not just the shell", "Blur strength slider description") : I18n.tr("Your compositor does not support background blur (ext-background-effect-v1)")
visible: BlurService.available
checked: SettingsData.blurEnabled ?? false
enabled: BlurService.available
value: BlurService.strength
minimum: 16
maximum: 160
@@ -210,11 +209,19 @@ Column {
onSliderValueChanged: newValue => SettingsData.set("blurStrength", newValue)
}
SettingsNoteRow {
visible: BlurService.probed && !BlurService.available
noteIconName: "info"
tint: Theme.surfaceVariantText
tintBackground: Theme.surfaceVariantAlpha
text: I18n.tr("Your compositor does not support ext-background blur")
}
SettingsNavRow {
tab: "theme"
tags: ["blur", "xray", "compositor", "layout"]
settingKey: "blurXrayLink"
visible: CompositorService.isNiri || CompositorService.isHyprland
visible: BlurService.available && (CompositorService.isNiri || CompositorService.isHyprland)
title: I18n.tr("Xray options are in Compositor → Layout")
onClicked: keyboard => root.parentModal?.navigateTo("compositor_layout", keyboard)
}
+2
View File
@@ -14,6 +14,7 @@ Singleton {
property bool compositorSupported: false
property bool _probed: false
property bool probed: false
readonly property bool available: compositorSupported
readonly property bool blurRequested: SettingsData.blurEnabled ?? false
onBlurRequestedChanged: {
@@ -64,6 +65,7 @@ Singleton {
stdout: StdioCollector {
onStreamFinished: {
root.compositorSupported = text.trim() === "supported";
root.probed = true;
if (root.compositorSupported)
log.info("Compositor supports ext-background-effect-v1");
else
+3 -1
View File
@@ -151,7 +151,7 @@ Singleton {
readonly property bool supportsSmartDock: isNiri || isHyprland || isMango || isAqueous
readonly property bool supportsNativeOverview: isNiri || isAqueous
readonly property bool supportsPointerConfig: isNiri || isHyprland || isMango
readonly property bool supportsInputConfig: isNiri || isHyprland
readonly property bool supportsInputConfig: isNiri || isHyprland || isMango
readonly property string displayName: {
switch (compositor) {
@@ -2184,6 +2184,8 @@ Singleton {
NiriService.generateNiriInputConfig();
if (root.isHyprland && typeof HyprlandService !== "undefined")
HyprlandService.generateInputConfig();
if (root.isMango && typeof MangoService !== "undefined")
MangoService.generateInputConfig();
}
function onCompositorCursorRefreshNeeded() {
+113 -2
View File
@@ -28,10 +28,14 @@ Singleton {
readonly property string outputsPath: mangoDmsDir + "/outputs.conf"
readonly property string layoutPath: mangoDmsDir + "/layout.conf"
readonly property string cursorPath: mangoDmsDir + "/cursor.conf"
readonly property string inputPath: mangoDmsDir + "/input.conf"
readonly property string windowRulesPath: mangoDmsDir + "/windowrules.conf"
// Mango after 0.17.5 renamed every config key to snake_case with no aliases.
property bool snakeKeys: false
property bool dialectReady: false
property bool inputGenerationPending: false
property bool inputGenerationRunning: false
property int _lastGapValue: -1
property real _ignoreWatchedReloadUntil: 0
property string _lastMonitorsLine: ""
@@ -83,6 +87,13 @@ Singleton {
onFileChanged: root.handleWatchedConfigChanged()
}
FileView {
id: mangoInputWatcher
path: CompositorService.isMango ? root.inputPath : ""
watchChanges: CompositorService.isMango
onFileChanged: root.handleWatchedConfigChanged()
}
FileView {
id: mangoOutputsWatcher
path: CompositorService.isMango ? root.outputsPath : ""
@@ -453,6 +464,11 @@ Singleton {
onTriggered: root.reloadConfig(false, false)
}
DeferredAction {
id: inputGenerationAction
onTriggered: root.doGenerateInputConfig()
}
function handleWatchedConfigChanged() {
if (!CompositorService.isMango || !root.available)
return;
@@ -582,7 +598,9 @@ Singleton {
if (exitCode !== 0)
log.warn("mango-migrate exited", exitCode, "- some fragments may keep the old key spelling");
root.snakeKeys = output.trim().split("\n").pop() === "snake";
root.dialectReady = true;
generateLayoutConfig();
generateInputConfig();
});
}
@@ -673,10 +691,8 @@ gappov=${gapsOut}
const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme;
const size = settings.size || 24;
const hideTimeout = settings.mango?.cursorHideTimeout || 0;
const naturalScrolling = SettingsData.mangoTrackpadNaturalScrolling ? 1 : 0;
let content = `# Auto-generated by DMS - do not edit manually
trackpad_natural_scrolling=${naturalScrolling}
cursor_size=${size}`;
if (themeName)
@@ -697,4 +713,99 @@ cursor_size=${size}`;
reloadConfig(false);
});
}
function generateInputConfig() {
if (!CompositorService.isMango)
return;
inputGenerationPending = true;
inputGenerationAction.schedule();
}
function doGenerateInputConfig() {
if (inputGenerationRunning)
return;
inputGenerationPending = false;
if (!CompositorService.isMango)
return;
// numlock is spelled per dialect, so the first write waits for mango-migrate
if (!dialectReady) {
inputGenerationPending = true;
return;
}
inputGenerationRunning = true;
const content = ["# Auto-generated by DMS - do not edit manually"].concat(mangoInputLines(SettingsData, snakeKeys), [""]).join("\n");
// Exit 3 = unchanged, so a shell start does not reload Mango for nothing
const script = `mkdir -p "${mangoDmsDir}" && cat > "${inputPath}.tmp" << 'EOF'\n${content}EOF\nif cmp -s "${inputPath}.tmp" "${inputPath}"; then rm -f "${inputPath}.tmp"; exit 3; fi\nmv -f "${inputPath}.tmp" "${inputPath}"`;
suppressWatchedConfigReloads(1500);
Proc.runCommand("mango-write-input", ["sh", "-c", script], (output, exitCode) => {
inputGenerationRunning = false;
if (exitCode === 3) {
if (inputGenerationPending)
inputGenerationAction.schedule();
return;
}
if (exitCode !== 0) {
log.warn("Failed to write input config:", output);
} else {
log.info("Generated input config at", inputPath);
reloadConfig(false);
}
if (inputGenerationPending)
inputGenerationAction.schedule();
});
}
// Mouse and trackpad keys are the split names Mango has had since 0.16.1; libinput enums are numeric
function mangoInputLines(s, snake) {
const flag = value => value ? 1 : 0;
const profile = name => name === "flat" ? 1 : name === "adaptive" ? 2 : -1;
const scrollMethod = name => ({
"no-scroll": 0,
"two-finger": 1,
"edge": 2,
"on-button-down": 4
})[name] ?? -1;
const clickMethod = name => name === "button-areas" ? 1 : name === "clickfinger" ? 2 : -1;
const lines = [];
// -1 is a "default" choice: the key stays out so Mango's own default applies
const add = (key, value) => {
if (value !== -1 && value !== "")
lines.push(`${key}=${value}`);
};
add("mouse_accel_speed", s.mouseAccelSpeed.toFixed(2));
add("mouse_accel_profile", profile(s.mouseAccelProfile));
add("mouse_natural_scrolling", flag(s.mouseNaturalScroll));
add("mouse_left_handed", flag(s.mouseLeftHanded));
add("mouse_middle_button_emulation", flag(s.mouseMiddleEmulation));
add("axis_scroll_factor", s.mouseScrollFactor.toFixed(2));
add("mouse_scroll_method", scrollMethod(s.mouseScrollMethod));
add("tap_to_click", flag(s.touchpadTapToClick));
add("tap_and_drag", flag(s.touchpadTapAndDrag));
add("drag_lock", flag(s.touchpadDragLock));
add("trackpad_accel_speed", s.touchpadAccelSpeed.toFixed(2));
add("trackpad_accel_profile", profile(s.touchpadAccelProfile));
add("trackpad_natural_scrolling", flag(s.touchpadNaturalScroll));
add("trackpad_scroll_factor", s.touchpadScrollFactor.toFixed(2));
add("trackpad_scroll_method", scrollMethod(s.touchpadScrollMethod));
add("trackpad_click_method", clickMethod(s.touchpadClickMethod));
add("trackpad_disable_while_typing", flag(s.touchpadDisableWhileTyping));
add("trackpad_middle_button_emulation", flag(s.touchpadMiddleEmulation));
add("trackpad_send_events_mode", s.touchpadDisableOnExternalMouse ? 2 : 0);
// Unconfigured keyboard keeps the user's own xkb_rules_* keys and the XKB defaults
const keyboardConfigured = s.keyboardLayouts || s.keyboardVariants || s.keyboardModel || s.keyboardOptions || s.keyboardRepeatDelay > 0 || s.keyboardRepeatRate > 0 || s.keyboardNumlock;
if (!keyboardConfigured)
return lines;
add("xkb_rules_layout", s.keyboardLayouts);
add("xkb_rules_variant", s.keyboardVariants);
add("xkb_rules_model", s.keyboardModel);
add("xkb_rules_options", s.keyboardOptions);
if (s.keyboardRepeatDelay > 0)
add("repeat_delay", s.keyboardRepeatDelay);
if (s.keyboardRepeatRate > 0)
add("repeat_rate", s.keyboardRepeatRate);
add(snake ? "numlock_on" : "numlockon", flag(s.keyboardNumlock));
return lines;
}
}
@@ -68,6 +68,7 @@ Singleton {
"smartDockCapable": () => CompositorService.supportsSmartDock,
"workspaceFollowFocusCapable": () => CompositorService.supportsWorkspaceFollowFocus,
"isHyprlandOrNiri": () => CompositorService.isHyprland || CompositorService.isNiri,
"isNiriOrMango": () => CompositorService.isNiri || CompositorService.isMango,
"windowRulesCapable": () => CompositorService.supportsWindowRules,
"layoutCapable": () => CompositorService.supportsLayoutConfig,
"keybindsAvailable": () => KeybindsService.available,
+36 -4
View File
@@ -1,6 +1,7 @@
import assert from "node:assert/strict";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { execFileSync } from "node:child_process";
import { loadScript } from "./qml-script.mjs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import vm from "node:vm";
@@ -11,7 +12,7 @@ vm.runInContext(readFileSync(new URL("../Common/ConfigIncludeResolve.js", import
const plain = value => JSON.parse(JSON.stringify(value));
test("includeSpec returns null off the table", () => {
assert.equal(resolve.includeSpec("input", "mango"), null, "input exists for niri and hyprland only");
assert.equal(resolve.includeSpec("colors", "mango"), null, "colors is deployed by setup, never repaired");
assert.equal(resolve.includeSpec("colors", "niri"), null, "unknown kind");
assert.equal(resolve.includeSpec("outputs", "sway"), null, "unknown compositor");
assert.equal(resolve.includeSpec("outputs", ""), null, "empty compositor");
@@ -34,7 +35,8 @@ test("includePaths joins the compositor directory, with hypr for hyprland", () =
assert.deepEqual(plain(mango.fragmentFiles), ["/home/u/.config/mango/dms/cursor.conf"]);
const binds = resolve.includePaths("binds", "hyprland", "/home/u/.config");
assert.deepEqual(plain(binds.fragmentFiles), ["/home/u/.config/hypr/dms/binds.lua", "/home/u/.config/hypr/dms/binds-user.lua"]);
assert.equal(resolve.includePaths("input", "mango", "/home/u/.config"), null, "no spec, no paths");
assert.deepEqual(plain(resolve.includePaths("input", "mango", "/home/u/.config").fragmentFiles), ["/home/u/.config/mango/dms/input.conf"]);
assert.equal(resolve.includePaths("colors", "mango", "/home/u/.config"), null, "no spec, no paths");
});
test("resolveIncludeArgs spells mango as mangowc and names the fragment", () => {
@@ -42,11 +44,12 @@ test("resolveIncludeArgs spells mango as mangowc and names the fragment", () =>
assert.deepEqual(plain(resolve.resolveIncludeArgs("layout", "hyprland")), ["hyprland", "layout.lua"]);
assert.deepEqual(plain(resolve.resolveIncludeArgs("input", "hyprland")), ["hyprland", "input.lua"]);
assert.deepEqual(plain(resolve.resolveIncludeArgs("windowrules", "mango")), ["mangowc", "windowrules.conf"]);
assert.equal(resolve.resolveIncludeArgs("input", "mango"), null, "no spec, no args");
assert.deepEqual(plain(resolve.resolveIncludeArgs("input", "mango")), ["mangowc", "input.conf"]);
assert.equal(resolve.resolveIncludeArgs("colors", "mango"), null, "no spec, no args");
});
test("repairScriptFor returns an empty script off the table", () => {
assert.equal(resolve.repairScriptFor("input", "mango", "/home/u/.config", "/x"), "");
assert.equal(resolve.repairScriptFor("colors", "mango", "/home/u/.config", "/x"), "");
assert.equal(resolve.repairScriptFor("nope", "niri", "/home/u/.config", "/x"), "");
});
@@ -79,3 +82,32 @@ test("repair preserves config and fragments, backs up, and adds live includes on
assert.equal(readFileSync(paths.configFile, "utf8"), repaired);
}
});
test("mango input fragment maps choices onto libinput numbers and spells numlock per dialect", () => {
const SPEC = loadScript(new URL("../Common/settings/SettingsSpec.js", import.meta.url)).SPEC;
const source = readFileSync(new URL("../Services/MangoService.qml", import.meta.url), "utf8");
const found = source.match(/^ function mangoInputLines\([^)]*\) \{\n[\s\S]*?^ \}/m);
assert.ok(found, "mangoInputLines not found in MangoService.qml");
const scope = vm.createContext({});
vm.runInContext(found[0], scope);
const defaults = Object.fromEntries(Object.keys(SPEC).filter(key => /^(mouse|touchpad|keyboard)[A-Z]/.test(key)).map(key => [key, SPEC[key].def]));
const lines = (overrides, snake = false) => [...scope.mangoInputLines(Object.assign({}, defaults, overrides), snake)];
const value = (list, key) => list.find(line => line.startsWith(key + "="))?.slice(key.length + 1);
const stock = lines({});
assert.equal(value(stock, "trackpad_natural_scrolling"), "1");
assert.equal(value(stock, "mouse_accel_profile"), undefined, "default profile leaves the key to Mango");
assert.ok(!stock.some(line => /^(xkb_rules_|repeat_|numlock)/.test(line)), "unconfigured keyboard writes nothing");
const chosen = lines({ mouseScrollMethod: "no-scroll", touchpadAccelProfile: "adaptive", touchpadScrollMethod: "on-button-down", touchpadClickMethod: "clickfinger", touchpadDisableOnExternalMouse: true, keyboardLayouts: "us,de", keyboardRepeatDelay: 300 });
assert.equal(value(chosen, "mouse_scroll_method"), "0");
assert.equal(value(chosen, "trackpad_accel_profile"), "2");
assert.equal(value(chosen, "trackpad_scroll_method"), "4");
assert.equal(value(chosen, "trackpad_click_method"), "2");
assert.equal(value(chosen, "trackpad_send_events_mode"), "2");
assert.equal(value(chosen, "xkb_rules_layout"), "us,de");
assert.equal(value(chosen, "xkb_rules_variant"), undefined, "empty fields stay out");
assert.equal(value(chosen, "repeat_delay"), "300");
assert.equal(value(chosen, "numlockon"), "0");
assert.equal(value(lines({ keyboardNumlock: true }, true), "numlock_on"), "1");
});
@@ -487,6 +487,10 @@ def find_settings_components(content, filename, wrappers, tab_meta, hub_meta):
condition_key = "isAqueous"
elif all(c in visible_raw for c in ("CompositorService.isNiri", "CompositorService.isHyprland", "CompositorService.isMango")):
condition_key = "windowRulesCapable"
elif all(c in visible_raw for c in ("CompositorService.isNiri", "CompositorService.isHyprland")):
condition_key = "isHyprlandOrNiri"
elif all(c in visible_raw for c in ("CompositorService.isNiri", "CompositorService.isMango")):
condition_key = "isNiriOrMango"
elif "CompositorService.isNiri" in visible_raw:
condition_key = "isNiri"
elif "CompositorService.isHyprland" in visible_raw:
@@ -251,24 +251,18 @@
"keywords": [
"background",
"blur",
"every",
"frosted",
"glass",
"interface",
"just",
"passes",
"radius",
"reach",
"sets",
"shell",
"size",
"strength",
"style",
"transparency",
"window"
"transparency"
],
"page": "theme_surfaces",
"description": "Sets the compositor's blur for every window, not just the shell"
"page": "theme_surfaces"
},
{
"section": "wallpaperBackgroundColorMode",
@@ -1229,7 +1223,7 @@
"wallpaper"
],
"page": "personalization",
"conditionKey": "isNiri"
"conditionKey": "isHyprlandOrNiri"
},
{
"section": "notificationHistory",
@@ -2704,7 +2698,7 @@
"xray"
],
"page": "theme_surfaces",
"conditionKey": "isNiri"
"conditionKey": "isHyprlandOrNiri"
},
{
"section": "_hub_personalization",
@@ -13040,7 +13034,7 @@
"toast"
],
"icon": "notifications",
"conditionKey": "isNiri"
"conditionKey": "isNiriOrMango"
},
{
"section": "hyprlandLayoutGapsOutOverride",
@@ -14319,7 +14313,7 @@
"touchpad"
],
"parentLabel": "Input",
"conditionKey": "isNiri"
"conditionKey": "isNiriOrMango"
},
{
"section": "touchpadDragLock",
@@ -14367,7 +14361,7 @@
"touchpad"
],
"parentLabel": "Input",
"conditionKey": "isNiri"
"conditionKey": "isNiriOrMango"
},
{
"section": "touchpadMiddleEmulation",
@@ -14420,23 +14414,6 @@
"description": "Speed, scrolling, tap to click",
"conditionKey": "pointerCapable"
},
{
"section": "mangoTrackpadNaturalScrolling",
"label": "Natural scrolling",
"tabIndex": 44,
"category": "Mouse & touchpad",
"keywords": [
"input",
"invert",
"mouse",
"natural",
"scrolling",
"touchpad",
"trackpad"
],
"parentLabel": "Input",
"conditionKey": "pointerCapable"
},
{
"section": "mouseNaturalScroll",
"label": "Natural scrolling",
@@ -14597,24 +14574,6 @@
"parentLabel": "Input",
"conditionKey": "pointerCapable"
},
{
"section": "mangoTouchpadSettings",
"label": "Touchpad",
"tabIndex": 44,
"category": "Mouse & touchpad",
"keywords": [
"input",
"invert",
"mouse",
"natural",
"scrolling",
"touchpad",
"trackpad"
],
"parentLabel": "Input",
"icon": "trackpad_input_2",
"conditionKey": "isMango"
},
{
"section": "touchpadSettings",
"label": "Touchpad",