From 1b6c2fee91ac915fdad4f207322e5362d4ab7b8d Mon Sep 17 00:00:00 2001 From: Damocles Date: Sat, 18 Apr 2026 13:34:04 +0200 Subject: [PATCH 1/2] use Instantiator for mpris state watchers instead of manual createObject --- shell/services/MprisService.qml | 44 ++++++++++----------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/shell/services/MprisService.qml b/shell/services/MprisService.qml index d5941d5..c88aefa 100644 --- a/shell/services/MprisService.qml +++ b/shell/services/MprisService.qml @@ -1,6 +1,7 @@ pragma Singleton import QtQuick +import QtQml.Models import Quickshell.Services.Mpris QtObject { @@ -13,7 +14,6 @@ QtObject { property string _selectedIdentity: "" property var _lastPlayedTime: ({}) - property var _watchers: [] onPlayerChanged: { if (player) @@ -33,33 +33,18 @@ QtObject { } } - // Watch raw Mpris.players for add/remove - this does NOT fire on state changes - property Connections _mprisConn: Connections { - target: Mpris - function onPlayersChanged() { - root._reconnectWatchers(); - } - } - - function _reconnectWatchers() { - for (const w of _watchers) - w.destroy(); - - const raw = Mpris.players.values ?? []; - const newWatchers = []; - for (const p of raw) { - const conn = _watcherComp.createObject(root, { - target: p - }); - newWatchers.push(conn); - } - _watchers = newWatchers; - } - - property Component _watcherComp: Component { - Connections { - function onPlaybackStateChanged() { - root._onPlaybackStateChanged(target); + // Watch all raw players for state changes via Instantiator - + // delegates persist across state changes since the model only + // changes on player add/remove, not property changes + property Instantiator _stateWatchers: Instantiator { + model: Mpris.players + delegate: QtObject { + required property MprisPlayer modelData + property Connections _conn: Connections { + target: modelData + function onPlaybackStateChanged() { + root._onPlaybackStateChanged(modelData); + } } } } @@ -84,7 +69,6 @@ QtObject { } } } else if (p.playbackState === MprisPlaybackState.Paused && p === player) { - // Current player paused - switch to a playing one if available _switchToPlaying(); } } @@ -139,6 +123,4 @@ QtObject { if (players[idx]) _selectedIdentity = players[idx].identity ?? ""; } - - Component.onCompleted: _reconnectWatchers() } From 22ca356fb50af6ae84425193e239f05e4bcc9db5 Mon Sep 17 00:00:00 2001 From: Damocles Date: Sat, 18 Apr 2026 14:21:00 +0200 Subject: [PATCH 2/2] wrap mpris player selection pills into multiple rows with Flow --- shell/applets/MprisApplet.qml | 78 ++++++++++++++++------------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/shell/applets/MprisApplet.qml b/shell/applets/MprisApplet.qml index 1dd4de6..e06c531 100644 --- a/shell/applets/MprisApplet.qml +++ b/shell/applets/MprisApplet.qml @@ -306,58 +306,50 @@ Column { // Player switcher Item { width: root.width - height: root.players.length > 1 ? 28 : 0 + height: root.players.length > 1 ? _playerFlow.implicitHeight + 6 : 0 visible: root.players.length > 1 - Flickable { - id: _switcher - anchors.centerIn: parent - width: Math.min(_playerRow.implicitWidth, parent.width - 16) - height: 22 - contentWidth: _playerRow.implicitWidth - clip: true + Flow { + id: _playerFlow + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + width: parent.width - 16 + spacing: 6 - Row { - id: _playerRow - height: 22 - spacing: 6 + Repeater { + model: root.players - Repeater { - model: root.players + delegate: Rectangle { + required property var modelData + required property int index - delegate: Rectangle { - required property var modelData - required property int index + readonly property bool _active: index === root.playerIdx - readonly property bool _active: index === root.playerIdx + width: _pLabel.implicitWidth + 12 + height: 18 + radius: 9 + color: _active ? S.Theme.base02 : (pHover.hovered ? S.Theme.base02 : "transparent") + border.color: _active ? root.accentColor : S.Theme.base03 + border.width: _active ? 1 : 0 - width: _pLabel.implicitWidth + 12 - height: 18 - radius: 9 - color: _active ? S.Theme.base02 : (pHover.hovered ? S.Theme.base02 : "transparent") - border.color: _active ? root.accentColor : S.Theme.base03 - border.width: _active ? 1 : 0 - anchors.verticalCenter: parent.verticalCenter + Text { + id: _pLabel + anchors.centerIn: parent + text: modelData.identity ?? "Player" + color: _active ? root.accentColor : S.Theme.base04 + font.pixelSize: S.Theme.fontSize - 2 + font.family: S.Theme.fontFamily + font.bold: _active + } - Text { - id: _pLabel - anchors.centerIn: parent - text: modelData.identity ?? "Player" - color: _active ? root.accentColor : S.Theme.base04 - font.pixelSize: S.Theme.fontSize - 2 - font.family: S.Theme.fontFamily - font.bold: _active - } + HoverHandler { + id: pHover + cursorShape: Qt.PointingHandCursor + } - HoverHandler { - id: pHover - cursorShape: Qt.PointingHandCursor - } - - TapHandler { - onTapped: { - root.playerSwitched(index); - } + TapHandler { + onTapped: { + root.playerSwitched(index); } } }