parent
4de0b93305
commit
d674d9ecf7
|
@ -866,6 +866,11 @@ if(HAVE_DBUS)
|
||||||
dbus/org.mpris.MediaPlayer2.TrackList.xml
|
dbus/org.mpris.MediaPlayer2.TrackList.xml
|
||||||
core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList)
|
||||||
|
|
||||||
|
# MPRIS 2.1 DBUS interfaces
|
||||||
|
qt4_add_dbus_adaptor(SOURCES
|
||||||
|
dbus/org.mpris.MediaPlayer2.Playlists.xml
|
||||||
|
core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists)
|
||||||
|
|
||||||
# org.freedesktop.Notifications DBUS interface
|
# org.freedesktop.Notifications DBUS interface
|
||||||
qt4_add_dbus_interface(SOURCES
|
qt4_add_dbus_interface(SOURCES
|
||||||
dbus/org.freedesktop.Notifications.xml
|
dbus/org.freedesktop.Notifications.xml
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#cmakedefine HAVE_IMOBILEDEVICE
|
#cmakedefine HAVE_IMOBILEDEVICE
|
||||||
#cmakedefine HAVE_LIBARCHIVE
|
#cmakedefine HAVE_LIBARCHIVE
|
||||||
#cmakedefine HAVE_LIBGPOD
|
#cmakedefine HAVE_LIBGPOD
|
||||||
#cmakedefine HAVE_LIBINDICATE
|
|
||||||
#cmakedefine HAVE_LIBLASTFM
|
#cmakedefine HAVE_LIBLASTFM
|
||||||
#cmakedefine HAVE_LIBLASTFM1
|
#cmakedefine HAVE_LIBLASTFM1
|
||||||
#cmakedefine HAVE_LIBMTP
|
#cmakedefine HAVE_LIBMTP
|
||||||
|
|
|
@ -73,5 +73,8 @@ void RegisterMetaTypes() {
|
||||||
qDBusRegisterMetaType<TrackMetadata>();
|
qDBusRegisterMetaType<TrackMetadata>();
|
||||||
qDBusRegisterMetaType<TrackIds>();
|
qDBusRegisterMetaType<TrackIds>();
|
||||||
qDBusRegisterMetaType<QList<QByteArray> >();
|
qDBusRegisterMetaType<QList<QByteArray> >();
|
||||||
|
qDBusRegisterMetaType<MprisPlaylist>();
|
||||||
|
qDBusRegisterMetaType<MaybePlaylist>();
|
||||||
|
qDBusRegisterMetaType<MprisPlaylistList>();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ Mpris::Mpris(Application* app, QObject* parent)
|
||||||
mpris2_(new mpris::Mpris2(app, mpris1_, this))
|
mpris2_(new mpris::Mpris2(app, mpris1_, this))
|
||||||
{
|
{
|
||||||
connect(mpris2_, SIGNAL(RaiseMainWindow()), SIGNAL(RaiseMainWindow()));
|
connect(mpris2_, SIGNAL(RaiseMainWindow()), SIGNAL(RaiseMainWindow()));
|
||||||
mpris2_->InitLibIndicate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mpris
|
} // namespace mpris
|
||||||
|
|
|
@ -15,13 +15,17 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "mpris2.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "mpris_common.h"
|
#include "mpris_common.h"
|
||||||
#include "mpris1.h"
|
#include "mpris1.h"
|
||||||
#include "mpris2.h"
|
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/mpris2_player.h"
|
#include "core/mpris2_player.h"
|
||||||
|
#include "core/mpris2_playlists.h"
|
||||||
#include "core/mpris2_root.h"
|
#include "core/mpris2_root.h"
|
||||||
#include "core/mpris2_tracklist.h"
|
#include "core/mpris2_tracklist.h"
|
||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
|
@ -37,9 +41,36 @@
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
|
||||||
#ifdef HAVE_LIBINDICATE
|
QDBusArgument& operator<< (QDBusArgument& arg, const MprisPlaylist& playlist) {
|
||||||
# include <qindicateserver.h>
|
arg.beginStructure();
|
||||||
#endif
|
arg << playlist.id << playlist.name << playlist.icon;
|
||||||
|
arg.endStructure();
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator>> (
|
||||||
|
const QDBusArgument& arg, MprisPlaylist& playlist) {
|
||||||
|
arg.beginStructure();
|
||||||
|
arg >> playlist.id >> playlist.name >> playlist.icon;
|
||||||
|
arg.endStructure();
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDBusArgument& operator<< (QDBusArgument& arg, const MaybePlaylist& playlist) {
|
||||||
|
arg.beginStructure();
|
||||||
|
arg << playlist.valid;
|
||||||
|
arg << playlist.playlist;
|
||||||
|
arg.endStructure();
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument& operator>> (
|
||||||
|
const QDBusArgument& arg, MaybePlaylist& playlist) {
|
||||||
|
arg.beginStructure();
|
||||||
|
arg >> playlist.valid >> playlist.playlist;
|
||||||
|
arg.endStructure();
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
namespace mpris {
|
namespace mpris {
|
||||||
|
|
||||||
|
@ -55,6 +86,7 @@ Mpris2::Mpris2(Application* app, Mpris1* mpris1, QObject* parent)
|
||||||
new Mpris2Root(this);
|
new Mpris2Root(this);
|
||||||
new Mpris2TrackList(this);
|
new Mpris2TrackList(this);
|
||||||
new Mpris2Player(this);
|
new Mpris2Player(this);
|
||||||
|
new Mpris2Playlists(this);
|
||||||
|
|
||||||
if (!QDBusConnection::sessionBus().registerService(kServiceName)) {
|
if (!QDBusConnection::sessionBus().registerService(kServiceName)) {
|
||||||
qLog(Warning) << "Failed to register" << QString(kServiceName) << "on the session bus";
|
qLog(Warning) << "Failed to register" << QString(kServiceName) << "on the session bus";
|
||||||
|
@ -71,15 +103,7 @@ Mpris2::Mpris2(Application* app, Mpris1* mpris1, QObject* parent)
|
||||||
|
|
||||||
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()), SLOT(PlaylistManagerInitialized()));
|
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()), SLOT(PlaylistManagerInitialized()));
|
||||||
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song)));
|
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song)));
|
||||||
}
|
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)), SLOT(PlaylistChanged()));
|
||||||
|
|
||||||
void Mpris2::InitLibIndicate() {
|
|
||||||
#ifdef HAVE_LIBINDICATE
|
|
||||||
QIndicate::Server* indicate_server = QIndicate::Server::defaultInstance();
|
|
||||||
indicate_server->setType("music.clementine");
|
|
||||||
indicate_server->setDesktopFile(DesktopEntryAbsolutePath());
|
|
||||||
indicate_server->show();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when PlaylistManager gets it ready, we connect PlaylistSequence with this
|
// when PlaylistManager gets it ready, we connect PlaylistSequence with this
|
||||||
|
@ -474,4 +498,75 @@ void Mpris2::GoTo(const QDBusObjectPath &trackId) {
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint32 Mpris2::PlaylistCount() const {
|
||||||
|
return app_->playlist_manager()->GetAllPlaylists().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Mpris2::Orderings() const {
|
||||||
|
return QStringList() << "User";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QDBusObjectPath MakePlaylistPath(int id) {
|
||||||
|
return QDBusObjectPath(QString(
|
||||||
|
"/org/mpris/MediaPlayer2/Playlists/%1").arg(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybePlaylist Mpris2::ActivePlaylist() const {
|
||||||
|
MaybePlaylist maybe_playlist;
|
||||||
|
Playlist* current_playlist = app_->playlist_manager()->current();
|
||||||
|
maybe_playlist.valid = current_playlist;
|
||||||
|
if (!current_playlist) {
|
||||||
|
return maybe_playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_playlist.playlist.id = MakePlaylistPath(current_playlist->id());
|
||||||
|
maybe_playlist.playlist.name =
|
||||||
|
app_->playlist_manager()->GetPlaylistName(current_playlist->id());
|
||||||
|
return maybe_playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mpris2::ActivatePlaylist(const QDBusObjectPath& playlist_id) {
|
||||||
|
QStringList split_path = playlist_id.path().split('/');
|
||||||
|
qLog(Debug) << Q_FUNC_INFO << playlist_id.path() << split_path;
|
||||||
|
if (split_path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
int p = split_path.last().toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
app_->playlist_manager()->SetActivePlaylist(p);
|
||||||
|
app_->player()->Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support sort orders.
|
||||||
|
MprisPlaylistList Mpris2::GetPlaylists(
|
||||||
|
quint32 index, quint32 max_count, const QString& order, bool reverse_order) {
|
||||||
|
MprisPlaylistList ret;
|
||||||
|
foreach (Playlist* p, app_->playlist_manager()->GetAllPlaylists()) {
|
||||||
|
MprisPlaylist mpris_playlist;
|
||||||
|
mpris_playlist.id = MakePlaylistPath(p->id());
|
||||||
|
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(p->id());
|
||||||
|
ret << mpris_playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse_order) {
|
||||||
|
std::reverse(ret.begin(), ret.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.mid(index, max_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mpris2::PlaylistChanged(Playlist* playlist) {
|
||||||
|
MprisPlaylist mpris_playlist;
|
||||||
|
mpris_playlist.id = MakePlaylistPath(playlist->id());
|
||||||
|
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(playlist->id());
|
||||||
|
emit PlaylistChanged(mpris_playlist);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mpris
|
} // namespace mpris
|
||||||
|
|
|
@ -28,11 +28,36 @@
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
|
class Playlist;
|
||||||
|
|
||||||
typedef QList<QVariantMap> TrackMetadata;
|
typedef QList<QVariantMap> TrackMetadata;
|
||||||
typedef QList<QDBusObjectPath> TrackIds;
|
typedef QList<QDBusObjectPath> TrackIds;
|
||||||
Q_DECLARE_METATYPE(TrackMetadata)
|
Q_DECLARE_METATYPE(TrackMetadata)
|
||||||
|
|
||||||
|
struct MprisPlaylist {
|
||||||
|
QDBusObjectPath id;
|
||||||
|
QString name;
|
||||||
|
QString icon; // Uri
|
||||||
|
};
|
||||||
|
typedef QList<MprisPlaylist> MprisPlaylistList;
|
||||||
|
Q_DECLARE_METATYPE(MprisPlaylist);
|
||||||
|
Q_DECLARE_METATYPE(MprisPlaylistList);
|
||||||
|
|
||||||
|
struct MaybePlaylist {
|
||||||
|
bool valid;
|
||||||
|
MprisPlaylist playlist;
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(MaybePlaylist);
|
||||||
|
|
||||||
|
QDBusArgument& operator<< (QDBusArgument& arg, const MprisPlaylist& playlist);
|
||||||
|
const QDBusArgument& operator>> (
|
||||||
|
const QDBusArgument& arg, MprisPlaylist& playlist);
|
||||||
|
|
||||||
|
QDBusArgument& operator<< (QDBusArgument& arg, const MaybePlaylist& playlist);
|
||||||
|
const QDBusArgument& operator>> (
|
||||||
|
const QDBusArgument& arg, MaybePlaylist& playlist);
|
||||||
|
|
||||||
|
|
||||||
namespace mpris {
|
namespace mpris {
|
||||||
|
|
||||||
class Mpris1;
|
class Mpris1;
|
||||||
|
@ -40,6 +65,7 @@ class Mpris1;
|
||||||
class Mpris2 : public QObject {
|
class Mpris2 : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
//org.mpris.MediaPlayer2 MPRIS 2.0 Root interface
|
//org.mpris.MediaPlayer2 MPRIS 2.0 Root interface
|
||||||
Q_PROPERTY( bool CanQuit READ CanQuit )
|
Q_PROPERTY( bool CanQuit READ CanQuit )
|
||||||
Q_PROPERTY( bool CanRaise READ CanRaise )
|
Q_PROPERTY( bool CanRaise READ CanRaise )
|
||||||
|
@ -74,10 +100,12 @@ class Mpris2 : public QObject {
|
||||||
Q_PROPERTY( TrackIds Tracks READ Tracks )
|
Q_PROPERTY( TrackIds Tracks READ Tracks )
|
||||||
Q_PROPERTY( bool CanEditTracks READ CanEditTracks )
|
Q_PROPERTY( bool CanEditTracks READ CanEditTracks )
|
||||||
|
|
||||||
public:
|
//org.mpris.MediaPlayer2.Playlists MPRIS 2.1 Playlists interface
|
||||||
Mpris2(Application* app, Mpris1* mpris1, QObject* parent = 0);
|
Q_PROPERTY( quint32 PlaylistCount READ PlaylistCount )
|
||||||
|
Q_PROPERTY( QStringList Orderings READ Orderings )
|
||||||
|
Q_PROPERTY( MaybePlaylist ActivePlaylist READ ActivePlaylist )
|
||||||
|
|
||||||
void InitLibIndicate();
|
Mpris2(Application* app, Mpris1* mpris1, QObject* parent = 0);
|
||||||
|
|
||||||
// Root Properties
|
// Root Properties
|
||||||
bool CanQuit() const;
|
bool CanQuit() const;
|
||||||
|
@ -139,6 +167,16 @@ public:
|
||||||
void RemoveTrack(const QDBusObjectPath& trackId);
|
void RemoveTrack(const QDBusObjectPath& trackId);
|
||||||
void GoTo(const QDBusObjectPath& trackId);
|
void GoTo(const QDBusObjectPath& trackId);
|
||||||
|
|
||||||
|
// Playlist Properties
|
||||||
|
quint32 PlaylistCount() const;
|
||||||
|
QStringList Orderings() const;
|
||||||
|
MaybePlaylist ActivePlaylist() const;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
void ActivatePlaylist(const QDBusObjectPath& playlist_id);
|
||||||
|
QList<MprisPlaylist> GetPlaylists(
|
||||||
|
quint32 index, quint32 max_count, const QString& order, bool reverse_order);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Player
|
// Player
|
||||||
void Seeked(qlonglong position);
|
void Seeked(qlonglong position);
|
||||||
|
@ -151,6 +189,9 @@ signals:
|
||||||
|
|
||||||
void RaiseMainWindow();
|
void RaiseMainWindow();
|
||||||
|
|
||||||
|
// Playlist
|
||||||
|
void PlaylistChanged(const MprisPlaylist& playlist);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ArtLoaded(const Song& song, const QString& art_uri);
|
void ArtLoaded(const Song& song, const QString& art_uri);
|
||||||
void EngineStateChanged(Engine::State newState);
|
void EngineStateChanged(Engine::State newState);
|
||||||
|
@ -160,6 +201,7 @@ private slots:
|
||||||
void CurrentSongChanged(const Song& song);
|
void CurrentSongChanged(const Song& song);
|
||||||
void ShuffleModeChanged();
|
void ShuffleModeChanged();
|
||||||
void RepeatModeChanged();
|
void RepeatModeChanged();
|
||||||
|
void PlaylistChanged(Playlist* playlist);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EmitNotification(const QString& name);
|
void EmitNotification(const QString& name);
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
|
||||||
|
<node>
|
||||||
|
<interface name='org.mpris.MediaPlayer2.Playlists'>
|
||||||
|
<property name='PlaylistCount' type='u' access='read' />
|
||||||
|
<property name='Orderings' type='as' access='read' />
|
||||||
|
<property name='ActivePlaylist' type='(b(oss))' access='read'>
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName" value="MaybePlaylist"/>
|
||||||
|
</property>
|
||||||
|
<method name='ActivatePlaylist'>
|
||||||
|
<arg direction='in' name='PlaylistId' type='o' />
|
||||||
|
</method>
|
||||||
|
<method name='GetPlaylists'>
|
||||||
|
<arg direction='in' name='Index' type='u' />
|
||||||
|
<arg direction='in' name='MaxCount' type='u' />
|
||||||
|
<arg direction='in' name='Order' type='s' />
|
||||||
|
<arg direction='in' name='ReverseOrder' type='b' />
|
||||||
|
<arg direction='out' name='Playlists' type='a(oss)' />
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MprisPlaylistList"/>
|
||||||
|
</method>
|
||||||
|
<signal name='PlaylistChanged'>
|
||||||
|
<arg name='Playlist' type='(oss)' />
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MprisPlaylist" />
|
||||||
|
</signal>
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName" value="MaybePlaylist" />
|
||||||
|
</interface>
|
||||||
|
</node>
|
Loading…
Reference in New Issue