From ada611d6c5b581d7c357d95f197f1837d5695406 Mon Sep 17 00:00:00 2001 From: Damocles Date: Fri, 24 Apr 2026 23:40:42 +0200 Subject: [PATCH 1/3] gate non-essential animations behind reducedMotion config toggle --- shell/applets/BluetoothApplet.qml | 2 +- shell/lock/LockSurface.qml | 2 +- shell/modules/BarGroup.qml | 2 +- shell/modules/HoverPanel.qml | 15 +++++++++++++-- shell/modules/NotifPopup.qml | 16 +++++++++++++--- shell/modules/NotificationsModule.qml | 2 +- shell/modules/PulseAnimation.qml | 3 ++- shell/modules/Tooltip.qml | 13 +++++++++++-- 8 files changed, 43 insertions(+), 12 deletions(-) diff --git a/shell/applets/BluetoothApplet.qml b/shell/applets/BluetoothApplet.qml index 1f7eeb4..89ff63b 100644 --- a/shell/applets/BluetoothApplet.qml +++ b/shell/applets/BluetoothApplet.qml @@ -57,7 +57,7 @@ Column { // Pulse animation while pending SequentialAnimation on opacity { loops: Animation.Infinite - running: entry._pending + running: entry._pending && !S.Theme.reducedMotion NumberAnimation { to: 0.5 duration: 400 diff --git a/shell/lock/LockSurface.qml b/shell/lock/LockSurface.qml index 27f14f9..91c8140 100644 --- a/shell/lock/LockSurface.qml +++ b/shell/lock/LockSurface.qml @@ -371,7 +371,7 @@ WlSessionLockSurface { SequentialAnimation { id: _heartbeatAnim loops: Animation.Infinite - running: root._threatEnabled && root.auth.failCount >= 3 && root.lock.secure + running: root._threatEnabled && root.auth.failCount >= 3 && root.lock.secure && !S.Theme.reducedMotion // Systole (sharp spike) NumberAnimation { diff --git a/shell/modules/BarGroup.qml b/shell/modules/BarGroup.qml index 912c94f..5cbbe6e 100644 --- a/shell/modules/BarGroup.qml +++ b/shell/modules/BarGroup.qml @@ -125,7 +125,7 @@ Item { property real _pulse: 0.08 SequentialAnimation on _pulse { - running: root._hovered + running: root._hovered && !S.Theme.reducedMotion loops: Animation.Infinite NumberAnimation { to: 0.22 diff --git a/shell/modules/HoverPanel.qml b/shell/modules/HoverPanel.qml index 7585fa9..ab17583 100644 --- a/shell/modules/HoverPanel.qml +++ b/shell/modules/HoverPanel.qml @@ -133,7 +133,12 @@ PanelWindow { } _winVisible = true; hideAnim.stop(); - showAnim.start(); + if (S.Theme.reducedMotion) { + panelContainer.opacity = 1; + panelContainer.y = 0; + } else { + showAnim.start(); + } _grace = true; _graceTimer.restart(); } @@ -141,7 +146,13 @@ PanelWindow { function dismiss() { _pinned = false; showAnim.stop(); - hideAnim.start(); + if (S.Theme.reducedMotion) { + _winVisible = false; + if (popupMode) + dismissed(); + } else { + hideAnim.start(); + } _grace = false; _graceTimer.stop(); } diff --git a/shell/modules/NotifPopup.qml b/shell/modules/NotifPopup.qml index 25ba8fd..41ad6d8 100644 --- a/shell/modules/NotifPopup.qml +++ b/shell/modules/NotifPopup.qml @@ -68,7 +68,13 @@ PanelWindow { _heightScale = 1; } else { popupCol._knownIds[modelData.id] = true; - slideIn.start(); + if (S.Theme.reducedMotion) { + opacity = 1; + x = 0; + _heightScale = 1; + } else { + slideIn.start(); + } } _entered = true; } @@ -82,7 +88,7 @@ PanelWindow { } Behavior on y { - enabled: popupItem._entered + enabled: popupItem._entered && !S.Theme.reducedMotion NumberAnimation { duration: 200 easing.type: Easing.OutCubic @@ -123,7 +129,11 @@ PanelWindow { popupItem.modelData.beginDismiss(); _fullDismiss = !!full; slideIn.stop(); - slideOut.start(); + if (S.Theme.reducedMotion) { + full ? S.NotifService.dismiss(modelData.id) : S.NotifService.dismissPopup(modelData.id); + } else { + slideOut.start(); + } } SequentialAnimation { diff --git a/shell/modules/NotificationsModule.qml b/shell/modules/NotificationsModule.qml index 1af6743..044dc41 100644 --- a/shell/modules/NotificationsModule.qml +++ b/shell/modules/NotificationsModule.qml @@ -63,7 +63,7 @@ M.PinnableSection { Connections { target: S.NotifService function onCountChanged() { - if (S.NotifService.count > 0) + if (S.NotifService.count > 0 && !S.Theme.reducedMotion) popAnim.start(); } } diff --git a/shell/modules/PulseAnimation.qml b/shell/modules/PulseAnimation.qml index a0270e8..b288f4a 100644 --- a/shell/modules/PulseAnimation.qml +++ b/shell/modules/PulseAnimation.qml @@ -1,8 +1,9 @@ import QtQuick +import "../services" as S SequentialAnimation { id: root - loops: Animation.Infinite + loops: S.Theme.reducedMotion ? 0 : Animation.Infinite property real minOpacity: 0.4 property int halfDuration: 400 diff --git a/shell/modules/Tooltip.qml b/shell/modules/Tooltip.qml index 7424211..d8aa5be 100644 --- a/shell/modules/Tooltip.qml +++ b/shell/modules/Tooltip.qml @@ -19,10 +19,19 @@ PanelWindow { if (_shown) { _winVisible = true; hideAnim.stop(); - showAnim.start(); + if (S.Theme.reducedMotion) { + content.opacity = 1; + content.y = 0; + } else { + showAnim.start(); + } } else { showAnim.stop(); - hideAnim.start(); + if (S.Theme.reducedMotion) { + _winVisible = false; + } else { + hideAnim.start(); + } } } From 412f6d024b2bc42b05520ae5af6c047b7d0fd311 Mon Sep 17 00:00:00 2001 From: Damocles Date: Fri, 24 Apr 2026 23:56:17 +0200 Subject: [PATCH 2/3] add reducedMotion to hm-module theme docs, update description --- nix/hm-module.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix/hm-module.nix b/nix/hm-module.nix index c706f45..c39cc54 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -253,7 +253,8 @@ in description = '' Theme overrides written to `$XDG_CONFIG_HOME/nova-shell/theme.json`. Keys: colors (base00-base0F), fontFamily, iconFontFamily, fontSize, - barOpacity, barHeight, barPadding, groupSpacing, groupPadding, moduleSpacing, radius, screenRadius. + barOpacity, barHeight, barPadding, groupSpacing, groupPadding, moduleSpacing, + radius, screenRadius, reducedMotion. Automatically populated from stylix when it is available. ''; }; From b6fe6704676007749f6caa2f60cacdbd0d7c11f8 Mon Sep 17 00:00:00 2001 From: Damocles Date: Sat, 25 Apr 2026 00:32:51 +0200 Subject: [PATCH 3/3] tray: fix invisible module - use .count instead of .length on UntypedObjectModel --- shell/modules/PulseAnimation.qml | 2 +- shell/modules/TrayModule.qml | 2 +- test/qmllint-baseline.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/modules/PulseAnimation.qml b/shell/modules/PulseAnimation.qml index b288f4a..555a258 100644 --- a/shell/modules/PulseAnimation.qml +++ b/shell/modules/PulseAnimation.qml @@ -3,7 +3,7 @@ import "../services" as S SequentialAnimation { id: root - loops: S.Theme.reducedMotion ? 0 : Animation.Infinite + loops: S.Theme.reducedMotion ? 1 : Animation.Infinite property real minOpacity: 0.4 property int halfDuration: 400 diff --git a/shell/modules/TrayModule.qml b/shell/modules/TrayModule.qml index a8ed98f..3f4fa81 100644 --- a/shell/modules/TrayModule.qml +++ b/shell/modules/TrayModule.qml @@ -10,7 +10,7 @@ import "../services" as S RowLayout { id: root spacing: S.Theme.moduleSpacing + 2 - visible: S.Modules.tray.enable && SystemTray.items.length > 0 + visible: S.Modules.tray.enable && SystemTray.items.count > 0 required property var bar property var _activeMenu: null diff --git a/test/qmllint-baseline.txt b/test/qmllint-baseline.txt index a5112d2..06ceb4d 100644 --- a/test/qmllint-baseline.txt +++ b/test/qmllint-baseline.txt @@ -70,7 +70,7 @@ shell/modules/Tooltip.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/Tooltip.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/Tooltip.qml: unknown grouped property scope margins. [unqualified] shell/modules/TrayMenu.qml: Unqualified access [unqualified] -shell/modules/TrayModule.qml: Member "length" not found on type "UntypedObjectModel" [missing-property] +shell/modules/TrayModule.qml: Member "count" not found on type "UntypedObjectModel" [missing-property] shell/modules/TrayModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/TrayModule.qml: Type "qs::dbus::dbusmenu::DBusMenuHandle" of property "menu" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/TrayModule.qml: Unqualified access [unqualified]