diff --git a/README.md b/README.md index 3d21ada..2e29645 100644 --- a/README.md +++ b/README.md @@ -111,8 +111,6 @@ programs.nova-shell.modules = { lock.notifications = false; # hide notification icons on the lock screen lock.mpris = false; # hide media controls on the lock screen lock.volume = false; # hide volume slider on the lock screen - lock.weather = false; # hide weather summary on the lock screen - lock.threatEffect = false; # disable red vignette on wrong password # modules with extra config backlight.step = 2; # brightness adjustment % diff --git a/shell/modules/BatteryModule.qml b/shell/modules/BatteryModule.qml index 9050f3e..7368682 100644 --- a/shell/modules/BatteryModule.qml +++ b/shell/modules/BatteryModule.qml @@ -4,12 +4,12 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing opacity: S.Modules.battery.enable && S.BatteryService.available ? 1 : 0 visible: opacity > 0 - _panelHovered: hoverPanel.panelHovered + tooltip: "" property real _blinkOpacity: 1 @@ -34,6 +34,24 @@ M.PinnableSection { root._blinkOpacity = 1 } + // Panel state + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + // Bar widgets M.BarIcon { icon: { diff --git a/shell/modules/BluetoothModule.qml b/shell/modules/BluetoothModule.qml index 91b0bc5..6cf34e0 100644 --- a/shell/modules/BluetoothModule.qml +++ b/shell/modules/BluetoothModule.qml @@ -4,12 +4,29 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing opacity: S.Modules.bluetooth.enable && S.BluetoothService.state !== "unavailable" ? 1 : 0 visible: opacity > 0 - _panelHovered: hoverPanel.panelHovered + tooltip: "" + + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } M.BarIcon { icon: "\uF294" diff --git a/shell/modules/ClockModule.qml b/shell/modules/ClockModule.qml index 69e3663..fa06723 100644 --- a/shell/modules/ClockModule.qml +++ b/shell/modules/ClockModule.qml @@ -4,16 +4,33 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing - _panelHovered: hoverPanel.panelHovered + tooltip: "" SystemClock { id: clock precision: SystemClock.Seconds } + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarLabel { font.pixelSize: S.Theme.fontSize + 1 label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm") diff --git a/shell/modules/CpuModule.qml b/shell/modules/CpuModule.qml index 16e5db6..825be3f 100644 --- a/shell/modules/CpuModule.qml +++ b/shell/modules/CpuModule.qml @@ -4,15 +4,19 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) - _panelHovered: hoverPanel.panelHovered + tooltip: "" readonly property var _cores: S.SystemStats.cpuCores readonly property var _coreMaxFreq: S.SystemStats.cpuCoreMaxFreq readonly property var _coreTypes: S.SystemStats.cpuCoreTypes + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + property bool _coreConsumerActive: false on_ShowPanelChanged: { @@ -31,6 +35,19 @@ M.PinnableSection { onProcessesChanged: hoverPanel.keepOpen(300) } + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: "\uF2DB" anchors.verticalCenter: parent.verticalCenter diff --git a/shell/modules/DiskModule.qml b/shell/modules/DiskModule.qml index 616ed65..425ce38 100644 --- a/shell/modules/DiskModule.qml +++ b/shell/modules/DiskModule.qml @@ -4,10 +4,10 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) - _panelHovered: hoverPanel.panelHovered + tooltip: "" property var _mounts: S.SystemStats.diskMounts property int _rootPct: S.SystemStats.diskRootPct @@ -19,6 +19,23 @@ M.PinnableSection { return false; } + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: "\uF0C9" color: root._anyWarn ? S.Theme.base09 : root.accentColor diff --git a/shell/modules/GpuModule.qml b/shell/modules/GpuModule.qml index 794ad55..106463b 100644 --- a/shell/modules/GpuModule.qml +++ b/shell/modules/GpuModule.qml @@ -4,11 +4,28 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) + tooltip: "" visible: S.Modules.gpu.enable && S.SystemStats.gpuAvailable - _panelHovered: hoverPanel.panelHovered + + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } M.BarIcon { icon: "\uEB4C" diff --git a/shell/modules/MemoryModule.qml b/shell/modules/MemoryModule.qml index d1d54bc..64f5eff 100644 --- a/shell/modules/MemoryModule.qml +++ b/shell/modules/MemoryModule.qml @@ -4,10 +4,10 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) - _panelHovered: hoverPanel.panelHovered + tooltip: "" property int percent: S.SystemStats.memPercent property real usedGb: S.SystemStats.memUsedGb @@ -16,12 +16,29 @@ M.PinnableSection { property real cachedGb: S.SystemStats.memCachedGb property real buffersGb: S.SystemStats.memBuffersGb + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + property M.ProcessList _procs: M.ProcessList { sortBy: "mem" active: root._showPanel onProcessesChanged: hoverPanel.keepOpen(300) } + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: "\uEFC5" anchors.verticalCenter: parent.verticalCenter diff --git a/shell/modules/MprisModule.qml b/shell/modules/MprisModule.qml index cd32262..0edbf0e 100644 --- a/shell/modules/MprisModule.qml +++ b/shell/modules/MprisModule.qml @@ -6,12 +6,12 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing opacity: S.Modules.mpris.enable && player !== null ? 1 : 0 visible: opacity > 0 - _panelHovered: hoverPanel.panelHovered + tooltip: "" readonly property var _players: S.MprisService.players readonly property MprisPlayer player: S.MprisService.player @@ -71,6 +71,23 @@ M.PinnableSection { required property var bar + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: root.playing ? "\uF04B" : (root.player?.playbackState === MprisPlaybackState.Paused ? "\uDB80\uDFE4" : "\uDB81\uDCDB") anchors.verticalCenter: parent.verticalCenter diff --git a/shell/modules/NetworkModule.qml b/shell/modules/NetworkModule.qml index df827c2..5624489 100644 --- a/shell/modules/NetworkModule.qml +++ b/shell/modules/NetworkModule.qml @@ -4,13 +4,30 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing - _panelHovered: hoverPanel.panelHovered + tooltip: "" readonly property string state: S.NetworkService.state + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: { if (root.state === "wifi") diff --git a/shell/modules/NotificationsModule.qml b/shell/modules/NotificationsModule.qml index 1af6743..7df4b2b 100644 --- a/shell/modules/NotificationsModule.qml +++ b/shell/modules/NotificationsModule.qml @@ -5,13 +5,30 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing - _panelHovered: hoverPanel.panelHovered + tooltip: "" readonly property bool hasUrgent: S.NotifService.list.some(n => n.urgency === NotificationUrgency.Critical && n.state !== "dismissed") + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: { if (S.NotifService.dnd) diff --git a/shell/modules/PinnableSection.qml b/shell/modules/PinnableSection.qml deleted file mode 100644 index 12aff05..0000000 --- a/shell/modules/PinnableSection.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick - -// Base component for bar modules with a pinnable hover panel. -// Provides the _pinned/_anyHover/_showPanel/_unpinTimer boilerplate. -// Modules bind _panelHovered to their HoverPanel's panelHovered property. -BarSection { - id: root - tooltip: "" - - property bool _pinned: false - property bool _panelHovered: false - readonly property bool _anyHover: root._hovered || _panelHovered - readonly property bool _showPanel: _anyHover || _pinned - - on_AnyHoverChanged: { - if (_anyHover) - _unpinTimer.stop(); - else if (_pinned) - _unpinTimer.start(); - } - - Timer { - id: _unpinTimer - interval: 500 - onTriggered: root._pinned = false - } -} diff --git a/shell/modules/TemperatureModule.qml b/shell/modules/TemperatureModule.qml index b352759..89bd8e5 100644 --- a/shell/modules/TemperatureModule.qml +++ b/shell/modules/TemperatureModule.qml @@ -4,10 +4,10 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: Math.max(1, S.Theme.moduleSpacing - 2) - _panelHovered: hoverPanel.panelHovered + tooltip: "" readonly property int _warm: S.Modules.temperature.warm || 80 readonly property int _hot: S.Modules.temperature.hot || 90 @@ -30,6 +30,23 @@ M.PinnableSection { } } + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } + M.BarIcon { icon: "\uF2C9" color: root._stateColor diff --git a/shell/modules/WeatherModule.qml b/shell/modules/WeatherModule.qml index b22b24c..b9f7f02 100644 --- a/shell/modules/WeatherModule.qml +++ b/shell/modules/WeatherModule.qml @@ -4,11 +4,28 @@ import "." as M import "../services" as S import "../applets" as C -M.PinnableSection { +M.BarSection { id: root spacing: S.Theme.moduleSpacing + tooltip: "" visible: S.Modules.weather.enable && S.WeatherService.available - _panelHovered: hoverPanel.panelHovered + + property bool _pinned: false + readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered + readonly property bool _showPanel: _anyHover || _pinned + + on_AnyHoverChanged: { + if (_anyHover) + _unpinTimer.stop(); + else if (_pinned) + _unpinTimer.start(); + } + + Timer { + id: _unpinTimer + interval: 500 + onTriggered: root._pinned = false + } M.BarIcon { icon: S.WeatherService.icon diff --git a/shell/modules/qmldir b/shell/modules/qmldir index 8d09375..3a8eee3 100644 --- a/shell/modules/qmldir +++ b/shell/modules/qmldir @@ -23,7 +23,6 @@ NotifCard 1.0 NotifCard.qml NotifPopup 1.0 NotifPopup.qml NotificationsModule 1.0 NotificationsModule.qml OverviewBackdrop 1.0 OverviewBackdrop.qml -PinnableSection 1.0 PinnableSection.qml PopupBackground 1.0 PopupBackground.qml PowerMenu 1.0 PowerMenu.qml PowerModule 1.0 PowerModule.qml diff --git a/test/qmllint-baseline.txt b/test/qmllint-baseline.txt index 7014c15..d417ffc 100644 --- a/test/qmllint-baseline.txt +++ b/test/qmllint-baseline.txt @@ -1,5 +1,3 @@ -shell/applets/BluetoothApplet.qml: Unqualified access [unqualified] -shell/applets/ClockApplet.qml: Unqualified access [unqualified] shell/applets/CpuApplet.qml: Member "_barColor" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "_f" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "_throttled" not found on type "QQuickItem" [missing-property] @@ -10,10 +8,6 @@ shell/applets/MemoryApplet.qml: Unqualified access [unqualified] shell/applets/MprisApplet.qml: Member "frac" not found on type "QQuickItem" [missing-property] shell/applets/MprisApplet.qml: Member "spacing" not found on type "Repeater" [missing-property] shell/applets/MprisApplet.qml: Unqualified access [unqualified] -shell/applets/NetworkApplet.qml: Unqualified access [unqualified] -shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property] -shell/applets/NotifApplet.qml: Member "_type" not found on type "QQuickItem" [missing-property] -shell/applets/NotifApplet.qml: Unqualified access [unqualified] shell/applets/TemperatureApplet.qml: Unqualified access [unqualified] shell/applets/VolumeApplet.qml: Unqualified access [unqualified] shell/lock/Lock.qml: Unqualified access [unqualified] @@ -31,9 +25,9 @@ shell/modules/BarLabel.qml: Member "screen" not found on type "QObject" [missing shell/modules/BarSection.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] shell/modules/BarSection.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BatteryModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/BluetoothMenu.qml: Unqualified access [unqualified] shell/modules/BluetoothModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BluetoothModule.qml: Unqualified access [unqualified] -shell/modules/ClockModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/CpuModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/DiskModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/Flyout.qml: Could not find property "left". [missing-property] @@ -48,9 +42,12 @@ shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unres shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified] shell/modules/MemoryModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/MprisModule.qml: Member "screen" not found on type "QObject" [missing-property] +shell/modules/NetworkMenu.qml: Unqualified access [unqualified] shell/modules/NetworkModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/NetworkModule.qml: Unqualified access [unqualified] shell/modules/NotifCard.qml: Unqualified access [unqualified] +shell/modules/NotifCenter.qml: Member "_notif" not found on type "QQuickItem" [missing-property] +shell/modules/NotifCenter.qml: Member "_type" not found on type "QQuickItem" [missing-property] +shell/modules/NotifCenter.qml: Unqualified access [unqualified] shell/modules/NotifPopup.qml: Could not find property "right". [missing-property] shell/modules/NotifPopup.qml: Could not find property "top". [missing-property] shell/modules/NotifPopup.qml: Type PanelWindow is not creatable. [uncreatable-type] @@ -74,11 +71,9 @@ shell/modules/TrayModule.qml: Member "screen" not found on type "QObject" [missi 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] shell/modules/VolumeModule.qml: Member "screen" not found on type "QObject" [missing-property] -shell/modules/WeatherModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/WindowTitleModule.qml: Unqualified access [unqualified] shell/modules/WorkspacesModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/WorkspacesModule.qml: Unqualified access [unqualified] -shell/services/BatteryService.qml: Unqualified access [unqualified] shell/services/BluetoothService.qml: Unqualified access [unqualified] shell/services/LockService.qml: Type QProcess::ExitStatus of parameter exitStatus in signal called exited was not found, but is required to compile onExited. Did you add all imports and dependencies? [signal-handler-parameters] shell/services/LockService.qml: Unqualified access [unqualified]