mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-30 15:07:49 -04:00
feat(input): focus follows mouse on niri and mango
This commit is contained in:
1 parent
80ca0f0ee5
commit
ce389d2e87
11 files changed
+37
-42
No files matched your search
@@ -245,7 +245,7 @@ Singleton {
|
||||
property int mangoLayoutGapsOutOverride: Spec.SPEC.mangoLayoutGapsOutOverride.def
|
||||
property int mangoLayoutRadiusOverride: Spec.SPEC.mangoLayoutRadiusOverride.def
|
||||
property int mangoLayoutBorderSize: Spec.SPEC.mangoLayoutBorderSize.def
|
||||
property int hyprlandFollowMouse: Spec.SPEC.hyprlandFollowMouse.def
|
||||
property int focusFollowsMouse: Spec.SPEC.focusFollowsMouse.def
|
||||
property string mouseAccelProfile: Spec.SPEC.mouseAccelProfile.def
|
||||
property real mouseAccelSpeed: Spec.SPEC.mouseAccelSpeed.def
|
||||
property bool mouseLeftHanded: Spec.SPEC.mouseLeftHanded.def
|
||||
|
||||
@@ -315,7 +315,7 @@ var LOCAL_SPEC = {
|
||||
def: -1,
|
||||
onChange: "updateCompositorLayout"
|
||||
},
|
||||
hyprlandFollowMouse: {
|
||||
focusFollowsMouse: {
|
||||
def: -1,
|
||||
onChange: "updateCompositorInput"
|
||||
},
|
||||
|
||||
@@ -33,15 +33,16 @@ Item {
|
||||
iconName: "mouse"
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: CompositorService.isHyprland && HyprlandService.hyprSupports("input:follow_mouse")
|
||||
enabled: inputInclude.included && !inputInclude.readOnly && HyprlandService.luaConfigActive && HyprlandService.followMouseMode >= 0
|
||||
tags: ["mouse", "focus", "follow", "pointer", "window", "hyprland"]
|
||||
settingKey: "hyprlandFollowMouse"
|
||||
resetKeys: ["hyprlandFollowMouse"]
|
||||
text: I18n.tr("Focus follows mouse", "Hyprland toggle that focuses a window when the pointer moves over it")
|
||||
description: I18n.tr("Focus windows when the pointer moves over them.", "Description of the Hyprland focus follows mouse toggle")
|
||||
checked: (SettingsData.hyprlandFollowMouse < 0 ? HyprlandService.followMouseMode : SettingsData.hyprlandFollowMouse) === 1
|
||||
onToggled: checked => SettingsData.set("hyprlandFollowMouse", checked ? 1 : 0)
|
||||
// Only Hyprland can report the live mode; untouched niri and Mango show their defaults
|
||||
readonly property int inheritedMode: CompositorService.isHyprland ? HyprlandService.followMouseMode : CompositorService.isMango ? 1 : 0
|
||||
visible: CompositorService.supportsInputConfig && (!CompositorService.isHyprland || HyprlandService.hyprSupports("input:follow_mouse"))
|
||||
enabled: inputInclude.included && !inputInclude.readOnly && (!CompositorService.isHyprland || (HyprlandService.luaConfigActive && HyprlandService.followMouseMode >= 0))
|
||||
tags: ["mouse", "focus", "follow", "pointer", "window", "sloppy"]
|
||||
settingKey: "focusFollowsMouse"
|
||||
resetKeys: ["focusFollowsMouse"]
|
||||
text: I18n.tr("Focus follows mouse", "Toggle that focuses a window when the pointer moves over it")
|
||||
checked: (SettingsData.focusFollowsMouse < 0 ? inheritedMode : SettingsData.focusFollowsMouse) === 1
|
||||
onToggled: checked => SettingsData.set("focusFollowsMouse", checked ? 1 : 0)
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
|
||||
@@ -483,6 +483,8 @@ Singleton {
|
||||
|
||||
function onRawEvent(event) {
|
||||
if (event.name === "monitoraddedv2" || event.name === "monitorremoved" || event.name === "configreloaded") {
|
||||
if (event.name === "configreloaded")
|
||||
HyprlandService.refreshFollowMouse();
|
||||
root.refreshHyprlandMonitorLayout();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,14 +239,6 @@ Singleton {
|
||||
});
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CompositorService.isHyprland ? Hyprland : null
|
||||
function onRawEvent(event) {
|
||||
if (event.name === "configreloaded")
|
||||
root.refreshFollowMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function loadHyprOptionNames() {
|
||||
if (!CompositorService.isHyprland || hyprOptionsReady || hyprOptionsLoading)
|
||||
return;
|
||||
@@ -848,8 +840,8 @@ hl.layer_rule({
|
||||
lines.push(line);
|
||||
};
|
||||
// -1 leaves existing follow_mouse modes untouched until the user operates the toggle.
|
||||
if (s.hyprlandFollowMouse === 0 || s.hyprlandFollowMouse === 1)
|
||||
add("input:follow_mouse", `follow_mouse = ${s.hyprlandFollowMouse},`);
|
||||
if (s.focusFollowsMouse === 0 || s.focusFollowsMouse === 1)
|
||||
add("input:follow_mouse", `follow_mouse = ${s.focusFollowsMouse},`);
|
||||
if (s.mouseAccelSpeed !== 0)
|
||||
add("input:sensitivity", `sensitivity = ${s.mouseAccelSpeed.toFixed(2)},`);
|
||||
if (s.mouseAccelProfile !== "default")
|
||||
|
||||
@@ -780,6 +780,7 @@ cursor_size=${size}`;
|
||||
add("mouse_middle_button_emulation", flag(s.mouseMiddleEmulation));
|
||||
add("axis_scroll_factor", s.mouseScrollFactor.toFixed(2));
|
||||
add("mouse_scroll_method", scrollMethod(s.mouseScrollMethod));
|
||||
add("sloppy_focus", s.focusFollowsMouse);
|
||||
add("tap_to_click", flag(s.touchpadTapToClick));
|
||||
add("tap_and_drag", flag(s.touchpadTapAndDrag));
|
||||
add("drag_lock", flag(s.touchpadDragLock));
|
||||
|
||||
@@ -1748,6 +1748,10 @@ window-rule {
|
||||
`;
|
||||
|
||||
let inputContent = dmsWarning + "input {\n";
|
||||
// Niri flags take no false, so off can only leave it out
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.focusFollowsMouse === 1) {
|
||||
inputContent += " focus-follows-mouse max-scroll-amount=\"0%\"\n";
|
||||
}
|
||||
|
||||
// Mouse block
|
||||
inputContent += " mouse {\n";
|
||||
|
||||
@@ -61,7 +61,7 @@ test("mango input fragment maps choices onto libinput numbers and spells numlock
|
||||
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 defaults = Object.fromEntries(Object.keys(SPEC).filter(key => /^(mouse|touchpad|keyboard)[A-Z]|^focusFollowsMouse$/.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);
|
||||
|
||||
@@ -81,4 +81,8 @@ test("mango input fragment maps choices onto libinput numbers and spells numlock
|
||||
assert.equal(value(chosen, "repeat_delay"), "300");
|
||||
assert.equal(value(chosen, "numlockon"), "0");
|
||||
assert.equal(value(lines({ keyboardNumlock: true }, true), "numlock_on"), "1");
|
||||
|
||||
assert.equal(value(stock, "sloppy_focus"), undefined, "untouched focus mode stays Mango's");
|
||||
for (const mode of [0, 1])
|
||||
assert.equal(value(lines({ focusFollowsMouse: mode }), "sloppy_focus"), String(mode));
|
||||
});
|
||||
@@ -145,7 +145,7 @@ test("input: turning natural scroll off is written so the template's true cannot
|
||||
});
|
||||
|
||||
test("input: focus follows mouse writes both on and off, leaves unmanaged modes alone, and skips unsupported options", () => {
|
||||
const modeLine = mode => inputLines(input({ hyprlandFollowMouse: mode })).filter(line => line.startsWith("follow_mouse ="));
|
||||
const modeLine = mode => inputLines(input({ focusFollowsMouse: mode })).filter(line => line.startsWith("follow_mouse ="));
|
||||
assert.deepEqual(modeLine(1), ["follow_mouse = 1,"]);
|
||||
assert.deepEqual(modeLine(0), ["follow_mouse = 0,"]);
|
||||
assert.deepEqual(modeLine(-1), []);
|
||||
|
||||
@@ -53,11 +53,11 @@ test("a coerced key normalises a percentage and leaves a unit value alone", () =
|
||||
test("a focus override persists both off and on, and resetting removes it", () => {
|
||||
const root = defaultRoot();
|
||||
for (const mode of [0, 1]) {
|
||||
root.hyprlandFollowMouse = mode;
|
||||
root.focusFollowsMouse = mode;
|
||||
const json = store.toJson(root, new Set());
|
||||
assert.equal(json.hyprlandFollowMouse, mode);
|
||||
assert.equal(loaded(json).hyprlandFollowMouse, mode);
|
||||
assert.equal(json.focusFollowsMouse, mode);
|
||||
assert.equal(loaded(json).focusFollowsMouse, mode);
|
||||
}
|
||||
root.hyprlandFollowMouse = -1;
|
||||
assert.equal("hyprlandFollowMouse" in store.toJson(root, new Set()), false);
|
||||
root.focusFollowsMouse = -1;
|
||||
assert.equal("focusFollowsMouse" in store.toJson(root, new Set()), false);
|
||||
});
|
||||
@@ -14376,7 +14376,7 @@
|
||||
"conditionKey": "pointerCapable"
|
||||
},
|
||||
{
|
||||
"section": "hyprlandFollowMouse",
|
||||
"section": "focusFollowsMouse",
|
||||
"label": "Focus follows mouse",
|
||||
"tabIndex": 44,
|
||||
"category": "Mouse & touchpad",
|
||||
@@ -14384,19 +14384,15 @@
|
||||
"focus",
|
||||
"follow",
|
||||
"follows",
|
||||
"hyprland",
|
||||
"input",
|
||||
"mouse",
|
||||
"moves",
|
||||
"over",
|
||||
"pointer",
|
||||
"sloppy",
|
||||
"touchpad",
|
||||
"window",
|
||||
"windows"
|
||||
"window"
|
||||
],
|
||||
"parentLabel": "Input",
|
||||
"description": "Focus windows when the pointer moves over them.",
|
||||
"conditionKey": "isHyprland"
|
||||
"conditionKey": "inputCapable"
|
||||
},
|
||||
{
|
||||
"section": "mouseLeftHanded",
|
||||
@@ -14454,19 +14450,14 @@
|
||||
"category": "Mouse & touchpad",
|
||||
"keywords": [
|
||||
"acceleration",
|
||||
"focus",
|
||||
"input",
|
||||
"mouse",
|
||||
"moves",
|
||||
"over",
|
||||
"pointer",
|
||||
"sensitivity",
|
||||
"touchpad",
|
||||
"windows"
|
||||
"touchpad"
|
||||
],
|
||||
"parentLabel": "Input",
|
||||
"icon": "mouse",
|
||||
"description": "Focus windows when the pointer moves over them.",
|
||||
"conditionKey": "inputCapable"
|
||||
},
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user