From c4aea85296a3a20e34be7e467170265c0c29dc38 Mon Sep 17 00:00:00 2001 From: purian23 Date: Thu, 15 Oct 2026 02:01:02 -0400 Subject: [PATCH] niri: drive touchpad OSD from native compositor events --- core/internal/config/embedded/niri-binds.kdl | 8 +++- distro/nix/niri.nix | 12 +++++- quickshell/Common/KeyUtils.js | 2 + quickshell/Modules/OSD/TouchpadOSD.qml | 15 ++++--- quickshell/Services/NiriService.qml | 43 ++++++++++---------- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/core/internal/config/embedded/niri-binds.kdl b/core/internal/config/embedded/niri-binds.kdl index a1459a5f4..4d4410f8f 100644 --- a/core/internal/config/embedded/niri-binds.kdl +++ b/core/internal/config/embedded/niri-binds.kdl @@ -92,7 +92,13 @@ binds { // === Input === XF86TouchpadToggle allow-when-locked=true repeat=false { - spawn "dms" "ipc" "call" "niri" "toggleTouchpad"; + spawn "niri" "msg" "action" "toggle-touchpad"; + } + XF86TouchpadOn allow-when-locked=true repeat=false { + spawn "dms" "ipc" "call" "niri" "showTouchpadOsd" "true"; + } + XF86TouchpadOff allow-when-locked=true repeat=false { + spawn "dms" "ipc" "call" "niri" "showTouchpadOsd" "false"; } // === Window Management === diff --git a/distro/nix/niri.nix b/distro/nix/niri.nix index 229f43bfe..ab9e469cd 100644 --- a/distro/nix/niri.nix +++ b/distro/nix/niri.nix @@ -158,7 +158,17 @@ in { "XF86TouchpadToggle" = { allow-when-locked = true; repeat = false; - action = dms-ipc "niri" "toggleTouchpad"; + action = spawn "niri" "msg" "action" "toggle-touchpad"; + }; + "XF86TouchpadOn" = { + allow-when-locked = true; + repeat = false; + action = dms-ipc "niri" "showTouchpadOsd" "true"; + }; + "XF86TouchpadOff" = { + allow-when-locked = true; + repeat = false; + action = dms-ipc "niri" "showTouchpadOsd" "false"; }; "Mod+Alt+N" = { allow-when-locked = true; diff --git a/quickshell/Common/KeyUtils.js b/quickshell/Common/KeyUtils.js index 8e99c1f93..cc449a115 100644 --- a/quickshell/Common/KeyUtils.js +++ b/quickshell/Common/KeyUtils.js @@ -40,6 +40,8 @@ const KEY_MAP = { 16777329: "XF86AudioMute", 16842808: "XF86AudioMicMute", 16777488: "XF86TouchpadToggle", + 16777489: "XF86TouchpadOn", + 16777490: "XF86TouchpadOff", 16777344: "XF86AudioPlay", 16777345: "XF86AudioStop", 16777346: "XF86AudioPrev", diff --git a/quickshell/Modules/OSD/TouchpadOSD.qml b/quickshell/Modules/OSD/TouchpadOSD.qml index 4690618ac..0cfdc026d 100644 --- a/quickshell/Modules/OSD/TouchpadOSD.qml +++ b/quickshell/Modules/OSD/TouchpadOSD.qml @@ -13,13 +13,16 @@ DOSD { autoHideInterval: 2000 enableMouseInteraction: false + property bool touchpadEnabled: true + Connections { target: NiriService - function onTouchpadToggled() { - if (SettingsData.osdTouchpadEnabled) { - root.show(); - } + function onTouchpadOsdRequested(enabled: bool) { + if (!SettingsData.osdTouchpadEnabled) + return; + root.touchpadEnabled = enabled; + root.show(); } } @@ -27,8 +30,8 @@ DOSD { OsdIcon { tonal: false anchors.centerIn: parent - iconName: NiriService.touchpadDisabled ? "touchpad_mouse_off" : "touchpad_mouse" - iconColor: NiriService.touchpadDisabled ? Theme.outline : Theme.primary + iconName: root.touchpadEnabled ? "touchpad_mouse" : "touchpad_mouse_off" + iconColor: root.touchpadEnabled ? Theme.primary : Theme.outline } } } diff --git a/quickshell/Services/NiriService.qml b/quickshell/Services/NiriService.qml index f796aeefb..e18ce1848 100644 --- a/quickshell/Services/NiriService.qml +++ b/quickshell/Services/NiriService.qml @@ -41,9 +41,9 @@ Singleton { property int currentKeyboardLayoutIndex: 0 property var keyboardLayoutNames: [] - // niri never reports toggle-touchpad state, so this only tracks toggles issued through DMS. - property bool touchpadDisabled: false - signal touchpadToggled + property bool touchpadEnabled: true + property bool _touchpadStateInitialized: false + signal touchpadOsdRequested(bool enabled) property string configValidationOutput: "" property bool hasInitialConnection: false @@ -259,7 +259,8 @@ Singleton { connected: CompositorService.isNiri onConnectionStateChanged: { - if (connected) { + root._touchpadStateInitialized = false; + if (linkUp) { send('"EventStream"'); fetchOutputs(); } @@ -428,6 +429,9 @@ Singleton { case 'KeyboardLayoutSwitched': handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched); break; + case 'TouchpadToggled': + handleTouchpadToggled(event.TouchpadToggled); + break; case 'WorkspaceUrgencyChanged': handleWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged); break; @@ -449,6 +453,15 @@ Singleton { } } + function handleTouchpadToggled(data) { + // Each subscription starts with a snapshot; only later changes show the OSD. + const showOsd = _touchpadStateInitialized && touchpadEnabled !== data.on; + touchpadEnabled = data.on; + _touchpadStateInitialized = true; + if (showOsd) + touchpadOsdRequested(touchpadEnabled); + } + function handleWorkspacesChanged(data) { const newWorkspaces = {}; @@ -814,19 +827,6 @@ Singleton { }); } - function toggleTouchpad() { - if (!CompositorService.isNiri) - return; - Proc.runCommand("niri-toggle-touchpad", ["niri", "msg", "action", "toggle-touchpad"], (output, exitCode) => { - if (exitCode !== 0) { - log.warn("toggle-touchpad failed, exit code:", exitCode); - return; - } - touchpadDisabled = !touchpadDisabled; - touchpadToggled(); - }); - } - function toggleOverview() { return send({ "Action": { @@ -1940,12 +1940,11 @@ window-rule { return "SCREENSHOT_WINDOW_FAILED"; } - function toggleTouchpad(): string { - if (!CompositorService.isNiri) { + function showTouchpadOsd(enabled: bool): string { + if (!CompositorService.isNiri) return "NIRI_NOT_AVAILABLE"; - } - NiriService.toggleTouchpad(); - return "TOUCHPAD_TOGGLED"; + NiriService.touchpadOsdRequested(enabled); + return "TOUCHPAD_OSD_SHOWN"; } target: "niri"