From 60989e52b3f3bc0a95d3e61bd8e59fa4d9b7ab83 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Sun, 26 Nov 2023 01:10:36 -0500 Subject: The 2 year constipation. (mpris plugin) Probably buggy as hell. --- mpris-plugin/CMakeLists.txt | 30 +++++ mpris-plugin/qmpmpris.cpp | 29 +++++ mpris-plugin/qmpmpris.hpp | 32 ++++++ mpris-plugin/qmpmprisimpl.cpp | 206 +++++++++++++++++++++++++++++++++++ mpris-plugin/qmpmprisimpl.hpp | 72 ++++++++++++ mpris-plugin/qmprisdbusinterface.cpp | 200 ++++++++++++++++++++++++++++++++++ mpris-plugin/qmprisdbusinterface.hpp | 148 +++++++++++++++++++++++++ mpris-plugin/qmpriswrapper.cpp | 77 +++++++++++++ mpris-plugin/qmpriswrapper.hpp | 53 +++++++++ 9 files changed, 847 insertions(+) create mode 100644 mpris-plugin/CMakeLists.txt create mode 100644 mpris-plugin/qmpmpris.cpp create mode 100644 mpris-plugin/qmpmpris.hpp create mode 100644 mpris-plugin/qmpmprisimpl.cpp create mode 100644 mpris-plugin/qmpmprisimpl.hpp create mode 100644 mpris-plugin/qmprisdbusinterface.cpp create mode 100644 mpris-plugin/qmprisdbusinterface.hpp create mode 100644 mpris-plugin/qmpriswrapper.cpp create mode 100644 mpris-plugin/qmpriswrapper.hpp (limited to 'mpris-plugin') diff --git a/mpris-plugin/CMakeLists.txt b/mpris-plugin/CMakeLists.txt new file mode 100644 index 0000000..c0395c0 --- /dev/null +++ b/mpris-plugin/CMakeLists.txt @@ -0,0 +1,30 @@ +set(qmpmpris_SOURCES + qmpmpris.hpp + qmprisdbusinterface.hpp + qmpriswrapper.hpp + qmpmprisimpl.hpp + qmpmpris.cpp + qmprisdbusinterface.cpp + qmpriswrapper.cpp + qmpmprisimpl.cpp +) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +find_package(Qt5 REQUIRED COMPONENTS DBus) + +include_directories(${PROJECT_SOURCE_DIR}/include/) + +add_library(qmpmpris MODULE + ${qmpmpris_SOURCES} +) + +target_link_libraries(qmpmpris + Qt5::Core + Qt5::Widgets + Qt5::DBus +) + +install(TARGETS qmpmpris LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/qmidiplayer/) diff --git a/mpris-plugin/qmpmpris.cpp b/mpris-plugin/qmpmpris.cpp new file mode 100644 index 0000000..2eb18fd --- /dev/null +++ b/mpris-plugin/qmpmpris.cpp @@ -0,0 +1,29 @@ +#include +#include "qmpmpris.hpp" +#include "qmpriswrapper.hpp" +#include "qmpmprisimpl.hpp" + +qmpMPrisPlugin::qmpMPrisPlugin(qmpPluginAPI *_api) +{ + api = _api; +} +qmpMPrisPlugin::~qmpMPrisPlugin() +{ + api = nullptr; +} +void qmpMPrisPlugin::init() +{ + mw = QMPrisWrapper::create("qmidiplayer", api); +} +void qmpMPrisPlugin::deinit() +{ + delete mw; +} +const char *qmpMPrisPlugin::pluginGetName() +{ + return "QMidiPlayer MPris Support"; +} +const char *qmpMPrisPlugin::pluginGetVersion() +{ + return "0.8.8"; +} diff --git a/mpris-plugin/qmpmpris.hpp b/mpris-plugin/qmpmpris.hpp new file mode 100644 index 0000000..fbc8bfa --- /dev/null +++ b/mpris-plugin/qmpmpris.hpp @@ -0,0 +1,32 @@ +#ifndef QMPMPRIS_HPP +#define QMPMPRIS_HPP + +#include "../include/qmpcorepublic.hpp" + +class QMPrisWrapper; +class qmpMPrisPlugin: public qmpPluginIntf +{ +private: + qmpPluginAPI *api; + QMPrisWrapper *mw = nullptr; +public: + qmpMPrisPlugin(qmpPluginAPI *_api); + ~qmpMPrisPlugin(); + void init(); + void deinit(); + const char *pluginGetName(); + const char *pluginGetVersion(); +}; + +extern "C" { + EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api) + { + return new qmpMPrisPlugin(api); + } + EXPORTSYM const char *qmpPluginGetAPIRev() + { + return QMP_PLUGIN_API_REV; + } +} + +#endif diff --git a/mpris-plugin/qmpmprisimpl.cpp b/mpris-plugin/qmpmprisimpl.cpp new file mode 100644 index 0000000..335a638 --- /dev/null +++ b/mpris-plugin/qmpmprisimpl.cpp @@ -0,0 +1,206 @@ +#include + +#include "../include/qmpcorepublic.hpp" +#include "../qmidiplayer-desktop/qmpmainwindow.hpp" +#include "qmpmprisimpl.hpp" + +inline QVariantMap get_metadata(qmpPluginAPI *api) +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + return { + {"mpris:trackid", QDBusObjectPath("/org/chrisoft/qmidiplayer/dummylist/0")}, + {"xesam:url", QString::fromStdWString(api->getWFilePath())}, + {"xesam:title", QString::fromStdWString(api->getWTitle())}, + {"mpris:length", qlonglong(ps.maxtime_ms * 1000)} + }; +} + +QMPPlayer::QMPPlayer(qmpPluginAPI *_api, QObject *parent) : + api(_api), + QMPrisPlayer(parent) +{ + qmw = static_cast(api->getMainWindow()); +} + +QString QMPPlayer::getPlaybackStatus() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + QMPrisPlayer::PlaybackStatus r = QMPrisPlayer::PlaybackStatus::Stopped; + if (!ps.stopped) + r = ps.paused ? QMPrisPlayer::PlaybackStatus::Paused : QMPrisPlayer::PlaybackStatus::Playing; + return QMetaEnum::fromType().key(r); +} + +QString QMPPlayer::getLoopStatus() +{ + return QMetaEnum::fromType().key(QMPrisPlayer::LoopStatus::None); +} + +double QMPPlayer::getRate() +{ + return 1; +} + +bool QMPPlayer::getShuffle() +{ + return false; +} + +QVariantMap QMPPlayer::getMetadata() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + if (ps.stopped) return {}; + return get_metadata(api); +} + +qlonglong QMPPlayer::getPosition() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + fprintf(stderr, "%lu\n", ps.curtime_ms); + return ps.curtime_ms * 1000; +} + +bool QMPPlayer::getCanGoNext() +{ + return getCanPlay(); +} + +bool QMPPlayer::getCanGoPrevious() +{ + return getCanPlay(); +} + +bool QMPPlayer::getCanPlay() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + return !ps.stopped; +} + +bool QMPPlayer::getCanPause() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + return !ps.stopped && !ps.paused; +} + +bool QMPPlayer::getCanSeek() +{ + return getCanPlay(); +} + +bool QMPPlayer::getCanControl() +{ + return true; +} + +void QMPPlayer::Pause() +{ + api->playbackControl(PlaybackControlCommand::Pause, nullptr); +} + +void QMPPlayer::PlayPause() +{ + api->playbackControl(PlaybackControlCommand::TogglePause, nullptr); +} + +void QMPPlayer::Stop() +{ + api->playbackControl(PlaybackControlCommand::Stop, nullptr); +} + +void QMPPlayer::Play() +{ + api->playbackControl(PlaybackControlCommand::Play, nullptr); +} + +void QMPPlayer::Next() +{ + api->playbackControl(PlaybackControlCommand::NextTrack, nullptr); +} + +void QMPPlayer::Previous() +{ + api->playbackControl(PlaybackControlCommand::PrevTrack, nullptr); +} + +void QMPPlayer::Seek(qlonglong t) +{ + double td = t / 1e6; + api->playbackControl(PlaybackControlCommand::SeekAbs, &td); +} + +void QMPPlayer::SetPosition(QDBusObjectPath o, qlonglong t) +{ + if (o.path() == QString("/org/chrisoft/qmidiplayer/dummylist/0")) + { + double td = t / 1e6; + api->playbackControl(PlaybackControlCommand::SeekAbs, &td); + } +} + +QMPMediaPlayer2::QMPMediaPlayer2(qmpPluginAPI *_api, QObject *parent) : + api(_api), + QMPrisMediaPlayer2(parent) +{ + qmw = static_cast(api->getMainWindow()); +} + +void QMPMediaPlayer2::Raise() +{ + qmw->raise(); +} + +void QMPMediaPlayer2::Quit() +{ + qmw->close(); +} + +bool QMPMediaPlayer2::getCanQuit() +{ + return true; +} + +bool QMPMediaPlayer2::getCanRaise() +{ + return true; +} + +QString QMPMediaPlayer2::getIdentity() +{ + return QString("QMidiPlayer"); +} + +QString QMPMediaPlayer2::getDesktopEntry() +{ + return QString("qmidiplayer"); +} + +bool QMPMediaPlayer2::getHasTrackList() +{ + return true; +} + +QMPTrackList::QMPTrackList(qmpPluginAPI *_api, QObject *parent) : + api(_api), + QMPrisTrackList(parent) +{ +} + +QList QMPTrackList::GetTracksMetaData(QList trackIds) +{ + QList ret; + for (auto &i : trackIds) + { + if (i.path() == QString("/org/chrisoft/qmidiplayer/dummylist/0")) + ret.push_back(get_metadata(api)); + else ret.push_back({}); + } + return ret; +} + +QList QMPTrackList::getTracks() +{ + ::PlaybackStatus ps = api->getPlaybackStatus(); + if (ps.stopped) + return {}; + return {QDBusObjectPath("/org/chrisoft/qmidiplayer/dummylist/0")}; +} diff --git a/mpris-plugin/qmpmprisimpl.hpp b/mpris-plugin/qmpmprisimpl.hpp new file mode 100644 index 0000000..b9dec93 --- /dev/null +++ b/mpris-plugin/qmpmprisimpl.hpp @@ -0,0 +1,72 @@ +#ifndef QMPMPRISIMPL_HPP +#define QMPMPRISIMPL_HPP + +#include "qmprisdbusinterface.hpp" + +class qmpPluginAPI; +class qmpMainWindow; + +class QMPPlayer : public QMPrisPlayer +{ +public: + explicit QMPPlayer(qmpPluginAPI *_api, QObject *parent=nullptr); + + QString getPlaybackStatus(); + QString getLoopStatus(); + double getRate(); + bool getShuffle(); + QVariantMap getMetadata(); + //double getVolume(); + qlonglong getPosition(); + //double getMinimumRate(); + //double getMaximumRate(); + bool getCanGoNext(); + bool getCanGoPrevious(); + bool getCanPlay(); + bool getCanPause(); + bool getCanSeek(); + bool getCanControl(); + + void Pause(); + void PlayPause(); + void Stop(); + void Play(); + void Next(); + void Previous(); + void Seek(qlonglong t); + void SetPosition(QDBusObjectPath o, qlonglong t); +private: + qmpPluginAPI *api; + qmpMainWindow *qmw; +}; + +class QMPTrackList : public QMPrisTrackList +{ +public: + explicit QMPTrackList(qmpPluginAPI *_api, QObject *parent=nullptr); + + QList GetTracksMetaData(QList trackIds); + QList getTracks(); +private: + qmpPluginAPI *api; +}; + +class QMPMediaPlayer2 : public QMPrisMediaPlayer2 +{ +public: + explicit QMPMediaPlayer2(qmpPluginAPI *_api, QObject *parent=nullptr); + + void Raise() override; + void Quit() override; + + bool getCanQuit() override; + bool getCanRaise() override; + QString getIdentity() override; + QString getDesktopEntry() override; + bool getHasTrackList() override; +private: + qmpPluginAPI *api; + qmpMainWindow *qmw; +}; + +#endif diff --git a/mpris-plugin/qmprisdbusinterface.cpp b/mpris-plugin/qmprisdbusinterface.cpp new file mode 100644 index 0000000..822a705 --- /dev/null +++ b/mpris-plugin/qmprisdbusinterface.cpp @@ -0,0 +1,200 @@ +#include "qmprisdbusinterface.hpp" +#include "qmpriswrapper.hpp" + +#include + +QMPrisPlayer::QMPrisPlayer(QObject* parent) : QDBusAbstractAdaptor(parent) +{ +} + +QString QMPrisPlayer::getPlaybackStatus() +{ + /*if (par->pbstgetter) + return QMetaEnum::fromType().key(par->pbstgetter());*/ + return QString(); +} +QString QMPrisPlayer::getLoopStatus() +{ + /*if (par->lpstgetter) + return QMetaEnum::fromType().key(par->lpstgetter());*/ + return QString(); +} +double QMPrisPlayer::getRate() +{ + return 1.0; +} +bool QMPrisPlayer::getShuffle() +{ + return false; +} +QVariantMap QMPrisPlayer::getMetadata() +{ + return {}; +} +double QMPrisPlayer::getVolume() +{ + return 1.0; +} +qlonglong QMPrisPlayer::getPosition() +{ + return 0; +} +double QMPrisPlayer::getMinimumRate() +{ + return 1; +} +double QMPrisPlayer::getMaximumRate() +{ + return 1; +} +bool QMPrisPlayer::getCanGoNext() +{ + return false; +} +bool QMPrisPlayer::getCanGoPrevious() +{ + return false; +} +bool QMPrisPlayer::getCanPlay() +{ + return false; +} +bool QMPrisPlayer::getCanPause() +{ + return false; +} +bool QMPrisPlayer::getCanSeek() +{ + return false; +} +bool QMPrisPlayer::getCanControl() +{ + return false; +} + +void QMPrisPlayer::setLoopStatus(QString loopStatus) +{ +} +void QMPrisPlayer::setRate(double playbackRate) +{ +} +bool QMPrisPlayer::setShuffle(bool shuffle) +{ + return false; +} +void QMPrisPlayer::setVolume(double volume) +{ +} + +void QMPrisPlayer::Next() +{ +} +void QMPrisPlayer::Previous() +{ +} +void QMPrisPlayer::Pause() +{ +} +void QMPrisPlayer::PlayPause() +{ +} +void QMPrisPlayer::Stop() +{ +} +void QMPrisPlayer::Play() +{ +} +void QMPrisPlayer::Seek(qlonglong t) +{ +} + +void QMPrisPlayer::SetPosition(QDBusObjectPath o, qlonglong t) +{ +} +void QMPrisPlayer::OpenUri(QString s) +{ +} + +void QMPrisMediaPlayer2::Raise() +{ +} +void QMPrisMediaPlayer2::Quit() +{ +} + +QMPrisMediaPlayer2::QMPrisMediaPlayer2(QObject *parent) : QDBusAbstractAdaptor(parent) +{ +} + +bool QMPrisMediaPlayer2::getCanQuit() +{ + return false; +} +bool QMPrisMediaPlayer2::getCanRaise() +{ + return false; +} +bool QMPrisMediaPlayer2::getFullscreen() +{ + return false; +} +bool QMPrisMediaPlayer2::getCanSetFullscreen() +{ + return false; +} +bool QMPrisMediaPlayer2::getHasTrackList() +{ + return false; +} + +QString QMPrisMediaPlayer2::getIdentity() +{ + return QString(); +} +QString QMPrisMediaPlayer2::getDesktopEntry() +{ + return QString(); +} +QStringList QMPrisMediaPlayer2::getSupportedUriSchemes() +{ + return {}; +} +QStringList QMPrisMediaPlayer2::getSupportedMimeTypes() +{ + return {}; +} + +void QMPrisMediaPlayer2::setFullscreen(bool fullscreen) +{ +} + +QList QMPrisTrackList::GetTracksMetaData(QList trackIds) +{ + return {}; +} + +void QMPrisTrackList::AddTrack(QString uri, QDBusObjectPath after, bool setCurrent) +{ +} + +void QMPrisTrackList::RemoveTrack(QDBusObjectPath trackId) +{ +} + +void QMPrisTrackList::GoTo(QDBusObjectPath trackId) +{ +} + +QMPrisTrackList::QMPrisTrackList(QObject *parent) : QDBusAbstractAdaptor(parent) +{ +} + +QList QMPrisTrackList::getTracks() +{ + return {}; +} + +bool QMPrisTrackList::getCanEditTracks() +{ + return false; +} diff --git a/mpris-plugin/qmprisdbusinterface.hpp b/mpris-plugin/qmprisdbusinterface.hpp new file mode 100644 index 0000000..071c509 --- /dev/null +++ b/mpris-plugin/qmprisdbusinterface.hpp @@ -0,0 +1,148 @@ +/* + * DBus adaptor for the MPRIS Interface + * Based on MPRIS D-Bus Interface Specification Version 2.2: + * https://specifications.freedesktop.org/mpris-spec/2.2/index.html + */ +#ifndef QMPRISDBUSINTERFACE_HPP +#define QMPRISDBUSINTERFACE_HPP + +#include +#include +#include + +class QMPrisWrapper; + +class QMPrisPlayer : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.Player") + + Q_PROPERTY(QString PlaybackStatus READ getPlaybackStatus) + Q_PROPERTY(QString LoopStatus READ getLoopStatus WRITE setLoopStatus) + Q_PROPERTY(double Rate READ getRate WRITE setRate) + Q_PROPERTY(bool Shuffle READ getShuffle WRITE setShuffle) + Q_PROPERTY(QVariantMap Metadata READ getMetadata) + Q_PROPERTY(double Volume READ getVolume WRITE setVolume) + Q_PROPERTY(qlonglong Position READ getPosition) + Q_PROPERTY(double MinimumRate READ getMinimumRate) + Q_PROPERTY(double MaximumRate READ getMaximumRate) + + Q_PROPERTY(bool CanGoNext READ getCanGoNext) + Q_PROPERTY(bool CanGoPrevious READ getCanGoPrevious) + Q_PROPERTY(bool CanPlay READ getCanPlay) + Q_PROPERTY(bool CanPause READ getCanPause) + Q_PROPERTY(bool CanSeek READ getCanSeek) + Q_PROPERTY(bool CanControl READ getCanControl) +public: + enum PlaybackStatus + { + Playing, + Paused, + Stopped + }; + Q_ENUM(PlaybackStatus) + + enum LoopStatus + { + None, + Track, + Playlist + }; + Q_ENUM(LoopStatus) + + explicit QMPrisPlayer(QObject *parent=nullptr); + + virtual QString getPlaybackStatus(); + virtual QString getLoopStatus(); + virtual double getRate(); + virtual bool getShuffle(); + virtual QVariantMap getMetadata(); + virtual double getVolume(); + virtual qlonglong getPosition(); + virtual double getMinimumRate(); + virtual double getMaximumRate(); + virtual bool getCanGoNext(); + virtual bool getCanGoPrevious(); + virtual bool getCanPlay(); + virtual bool getCanPause(); + virtual bool getCanSeek(); + virtual bool getCanControl(); + + virtual void setLoopStatus(QString loopStatus); + virtual void setRate(double playbackRate); + virtual bool setShuffle(bool shuffle); + virtual void setVolume(double volume); + +public slots: + virtual void Next(); + virtual void Previous(); + virtual void Pause(); + virtual void PlayPause(); + virtual void Stop(); + virtual void Play(); + virtual void Seek(qlonglong t); + virtual void SetPosition(QDBusObjectPath o, qlonglong t); + virtual void OpenUri(QString s); + +signals: + void Seeked(qlonglong t); +}; + +class QMPrisTrackList : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.TrackList") + Q_PROPERTY(QList Tracks READ getTracks) + Q_PROPERTY(bool CanEditTracks READ getCanEditTracks) +public slots: + virtual QList GetTracksMetaData(QList trackIds); + virtual void AddTrack(QString uri, QDBusObjectPath after, bool setCurrent); + virtual void RemoveTrack(QDBusObjectPath trackId); + virtual void GoTo(QDBusObjectPath trackId); +signals: + void TrackListReplaced(QList tracks, QDBusObjectPath currentTrack); + void TrackAdded(QVariantMap metadata, QDBusObjectPath after); + void TrackRemoved(QDBusObjectPath track); + void TrackMetadataChanged(QDBusObjectPath track, QVariantMap metadata); +public: + explicit QMPrisTrackList(QObject *parent=nullptr); + virtual QList getTracks(); + virtual bool getCanEditTracks(); +}; + +class QMPrisMediaPlayer2 : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2") + + Q_PROPERTY(bool CanQuit READ getCanQuit) + Q_PROPERTY(bool CanRaise READ getCanRaise) + Q_PROPERTY(bool Fullscreen READ getFullscreen WRITE setFullscreen) + Q_PROPERTY(bool CanSetFullscreen READ getCanSetFullscreen) + Q_PROPERTY(bool HasTrackList READ getHasTrackList) + Q_PROPERTY(QString Identity READ getIdentity) + Q_PROPERTY(QString DesktopEntry READ getDesktopEntry) + Q_PROPERTY(QStringList SupportedUriSchemes READ getSupportedUriSchemes) + Q_PROPERTY(QStringList SupportedMimeTypes READ getSupportedMimeTypes) + +public slots: + virtual void Raise(); + virtual void Quit(); + +public: + explicit QMPrisMediaPlayer2(QObject *parent=nullptr); + + virtual bool getCanQuit(); + virtual bool getCanRaise(); + virtual bool getFullscreen(); + virtual bool getCanSetFullscreen(); + virtual bool getHasTrackList(); + virtual QString getIdentity(); + virtual QString getDesktopEntry(); + virtual QStringList getSupportedUriSchemes(); + virtual QStringList getSupportedMimeTypes(); + + virtual void setFullscreen(bool fullscreen); +}; + +#endif // QMPRISDBUSINTERFACE_HPP diff --git a/mpris-plugin/qmpriswrapper.cpp b/mpris-plugin/qmpriswrapper.cpp new file mode 100644 index 0000000..8a3f273 --- /dev/null +++ b/mpris-plugin/qmpriswrapper.cpp @@ -0,0 +1,77 @@ +#include "qmpriswrapper.hpp" +#include "qmprisdbusinterface.hpp" +#include +#include +#include + +#include "../include/qmpcorepublic.hpp" + +QMPrisWrapper::QMPrisWrapper(QString serviceSuffix, qmpPluginAPI *_api, QObject *parent) : + api(_api), + QObject(parent), + svcsuffix(serviceSuffix) +{ + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); +} + +void QMPrisWrapper::post_creation() +{ + QDBusConnection sessbus = QDBusConnection::sessionBus(); + sessbus.registerService("org.mpris.MediaPlayer2." + svcsuffix); + sessbus.registerObject("/org/mpris/MediaPlayer2", this); + api->registerUIHook("main.stop", [this](const void* a, void* _) { + tracklist->TrackListReplaced({}, QDBusObjectPath("/")); + this->notifyPropertyChange(PLAYER_INTERFACE, "Metadata", player->getMetadata()); + this->notifyPropertyChange(PLAYER_INTERFACE, "PlaybackStatus", player->getPlaybackStatus()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPause", player->getCanPause()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPlay", player->getCanPlay()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanSeek", player->getCanSeek()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoNext", player->getCanGoNext()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoPrevious", player->getCanGoPrevious()); + }, nullptr); + api->registerUIHook("main.start", [this](const void* a, void* _) { + tracklist->TrackListReplaced(tracklist->getTracks(), QDBusObjectPath("/org/chrisoft/qmidiplayer/dummylist/0")); + this->notifyPropertyChange(PLAYER_INTERFACE, "Metadata", player->getMetadata()); + this->notifyPropertyChange(PLAYER_INTERFACE, "PlaybackStatus", player->getPlaybackStatus()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPause", player->getCanPause()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPlay", player->getCanPlay()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanSeek", player->getCanSeek()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoNext", player->getCanGoNext()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoPrevious", player->getCanGoPrevious()); + this->notifyPropertyChange(PLAYER_INTERFACE, "Rate", player->getRate()); + }, nullptr); + api->registerUIHook("main.pause", [this](const void* a, void* _) { + this->notifyPropertyChange(PLAYER_INTERFACE, "PlaybackStatus", player->getPlaybackStatus()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPause", player->getCanPause()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanPlay", player->getCanPlay()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanSeek", player->getCanSeek()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoNext", player->getCanGoNext()); + this->notifyPropertyChange(PLAYER_INTERFACE, "CanGoPrevious", player->getCanGoPrevious()); + }, nullptr); + api->registerUIHook("main.seek", [this](const void* a, void *_) { + auto ps = static_cast(a); + player->Seeked(ps->curtime_ms * 1000); + }, nullptr); +} + +QMPrisWrapper::~QMPrisWrapper() +{ + QDBusConnection sessbus = QDBusConnection::sessionBus(); + sessbus.unregisterObject("/org/mpris/MediaPlayer2"); + sessbus.unregisterService("org.mpris.MediaPlayer2." + svcsuffix); +} + +void QMPrisWrapper::notifyPropertyChange(QString intf, QString prop, QVariant val) +{ + QDBusConnection sessbus = QDBusConnection::sessionBus(); + auto signal = QDBusMessage::createSignal("/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "PropertiesChanged"); + signal.setArguments({ + intf, + QVariantMap{{prop, val}}, + QStringList{} + }); + sessbus.send(signal); +} diff --git a/mpris-plugin/qmpriswrapper.hpp b/mpris-plugin/qmpriswrapper.hpp new file mode 100644 index 0000000..54186d2 --- /dev/null +++ b/mpris-plugin/qmpriswrapper.hpp @@ -0,0 +1,53 @@ +#ifndef QMPRISWRAPPER_HPP +#define QMPRISWRAPPER_HPP + +#include + +class QMPrisMediaPlayer2; +class QMPrisPlayer; +class QMPrisTrackList; +class qmpPluginAPI; + +class QMPrisWrapper : public QObject +{ + Q_OBJECT +public: + ~QMPrisWrapper(); + + template + static QMPrisWrapper *create(QString serviceSuffix, qmpPluginAPI *api, QObject *parent = nullptr) + { + static_assert(std::is_base_of(), "TP must be a subclass of QMPrisPlayer"); + static_assert(std::is_base_of(), "TM must be a subclass of QMPrisMediaPlayer2"); + static_assert(std::is_base_of(), "TT must be a subclass of QMPrisTrackList"); + + auto w = new QMPrisWrapper(serviceSuffix, api, parent); + auto p = new TP(api, w); + auto t = new TT(api, w); + auto mp = new TM(api, w); + w->player = p; + w->tracklist = t; + w->mediaplayer = mp; + w->post_creation(); + + return w; + } + + static void notifyPropertyChange(QString intf, QString prop, QVariant val); + +private: + explicit QMPrisWrapper(QString serviceSuffix, qmpPluginAPI *_api, QObject *parent = nullptr); + void post_creation(); + QMPrisPlayer *player = nullptr; + QMPrisMediaPlayer2 *mediaplayer = nullptr; + QMPrisTrackList *tracklist = nullptr; + QString svcsuffix; + qmpPluginAPI *api; + + const QString PLAYER_INTERFACE = "org.mpris.MediaPlayer2.Player"; + + friend class QMPrisPlayer; + friend class QMPrisMediaPlayer2; +}; + +#endif // QMPRISWRAPPER_HPP -- cgit v1.2.3