forked from quickshell/quickshell
		
	service/mpris: adopt bindable properties
This commit is contained in:
		
							parent
							
								
									1955deee74
								
							
						
					
					
						commit
						db9e633197
					
				
					 3 changed files with 263 additions and 250 deletions
				
			
		| 
						 | 
					@ -290,3 +290,24 @@ bool setSimpleObjectHandle(auto* parent, auto* value) {
 | 
				
			||||||
	[[nodiscard]] Type getter() { return this->member.value(); }                                     \
 | 
						[[nodiscard]] Type getter() { return this->member.value(); }                                     \
 | 
				
			||||||
	[[nodiscard]] QBindable<Type> bindable() { return &this->member; }
 | 
						[[nodiscard]] QBindable<Type> bindable() { return &this->member; }
 | 
				
			||||||
// NOLINTEND
 | 
					// NOLINTEND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <auto methodPtr>
 | 
				
			||||||
 | 
					class MethodFunctor {
 | 
				
			||||||
 | 
						using PtrMeta = MemberPointerTraits<decltype(methodPtr)>;
 | 
				
			||||||
 | 
						using Class = PtrMeta::Class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						MethodFunctor(Class* obj): obj(obj) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void operator()() { (this->obj->*methodPtr)(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						Class* obj;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTBEGIN
 | 
				
			||||||
 | 
					#define QS_BINDING_SUBSCRIBE_METHOD(Class, bindable, method, strategy)                             \
 | 
				
			||||||
 | 
						QPropertyChangeHandler<MethodFunctor<&Class::method>>                                            \
 | 
				
			||||||
 | 
						    _qs_method_subscribe_##bindable##_##method =                                                 \
 | 
				
			||||||
 | 
						        (bindable).strategy(MethodFunctor<&Class::method>(this));
 | 
				
			||||||
 | 
					// NOLINTEND
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,15 +4,16 @@
 | 
				
			||||||
#include <qdatetime.h>
 | 
					#include <qdatetime.h>
 | 
				
			||||||
#include <qdbusconnection.h>
 | 
					#include <qdbusconnection.h>
 | 
				
			||||||
#include <qdbusextratypes.h>
 | 
					#include <qdbusextratypes.h>
 | 
				
			||||||
 | 
					#include <qlist.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
#include <qloggingcategory.h>
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qproperty.h>
 | 
					#include <qproperty.h>
 | 
				
			||||||
#include <qstring.h>
 | 
					#include <qstring.h>
 | 
				
			||||||
 | 
					#include <qstringliteral.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../core/util.hpp"
 | 
					 | 
				
			||||||
#include "../../dbus/properties.hpp"
 | 
					#include "../../dbus/properties.hpp"
 | 
				
			||||||
#include "dbus_player.h"
 | 
					#include "dbus_player.h"
 | 
				
			||||||
#include "dbus_player_app.h"
 | 
					#include "dbus_player_app.h"
 | 
				
			||||||
| 
						 | 
					@ -57,37 +58,81 @@ MprisPlayer::MprisPlayer(const QString& address, QObject* parent): QObject(paren
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bCanPlay.setBinding([this]() { return this->bCanControl && this->bpCanPlay; });
 | 
				
			||||||
 | 
						this->bCanPause.setBinding([this]() { return this->bCanControl && this->bpCanPause; });
 | 
				
			||||||
 | 
						this->bCanSeek.setBinding([this]() { return this->bCanControl && this->bpCanSeek; });
 | 
				
			||||||
 | 
						this->bCanGoNext.setBinding([this]() { return this->bCanControl && this->bpCanGoNext; });
 | 
				
			||||||
 | 
						this->bCanGoPrevious.setBinding([this]() { return this->bCanControl && this->bpCanGoPrevious; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bCanTogglePlaying.setBinding([this]() {
 | 
				
			||||||
 | 
							return this->bPlaybackState == MprisPlaybackState::Playing ? this->bCanPause.value()
 | 
				
			||||||
 | 
							                                                           : this->bCanPlay.value();
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bTrackTitle.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& title = this->bMetadata.value().value("xesam:title").toString();
 | 
				
			||||||
 | 
							return title.isNull() ? QStringLiteral("Unknown Track") : title;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bTrackAlbum.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& album = this->bMetadata.value().value("xesam:album").toString();
 | 
				
			||||||
 | 
							return album.isNull() ? QStringLiteral("Unknown Album") : album;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bTrackArtist.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& artist = this->bMetadata.value().value("xesam:artist").value<QList<QString>>();
 | 
				
			||||||
 | 
							return artist.isEmpty() ? QStringLiteral("Unknown Artist") : artist.join(", ");
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bTrackAlbumArtist.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& artist = this->bMetadata.value().value("xesam:albumArtist").toString();
 | 
				
			||||||
 | 
							return artist.isNull() ? QStringLiteral("Unknown Artist") : artist;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bTrackArtUrl.setBinding([this]() {
 | 
				
			||||||
 | 
							return this->bMetadata.value().value("mpris:artUrl").toString();
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bInternalLength.setBinding([this]() {
 | 
				
			||||||
 | 
							auto variant = this->bMetadata.value().value("mpris:length");
 | 
				
			||||||
 | 
							if (variant.isValid() && variant.canConvert<qlonglong>()) {
 | 
				
			||||||
 | 
								return variant.value<qlonglong>();
 | 
				
			||||||
 | 
							} else return static_cast<qlonglong>(-1);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bPlaybackState.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& status = this->bpPlaybackStatus.value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (status == "Playing") {
 | 
				
			||||||
 | 
								return MprisPlaybackState::Playing;
 | 
				
			||||||
 | 
							} else if (status == "Paused") {
 | 
				
			||||||
 | 
								this->pausedTime = QDateTime::currentDateTimeUtc();
 | 
				
			||||||
 | 
								return MprisPlaybackState::Paused;
 | 
				
			||||||
 | 
							} else if (status == "Stopped") {
 | 
				
			||||||
 | 
								return MprisPlaybackState::Stopped;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								qWarning() << "Received unexpected PlaybackStatus for" << this << status;
 | 
				
			||||||
 | 
								return MprisPlaybackState::Stopped;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->bLoopState.setBinding([this]() {
 | 
				
			||||||
 | 
							const auto& status = this->bpLoopStatus.value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (status == "None") {
 | 
				
			||||||
 | 
								return MprisLoopState::None;
 | 
				
			||||||
 | 
							} else if (status == "Track") {
 | 
				
			||||||
 | 
								return MprisLoopState::Track;
 | 
				
			||||||
 | 
							} else if (status == "Playlist") {
 | 
				
			||||||
 | 
								return MprisLoopState::Playlist;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								qWarning() << "Received unexpected LoopStatus for" << this << status;
 | 
				
			||||||
 | 
								return MprisLoopState::None;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
	QObject::connect(&this->pCanQuit, &AbstractDBusProperty::changed, this, &MprisPlayer::canQuitChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanRaise, &AbstractDBusProperty::changed, this, &MprisPlayer::canRaiseChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanSetFullscreen, &AbstractDBusProperty::changed, this, &MprisPlayer::canSetFullscreenChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pIdentity, &AbstractDBusProperty::changed, this, &MprisPlayer::identityChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pDesktopEntry, &AbstractDBusProperty::changed, this, &MprisPlayer::desktopEntryChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pFullscreen, &AbstractDBusProperty::changed, this, &MprisPlayer::fullscreenChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pSupportedUriSchemes, &AbstractDBusProperty::changed, this, &MprisPlayer::supportedUriSchemesChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pSupportedMimeTypes, &AbstractDBusProperty::changed, this, &MprisPlayer::supportedMimeTypesChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanControl, &AbstractDBusProperty::changed, this, &MprisPlayer::canControlChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanSeek, &AbstractDBusProperty::changed, this, &MprisPlayer::canSeekChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanGoNext, &AbstractDBusProperty::changed, this, &MprisPlayer::canGoNextChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanGoPrevious, &AbstractDBusProperty::changed, this, &MprisPlayer::canGoPreviousChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanPlay, &AbstractDBusProperty::changed, this, &MprisPlayer::canPlayChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanPause, &AbstractDBusProperty::changed, this, &MprisPlayer::canPauseChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanPlay, &AbstractDBusProperty::changed, this, &MprisPlayer::canTogglePlayingChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pCanPause, &AbstractDBusProperty::changed, this, &MprisPlayer::canTogglePlayingChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QObject::connect(&this->pPosition, &AbstractDBusProperty::changed, this, &MprisPlayer::onPositionChanged);
 | 
					 | 
				
			||||||
	QObject::connect(this->player, &DBusMprisPlayer::Seeked, this, &MprisPlayer::onSeek);
 | 
						QObject::connect(this->player, &DBusMprisPlayer::Seeked, this, &MprisPlayer::onSeek);
 | 
				
			||||||
	QObject::connect(&this->pVolume, &AbstractDBusProperty::changed, this, &MprisPlayer::volumeChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pMetadata, &AbstractDBusProperty::changed, this, &MprisPlayer::onMetadataChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pPlaybackStatus, &AbstractDBusProperty::changed, this, &MprisPlayer::onPlaybackStatusChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pLoopStatus, &AbstractDBusProperty::changed, this, &MprisPlayer::onLoopStatusChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pRate, &AbstractDBusProperty::changed, this, &MprisPlayer::rateChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pMinRate, &AbstractDBusProperty::changed, this, &MprisPlayer::minRateChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pMaxRate, &AbstractDBusProperty::changed, this, &MprisPlayer::maxRateChanged);
 | 
					 | 
				
			||||||
	QObject::connect(&this->pShuffle, &AbstractDBusProperty::changed, this, &MprisPlayer::shuffleChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QObject::connect(&this->playerProperties, &DBusPropertyGroup::getAllFinished, this, &MprisPlayer::onGetAllFinished);
 | 
						QObject::connect(&this->playerProperties, &DBusPropertyGroup::getAllFinished, this, &MprisPlayer::onGetAllFinished);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Ensure user triggered position updates can update length.
 | 
						// Ensure user triggered position updates can update length.
 | 
				
			||||||
| 
						 | 
					@ -151,41 +196,22 @@ void MprisPlayer::seek(qreal offset) {
 | 
				
			||||||
bool MprisPlayer::isValid() const { return this->player->isValid(); }
 | 
					bool MprisPlayer::isValid() const { return this->player->isValid(); }
 | 
				
			||||||
QString MprisPlayer::address() const { return this->player->service(); }
 | 
					QString MprisPlayer::address() const { return this->player->service(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool MprisPlayer::canControl() const { return this->pCanControl.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canPlay() const { return this->canControl() && this->pCanPlay.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canPause() const { return this->canControl() && this->pCanPause.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool MprisPlayer::canTogglePlaying() const {
 | 
					 | 
				
			||||||
	if (this->mPlaybackState == MprisPlaybackState::Playing) return this->canPlay();
 | 
					 | 
				
			||||||
	else return this->canPause();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool MprisPlayer::canSeek() const { return this->canControl() && this->pCanSeek.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canGoNext() const { return this->canControl() && this->pCanGoNext.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canGoPrevious() const { return this->canControl() && this->pCanGoPrevious.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canQuit() const { return this->pCanQuit.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canRaise() const { return this->pCanRaise.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::canSetFullscreen() const { return this->pCanSetFullscreen.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const QString& MprisPlayer::identity() const { return this->pIdentity.get(); }
 | 
					 | 
				
			||||||
const QString& MprisPlayer::desktopEntry() const { return this->pDesktopEntry.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qlonglong MprisPlayer::positionMs() const {
 | 
					qlonglong MprisPlayer::positionMs() const {
 | 
				
			||||||
	if (!this->positionSupported()) return 0; // unsupported
 | 
						if (!this->positionSupported()) return 0; // unsupported
 | 
				
			||||||
	if (this->mPlaybackState == MprisPlaybackState::Stopped) return 0;
 | 
						if (this->bPlaybackState == MprisPlaybackState::Stopped) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto paused = this->mPlaybackState == MprisPlaybackState::Paused;
 | 
						auto paused = this->bPlaybackState == MprisPlaybackState::Paused;
 | 
				
			||||||
	auto time = paused ? this->pausedTime : QDateTime::currentDateTime();
 | 
						auto time = paused ? this->pausedTime : QDateTime::currentDateTime();
 | 
				
			||||||
	auto offset = time - this->lastPositionTimestamp;
 | 
						auto offset = time - this->lastPositionTimestamp;
 | 
				
			||||||
	auto rateMul = static_cast<qlonglong>(this->pRate.get() * 1000);
 | 
						auto rateMul = static_cast<qlonglong>(this->bRate.value() * 1000);
 | 
				
			||||||
	offset = (offset * rateMul) / 1000;
 | 
						offset = (offset * rateMul) / 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (this->pPosition.get() / 1000) + offset.count();
 | 
						return (this->bpPosition.value() / 1000) + offset.count();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qreal MprisPlayer::position() const {
 | 
					qreal MprisPlayer::position() const {
 | 
				
			||||||
	if (!this->positionSupported()) return 0; // unsupported
 | 
						if (!this->positionSupported()) return 0; // unsupported
 | 
				
			||||||
	if (this->mPlaybackState == MprisPlaybackState::Stopped) return 0;
 | 
						if (this->bPlaybackState == MprisPlaybackState::Stopped) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return static_cast<qreal>(this->positionMs()) / 1000.0; // NOLINT
 | 
						return static_cast<qreal>(this->positionMs()) / 1000.0; // NOLINT
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -193,7 +219,7 @@ qreal MprisPlayer::position() const {
 | 
				
			||||||
bool MprisPlayer::positionSupported() const { return this->pPosition.exists(); }
 | 
					bool MprisPlayer::positionSupported() const { return this->pPosition.exists(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::setPosition(qreal position) {
 | 
					void MprisPlayer::setPosition(qreal position) {
 | 
				
			||||||
	if (this->pPosition.get() == -1) {
 | 
						if (this->bpPosition.value() == -1) {
 | 
				
			||||||
		qWarning() << "Cannot set position of" << this << "because position is not supported.";
 | 
							qWarning() << "Cannot set position of" << this << "because position is not supported.";
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -212,10 +238,10 @@ void MprisPlayer::setPosition(qreal position) {
 | 
				
			||||||
		this->player->Seek(target - pos);
 | 
							this->player->Seek(target - pos);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pPosition.set(target);
 | 
						this->bpPosition = target;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::onPositionChanged() {
 | 
					void MprisPlayer::onPositionUpdated() {
 | 
				
			||||||
	const bool firstChange = !this->lastPositionTimestamp.isValid();
 | 
						const bool firstChange = !this->lastPositionTimestamp.isValid();
 | 
				
			||||||
	this->lastPositionTimestamp = QDateTime::currentDateTimeUtc();
 | 
						this->lastPositionTimestamp = QDateTime::currentDateTimeUtc();
 | 
				
			||||||
	this->pausedTime = this->lastPositionTimestamp;
 | 
						this->pausedTime = this->lastPositionTimestamp;
 | 
				
			||||||
| 
						 | 
					@ -227,19 +253,18 @@ void MprisPlayer::onExportedPositionChanged() {
 | 
				
			||||||
	if (!this->lengthSupported()) emit this->lengthChanged();
 | 
						if (!this->lengthSupported()) emit this->lengthChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::onSeek(qlonglong time) { this->pPosition.set(time); }
 | 
					void MprisPlayer::onSeek(qlonglong time) { this->bpPosition = time; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qreal MprisPlayer::length() const {
 | 
					qreal MprisPlayer::length() const {
 | 
				
			||||||
	if (this->mLength == -1) {
 | 
						if (this->bInternalLength == -1) {
 | 
				
			||||||
		return this->position(); // unsupported
 | 
							return this->position(); // unsupported
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return static_cast<qreal>(this->mLength / 1000) / 1000; // NOLINT
 | 
							return static_cast<qreal>(this->bInternalLength / 1000) / 1000; // NOLINT
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool MprisPlayer::lengthSupported() const { return this->mLength != -1; }
 | 
					bool MprisPlayer::lengthSupported() const { return this->bInternalLength != -1; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qreal MprisPlayer::volume() const { return this->pVolume.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::volumeSupported() const { return this->pVolume.exists(); }
 | 
					bool MprisPlayer::volumeSupported() const { return this->pVolume.exists(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::setVolume(qreal volume) {
 | 
					void MprisPlayer::setVolume(qreal volume) {
 | 
				
			||||||
| 
						 | 
					@ -253,21 +278,15 @@ void MprisPlayer::setVolume(qreal volume) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pVolume.set(volume);
 | 
						this->bVolume = volume;
 | 
				
			||||||
	this->pVolume.write();
 | 
						this->pVolume.write();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::onMetadataChanged() {
 | 
					void MprisPlayer::onMetadataChanged() {
 | 
				
			||||||
	auto lengthVariant = this->pMetadata.get().value("mpris:length");
 | 
					 | 
				
			||||||
	qlonglong length = -1;
 | 
					 | 
				
			||||||
	if (lengthVariant.isValid() && lengthVariant.canConvert<qlonglong>()) {
 | 
					 | 
				
			||||||
		length = lengthVariant.value<qlonglong>();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto trackChanged = false;
 | 
						auto trackChanged = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QString trackId;
 | 
						QString trackId;
 | 
				
			||||||
	auto trackidVariant = this->pMetadata.get().value("mpris:trackid");
 | 
						auto trackidVariant = this->bpMetadata.value().value("mpris:trackid");
 | 
				
			||||||
	if (trackidVariant.isValid()) {
 | 
						if (trackidVariant.isValid()) {
 | 
				
			||||||
		if (trackidVariant.canConvert<QString>()) {
 | 
							if (trackidVariant.canConvert<QString>()) {
 | 
				
			||||||
			trackId = trackidVariant.toString();
 | 
								trackId = trackidVariant.toString();
 | 
				
			||||||
| 
						 | 
					@ -282,7 +301,7 @@ void MprisPlayer::onMetadataChanged() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Helps to catch players without trackid.
 | 
						// Helps to catch players without trackid.
 | 
				
			||||||
	auto urlVariant = this->pMetadata.get().value("xesam:url");
 | 
						auto urlVariant = this->bpMetadata.value().value("xesam:url");
 | 
				
			||||||
	if (urlVariant.isValid() && urlVariant.canConvert<QString>()) {
 | 
						if (urlVariant.isValid() && urlVariant.canConvert<QString>()) {
 | 
				
			||||||
		auto url = urlVariant.toString();
 | 
							auto url = urlVariant.toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,47 +311,25 @@ void MprisPlayer::onMetadataChanged() {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trackChanged) {
 | 
					 | 
				
			||||||
		emit this->trackChanged();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Qt::beginPropertyUpdateGroup();
 | 
						Qt::beginPropertyUpdateGroup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->bMetadata = this->pMetadata.get();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto trackTitle = this->pMetadata.get().value("xesam:title").toString();
 | 
					 | 
				
			||||||
	this->bTrackTitle = trackTitle.isNull() ? "Unknown Track" : trackTitle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto trackArtist = this->pMetadata.get().value("xesam:artist").value<QVector<QString>>();
 | 
					 | 
				
			||||||
	this->bTrackArtist = trackArtist.join(", ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto trackAlbum = this->pMetadata.get().value("xesam:album").toString();
 | 
					 | 
				
			||||||
	this->bTrackAlbum = trackAlbum.isNull() ? "Unknown Album" : trackAlbum;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->bTrackAlbumArtist = this->pMetadata.get().value("xesam:albumArtist").toString();
 | 
					 | 
				
			||||||
	this->bTrackArtUrl = this->pMetadata.get().value("mpris:artUrl").toString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (trackChanged) {
 | 
						if (trackChanged) {
 | 
				
			||||||
		emit this->trackChanged();
 | 
							emit this->trackChanged();
 | 
				
			||||||
		this->bUniqueId = this->bUniqueId + 1;
 | 
							this->bUniqueId = this->bUniqueId + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Some players don't seem to send position updates or seeks on track change.
 | 
							// Some players don't seem to send position updates or seeks on track change.
 | 
				
			||||||
		this->pPosition.update();
 | 
							this->pPosition.requestUpdate();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Qt::endPropertyUpdateGroup();
 | 
						this->bMetadata = this->bpMetadata.value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->setLength(length);
 | 
						Qt::endPropertyUpdateGroup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit this->postTrackChanged();
 | 
						emit this->postTrackChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_MEMBER_SET(MprisPlayer, length, setLength);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MprisPlaybackState::Enum MprisPlayer::playbackState() const { return this->mPlaybackState; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void MprisPlayer::setPlaybackState(MprisPlaybackState::Enum playbackState) {
 | 
					void MprisPlayer::setPlaybackState(MprisPlaybackState::Enum playbackState) {
 | 
				
			||||||
	if (playbackState == this->mPlaybackState) return;
 | 
						if (playbackState == this->bPlaybackState) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (playbackState) {
 | 
						switch (playbackState) {
 | 
				
			||||||
	case MprisPlaybackState::Stopped:
 | 
						case MprisPlaybackState::Stopped:
 | 
				
			||||||
| 
						 | 
					@ -371,38 +368,13 @@ void MprisPlayer::pause() { this->setPlaybackState(MprisPlaybackState::Paused);
 | 
				
			||||||
void MprisPlayer::stop() { this->setPlaybackState(MprisPlaybackState::Stopped); }
 | 
					void MprisPlayer::stop() { this->setPlaybackState(MprisPlaybackState::Stopped); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::togglePlaying() {
 | 
					void MprisPlayer::togglePlaying() {
 | 
				
			||||||
	if (this->mPlaybackState == MprisPlaybackState::Playing) {
 | 
						if (this->bPlaybackState == MprisPlaybackState::Playing) {
 | 
				
			||||||
		this->pause();
 | 
							this->pause();
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		this->play();
 | 
							this->play();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::onPlaybackStatusChanged() {
 | 
					 | 
				
			||||||
	const auto& status = this->pPlaybackStatus.get();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto state = MprisPlaybackState::Stopped;
 | 
					 | 
				
			||||||
	if (status == "Playing") {
 | 
					 | 
				
			||||||
		state = MprisPlaybackState::Playing;
 | 
					 | 
				
			||||||
	} else if (status == "Paused") {
 | 
					 | 
				
			||||||
		this->pausedTime = QDateTime::currentDateTimeUtc();
 | 
					 | 
				
			||||||
		state = MprisPlaybackState::Paused;
 | 
					 | 
				
			||||||
	} else if (status == "Stopped") {
 | 
					 | 
				
			||||||
		state = MprisPlaybackState::Stopped;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		state = MprisPlaybackState::Stopped;
 | 
					 | 
				
			||||||
		qWarning() << "Received unexpected PlaybackStatus for" << this << status;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state != this->mPlaybackState) {
 | 
					 | 
				
			||||||
		// make sure we're in sync at least on play/pause. Some players don't automatically send this.
 | 
					 | 
				
			||||||
		this->pPosition.update();
 | 
					 | 
				
			||||||
		this->mPlaybackState = state;
 | 
					 | 
				
			||||||
		emit this->playbackStateChanged();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MprisLoopState::Enum MprisPlayer::loopState() const { return this->mLoopState; }
 | 
					 | 
				
			||||||
bool MprisPlayer::loopSupported() const { return this->pLoopStatus.exists(); }
 | 
					bool MprisPlayer::loopSupported() const { return this->pLoopStatus.exists(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {
 | 
					void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {
 | 
				
			||||||
| 
						 | 
					@ -416,7 +388,7 @@ void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (loopState == this->mLoopState) return;
 | 
						if (loopState == this->bLoopState) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QString loopStatusStr;
 | 
						QString loopStatusStr;
 | 
				
			||||||
	switch (loopState) {
 | 
						switch (loopState) {
 | 
				
			||||||
| 
						 | 
					@ -428,46 +400,24 @@ void MprisPlayer::setLoopState(MprisLoopState::Enum loopState) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pLoopStatus.set(loopStatusStr);
 | 
						this->bpLoopStatus = loopStatusStr;
 | 
				
			||||||
	this->pLoopStatus.write();
 | 
						this->pLoopStatus.write();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::onLoopStatusChanged() {
 | 
					 | 
				
			||||||
	const auto& status = this->pLoopStatus.get();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (status == "None") {
 | 
					 | 
				
			||||||
		this->mLoopState = MprisLoopState::None;
 | 
					 | 
				
			||||||
	} else if (status == "Track") {
 | 
					 | 
				
			||||||
		this->mLoopState = MprisLoopState::Track;
 | 
					 | 
				
			||||||
	} else if (status == "Playlist") {
 | 
					 | 
				
			||||||
		this->mLoopState = MprisLoopState::Playlist;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		this->mLoopState = MprisLoopState::None;
 | 
					 | 
				
			||||||
		qWarning() << "Received unexpected LoopStatus for" << this << status;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	emit this->loopStateChanged();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qreal MprisPlayer::rate() const { return this->pRate.get(); }
 | 
					 | 
				
			||||||
qreal MprisPlayer::minRate() const { return this->pMinRate.get(); }
 | 
					 | 
				
			||||||
qreal MprisPlayer::maxRate() const { return this->pMaxRate.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void MprisPlayer::setRate(qreal rate) {
 | 
					void MprisPlayer::setRate(qreal rate) {
 | 
				
			||||||
	if (rate == this->pRate.get()) return;
 | 
						if (rate == this->bRate.value()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rate < this->pMinRate.get() || rate > this->pMaxRate.get()) {
 | 
						if (rate < this->bMinRate.value() || rate > this->bMaxRate.value()) {
 | 
				
			||||||
		qWarning() << "Cannot set rate for" << this << "to" << rate
 | 
							qWarning() << "Cannot set rate for" << this << "to" << rate
 | 
				
			||||||
		           << "which is outside of minRate and maxRate" << this->pMinRate.get()
 | 
							           << "which is outside of minRate and maxRate" << this->bMinRate.value()
 | 
				
			||||||
		           << this->pMaxRate.get();
 | 
							           << this->bMaxRate.value();
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pRate.set(rate);
 | 
						this->bRate = rate;
 | 
				
			||||||
	this->pRate.write();
 | 
						this->pRate.write();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool MprisPlayer::shuffle() const { return this->pShuffle.get(); }
 | 
					 | 
				
			||||||
bool MprisPlayer::shuffleSupported() const { return this->pShuffle.exists(); }
 | 
					bool MprisPlayer::shuffleSupported() const { return this->pShuffle.exists(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MprisPlayer::setShuffle(bool shuffle) {
 | 
					void MprisPlayer::setShuffle(bool shuffle) {
 | 
				
			||||||
| 
						 | 
					@ -481,25 +431,20 @@ void MprisPlayer::setShuffle(bool shuffle) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pShuffle.set(shuffle);
 | 
						this->bShuffle = shuffle;
 | 
				
			||||||
	this->pShuffle.write();
 | 
						this->pShuffle.write();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool MprisPlayer::fullscreen() const { return this->pFullscreen.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void MprisPlayer::setFullscreen(bool fullscreen) {
 | 
					void MprisPlayer::setFullscreen(bool fullscreen) {
 | 
				
			||||||
	if (!this->canSetFullscreen()) {
 | 
						if (!this->canSetFullscreen()) {
 | 
				
			||||||
		qWarning() << "Cannot set fullscreen for" << this << "because canSetFullscreen is false.";
 | 
							qWarning() << "Cannot set fullscreen for" << this << "because canSetFullscreen is false.";
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pFullscreen.set(fullscreen);
 | 
						this->bFullscreen = fullscreen;
 | 
				
			||||||
	this->pFullscreen.write();
 | 
						this->pFullscreen.write();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QList<QString> MprisPlayer::supportedUriSchemes() const { return this->pSupportedUriSchemes.get(); }
 | 
					 | 
				
			||||||
QList<QString> MprisPlayer::supportedMimeTypes() const { return this->pSupportedMimeTypes.get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void MprisPlayer::onGetAllFinished() {
 | 
					void MprisPlayer::onGetAllFinished() {
 | 
				
			||||||
	if (this->volumeSupported()) emit this->volumeSupportedChanged();
 | 
						if (this->volumeSupported()) emit this->volumeSupportedChanged();
 | 
				
			||||||
	if (this->loopSupported()) emit this->loopSupportedChanged();
 | 
						if (this->loopSupported()) emit this->loopSupportedChanged();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,20 +63,20 @@ public:
 | 
				
			||||||
class MprisPlayer: public QObject {
 | 
					class MprisPlayer: public QObject {
 | 
				
			||||||
	Q_OBJECT;
 | 
						Q_OBJECT;
 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
	Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged);
 | 
						Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged BINDABLE bindableCanControl);
 | 
				
			||||||
	Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged);
 | 
						Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged BINDABLE bindableCanPlay);
 | 
				
			||||||
	Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged);
 | 
						Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged BINDABLE bindableCanPause);
 | 
				
			||||||
	Q_PROPERTY(bool canTogglePlaying READ canTogglePlaying NOTIFY canTogglePlayingChanged);
 | 
						Q_PROPERTY(bool canTogglePlaying READ canTogglePlaying NOTIFY canTogglePlayingChanged BINDABLE bindableCanTogglePlaying);
 | 
				
			||||||
	Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged);
 | 
						Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged BINDABLE bindableCanSeek);
 | 
				
			||||||
	Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged);
 | 
						Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged BINDABLE bindableCanGoNext);
 | 
				
			||||||
	Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged);
 | 
						Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged BINDABLE bindableCanGoPrevious);
 | 
				
			||||||
	Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged);
 | 
						Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged BINDABLE bindableCanQuit BINDABLE bindableCanQuit);
 | 
				
			||||||
	Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged);
 | 
						Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged BINDABLE bindableCanRaise BINDABLE bindableCanRaise);
 | 
				
			||||||
	Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged);
 | 
						Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged BINDABLE bindableCanSetFullscreen);
 | 
				
			||||||
	/// The human readable name of the media player.
 | 
						/// The human readable name of the media player.
 | 
				
			||||||
	Q_PROPERTY(QString identity READ identity NOTIFY identityChanged);
 | 
						Q_PROPERTY(QString identity READ identity NOTIFY identityChanged BINDABLE bindableIdentity);
 | 
				
			||||||
	/// The name of the desktop entry for the media player, or an empty string if not provided.
 | 
						/// The name of the desktop entry for the media player, or an empty string if not provided.
 | 
				
			||||||
	Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged);
 | 
						Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged BINDABLE bindableDesktopEntry);
 | 
				
			||||||
	/// The current position in the playing track, as seconds, with millisecond precision,
 | 
						/// The current position in the playing track, as seconds, with millisecond precision,
 | 
				
			||||||
	/// or `0` if @@positionSupported is false.
 | 
						/// or `0` if @@positionSupported is false.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,7 @@ class MprisPlayer: public QObject {
 | 
				
			||||||
	/// The volume of the playing track from 0.0 to 1.0, or 1.0 if @@volumeSupported is false.
 | 
						/// The volume of the playing track from 0.0 to 1.0, or 1.0 if @@volumeSupported is false.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// May only be written to if @@canControl and @@volumeSupported are true.
 | 
						/// May only be written to if @@canControl and @@volumeSupported are true.
 | 
				
			||||||
	Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged);
 | 
						Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged BINDABLE bindableVolume);
 | 
				
			||||||
	Q_PROPERTY(bool volumeSupported READ volumeSupported NOTIFY volumeSupportedChanged);
 | 
						Q_PROPERTY(bool volumeSupported READ volumeSupported NOTIFY volumeSupportedChanged);
 | 
				
			||||||
	/// Metadata of the current track.
 | 
						/// Metadata of the current track.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ class MprisPlayer: public QObject {
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// > [!WARNING] This is NOT `mpris:trackid` as that is sometimes missing or nonunique
 | 
						/// > [!WARNING] This is NOT `mpris:trackid` as that is sometimes missing or nonunique
 | 
				
			||||||
	/// > in some players.
 | 
						/// > in some players.
 | 
				
			||||||
	Q_PROPERTY(quint32 uniqueId READ uniqueId NOTIFY trackChanged BINDABLE bindableUniqueId);
 | 
						Q_PROPERTY(quint32 uniqueId READ uniqueId NOTIFY uniqueIdChanged BINDABLE bindableUniqueId);
 | 
				
			||||||
	/// The title of the current track, or "Unknown Track" if none was provided.
 | 
						/// The title of the current track, or "Unknown Track" if none was provided.
 | 
				
			||||||
	Q_PROPERTY(QString trackTitle READ trackTitle NOTIFY trackTitleChanged BINDABLE bindableTrackTitle);
 | 
						Q_PROPERTY(QString trackTitle READ trackTitle NOTIFY trackTitleChanged BINDABLE bindableTrackTitle);
 | 
				
			||||||
	/// The current track's artist, or an empty string if none was provided.
 | 
						/// The current track's artist, or an empty string if none was provided.
 | 
				
			||||||
| 
						 | 
					@ -153,11 +153,11 @@ class MprisPlayer: public QObject {
 | 
				
			||||||
	/// - If @@canPause is false, you cannot assign the `Paused` state.
 | 
						/// - If @@canPause is false, you cannot assign the `Paused` state.
 | 
				
			||||||
	/// - If @@canControl is false, you cannot assign the `Stopped` state.
 | 
						/// - If @@canControl is false, you cannot assign the `Stopped` state.
 | 
				
			||||||
	/// (or any of the others, though their repsective properties will also be false)
 | 
						/// (or any of the others, though their repsective properties will also be false)
 | 
				
			||||||
	Q_PROPERTY(qs::service::mpris::MprisPlaybackState::Enum playbackState READ playbackState WRITE setPlaybackState NOTIFY playbackStateChanged);
 | 
						Q_PROPERTY(qs::service::mpris::MprisPlaybackState::Enum playbackState READ playbackState WRITE setPlaybackState NOTIFY playbackStateChanged BINDABLE bindablePlaybackState);
 | 
				
			||||||
	/// The loop state of the media player, or `None` if @@loopSupported is false.
 | 
						/// The loop state of the media player, or `None` if @@loopSupported is false.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// May only be written to if @@canControl and @@loopSupported are true.
 | 
						/// May only be written to if @@canControl and @@loopSupported are true.
 | 
				
			||||||
	Q_PROPERTY(qs::service::mpris::MprisLoopState::Enum loopState READ loopState WRITE setLoopState NOTIFY loopStateChanged);
 | 
						Q_PROPERTY(qs::service::mpris::MprisLoopState::Enum loopState READ loopState WRITE setLoopState NOTIFY loopStateChanged BINDABLE bindableLoopState);
 | 
				
			||||||
	Q_PROPERTY(bool loopSupported READ loopSupported NOTIFY loopSupportedChanged);
 | 
						Q_PROPERTY(bool loopSupported READ loopSupported NOTIFY loopSupportedChanged);
 | 
				
			||||||
	/// The speed the song is playing at, as a multiplier.
 | 
						/// The speed the song is playing at, as a multiplier.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
| 
						 | 
					@ -165,22 +165,22 @@ class MprisPlayer: public QObject {
 | 
				
			||||||
	/// Additionally, It is recommended that you only write common values such as `0.25`, `0.5`, `1.0`, `2.0`
 | 
						/// Additionally, It is recommended that you only write common values such as `0.25`, `0.5`, `1.0`, `2.0`
 | 
				
			||||||
	/// to the property, as media players are free to ignore the value, and are more likely to
 | 
						/// to the property, as media players are free to ignore the value, and are more likely to
 | 
				
			||||||
	/// accept common ones.
 | 
						/// accept common ones.
 | 
				
			||||||
	Q_PROPERTY(qreal rate READ rate WRITE setRate NOTIFY rateChanged);
 | 
						Q_PROPERTY(qreal rate READ rate WRITE setRate NOTIFY rateChanged BINDABLE bindableRate);
 | 
				
			||||||
	Q_PROPERTY(qreal minRate READ minRate NOTIFY minRateChanged);
 | 
						Q_PROPERTY(qreal minRate READ minRate NOTIFY minRateChanged BINDABLE bindableMinRate);
 | 
				
			||||||
	Q_PROPERTY(qreal maxRate READ maxRate NOTIFY maxRateChanged);
 | 
						Q_PROPERTY(qreal maxRate READ maxRate NOTIFY maxRateChanged BINDABLE bindableMaxRate);
 | 
				
			||||||
	/// If the play queue is currently being shuffled, or false if @@shuffleSupported is false.
 | 
						/// If the play queue is currently being shuffled, or false if @@shuffleSupported is false.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// May only be written if @@canControl and @@shuffleSupported are true.
 | 
						/// May only be written if @@canControl and @@shuffleSupported are true.
 | 
				
			||||||
	Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged);
 | 
						Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged BINDABLE bindableShuffle);
 | 
				
			||||||
	Q_PROPERTY(bool shuffleSupported READ shuffleSupported NOTIFY shuffleSupportedChanged);
 | 
						Q_PROPERTY(bool shuffleSupported READ shuffleSupported NOTIFY shuffleSupportedChanged);
 | 
				
			||||||
	/// If the player is currently shown in fullscreen.
 | 
						/// If the player is currently shown in fullscreen.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// May only be written to if @@canSetFullscreen is true.
 | 
						/// May only be written to if @@canSetFullscreen is true.
 | 
				
			||||||
	Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged);
 | 
						Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged BINDABLE bindableFullscreen);
 | 
				
			||||||
	/// Uri schemes supported by @@openUri().
 | 
						/// Uri schemes supported by @@openUri().
 | 
				
			||||||
	Q_PROPERTY(QList<QString> supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged);
 | 
						Q_PROPERTY(QList<QString> supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged BINDABLE bindableSupportedUriSchemes);
 | 
				
			||||||
	/// Mime types supported by @@openUri().
 | 
						/// Mime types supported by @@openUri().
 | 
				
			||||||
	Q_PROPERTY(QList<QString> supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged);
 | 
						Q_PROPERTY(QList<QString> supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged BINDABLE bindableSupportedMimeTypes);
 | 
				
			||||||
	// clang-format on
 | 
						// clang-format on
 | 
				
			||||||
	QML_ELEMENT;
 | 
						QML_ELEMENT;
 | 
				
			||||||
	QML_UNCREATABLE("MprisPlayers can only be acquired from Mpris");
 | 
						QML_UNCREATABLE("MprisPlayers can only be acquired from Mpris");
 | 
				
			||||||
| 
						 | 
					@ -231,19 +231,19 @@ public:
 | 
				
			||||||
	[[nodiscard]] bool isValid() const;
 | 
						[[nodiscard]] bool isValid() const;
 | 
				
			||||||
	[[nodiscard]] QString address() const;
 | 
						[[nodiscard]] QString address() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] bool canControl() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanControl, canControl, bindableCanControl);
 | 
				
			||||||
	[[nodiscard]] bool canSeek() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanSeek, canSeek, bindableCanSeek);
 | 
				
			||||||
	[[nodiscard]] bool canGoNext() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanGoNext, canGoNext, bindableCanGoNext);
 | 
				
			||||||
	[[nodiscard]] bool canGoPrevious() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanGoPrevious, canGoPrevious, bindableCanGoPrevious);
 | 
				
			||||||
	[[nodiscard]] bool canPlay() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanPlay, canPlay, bindableCanPlay);
 | 
				
			||||||
	[[nodiscard]] bool canPause() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanPause, canPause, bindableCanPause);
 | 
				
			||||||
	[[nodiscard]] bool canTogglePlaying() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanTogglePlaying, canTogglePlaying, bindableCanTogglePlaying);
 | 
				
			||||||
	[[nodiscard]] bool canQuit() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanQuit, canQuit, bindableCanQuit);
 | 
				
			||||||
	[[nodiscard]] bool canRaise() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanRaise, canRaise, bindableCanRaise);
 | 
				
			||||||
	[[nodiscard]] bool canSetFullscreen() const;
 | 
						QS_BINDABLE_GETTER(bool, bCanSetFullscreen, canSetFullscreen, bindableCanSetFullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] const QString& identity() const;
 | 
						QS_BINDABLE_GETTER(QString, bIdentity, identity, bindableIdentity);
 | 
				
			||||||
	[[nodiscard]] const QString& desktopEntry() const;
 | 
						QS_BINDABLE_GETTER(QString, bDesktopEntry, desktopEntry, bindableDesktopEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] qlonglong positionMs() const;
 | 
						[[nodiscard]] qlonglong positionMs() const;
 | 
				
			||||||
	[[nodiscard]] qreal position() const;
 | 
						[[nodiscard]] qreal position() const;
 | 
				
			||||||
| 
						 | 
					@ -253,7 +253,7 @@ public:
 | 
				
			||||||
	[[nodiscard]] qreal length() const;
 | 
						[[nodiscard]] qreal length() const;
 | 
				
			||||||
	[[nodiscard]] bool lengthSupported() const;
 | 
						[[nodiscard]] bool lengthSupported() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] qreal volume() const;
 | 
						QS_BINDABLE_GETTER(qreal, bVolume, volume, bindableVolume);
 | 
				
			||||||
	[[nodiscard]] bool volumeSupported() const;
 | 
						[[nodiscard]] bool volumeSupported() const;
 | 
				
			||||||
	void setVolume(qreal volume);
 | 
						void setVolume(qreal volume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,27 +265,44 @@ public:
 | 
				
			||||||
	QS_BINDABLE_GETTER(QString, bTrackArtist, trackArtist, bindableTrackArtist);
 | 
						QS_BINDABLE_GETTER(QString, bTrackArtist, trackArtist, bindableTrackArtist);
 | 
				
			||||||
	QS_BINDABLE_GETTER(QString, bTrackArtUrl, trackArtUrl, bindableTrackArtUrl);
 | 
						QS_BINDABLE_GETTER(QString, bTrackArtUrl, trackArtUrl, bindableTrackArtUrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] MprisPlaybackState::Enum playbackState() const;
 | 
						QS_BINDABLE_GETTER(
 | 
				
			||||||
 | 
						    MprisPlaybackState::Enum,
 | 
				
			||||||
 | 
						    bPlaybackState,
 | 
				
			||||||
 | 
						    playbackState,
 | 
				
			||||||
 | 
						    bindablePlaybackState
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setPlaybackState(MprisPlaybackState::Enum playbackState);
 | 
						void setPlaybackState(MprisPlaybackState::Enum playbackState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] MprisLoopState::Enum loopState() const;
 | 
						QS_BINDABLE_GETTER(MprisLoopState::Enum, bLoopState, loopState, bindableLoopState);
 | 
				
			||||||
	[[nodiscard]] bool loopSupported() const;
 | 
						[[nodiscard]] bool loopSupported() const;
 | 
				
			||||||
	void setLoopState(MprisLoopState::Enum loopState);
 | 
						void setLoopState(MprisLoopState::Enum loopState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] qreal rate() const;
 | 
						QS_BINDABLE_GETTER(qreal, bRate, rate, bindableRate);
 | 
				
			||||||
	[[nodiscard]] qreal minRate() const;
 | 
						QS_BINDABLE_GETTER(qreal, bRate, minRate, bindableMinRate);
 | 
				
			||||||
	[[nodiscard]] qreal maxRate() const;
 | 
						QS_BINDABLE_GETTER(qreal, bRate, maxRate, bindableMaxRate);
 | 
				
			||||||
	void setRate(qreal rate);
 | 
						void setRate(qreal rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] bool shuffle() const;
 | 
						QS_BINDABLE_GETTER(bool, bShuffle, shuffle, bindableShuffle);
 | 
				
			||||||
	[[nodiscard]] bool shuffleSupported() const;
 | 
						[[nodiscard]] bool shuffleSupported() const;
 | 
				
			||||||
	void setShuffle(bool shuffle);
 | 
						void setShuffle(bool shuffle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] bool fullscreen() const;
 | 
						QS_BINDABLE_GETTER(bool, bFullscreen, fullscreen, bindableFullscreen);
 | 
				
			||||||
	void setFullscreen(bool fullscreen);
 | 
						void setFullscreen(bool fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] QList<QString> supportedUriSchemes() const;
 | 
						QS_BINDABLE_GETTER(
 | 
				
			||||||
	[[nodiscard]] QList<QString> supportedMimeTypes() const;
 | 
						    QList<QString>,
 | 
				
			||||||
 | 
						    bSupportedUriSchemes,
 | 
				
			||||||
 | 
						    supportedUriSchemes,
 | 
				
			||||||
 | 
						    bindableSupportedUriSchemes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QS_BINDABLE_GETTER(
 | 
				
			||||||
 | 
						    QList<QString>,
 | 
				
			||||||
 | 
						    bSupportedMimeTypes,
 | 
				
			||||||
 | 
						    supportedMimeTypes,
 | 
				
			||||||
 | 
						    bindableSupportedMimeTypes
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
	/// The track has changed.
 | 
						/// The track has changed.
 | 
				
			||||||
| 
						 | 
					@ -327,6 +344,7 @@ signals:
 | 
				
			||||||
	void volumeChanged();
 | 
						void volumeChanged();
 | 
				
			||||||
	void volumeSupportedChanged();
 | 
						void volumeSupportedChanged();
 | 
				
			||||||
	void metadataChanged();
 | 
						void metadataChanged();
 | 
				
			||||||
 | 
						void uniqueIdChanged();
 | 
				
			||||||
	void trackTitleChanged();
 | 
						void trackTitleChanged();
 | 
				
			||||||
	void trackArtistChanged();
 | 
						void trackArtistChanged();
 | 
				
			||||||
	void trackAlbumChanged();
 | 
						void trackAlbumChanged();
 | 
				
			||||||
| 
						 | 
					@ -346,66 +364,95 @@ signals:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onGetAllFinished();
 | 
						void onGetAllFinished();
 | 
				
			||||||
	void onPositionChanged();
 | 
					 | 
				
			||||||
	void onExportedPositionChanged();
 | 
						void onExportedPositionChanged();
 | 
				
			||||||
	void onSeek(qlonglong time);
 | 
						void onSeek(qlonglong time);
 | 
				
			||||||
	void onMetadataChanged();
 | 
					 | 
				
			||||||
	void onPlaybackStatusChanged();
 | 
					 | 
				
			||||||
	void onLoopStatusChanged();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	// clang-format off
 | 
						void onMetadataChanged();
 | 
				
			||||||
	dbus::DBusPropertyGroup appProperties;
 | 
						void onPositionUpdated();
 | 
				
			||||||
	dbus::DBusProperty<QString> pIdentity {this->appProperties, "Identity"};
 | 
						void requestPositionUpdate() { this->pPosition.requestUpdate(); };
 | 
				
			||||||
	dbus::DBusProperty<QString> pDesktopEntry {this->appProperties, "DesktopEntry", "", false};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<bool> pCanQuit {this->appProperties, "CanQuit"};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<bool> pCanRaise {this->appProperties, "CanRaise"};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<bool> pFullscreen {this->appProperties, "Fullscreen", false, false};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<bool> pCanSetFullscreen {this->appProperties, "CanSetFullscreen", false, false};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<QList<QString>> pSupportedUriSchemes {this->appProperties, "SupportedUriSchemes"};
 | 
					 | 
				
			||||||
	dbus::DBusProperty<QList<QString>> pSupportedMimeTypes {this->appProperties, "SupportedMimeTypes"};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbus::DBusPropertyGroup playerProperties;
 | 
						// clang-format off
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanControl {this->playerProperties, "CanControl"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bIdentity, &MprisPlayer::identityChanged);
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanPlay {this->playerProperties, "CanPlay"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bDesktopEntry, &MprisPlayer::desktopEntryChanged);
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanPause {this->playerProperties, "CanPause"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanQuit, &MprisPlayer::canQuitChanged);
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanSeek {this->playerProperties, "CanSeek"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanRaise, &MprisPlayer::canRaiseChanged);
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanGoNext {this->playerProperties, "CanGoNext"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bFullscreen, &MprisPlayer::fullscreenChanged);
 | 
				
			||||||
	dbus::DBusProperty<bool> pCanGoPrevious {this->playerProperties, "CanGoPrevious"};
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanSetFullscreen, &MprisPlayer::canSetFullscreenChanged);
 | 
				
			||||||
	dbus::DBusProperty<qlonglong> pPosition {this->playerProperties, "Position", 0, false}; // "required"
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QList<QString>, bSupportedUriSchemes, &MprisPlayer::supportedUriSchemesChanged);
 | 
				
			||||||
	dbus::DBusProperty<double> pVolume {this->playerProperties, "Volume", 1, false}; // "required"
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QList<QString>, bSupportedMimeTypes, &MprisPlayer::supportedMimeTypesChanged);
 | 
				
			||||||
	dbus::DBusProperty<QVariantMap> pMetadata {this->playerProperties, "Metadata"};
 | 
					
 | 
				
			||||||
	dbus::DBusProperty<QString> pPlaybackStatus {this->playerProperties, "PlaybackStatus"};
 | 
						QS_DBUS_BINDABLE_PROPERTY_GROUP(MprisPlayer, appProperties);
 | 
				
			||||||
	dbus::DBusProperty<QString> pLoopStatus {this->playerProperties, "LoopStatus", "", false};
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pIdentity, bIdentity, appProperties, "Identity");
 | 
				
			||||||
	dbus::DBusProperty<double> pRate {this->playerProperties, "Rate", 1, false}; // "required"
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pDesktopEntry, bDesktopEntry, appProperties, "DesktopEntry");
 | 
				
			||||||
	dbus::DBusProperty<double> pMinRate {this->playerProperties, "MinimumRate", 1, false}; // "required"
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanQuit, bCanQuit, appProperties, "CanQuit");
 | 
				
			||||||
	dbus::DBusProperty<double> pMaxRate {this->playerProperties, "MaximumRate", 1, false}; // "required"
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanRaise, bCanRaise, appProperties, "CanRaise");
 | 
				
			||||||
	dbus::DBusProperty<bool> pShuffle {this->playerProperties, "Shuffle", false, false};
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pFullscreen, bFullscreen, appProperties, "Fullscreen");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanSetFullscreen, bCanSetFullscreen, appProperties, "CanSetFullscreen");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pSupportedUriSchemes, bSupportedUriSchemes, appProperties, "SupportedUriSchemes");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pSupportedMimeTypes, bSupportedMimeTypes, appProperties, "SupportedMimeTypes");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bpCanPlay);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bpCanPause);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bpCanSeek);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bpCanGoNext);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bpCanGoPrevious);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QVariantMap, bpMetadata);
 | 
				
			||||||
 | 
						QS_BINDING_SUBSCRIBE_METHOD(MprisPlayer, bpMetadata, onMetadataChanged, onValueChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MprisPlayer, qlonglong, bpPosition, -1, &MprisPlayer::positionChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bpPlaybackStatus);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bpLoopStatus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanControl, &MprisPlayer::canControlChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanPlay, &MprisPlayer::canPlayChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanPause, &MprisPlayer::canPauseChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanTogglePlaying, &MprisPlayer::canTogglePlayingChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanSeek, &MprisPlayer::canSeekChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanGoNext, &MprisPlayer::canGoNextChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bCanGoPrevious, &MprisPlayer::canGoPreviousChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MprisPlayer, qreal, bVolume, 1, &MprisPlayer::volumeChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, MprisPlaybackState::Enum, bPlaybackState, &MprisPlayer::playbackStateChanged);
 | 
				
			||||||
 | 
						QS_BINDING_SUBSCRIBE_METHOD(MprisPlayer, bPlaybackState, requestPositionUpdate, onValueChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, MprisLoopState::Enum, bLoopState, &MprisPlayer::loopStateChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MprisPlayer, qreal, bRate, 1, &MprisPlayer::rateChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MprisPlayer, qreal, bMinRate, 1, &MprisPlayer::minRateChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MprisPlayer, qreal, bMaxRate, 1, &MprisPlayer::maxRateChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QVariantMap, bMetadata, &MprisPlayer::metadataChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, quint32, bUniqueId, &MprisPlayer::uniqueIdChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackTitle, &MprisPlayer::trackTitleChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackArtist, &MprisPlayer::trackArtistChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackAlbum, &MprisPlayer::trackAlbumChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackAlbumArtist, &MprisPlayer::trackAlbumArtistChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackArtUrl, &MprisPlayer::trackArtUrlChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, qlonglong, bInternalLength, &MprisPlayer::lengthChanged);
 | 
				
			||||||
 | 
						Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, bool, bShuffle, &MprisPlayer::shuffleChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QS_DBUS_BINDABLE_PROPERTY_GROUP(MprisPlayer, playerProperties);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanControl, bCanControl, playerProperties, "CanControl");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanPlay, bpCanPlay, playerProperties, "CanPlay");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanPause, bpCanPause, playerProperties, "CanPause");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanSeek, bpCanSeek, playerProperties, "CanSeek");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoNext, bpCanGoNext, playerProperties, "CanGoNext");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoPrevious, bpCanGoPrevious, playerProperties, "CanGoPrevious");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPosition, bpPosition, onPositionUpdated, playerProperties, "Position", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pVolume, bVolume, playerProperties, "Volume", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMetadata, bpMetadata, playerProperties, "Metadata");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPlaybackStatus, bpPlaybackStatus, playerProperties, "PlaybackStatus");
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pLoopStatus, bpLoopStatus, playerProperties, "LoopStatus", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pRate, bRate, playerProperties, "Rate", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMinRate, bMinRate, playerProperties, "MinimumRate", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMaxRate, bMaxRate, playerProperties, "MaximumRate", false);
 | 
				
			||||||
 | 
						QS_DBUS_PROPERTY_BINDING(MprisPlayer, pShuffle, bShuffle, playerProperties, "Shuffle", false);
 | 
				
			||||||
	// clang-format on
 | 
						// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MprisPlaybackState::Enum mPlaybackState = MprisPlaybackState::Stopped;
 | 
					 | 
				
			||||||
	MprisLoopState::Enum mLoopState = MprisLoopState::None;
 | 
					 | 
				
			||||||
	QDateTime lastPositionTimestamp;
 | 
						QDateTime lastPositionTimestamp;
 | 
				
			||||||
	QDateTime pausedTime;
 | 
						QDateTime pausedTime;
 | 
				
			||||||
	qlonglong mLength = -1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DBusMprisPlayerApp* app = nullptr;
 | 
						DBusMprisPlayerApp* app = nullptr;
 | 
				
			||||||
	DBusMprisPlayer* player = nullptr;
 | 
						DBusMprisPlayer* player = nullptr;
 | 
				
			||||||
	QString mTrackId;
 | 
						QString mTrackId;
 | 
				
			||||||
	QString mTrackUrl;
 | 
						QString mTrackUrl;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	DECLARE_MEMBER(MprisPlayer, length, mLength, lengthChanged);
 | 
					 | 
				
			||||||
	DECLARE_MEMBER_SET(length, setLength);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// clang-format off
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, quint32, bUniqueId);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QVariantMap, bMetadata, &MprisPlayer::metadataChanged);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackArtist, &MprisPlayer::trackArtistChanged);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackTitle, &MprisPlayer::trackTitleChanged);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackAlbum, &MprisPlayer::trackAlbumChanged);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackAlbumArtist, &MprisPlayer::trackAlbumArtistChanged);
 | 
					 | 
				
			||||||
	Q_OBJECT_BINDABLE_PROPERTY(MprisPlayer, QString, bTrackArtUrl, &MprisPlayer::trackArtUrlChanged);
 | 
					 | 
				
			||||||
	// clang-format on
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace qs::service::mpris
 | 
					} // namespace qs::service::mpris
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue