diff --git a/quickshell/Modules/OSD/BrightnessOSD.qml b/quickshell/Modules/OSD/BrightnessOSD.qml index b78bc435..7f835786 100644 --- a/quickshell/Modules/OSD/BrightnessOSD.qml +++ b/quickshell/Modules/OSD/BrightnessOSD.qml @@ -7,9 +7,10 @@ DankOSD { id: root readonly property bool useVertical: isVerticalLayout - property int targetBrightness: { - DisplayService.brightnessVersion; - return DisplayService.brightnessLevel; + property int _displayBrightness: 0 + + function _syncBrightness() { + _displayBrightness = DisplayService.brightnessLevel; } osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) @@ -20,9 +21,9 @@ DankOSD { Connections { target: DisplayService function onBrightnessChanged(showOsd) { - if (showOsd && SettingsData.osdBrightnessEnabled) { + root._syncBrightness(); + if (showOsd && SettingsData.osdBrightnessEnabled) root.show(); - } } } @@ -53,13 +54,11 @@ DankOSD { anchors.centerIn: parent name: { const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { + if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") return "brightness_medium"; - } else if (deviceInfo.name.includes("kbd")) { + if (deviceInfo.name.includes("kbd")) return "keyboard"; - } else { - return "lightbulb"; - } + return "lightbulb"; } size: Theme.iconSize color: Theme.primary @@ -77,20 +76,16 @@ DankOSD { const deviceInfo = DisplayService.getCurrentDeviceInfo(); if (!deviceInfo) return 1; - const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); - if (isExponential) { + if (SessionData.getBrightnessExponential(deviceInfo.id)) return 1; - } return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; } maximum: { const deviceInfo = DisplayService.getCurrentDeviceInfo(); if (!deviceInfo) return 100; - const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); - if (isExponential) { + if (SessionData.getBrightnessExponential(deviceInfo.id)) return 100; - } return deviceInfo.displayMax || 100; } enabled: DisplayService.brightnessAvailable @@ -99,28 +94,24 @@ DankOSD { const deviceInfo = DisplayService.getCurrentDeviceInfo(); if (!deviceInfo) return "%"; - const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); - if (isExponential) { + if (SessionData.getBrightnessExponential(deviceInfo.id)) return "%"; - } return deviceInfo.class === "ddc" ? "" : "%"; } thumbOutlineColor: Theme.surfaceContainer alwaysShowValue: SettingsData.osdAlwaysShowValue onSliderValueChanged: newValue => { - if (DisplayService.brightnessAvailable) { - DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true); - resetHideTimer(); - } + if (!DisplayService.brightnessAvailable) + return; + DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true); + resetHideTimer(); } - onContainsMouseChanged: { - setChildHovered(containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse) Binding on value { - value: root.targetBrightness + value: root._displayBrightness when: !brightnessSlider.isDragging } } @@ -146,13 +137,11 @@ DankOSD { anchors.centerIn: parent name: { const deviceInfo = DisplayService.getCurrentDeviceInfo(); - if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { + if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") return "brightness_medium"; - } else if (deviceInfo.name.includes("kbd")) { + if (deviceInfo.name.includes("kbd")) return "keyboard"; - } else { - return "lightbulb"; - } + return "lightbulb"; } size: Theme.iconSize color: Theme.primary @@ -170,7 +159,7 @@ DankOSD { property int value: 50 Binding on value { - value: root.targetBrightness + value: root._displayBrightness when: !vertSlider.dragging } @@ -178,8 +167,7 @@ DankOSD { const deviceInfo = DisplayService.getCurrentDeviceInfo(); if (!deviceInfo) return 1; - const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); - if (isExponential) + if (SessionData.getBrightnessExponential(deviceInfo.id)) return 1; return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0; } @@ -188,8 +176,7 @@ DankOSD { const deviceInfo = DisplayService.getCurrentDeviceInfo(); if (!deviceInfo) return 100; - const isExponential = SessionData.getBrightnessExponential(deviceInfo.id); - if (isExponential) + if (SessionData.getBrightnessExponential(deviceInfo.id)) return 100; return deviceInfo.displayMax || 100; } @@ -240,33 +227,25 @@ DankOSD { hoverEnabled: true cursorShape: Qt.PointingHandCursor - onContainsMouseChanged: { - setChildHovered(containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse) onPressed: mouse => { vertSlider.dragging = true; updateBrightness(mouse); } - onReleased: { - vertSlider.dragging = false; - } + onReleased: vertSlider.dragging = false onPositionChanged: mouse => { - if (pressed) { + if (pressed) updateBrightness(mouse); - } } - onClicked: mouse => { - updateBrightness(mouse); - } + onClicked: mouse => updateBrightness(mouse) function updateBrightness(mouse) { - if (!DisplayService.brightnessAvailable) { + if (!DisplayService.brightnessAvailable) return; - } const ratio = 1.0 - (mouse.y / height); const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum)); vertSlider.value = newValue; diff --git a/quickshell/Modules/OSD/MediaVolumeOSD.qml b/quickshell/Modules/OSD/MediaVolumeOSD.qml index 2ba4ddfa..147d81e8 100644 --- a/quickshell/Modules/OSD/MediaVolumeOSD.qml +++ b/quickshell/Modules/OSD/MediaVolumeOSD.qml @@ -8,13 +8,20 @@ DankOSD { readonly property bool useVertical: isVerticalLayout readonly property var player: MprisController.activePlayer - readonly property int currentVolume: player ? Math.min(100, Math.round(player.volume * 100)) : 0 readonly property bool volumeSupported: player?.volumeSupported ?? false property bool _suppressNewPlayer: false + property int _displayVolume: 0 + + function _syncVolume() { + if (!player) + return; + _displayVolume = Math.min(100, Math.round(player.volume * 100)); + } onPlayerChanged: { _suppressNewPlayer = true; _suppressTimer.restart(); + _syncVolume(); } Timer { @@ -37,25 +44,25 @@ DankOSD { } function toggleMute() { - if (player) { - player.volume = player.volume > 0 ? 0 : 1; - } + if (!player) + return; + player.volume = player.volume > 0 ? 0 : 1; } function setVolume(volumePercent) { - if (player) { - player.volume = volumePercent / 100; - resetHideTimer(); - } + if (!player) + return; + player.volume = volumePercent / 100; + resetHideTimer(); } Connections { target: player function onVolumeChanged() { - if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer) { + root._syncVolume(); + if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer) root.show(); - } } } @@ -96,9 +103,7 @@ DankOSD { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: toggleMute() - onContainsMouseChanged: { - setChildHovered(containsMouse || volumeSlider.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse) } } @@ -115,29 +120,21 @@ DankOSD { showValue: true unit: "%" thumbOutlineColor: Theme.surfaceContainer - valueOverride: currentVolume + valueOverride: root._displayVolume alwaysShowValue: SettingsData.osdAlwaysShowValue Component.onCompleted: { - value = currentVolume; + root._syncVolume(); + value = root._displayVolume; } - onSliderValueChanged: newValue => { - setVolume(newValue); - } + onSliderValueChanged: newValue => setVolume(newValue) - onContainsMouseChanged: { - setChildHovered(containsMouse || muteButton.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse) - Connections { - target: player - - function onVolumeChanged() { - if (volumeSlider && !volumeSlider.pressed) { - volumeSlider.value = currentVolume; - } - } + Binding on value { + value: root._displayVolume + when: !volumeSlider.pressed } } } @@ -172,9 +169,7 @@ DankOSD { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: toggleMute() - onContainsMouseChanged: { - setChildHovered(containsMouse || vertSliderArea.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse) } } @@ -186,7 +181,7 @@ DankOSD { y: gap * 2 + Theme.iconSize property bool dragging: false - property int value: currentVolume + property int value: root._displayVolume Rectangle { id: vertTrack @@ -231,28 +226,21 @@ DankOSD { hoverEnabled: true cursorShape: Qt.PointingHandCursor - onContainsMouseChanged: { - setChildHovered(containsMouse || muteButtonVert.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse) onPressed: mouse => { vertSlider.dragging = true; updateVolume(mouse); } - onReleased: { - vertSlider.dragging = false; - } + onReleased: vertSlider.dragging = false onPositionChanged: mouse => { - if (pressed) { + if (pressed) updateVolume(mouse); - } } - onClicked: mouse => { - updateVolume(mouse); - } + onClicked: mouse => updateVolume(mouse) function updateVolume(mouse) { const ratio = 1.0 - (mouse.y / height); @@ -260,16 +248,6 @@ DankOSD { setVolume(volume); } } - - Connections { - target: player - - function onVolumeChanged() { - if (!vertSlider.dragging) { - vertSlider.value = currentVolume; - } - } - } } StyledText { @@ -283,15 +261,4 @@ DankOSD { } } } - - onOsdShown: { - if (player && contentLoader.item && contentLoader.item.item) { - if (!useVertical) { - const slider = contentLoader.item.item.children[0].children[1]; - if (slider && slider.value !== undefined) { - slider.value = currentVolume; - } - } - } - } } diff --git a/quickshell/Modules/OSD/VolumeOSD.qml b/quickshell/Modules/OSD/VolumeOSD.qml index 6233437a..be07820a 100644 --- a/quickshell/Modules/OSD/VolumeOSD.qml +++ b/quickshell/Modules/OSD/VolumeOSD.qml @@ -7,6 +7,13 @@ DankOSD { id: root readonly property bool useVertical: isVerticalLayout + property int _displayVolume: 0 + + function _syncVolume() { + if (!AudioService.sink?.audio) + return; + _displayVolume = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); + } osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2) osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2) @@ -14,18 +21,17 @@ DankOSD { enableMouseInteraction: true Connections { - target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null + target: AudioService.sink?.audio ?? null function onVolumeChanged() { - if (SettingsData.osdVolumeEnabled) { + root._syncVolume(); + if (SettingsData.osdVolumeEnabled) root.show(); - } } function onMutedChanged() { - if (SettingsData.osdVolumeEnabled) { + if (SettingsData.osdVolumeEnabled) root.show(); - } } } @@ -33,9 +39,9 @@ DankOSD { target: AudioService function onSinkChanged() { - if (root.shouldBeVisible && SettingsData.osdVolumeEnabled) { + root._syncVolume(); + if (root.shouldBeVisible && SettingsData.osdVolumeEnabled) root.show(); - } } } @@ -64,7 +70,7 @@ DankOSD { DankIcon { anchors.centerIn: parent - name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ? "volume_off" : "volume_up" + name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up" size: Theme.iconSize color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText } @@ -75,60 +81,45 @@ DankOSD { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: { - AudioService.toggleMute(); - } - onContainsMouseChanged: { - setChildHovered(containsMouse || volumeSlider.containsMouse); - } + onClicked: AudioService.toggleMute() + onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse) } } DankSlider { id: volumeSlider - readonly property real actualVolumePercent: AudioService.sink && AudioService.sink.audio ? Math.round(AudioService.sink.audio.volume * 100) : 0 - readonly property real displayPercent: actualVolumePercent - width: parent.width - Theme.iconSize - parent.gap * 3 height: 40 x: parent.gap * 2 + Theme.iconSize anchors.verticalCenter: parent.verticalCenter minimum: 0 maximum: AudioService.sinkMaxVolume - enabled: AudioService.sink && AudioService.sink.audio + enabled: AudioService.sink?.audio showValue: true unit: "%" thumbOutlineColor: Theme.surfaceContainer - valueOverride: displayPercent + valueOverride: root._displayVolume alwaysShowValue: SettingsData.osdAlwaysShowValue Component.onCompleted: { - if (AudioService.sink && AudioService.sink.audio) { - value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); - } + root._syncVolume(); + value = root._displayVolume; } onSliderValueChanged: newValue => { - if (AudioService.sink && AudioService.sink.audio) { - SessionData.suppressOSDTemporarily(); - AudioService.sink.audio.volume = newValue / 100; - resetHideTimer(); - } + if (!AudioService.sink?.audio) + return; + SessionData.suppressOSDTemporarily(); + AudioService.sink.audio.volume = newValue / 100; + resetHideTimer(); } - onContainsMouseChanged: { - setChildHovered(containsMouse || muteButton.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse) - Connections { - target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null - - function onVolumeChanged() { - if (volumeSlider && !volumeSlider.pressed) { - volumeSlider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); - } - } + Binding on value { + value: root._displayVolume + when: !volumeSlider.pressed } } } @@ -151,7 +142,7 @@ DankOSD { DankIcon { anchors.centerIn: parent - name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ? "volume_off" : "volume_up" + name: AudioService.sink?.audio?.muted ? "volume_off" : "volume_up" size: Theme.iconSize color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText } @@ -162,12 +153,8 @@ DankOSD { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: { - AudioService.toggleMute(); - } - onContainsMouseChanged: { - setChildHovered(containsMouse || vertSliderArea.containsMouse); - } + onClicked: AudioService.toggleMute() + onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse) } } @@ -179,7 +166,7 @@ DankOSD { y: gap * 2 + Theme.iconSize property bool dragging: false - property int value: AudioService.sink && AudioService.sink.audio ? Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)) : 0 + property int value: root._displayVolume Rectangle { id: vertTrack @@ -220,50 +207,35 @@ DankOSD { id: vertSliderArea anchors.fill: parent anchors.margins: -12 - enabled: AudioService.sink && AudioService.sink.audio + enabled: AudioService.sink?.audio hoverEnabled: true cursorShape: Qt.PointingHandCursor - onContainsMouseChanged: { - setChildHovered(containsMouse || muteButtonVert.containsMouse); - } + onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse) onPressed: mouse => { vertSlider.dragging = true; updateVolume(mouse); } - onReleased: { - vertSlider.dragging = false; - } + onReleased: vertSlider.dragging = false onPositionChanged: mouse => { - if (pressed) { + if (pressed) updateVolume(mouse); - } } - onClicked: mouse => { - updateVolume(mouse); - } + onClicked: mouse => updateVolume(mouse) function updateVolume(mouse) { - if (AudioService.sink && AudioService.sink.audio) { - const maxVol = AudioService.sinkMaxVolume; - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol))); - SessionData.suppressOSDTemporarily(); - AudioService.sink.audio.volume = volume / 100; - resetHideTimer(); - } - } - } - - Connections { - target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null - - function onVolumeChanged() { - vertSlider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); + if (!AudioService.sink?.audio) + return; + const maxVol = AudioService.sinkMaxVolume; + const ratio = 1.0 - (mouse.y / height); + const volume = Math.max(0, Math.min(maxVol, Math.round(ratio * maxVol))); + SessionData.suppressOSDTemporarily(); + AudioService.sink.audio.volume = volume / 100; + resetHideTimer(); } } } @@ -279,15 +251,4 @@ DankOSD { } } } - - onOsdShown: { - if (AudioService.sink && AudioService.sink.audio && contentLoader.item && contentLoader.item.item) { - if (!useVertical) { - const slider = contentLoader.item.item.children[0].children[1]; - if (slider && slider.value !== undefined) { - slider.value = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)); - } - } - } - } } diff --git a/quickshell/Modules/Plugins/StringSetting.qml b/quickshell/Modules/Plugins/StringSetting.qml index 16041ba7..849807b9 100644 --- a/quickshell/Modules/Plugins/StringSetting.qml +++ b/quickshell/Modules/Plugins/StringSetting.qml @@ -18,36 +18,41 @@ Column { property bool isInitialized: false function loadValue() { - const settings = findSettings() + const settings = findSettings(); if (settings && settings.pluginService) { - const loadedValue = settings.loadValue(settingKey, defaultValue) - value = loadedValue - textField.text = loadedValue - isInitialized = true + const loadedValue = settings.loadValue(settingKey, defaultValue); + if (textField.activeFocus && isInitialized) + return; + value = loadedValue; + textField.text = loadedValue; + isInitialized = true; } } Component.onCompleted: { - Qt.callLater(loadValue) + Qt.callLater(loadValue); } - onValueChanged: { - if (!isInitialized) return - const settings = findSettings() - if (settings) { - settings.saveValue(settingKey, value) - } + function commit() { + if (!isInitialized) + return; + if (textField.text === value) + return; + value = textField.text; + const settings = findSettings(); + if (settings) + settings.saveValue(settingKey, value); } function findSettings() { - let item = parent + let item = parent; while (item) { if (item.saveValue !== undefined && item.loadValue !== undefined) { - return item + return item; } - item = item.parent + item = item.parent; } - return null + return null; } StyledText { @@ -70,16 +75,10 @@ Column { id: textField width: parent.width placeholderText: root.placeholder - onTextEdited: { - root.value = text - } - onEditingFinished: { - root.value = text - } + onEditingFinished: root.commit() onActiveFocusChanged: { - if (!activeFocus) { - root.value = text - } + if (!activeFocus) + root.commit(); } } } diff --git a/quickshell/Modules/Settings/PluginsTab.qml b/quickshell/Modules/Settings/PluginsTab.qml index 1c6f46d6..1ff1476d 100644 --- a/quickshell/Modules/Settings/PluginsTab.qml +++ b/quickshell/Modules/Settings/PluginsTab.qml @@ -375,8 +375,20 @@ FocusScope { if (!plugin || !PluginService.isPluginLoaded(pluginId)) return; var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); - if (isLauncher) - PluginService.reloadPlugin(pluginId); + if (isLauncher) { + pluginReloadTimer.pendingPluginId = pluginId; + pluginReloadTimer.restart(); + } + } + } + + Timer { + id: pluginReloadTimer + property string pendingPluginId: "" + interval: 500 + onTriggered: { + if (pendingPluginId) + PluginService.reloadPlugin(pendingPluginId); } } diff --git a/quickshell/Widgets/DankOSD.qml b/quickshell/Widgets/DankOSD.qml index 821ba370..2811540e 100644 --- a/quickshell/Widgets/DankOSD.qml +++ b/quickshell/Widgets/DankOSD.qml @@ -28,6 +28,10 @@ PanelWindow { function show() { if (SessionData.suppressOSD) return; + if (shouldBeVisible) { + hideTimer.restart(); + return; + } OSDManager.showOSD(root); closeTimer.stop(); shouldBeVisible = true; @@ -257,7 +261,7 @@ PanelWindow { property real shadowSpreadPx: 0 property real shadowBaseAlpha: 0.60 readonly property real popupSurfaceAlpha: SettingsData.popupTransparency - readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha * osdContainer.opacity)) + readonly property real effectiveShadowAlpha: shouldBeVisible ? Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha)) : 0 Rectangle { id: background