pax_global_header00006660000000000000000000000064133151437410014514gustar00rootroot0000000000000052 comment=7251898353f1f5804c9480172ad7df88c4fe7eb6 qtmpris-0.1.0/000077500000000000000000000000001331514374100132115ustar00rootroot00000000000000qtmpris-0.1.0/COPYING000066400000000000000000000643141331514374100142540ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE MPRIS component library Copyright (C) 2015 Jolla Ltd. Contact: info@jolla.com You may use, distribute and copy the MPRIS component library under the terms of GNU Lesser General Public License version 2.1. ------------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation and appearing in the file license.lgpl included in the packaging of this file. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! qtmpris-0.1.0/README.md000066400000000000000000000012511331514374100144670ustar00rootroot00000000000000Qt and QML MPRIS interface and adaptor ====================================== [MPRIS v.2](http://specifications.freedesktop.org/mpris-spec/latest/index.html) specification implementation for Qt and QML plugin. Installation: ------------- MPRIS for Qt depends on [Extended DBus for Qt](https://github.com/nemomobile/qtdbusextended) so make sure to install it before building this project. ``` $ qmake && make && make install ``` TO-DO: ------ * Implement the optional [Tracklist](http://specifications.freedesktop.org/mpris-spec/latest/Track_List_Interface.html) and [Playlists](http://specifications.freedesktop.org/mpris-spec/latest/Playlists_Interface.html) interfaces. qtmpris-0.1.0/common.pri000066400000000000000000000000271331514374100152140ustar00rootroot00000000000000MPRISQTLIB = mpris-qt5 qtmpris-0.1.0/declarative/000077500000000000000000000000001331514374100154745ustar00rootroot00000000000000qtmpris-0.1.0/declarative/declarative.pro000066400000000000000000000013111331514374100204750ustar00rootroot00000000000000include(../common.pri) TEMPLATE = lib CONFIG += qt plugin link_pkgconfig DEPENDPATH += ../src INCLUDEPATH += ../src QT = core dbus qml LIBS += -L../src -l$${MPRISQTLIB} PKGCONFIG = dbusextended-qt5 EXAMPLE = ../example/declarative/* OTHER_FILES += $${EXAMPLE} TARGET = $${MPRISQTLIB}-qml-plugin PLUGIN_IMPORT_PATH = org/nemomobile/mpris QMAKE_SUBSTITUTES = qmldir.in SOURCES += \ mprisplugin.cpp HEADERS += \ mprisplugin.h target.path = $$[QT_INSTALL_QML]/$$PLUGIN_IMPORT_PATH qml.files = qmldir plugins.qmltypes qml.path = $$target.path INSTALLS += target qml qmltypes.commands = qmlplugindump -nonrelocatable org.nemomobile.mpris 1.0 > $$PWD/plugins.qmltypes QMAKE_EXTRA_TARGETS += qmltypes qtmpris-0.1.0/declarative/mprisplugin.cpp000066400000000000000000000025601331514374100205540ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mprisplugin.h" #include #include #include #include MprisPlugin::MprisPlugin(QObject *parent) : QQmlExtensionPlugin(parent) { } MprisPlugin::~MprisPlugin() { } void MprisPlugin::registerTypes(const char *uri) { qmlRegisterSingletonType(uri, 1, 0, "Mpris", Mpris::api_factory); qmlRegisterType(uri, 1, 0, "MprisPlayer"); qmlRegisterType(uri, 1, 0, "MprisManager"); } qtmpris-0.1.0/declarative/mprisplugin.h000066400000000000000000000023741331514374100202240ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRIS_PLUGIN_H #define MPRIS_PLUGIN_H #include #include class MprisPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.nemomobile.mpris") public: MprisPlugin(QObject *parent = 0); ~MprisPlugin(); virtual void registerTypes(const char *uri); }; #endif /* MPRIS_PLUGIN_H */ qtmpris-0.1.0/declarative/plugins.qmltypes000066400000000000000000000355121331514374100207630ustar00rootroot00000000000000import QtQuick.tooling 1.2 // This file describes the plugin-supplied types contained in the library. // It is used for QML tooling purposes only. // // This file was auto-generated by: // 'qmlplugindump -nonrelocatable org.nemomobile.mpris 1.0' Module { dependencies: [] Component { name: "Mpris" prototype: "QObject" exports: ["org.nemomobile.mpris/Mpris 1.0"] isCreatable: false isSingleton: true exportMetaObjectRevisions: [0] Enum { name: "PlaybackStatus" values: { "InvalidPlaybackStatus": -1, "Playing": 0, "Paused": 1, "Stopped": 2 } } Enum { name: "LoopStatus" values: { "InvalidLoopStatus": -1, "None": 0, "Track": 1, "Playlist": 2 } } Enum { name: "Metadata" values: { "InvalidMetadata": -1, "TrackId": 0, "Length": 1, "ArtUrl": 2, "Album": 3, "AlbumArtist": 4, "Artist": 5, "AsText": 6, "AudioBPM": 7, "AutoRating": 8, "Comment": 9, "Composer": 10, "ContentCreated": 11, "DiscNumber": 12, "FirstUsed": 13, "Genre": 14, "LastUsed": 15, "Lyricist": 16, "Title": 17, "TrackNumber": 18, "Url": 19, "UseCount": 20, "UserRating": 21 } } Method { name: "metadataToString" type: "string" Parameter { name: "metadata"; type: "Metadata" } } } Component { name: "MprisManager" prototype: "QObject" exports: ["org.nemomobile.mpris/MprisManager 1.0"] exportMetaObjectRevisions: [0] Property { name: "singleService"; type: "bool" } Property { name: "currentService"; type: "string" } Property { name: "availableServices"; type: "QStringList"; isReadonly: true } Property { name: "canQuit"; type: "bool"; isReadonly: true } Property { name: "canRaise"; type: "bool"; isReadonly: true } Property { name: "canSetFullscreen"; type: "bool"; isReadonly: true } Property { name: "desktopEntry"; type: "string"; isReadonly: true } Property { name: "fullscreen"; type: "bool" } Property { name: "hasTrackList"; type: "bool"; isReadonly: true } Property { name: "identity"; type: "string"; isReadonly: true } Property { name: "supportedUriSchemes"; type: "QStringList"; isReadonly: true } Property { name: "supportedMimeTypes"; type: "QStringList"; isReadonly: true } Property { name: "canControl"; type: "bool"; isReadonly: true } Property { name: "canGoNext"; type: "bool"; isReadonly: true } Property { name: "canGoPrevious"; type: "bool"; isReadonly: true } Property { name: "canPause"; type: "bool"; isReadonly: true } Property { name: "canPlay"; type: "bool"; isReadonly: true } Property { name: "canSeek"; type: "bool"; isReadonly: true } Property { name: "loopStatus"; type: "Mpris::LoopStatus" } Property { name: "maximumRate"; type: "double"; isReadonly: true } Property { name: "metadata"; type: "QVariantMap"; isReadonly: true } Property { name: "minimumRate"; type: "double"; isReadonly: true } Property { name: "playbackStatus"; type: "Mpris::PlaybackStatus"; isReadonly: true } Property { name: "position"; type: "qlonglong"; isReadonly: true } Property { name: "rate"; type: "double" } Property { name: "shuffle"; type: "bool" } Property { name: "volume"; type: "double" } Signal { name: "positionChanged" Parameter { name: "position"; type: "qlonglong" } } Signal { name: "seeked" Parameter { name: "position"; type: "qlonglong" } } Method { name: "singleService"; type: "bool" } Method { name: "setSingleService" Parameter { name: "single"; type: "bool" } } Method { name: "currentService"; type: "string" } Method { name: "setCurrentService" Parameter { name: "service"; type: "string" } } Method { name: "availableServices"; type: "QStringList" } Method { name: "canQuit"; type: "bool" } Method { name: "canRaise"; type: "bool" } Method { name: "canSetFullscreen"; type: "bool" } Method { name: "desktopEntry"; type: "string" } Method { name: "fullscreen"; type: "bool" } Method { name: "setFullscreen" Parameter { name: "fullscreen"; type: "bool" } } Method { name: "hasTrackList"; type: "bool" } Method { name: "identity"; type: "string" } Method { name: "supportedUriSchemes"; type: "QStringList" } Method { name: "supportedMimeTypes"; type: "QStringList" } Method { name: "canControl"; type: "bool" } Method { name: "canGoNext"; type: "bool" } Method { name: "canGoPrevious"; type: "bool" } Method { name: "canPause"; type: "bool" } Method { name: "canPlay"; type: "bool" } Method { name: "canSeek"; type: "bool" } Method { name: "loopStatus"; type: "Mpris::LoopStatus" } Method { name: "setLoopStatus" Parameter { name: "loopStatus"; type: "Mpris::LoopStatus" } } Method { name: "maximumRate"; type: "double" } Method { name: "metadata"; type: "QVariantMap" } Method { name: "minimumRate"; type: "double" } Method { name: "playbackStatus"; type: "Mpris::PlaybackStatus" } Method { name: "position"; type: "qlonglong" } Method { name: "requestPosition" } Method { name: "rate"; type: "double" } Method { name: "setRate" Parameter { name: "rate"; type: "double" } } Method { name: "shuffle"; type: "bool" } Method { name: "setShuffle" Parameter { name: "shuffle"; type: "bool" } } Method { name: "volume"; type: "double" } Method { name: "setVolume" Parameter { name: "volume"; type: "double" } } Method { name: "quit"; type: "bool" } Method { name: "raise"; type: "bool" } Method { name: "next"; type: "bool" } Method { name: "openUri" type: "bool" Parameter { name: "uri"; type: "QUrl" } } Method { name: "pause"; type: "bool" } Method { name: "play"; type: "bool" } Method { name: "playPause"; type: "bool" } Method { name: "previous"; type: "bool" } Method { name: "seek" type: "bool" Parameter { name: "offset"; type: "qlonglong" } } Method { name: "setPosition" type: "bool" Parameter { name: "position"; type: "qlonglong" } } Method { name: "setPosition" type: "bool" Parameter { name: "trackId"; type: "string" } Parameter { name: "position"; type: "qlonglong" } } Method { name: "stop"; type: "bool" } } Component { name: "MprisPlayer" prototype: "QObject" exports: ["org.nemomobile.mpris/MprisPlayer 1.0"] exportMetaObjectRevisions: [0] Property { name: "serviceName"; type: "string" } Property { name: "canQuit"; type: "bool" } Property { name: "canRaise"; type: "bool" } Property { name: "canSetFullscreen"; type: "bool" } Property { name: "desktopEntry"; type: "string" } Property { name: "fullscreen"; type: "bool" } Property { name: "hasTrackList"; type: "bool" } Property { name: "identity"; type: "string" } Property { name: "supportedUriSchemes"; type: "QStringList" } Property { name: "supportedMimeTypes"; type: "QStringList" } Property { name: "canControl"; type: "bool" } Property { name: "canGoNext"; type: "bool" } Property { name: "canGoPrevious"; type: "bool" } Property { name: "canPause"; type: "bool" } Property { name: "canPlay"; type: "bool" } Property { name: "canSeek"; type: "bool" } Property { name: "loopStatus"; type: "Mpris::LoopStatus" } Property { name: "maximumRate"; type: "double" } Property { name: "metadata"; type: "QVariantMap" } Property { name: "minimumRate"; type: "double" } Property { name: "playbackStatus"; type: "Mpris::PlaybackStatus" } Property { name: "position"; type: "qlonglong" } Property { name: "rate"; type: "double" } Property { name: "shuffle"; type: "bool" } Property { name: "volume"; type: "double" } Signal { name: "fullscreenRequested" Parameter { name: "fullscreen"; type: "bool" } } Signal { name: "quitRequested" } Signal { name: "raiseRequested" } Signal { name: "loopStatusRequested" Parameter { name: "loopStatus"; type: "Mpris::LoopStatus" } } Signal { name: "rateRequested" Parameter { name: "rate"; type: "double" } } Signal { name: "shuffleRequested" Parameter { name: "shuffle"; type: "bool" } } Signal { name: "volumeRequested" Parameter { name: "volume"; type: "double" } } Signal { name: "nextRequested" } Signal { name: "openUriRequested" Parameter { name: "url"; type: "QUrl" } } Signal { name: "pauseRequested" } Signal { name: "playRequested" } Signal { name: "playPauseRequested" } Signal { name: "previousRequested" } Signal { name: "seekRequested" Parameter { name: "offset"; type: "qlonglong" } } Signal { name: "seeked" Parameter { name: "position"; type: "qlonglong" } } Signal { name: "setPositionRequested" Parameter { name: "trackId"; type: "QDBusObjectPath" } Parameter { name: "position"; type: "qlonglong" } } Signal { name: "stopRequested" } Method { name: "serviceName"; type: "string" } Method { name: "setServiceName" Parameter { name: "serviceName"; type: "string" } } Method { name: "canQuit"; type: "bool" } Method { name: "setCanQuit" Parameter { name: "canQuit"; type: "bool" } } Method { name: "canRaise"; type: "bool" } Method { name: "setCanRaise" Parameter { name: "canRaise"; type: "bool" } } Method { name: "canSetFullscreen"; type: "bool" } Method { name: "setCanSetFullscreen" Parameter { name: "canSetFullscreen"; type: "bool" } } Method { name: "desktopEntry"; type: "string" } Method { name: "setDesktopEntry" Parameter { name: "desktopEntry"; type: "string" } } Method { name: "fullscreen"; type: "bool" } Method { name: "setFullscreen" Parameter { name: "fullscreen"; type: "bool" } } Method { name: "hasTrackList"; type: "bool" } Method { name: "setHasTrackList" Parameter { name: "hasTrackList"; type: "bool" } } Method { name: "identity"; type: "string" } Method { name: "setIdentity" Parameter { name: "identity"; type: "string" } } Method { name: "supportedUriSchemes"; type: "QStringList" } Method { name: "setSupportedUriSchemes" Parameter { name: "supportedUriSchemes"; type: "QStringList" } } Method { name: "supportedMimeTypes"; type: "QStringList" } Method { name: "setSupportedMimeTypes" Parameter { name: "supportedMimeTypes"; type: "QStringList" } } Method { name: "canControl"; type: "bool" } Method { name: "setCanControl" Parameter { name: "canControl"; type: "bool" } } Method { name: "canGoNext"; type: "bool" } Method { name: "setCanGoNext" Parameter { name: "canGoNext"; type: "bool" } } Method { name: "canGoPrevious"; type: "bool" } Method { name: "setCanGoPrevious" Parameter { name: "canGoPrevious"; type: "bool" } } Method { name: "canPause"; type: "bool" } Method { name: "setCanPause" Parameter { name: "canPause"; type: "bool" } } Method { name: "canPlay"; type: "bool" } Method { name: "setCanPlay" Parameter { name: "canPlay"; type: "bool" } } Method { name: "canSeek"; type: "bool" } Method { name: "setCanSeek" Parameter { name: "canSeek"; type: "bool" } } Method { name: "loopStatus"; type: "Mpris::LoopStatus" } Method { name: "setLoopStatus" Parameter { name: "loopStatus"; type: "Mpris::LoopStatus" } } Method { name: "maximumRate"; type: "double" } Method { name: "setMaximumRate" Parameter { name: "maximumRate"; type: "double" } } Method { name: "metadata"; type: "QVariantMap" } Method { name: "setMetadata" Parameter { name: "metadata"; type: "QVariantMap" } } Method { name: "minimumRate"; type: "double" } Method { name: "setMinimumRate" Parameter { name: "minimumRate"; type: "double" } } Method { name: "playbackStatus"; type: "Mpris::PlaybackStatus" } Method { name: "setPlaybackStatus" Parameter { name: "playbackStatus"; type: "Mpris::PlaybackStatus" } } Method { name: "position"; type: "qlonglong" } Method { name: "setPosition" Parameter { name: "position"; type: "qlonglong" } } Method { name: "rate"; type: "double" } Method { name: "setRate" Parameter { name: "rate"; type: "double" } } Method { name: "shuffle"; type: "bool" } Method { name: "setShuffle" Parameter { name: "shuffle"; type: "bool" } } Method { name: "volume"; type: "double" } Method { name: "setVolume" Parameter { name: "volume"; type: "double" } } } } qtmpris-0.1.0/declarative/qmldir.in000066400000000000000000000001101331514374100173040ustar00rootroot00000000000000module org.nemomobile.mpris plugin $${TARGET} typeinfo plugins.qmltypes qtmpris-0.1.0/example/000077500000000000000000000000001331514374100146445ustar00rootroot00000000000000qtmpris-0.1.0/example/controller/000077500000000000000000000000001331514374100170275ustar00rootroot00000000000000qtmpris-0.1.0/example/controller/controller.cpp000066400000000000000000000027011331514374100217160ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include int main(int argc, char *argv[]) { QGuiApplication *app = new QGuiApplication(argc, argv); QQuickView *view = new QQuickView; qmlRegisterSingletonType("org.nemomobile.qtmpris", 1, 0, "Mpris", Mpris::api_factory); qmlRegisterType("org.nemomobile.qtmpris", 1, 0, "MprisManager"); view->setSource(app->applicationDirPath().append("/../qml/controller.qml")); view->show(); int retVal = app->exec(); return retVal; } qtmpris-0.1.0/example/controller/controller.pro000066400000000000000000000004541331514374100217370ustar00rootroot00000000000000include(../../common.pri) TEMPLATE = app TARGET = controller CONFIG += qt link_pkgconfig QT += qml quick DEPENDPATH += ../../src INCLUDEPATH += ../../src LIBS += -L../../src -l$${MPRISQTLIB} PKGCONFIG = dbusextended-qt5 SOURCES += \ controller.cpp target.path = /usr/bin INSTALLS += target qtmpris-0.1.0/example/player/000077500000000000000000000000001331514374100161405ustar00rootroot00000000000000qtmpris-0.1.0/example/player/player.cpp000066400000000000000000000026731331514374100201500ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include int main(int argc, char *argv[]) { QGuiApplication *app = new QGuiApplication(argc, argv); QQuickView *view = new QQuickView; qmlRegisterSingletonType("org.nemomobile.qtmpris", 1, 0, "Mpris", Mpris::api_factory); qmlRegisterType("org.nemomobile.qtmpris", 1, 0, "MprisPlayer"); view->setSource(app->applicationDirPath().append("/../qml/player.qml")); view->show(); int retVal = app->exec(); return retVal; } qtmpris-0.1.0/example/player/player.pro000066400000000000000000000004441331514374100201600ustar00rootroot00000000000000include(../../common.pri) TEMPLATE = app TARGET = player CONFIG += qt link_pkgconfig QT += qml quick DEPENDPATH += ../../src INCLUDEPATH += ../../src LIBS += -L../../src -l$${MPRISQTLIB} PKGCONFIG = dbusextended-qt5 SOURCES += \ player.cpp target.path = /usr/bin INSTALLS += target qtmpris-0.1.0/example/qml/000077500000000000000000000000001331514374100154355ustar00rootroot00000000000000qtmpris-0.1.0/example/qml/MprisControls.qml000066400000000000000000000062121331514374100207670ustar00rootroot00000000000000/*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ import QtQuick 2.0 import org.nemomobile.qtmpris 1.0 Item { id: controls property MprisManager mprisManager property bool isPlaying: mprisManager.currentService && mprisManager.playbackStatus == Mpris.Playing height: parent.height width: column.width Column { id: column Text { id: artistLabel text: if (mprisManager.currentService) { var artistTag = Mpris.metadataToString(Mpris.Artist) return (artistTag in mprisManager.metadata) ? mprisManager.metadata[artistTag].toString() : "" } width: parent.width elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter } Text { id: songLabel text: if (mprisManager.currentService) { var titleTag = Mpris.metadataToString(Mpris.Title) return (titleTag in mprisManager.metadata) ? mprisManager.metadata[titleTag].toString() : "" } width: parent.width elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter } Row { MouseArea { width: controls.parent.width * 0.25 height: width onClicked: if (mprisManager.canGoPrevious) mprisManager.previous() Text { anchors.centerIn: parent text: "⏮" } } MouseArea { width: controls.parent.width * 0.25 height: width onClicked: if ((controls.isPlaying && mprisManager.canPause) || (!controls.isPlaying && mprisManager.canPlay)) { mprisManager.playPause() } Text { anchors.centerIn: parent text: controls.isPlaying ? "⏸" : "⏵" } } MouseArea { width: controls.parent.width * 0.25 height: width onClicked: if (mprisManager.canGoPrevious) if (mprisManager.canGoNext) mprisManager.next() Text { anchors.centerIn: parent text: "⏭" } } } } } qtmpris-0.1.0/example/qml/controller.qml000066400000000000000000000024121331514374100203320ustar00rootroot00000000000000/*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ import QtQuick 2.0 import org.nemomobile.qtmpris 1.0 Item { id: mainItem anchors.fill: parent Loader { id: controlsLoader active: mprisManager.availableServices.length > 0 Component.onCompleted: setSource("MprisControls.qml", { "mprisManager": mprisManager, "parent": mainItem }) MprisManager { id: mprisManager } } } qtmpris-0.1.0/example/qml/player.qml000066400000000000000000000140541331514374100174500ustar00rootroot00000000000000/*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ import QtQuick 2.0 import org.nemomobile.qtmpris 1.0 Item { id: mainItem anchors.fill: parent Column { id: column x: (parent.width - width) * 0.5 width: parent.width * 0.75 Row { MouseArea { width: column.parent.width * 0.25 height: width onClicked: mprisPlayer.playbackStatus = Mpris.Stopped Text { anchors.centerIn: parent text: "Stop" } } MouseArea { width: column.parent.width * 0.25 height: width onClicked: mprisPlayer.playbackStatus = Mpris.Playing Text { anchors.centerIn: parent text: "Play" } } MouseArea { width: column.parent.width * 0.25 height: width onClicked: mprisPlayer.playbackStatus = Mpris.Paused Text { anchors.centerIn: parent text: "Pause" } } } Row { width: parent.width height: artistSet.height Text { id: artistLabel height: parent.height text: "Artist: " verticalAlignment: Text.AlignVCenter } TextInput { id: artistInput width: parent.width - artistLabel.width - artistSet.width height: parent.height verticalAlignment: Text.AlignVCenter } MouseArea { id: artistSet width: column.parent.width * 0.25 height: width onClicked: mprisPlayer.artist = artistInput.text Text { anchors.centerIn: parent text: "Set" } } } Row { width: parent.width height: songSet.height Text { id: songLabel height: parent.height text: "Song: " verticalAlignment: Text.AlignVCenter } TextInput { id: songInput width: parent.width - songLabel.width - songSet.width height: parent.height verticalAlignment: Text.AlignVCenter } MouseArea { id: songSet width: column.parent.width * 0.25 height: width onClicked: mprisPlayer.song = songInput.text Text { anchors.centerIn: parent text: "Set" } } } Text { id: message property string lastMessage text: "Last Message was: " + lastMessage width: parent.width elide: Text.ElideRight } } MprisPlayer { id: mprisPlayer property string artist property string song serviceName: "qtmpris" // Mpris2 Root Interface identity: "QtMpris Example" supportedUriSchemes: ["file"] supportedMimeTypes: ["audio/x-wav", "audio/x-vorbis+ogg"] // Mpris2 Player Interface canControl: true canGoNext: true canGoPrevious: true canPause: playbackStatus == Mpris.Playing canPlay: playbackStatus != Mpris.Playing canSeek: false playbackStatus: Mpris.Stopped loopStatus: Mpris.None shuffle: false volume: 1 onPauseRequested: message.lastMessage = "Pause requested" onPlayRequested: message.lastMessage = "Play requested" onPlayPauseRequested: message.lastMessage = "Play/Pause requested" onStopRequested: message.lastMessage = "Stop requested" onNextRequested: message.lastMessage = "Next requested" onPreviousRequested: message.lastMessage = "Previous requested" onSeekRequested: { message.lastMessage = "Seeked requested with offset - " + offset + " microseconds" emitSeeked() } onSetPositionRequested: { message.lastMessage = "Position requested to - " + position + " microseconds" emitSeeked() } onOpenUriRequested: message.lastMessage = "Requested to open uri \"" + url + "\"" onLoopStatusRequested: { if (loopStatus == Mpris.None) { repeatSwitch.checked = false } else if (loopStatus == Mpris.Playlist) { repeatSwitch.checked = true } } onShuffleRequested: shuffleSwitch.checked = shuffle onArtistChanged: { var metadata = mprisPlayer.metadata metadata[Mpris.metadataToString(Mpris.Artist)] = [artist] // List of strings mprisPlayer.metadata = metadata } onSongChanged: { var metadata = mprisPlayer.metadata metadata[Mpris.metadataToString(Mpris.Title)] = song // String mprisPlayer.metadata = metadata } } } qtmpris-0.1.0/mpris-qt.pro000066400000000000000000000001071331514374100155050ustar00rootroot00000000000000TEMPLATE = subdirs declarative.depends = src SUBDIRS = src declarative qtmpris-0.1.0/rpm/000077500000000000000000000000001331514374100140075ustar00rootroot00000000000000qtmpris-0.1.0/rpm/mpris-qt.spec000066400000000000000000000033111331514374100164350ustar00rootroot00000000000000Name: mpris-qt5 Summary: Qt and QML MPRIS interface and adaptor Version: 0.0.5 Release: 1 Group: Development/Libraries License: LGPLv2.1 URL: https://github.com/nemomobile/qtmpris Source0: %{name}-%{version}.tar.bz2 Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(Qt5Qml) BuildRequires: pkgconfig(dbusextended-qt5) >= 0.0.2 %description %{summary}. %package devel Summary: Development files for %{name} Requires: %{name} = %{version}-%{release} %description devel Development files for %{name}. %package qml-plugin Summary: QML plugin for %{name} Requires: %{name} = %{version}-%{release} %description qml-plugin QML plugin for %{name}. %prep %setup -q -n %{name}-%{version} %build %qmake5 make %{?_smp_mflags} %install rm -rf %{buildroot} %qmake5_install %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root,-) %{_libdir}/lib*.so.* %files devel %defattr(-,root,root,-) %{_datarootdir}/qt5/mkspecs/features/%{name}.prf %{_includedir}/qt5/MprisQt/MprisQt %{_includedir}/qt5/MprisQt/Mpris %{_includedir}/qt5/MprisQt/MprisPlayer %{_includedir}/qt5/MprisQt/MprisController %{_includedir}/qt5/MprisQt/MprisManager %{_includedir}/qt5/MprisQt/mprisqt.h %{_includedir}/qt5/MprisQt/mpris.h %{_includedir}/qt5/MprisQt/mprisplayer.h %{_includedir}/qt5/MprisQt/mpriscontroller.h %{_includedir}/qt5/MprisQt/mprismanager.h %{_libdir}/lib*.so %{_libdir}/pkgconfig/%{name}.pc %files qml-plugin %defattr(-,root,root,-) %{_libdir}/qt5/qml/org/nemomobile/mpris/libmpris-qt5-qml-plugin.so %{_libdir}/qt5/qml/org/nemomobile/mpris/plugins.qmltypes %{_libdir}/qt5/qml/org/nemomobile/mpris/qmldir qtmpris-0.1.0/src/000077500000000000000000000000001331514374100140005ustar00rootroot00000000000000qtmpris-0.1.0/src/Mpris000066400000000000000000000000231331514374100150100ustar00rootroot00000000000000#include "mpris.h" qtmpris-0.1.0/src/MprisController000066400000000000000000000000351331514374100170570ustar00rootroot00000000000000#include "mpriscontroller.h" qtmpris-0.1.0/src/MprisManager000066400000000000000000000000321331514374100163030ustar00rootroot00000000000000#include "mprismanager.h" qtmpris-0.1.0/src/MprisPlayer000066400000000000000000000000311331514374100161640ustar00rootroot00000000000000#include "mprisplayer.h" qtmpris-0.1.0/src/MprisQt000066400000000000000000000000251331514374100153170ustar00rootroot00000000000000#include "mprisqt.h" qtmpris-0.1.0/src/mpris-qt5.prf.in000066400000000000000000000000571331514374100167610ustar00rootroot00000000000000CONFIG += link_pkgconfig PKGCONFIG += $$TARGET qtmpris-0.1.0/src/mpris.cpp000066400000000000000000000076221331514374100156450ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mpris.h" #include #include static const char *playbackStatusStrings[] = { "Playing", "Paused", "Stopped" }; static const char *loopStatusStrings[] = { "None", "Track", "Playlist" }; static const char *metadataStrings[] = { "mpris:trackid", "mpris:length", "mpris:artUrl", "xesam:album", "xesam:albumArtist", "xesam:artist", "xesam:asText", "xesam:audioBPM", "xesam:autoRating", "xesam:comment", "xesam:composer", "xesam:contentCreated", "xesam:discNumber", "xesam:firstUsed", "xesam:genre", "xesam:lastUsed", "xesam:lyricist", "xesam:title", "xesam:trackNumber", "xesam:url", "xesam:useCount", "xesam:userRating" }; Mpris::Mpris(QObject *parent) : QObject(parent) { } Mpris::~Mpris() { } QObject *Mpris::api_factory(QQmlEngine *, QJSEngine *) { return new Mpris; } QString Mpris::metadataToString(Mpris::Metadata metadata) { return enumerationToString(metadata); } // Private template void Mpris::getEnumStringsAndSize(const char ***strings, int *size) { if (is_same::value) { *strings = loopStatusStrings; *size = arraySize(loopStatusStrings); } else if (is_same::value) { *strings = playbackStatusStrings; *size = arraySize(playbackStatusStrings); } else if (is_same::value) { *strings = metadataStrings; *size = arraySize(metadataStrings); } else { *strings = 0; *size = 0; } } template void Mpris::getEnumStringsAndSize(const char ***strings, int *size); template void Mpris::getEnumStringsAndSize(const char ***strings, int *size); template void Mpris::getEnumStringsAndSize(const char ***strings, int *size); template QString Mpris::enumerationToString(T enumeration) { const char **strings; int size; getEnumStringsAndSize(&strings, &size); return enumeration >= 0 && enumeration < size ? QString(QLatin1String(strings[enumeration])) : QString(); } template QString Mpris::enumerationToString(Mpris::LoopStatus enumeration); template QString Mpris::enumerationToString(Mpris::PlaybackStatus enumeration); template QString Mpris::enumerationToString(Mpris::Metadata enumeration); template T Mpris::enumerationFromString(const QString &string) { const char **strings; int size; getEnumStringsAndSize(&strings, &size); for (int i = 0; i < size; ++i) { if (string == QLatin1String(strings[i])) { return T(i); } } return T(-1); } template Mpris::LoopStatus Mpris::enumerationFromString(const QString &string); template Mpris::PlaybackStatus Mpris::enumerationFromString(const QString &string); template Mpris::Metadata Mpris::enumerationFromString(const QString &string); qtmpris-0.1.0/src/mpris.h000066400000000000000000000052071331514374100153070ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRIS_H #define MPRIS_H #include #include #include class QQmlEngine; class QJSEngine; class MPRIS_QT_EXPORT Mpris : public QObject { Q_OBJECT Q_ENUMS(PlaybackStatus LoopStatus Metadata) public: enum PlaybackStatus { InvalidPlaybackStatus = -1, Playing, Paused, Stopped }; enum LoopStatus { InvalidLoopStatus = -1, None, Track, Playlist }; enum Metadata { InvalidMetadata = -1, TrackId, Length, ArtUrl, Album, AlbumArtist, Artist, AsText, AudioBPM, AutoRating, Comment, Composer, ContentCreated, DiscNumber, FirstUsed, Genre, LastUsed, Lyricist, Title, TrackNumber, Url, UseCount, UserRating }; Mpris(QObject *parent = 0); ~Mpris(); static QObject *api_factory(QQmlEngine *, QJSEngine *); Q_INVOKABLE static QString metadataToString(Metadata metadata); private: template static int arraySize(T (&)[N]) { return N; }; template struct is_same { static const bool value = false; }; template struct is_same { static const bool value = true; }; template static void getEnumStringsAndSize(const char ***strings, int *size); template static QString enumerationToString(T enumeration); template static T enumerationFromString(const QString &string); friend class MprisRootAdaptor; friend class MprisPlayerAdaptor; friend class MprisPlayer; friend class MprisController; }; #endif /* MPRIS_H */ qtmpris-0.1.0/src/mpriscontroller.cpp000066400000000000000000000507671331514374100177610ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mpriscontroller.h" #include "mpriscontroller_p.h" #include #include #include static const QString mprisObjectPath = QStringLiteral("/org/mpris/MediaPlayer2"); MprisController::MprisController(const QString &service, const QDBusConnection &connection, QObject *parent) : QObject(parent) , m_mprisRootInterface(new MprisRootInterface(service, mprisObjectPath, connection, this)) , m_mprisPlayerInterface(new MprisPlayerInterface(service, mprisObjectPath, connection, this)) , m_initedRootInterface(false) , m_initedPlayerInterface(false) , m_requestedPosition(false) , m_canControlReceived(false) { // Mpris Root Interface connect(m_mprisRootInterface, &MprisRootInterface::asyncGetAllPropertiesFinished, this, &MprisController::onAsyncGetAllRootPropertiesFinished); connect(m_mprisRootInterface, &MprisRootInterface::canQuitChanged, this, &MprisController::canQuitChanged); connect(m_mprisRootInterface, &MprisRootInterface::canRaiseChanged, this, &MprisController::canRaiseChanged); connect(m_mprisRootInterface, &MprisRootInterface::canSetFullscreenChanged, this, &MprisController::canSetFullscreenChanged); connect(m_mprisRootInterface, &MprisRootInterface::desktopEntryChanged, this, &MprisController::desktopEntryChanged); connect(m_mprisRootInterface, &MprisRootInterface::fullscreenChanged, this, &MprisController::fullscreenChanged); connect(m_mprisRootInterface, &MprisRootInterface::hasTrackListChanged, this, &MprisController::hasTrackListChanged); connect(m_mprisRootInterface, &MprisRootInterface::identityChanged, this, &MprisController::identityChanged); connect(m_mprisRootInterface, &MprisRootInterface::supportedMimeTypesChanged, this, &MprisController::supportedMimeTypesChanged); connect(m_mprisRootInterface, &MprisRootInterface::supportedUriSchemesChanged, this, &MprisController::supportedUriSchemesChanged); m_mprisRootInterface->setUseCache(true); // Mpris Player Interface connect(m_mprisPlayerInterface, &MprisPlayerInterface::asyncGetAllPropertiesFinished, this, &MprisController::onAsyncGetAllPlayerPropertiesFinished); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canControlChanged, this, &MprisController::onCanControlChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canGoNextChanged, this, &MprisController::canGoNextChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canGoPreviousChanged, this, &MprisController::canGoPreviousChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canPauseChanged, this, &MprisController::canPauseChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canPlayChanged, this, &MprisController::canPlayChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canSeekChanged, this, &MprisController::canSeekChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::canSeekChanged, this, &MprisController::canSeekChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::loopStatusChanged, this, &MprisController::loopStatusChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::maximumRateChanged, this, &MprisController::maximumRateChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::metadataChanged, this, &MprisController::metadataChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::minimumRateChanged, this, &MprisController::minimumRateChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::playbackStatusChanged, this, &MprisController::playbackStatusChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::positionChanged, this, &MprisController::onPositionChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::rateChanged, this, &MprisController::rateChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::shuffleChanged, this, &MprisController::shuffleChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::volumeChanged, this, &MprisController::volumeChanged); connect(m_mprisPlayerInterface, &MprisPlayerInterface::seeked, this, &MprisController::seeked); m_mprisPlayerInterface->setUseCache(true); // This will initialize the properties, if needed isValid(); } MprisController::~MprisController() { } bool MprisController::isValid() const { if (!m_mprisRootInterface->isValid() || !m_mprisPlayerInterface->isValid()) { m_initedRootInterface = false; m_initedPlayerInterface = false; return false; } if (!m_initedRootInterface) { m_mprisRootInterface->getAllProperties(); if (m_mprisRootInterface->lastExtendedError().isValid()) { qWarning() << Q_FUNC_INFO << "Error" << m_mprisRootInterface->lastExtendedError().name() << "happened:" << m_mprisRootInterface->lastExtendedError().message(); } } if (!m_initedPlayerInterface) { m_mprisPlayerInterface->getAllProperties(); if (m_mprisPlayerInterface->lastExtendedError().isValid()) { qWarning() << Q_FUNC_INFO << "Error" << m_mprisPlayerInterface->lastExtendedError().name() << "happened:" << m_mprisPlayerInterface->lastExtendedError().message(); } } return m_initedRootInterface && m_initedPlayerInterface; } // Mpris2 Root Interface bool MprisController::quit() { if (!canQuit()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisRootInterface->Quit(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::raise() { if (!canRaise()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisRootInterface->Raise(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } // Mpris2 Player Interface bool MprisController::next() { if (!canGoNext()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Next(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::openUri(const QUrl &uri) { if (!canControl()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } if (!uri.isValid()) { qDebug() << Q_FUNC_INFO << "The uri is invalid"; return false; } if (!m_mprisRootInterface->supportedUriSchemes().contains(uri.scheme())) { qDebug() << Q_FUNC_INFO << "The scheme is not supported"; return false; } QMimeDatabase db; QMimeType mime; if (uri.isLocalFile()) { mime = db.mimeTypeForFile(uri.toLocalFile()); } else { mime = db.mimeTypeForFile(uri.fileName(), QMimeDatabase::MatchExtension); } QStringList mimeNames = mime.aliases(); mimeNames.prepend(mime.name()); for (int i = 0; i < mimeNames.size(); i++) { if (m_mprisRootInterface->supportedMimeTypes().contains(mimeNames[i])) { QDBusPendingReply<> reply = m_mprisPlayerInterface->OpenUri(uri.toString()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } } qDebug() << Q_FUNC_INFO << "The mime type is not supported"; return false; } bool MprisController::pause() { if (!canPause()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Pause(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::play() { if (!canPlay()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Play(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::playPause() { if (!canPause()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->PlayPause(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::previous() { if (!canGoPrevious()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Previous(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::seek(qlonglong offset) { if (!canSeek()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Seek(offset); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::setPosition(qlonglong position) { if (!canSeek()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QVariant trackId = m_mprisPlayerInterface->metadata()[Mpris::metadataToString(Mpris::TrackId)]; if (!trackId.isValid()) { qDebug() << Q_FUNC_INFO << "Unknown trackId in which to set the position"; return false; } return setPosition(trackId.value().path(), position); } bool MprisController::setPosition(const QString &aTrackId, qlonglong position) { if (!canSeek()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusObjectPath trackId(aTrackId); if (trackId.path().isEmpty()) { qDebug() << Q_FUNC_INFO << "trackId doesn't map to a valid DBus object path"; return false; } QVariant length = m_mprisPlayerInterface->metadata()[Mpris::metadataToString(Mpris::Length)]; if (!length.isValid()) { qlonglong reportedLength = length.toLongLong(); if (position < 0 || position > reportedLength) { qDebug() << Q_FUNC_INFO << "Unknown trackId in which to set the position"; return false; } } QDBusPendingReply<> reply = m_mprisPlayerInterface->SetPosition(trackId, position); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } bool MprisController::stop() { if (!canControl()) { qDebug() << Q_FUNC_INFO << "The method is not allowed"; return false; } QDBusPendingReply<> reply = m_mprisPlayerInterface->Stop(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*))); return true; } // Slots QString MprisController::service() const { return m_mprisRootInterface->service(); } // Mpris2 Root Interface bool MprisController::canQuit() const { if (isValid()) { return m_mprisRootInterface->canQuit(); } return false; } bool MprisController::canRaise() const { if (isValid()) { return m_mprisRootInterface->canRaise(); } return false; } bool MprisController::canSetFullscreen() const { if (isValid()) { return m_mprisRootInterface->canSetFullscreen(); } return false; } QString MprisController::desktopEntry() const { if (isValid()) { return m_mprisRootInterface->desktopEntry(); } return QString(); } bool MprisController::fullscreen() const { if (isValid()) { return m_mprisRootInterface->fullscreen(); } return false; } void MprisController::setFullscreen(bool fullscreen) { if (isValid()) { m_mprisRootInterface->setFullscreen(fullscreen); } } bool MprisController::hasTrackList() const { if (isValid()) { return m_mprisRootInterface->hasTrackList(); } return false; } QString MprisController::identity() const { if (isValid()) { return m_mprisRootInterface->identity(); } return QString(); } QStringList MprisController::supportedUriSchemes() const { if (isValid()) { return m_mprisRootInterface->supportedUriSchemes(); } return QStringList(); } QStringList MprisController::supportedMimeTypes() const { if (isValid()) { return m_mprisRootInterface->supportedMimeTypes(); } return QStringList(); } // Mpris2 Player Interface bool MprisController::canControl() const { if (isValid()) { return m_mprisPlayerInterface->canControl(); } return false; } bool MprisController::canGoNext() const { if (isValid() && canControl()) { return m_mprisPlayerInterface->canGoNext(); } return false; } bool MprisController::canGoPrevious() const { if (isValid() && canControl()) { return m_mprisPlayerInterface->canGoPrevious(); } return false; } bool MprisController::canPause() const { if (isValid() && canControl()) { return m_mprisPlayerInterface->canPause(); } return false; } bool MprisController::canPlay() const { if (isValid() && canControl()) { return m_mprisPlayerInterface->canPlay(); } return false; } bool MprisController::canSeek() const { if (isValid() && canControl()) { return m_mprisPlayerInterface->canSeek(); } return false; } Mpris::LoopStatus MprisController::loopStatus() const { if (isValid()) { return Mpris::enumerationFromString(m_mprisPlayerInterface->loopStatus()); } return Mpris::None; } void MprisController::setLoopStatus(Mpris::LoopStatus loopStatus) { if (isValid()) { m_mprisPlayerInterface->setLoopStatus(Mpris::enumerationToString(loopStatus)); } } double MprisController::maximumRate() const { if (isValid()) { return m_mprisPlayerInterface->maximumRate(); } return 1; } QVariantMap MprisController::metadata() const { if (isValid()) { return m_mprisPlayerInterface->metadata(); } return QVariantMap(); } double MprisController::minimumRate() const { if (isValid()) { return m_mprisPlayerInterface->minimumRate(); } return 1; } Mpris::PlaybackStatus MprisController::playbackStatus() const { if (isValid()) { return Mpris::enumerationFromString(m_mprisPlayerInterface->playbackStatus()); } return Mpris::Stopped; } qlonglong MprisController::position() const { if (isValid()) { m_mprisPlayerInterface->setSync(true); m_mprisPlayerInterface->setUseCache(false); qlonglong result = m_mprisPlayerInterface->position(); m_mprisPlayerInterface->setUseCache(true); m_mprisPlayerInterface->setSync(false); return result; } return -1; } void MprisController::requestPosition() const { if (m_requestedPosition) { return; } if (isValid()) { m_mprisPlayerInterface->setUseCache(false); m_mprisPlayerInterface->position(); m_mprisPlayerInterface->setUseCache(true); if (m_mprisPlayerInterface->lastExtendedError().isValid()) { qWarning() << Q_FUNC_INFO << "Failed requesting the current position in the MPRIS2 Player Interface!!!"; return; } m_requestedPosition = true; } } double MprisController::rate() const { if (isValid()) { return m_mprisPlayerInterface->rate(); } return 1; } void MprisController::setRate(double rate) { if (isValid()) { m_mprisPlayerInterface->setRate(rate); } } bool MprisController::shuffle() const { if (isValid()) { return m_mprisPlayerInterface->shuffle(); } return false; } void MprisController::setShuffle(bool shuffle) { if (isValid()) { m_mprisPlayerInterface->setShuffle(shuffle); } } double MprisController::volume() const { if (isValid()) { return m_mprisPlayerInterface->volume(); } return 0; } void MprisController::setVolume(double volume) { if (isValid()) { m_mprisPlayerInterface->setVolume(volume); } } // Protected void MprisController::onAsyncGetAllRootPropertiesFinished() { if (m_mprisRootInterface->lastExtendedError().isValid()) { qWarning() << Q_FUNC_INFO << "Error" << m_mprisRootInterface->lastExtendedError().name() << "happened:" << m_mprisRootInterface->lastExtendedError().message(); return; } m_initedRootInterface = true; } void MprisController::onAsyncGetAllPlayerPropertiesFinished() { if (m_mprisPlayerInterface->lastExtendedError().isValid()) { qWarning() << Q_FUNC_INFO << "Error" << m_mprisPlayerInterface->lastExtendedError().name() << "happened:" << m_mprisPlayerInterface->lastExtendedError().message(); return; } m_initedPlayerInterface = true; } void MprisController::onCanControlChanged() { // On first reception, we are using a "GetAll" so we can skip this if (m_canControlReceived) { // I could disconnect and re-connect the signals so I avoid // double arriving signals but this really shouldn't happen // ever. emit canGoNextChanged(); emit canGoPreviousChanged(); emit canPauseChanged(); emit canPlayChanged(); emit canSeekChanged(); qWarning() << Q_FUNC_INFO << "CanControl is not supposed to change its value!"; return; } m_canControlReceived = true; } void MprisController::onPositionChanged(qlonglong aPosition) { m_requestedPosition = false; emit positionChanged(aPosition); } // Private void MprisController::onFinishedPendingCall(QDBusPendingCallWatcher *call) { QDBusPendingReply<> reply = *call; if (reply.isError()) { qWarning() << Q_FUNC_INFO << "Error" << reply.error().name() << "happened:" << reply.error().message(); } call->deleteLater(); } qtmpris-0.1.0/src/mpriscontroller.h000066400000000000000000000145251331514374100174160ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRISCONTROLLER_H #define MPRISCONTROLLER_H #include #include #include #include #include #include #include #include #include #include #include class MprisRootInterface; class MprisPlayerInterface; class QDBusPendingCallWatcher; class MPRIS_QT_EXPORT MprisController : public QObject { Q_OBJECT Q_PROPERTY(QString service READ service) // Mpris2 Root Interface Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged) Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged) Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged) Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged) Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) Q_PROPERTY(bool hasTrackList READ hasTrackList NOTIFY hasTrackListChanged) Q_PROPERTY(QString identity READ identity NOTIFY identityChanged) Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged) Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged) // Mpris2 Player Interface Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged) Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged) Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged) Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged) Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged) Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged) Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged) Q_PROPERTY(double maximumRate READ maximumRate NOTIFY maximumRateChanged) Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged) Q_PROPERTY(double minimumRate READ minimumRate NOTIFY minimumRateChanged) Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus NOTIFY playbackStatusChanged) Q_PROPERTY(qlonglong position READ position) Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged) Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged) Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged) public: MprisController(const QString &service, const QDBusConnection &connection, QObject *parent = 0); ~MprisController(); bool isValid() const; // Mpris2 Root Interface bool quit(); bool raise(); // Mpris2 Player Interface bool next(); bool openUri(const QUrl &uri); bool pause(); bool play(); bool playPause(); bool previous(); bool seek(qlonglong offset); bool setPosition(qlonglong position); bool setPosition(const QString &aTrackId, qlonglong position); bool stop(); public slots: QString service() const; // Mpris2 Root Interface bool canQuit() const; bool canRaise() const; bool canSetFullscreen() const; QString desktopEntry() const; bool fullscreen() const; void setFullscreen(bool fullscreen); bool hasTrackList() const; QString identity() const; QStringList supportedUriSchemes() const; QStringList supportedMimeTypes() const; // Mpris2 Player Interface bool canControl() const; bool canGoNext() const; bool canGoPrevious() const; bool canPause() const; bool canPlay() const; bool canSeek() const; Mpris::LoopStatus loopStatus() const; void setLoopStatus(Mpris::LoopStatus loopStatus); double maximumRate() const; QVariantMap metadata() const; double minimumRate() const; Mpris::PlaybackStatus playbackStatus() const; qlonglong position() const; void requestPosition() const; double rate() const; void setRate(double rate); bool shuffle() const; void setShuffle(bool shuffle); double volume() const; void setVolume(double volume); signals: // Mpris2 Root Interface void canQuitChanged(); void canRaiseChanged(); void canSetFullscreenChanged(); void desktopEntryChanged(); void fullscreenChanged(); void hasTrackListChanged(); void identityChanged(); void supportedUriSchemesChanged(); void supportedMimeTypesChanged(); // Mpris2 Player Interface void canControlChanged(); void canGoNextChanged(); void canGoPreviousChanged(); void canPauseChanged(); void canPlayChanged(); void canSeekChanged(); void loopStatusChanged(); void maximumRateChanged(); void metadataChanged(); void minimumRateChanged(); void playbackStatusChanged(); void positionChanged(qlonglong position); void rateChanged(); void shuffleChanged(); void volumeChanged(); void seeked(qlonglong position); protected Q_SLOTS: void onAsyncGetAllRootPropertiesFinished(); void onAsyncGetAllPlayerPropertiesFinished(); void onCanControlChanged(); void onPositionChanged(qlonglong aPosition); void onFinishedPendingCall(QDBusPendingCallWatcher *call); private: MprisRootInterface *m_mprisRootInterface; MprisPlayerInterface *m_mprisPlayerInterface; mutable bool m_initedRootInterface; mutable bool m_initedPlayerInterface; mutable bool m_requestedPosition; bool m_canControlReceived; }; #endif /* MPRISCONTROLLER_H */ qtmpris-0.1.0/src/mpriscontroller_p.h000066400000000000000000000276201331514374100177350ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // // W A R N I N G // ------------- // // This file is not part of the public API. This header file may // change from version to version without notice, or even be // removed. // // We mean it. // // #ifndef MPRISCONTROLLER_P_H #define MPRISCONTROLLER_P_H #include #include #include #include #include #include #include #include #include /* * Proxy class for interface org.mpris.MediaPlayer2 */ class MprisRootInterface: public DBusExtendedAbstractInterface { Q_OBJECT public: static inline const char *staticInterfaceName() { return "org.mpris.MediaPlayer2"; } public: MprisRootInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); ~MprisRootInterface(); Q_PROPERTY(bool CanQuit READ canQuit NOTIFY canQuitChanged) inline bool canQuit() { return qvariant_cast< bool >(internalPropGet("CanQuit", &m_canQuit)); } Q_PROPERTY(bool CanRaise READ canRaise NOTIFY canRaiseChanged) inline bool canRaise() { return qvariant_cast< bool >(internalPropGet("CanRaise", &m_canRaise)); } Q_PROPERTY(bool CanSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged) inline bool canSetFullscreen() { return qvariant_cast< bool >(internalPropGet("CanSetFullscreen", &m_canSetFullscreen)); } Q_PROPERTY(QString DesktopEntry READ desktopEntry NOTIFY desktopEntryChanged) inline QString desktopEntry() { return qvariant_cast< QString >(internalPropGet("DesktopEntry", &m_desktopEntry)); } Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) inline bool fullscreen() { return qvariant_cast< bool >(internalPropGet("Fullscreen", &m_fullscreen)); } inline void setFullscreen(bool value) { m_fullscreen = value; internalPropSet("Fullscreen", QVariant::fromValue(value), &m_fullscreen); } Q_PROPERTY(bool HasTrackList READ hasTrackList NOTIFY hasTrackListChanged) inline bool hasTrackList() { return qvariant_cast< bool >(internalPropGet("HasTrackList", &m_hasTrackList)); } Q_PROPERTY(QString Identity READ identity NOTIFY identityChanged) inline QString identity() { return qvariant_cast< QString >(internalPropGet("Identity", &m_identity)); } Q_PROPERTY(QStringList SupportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged) inline QStringList supportedMimeTypes() { return qvariant_cast< QStringList >(internalPropGet("SupportedMimeTypes", &m_supportedMimeTypes)); } Q_PROPERTY(QStringList SupportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged) inline QStringList supportedUriSchemes() { return qvariant_cast< QStringList >(internalPropGet("SupportedUriSchemes", &m_supportedUriSchemes)); } public Q_SLOTS: // METHODS inline QDBusPendingReply<> Quit() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Quit"), argumentList); } inline QDBusPendingReply<> Raise() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Raise"), argumentList); } Q_SIGNALS: // SIGNALS void canQuitChanged(bool canQuit); void canRaiseChanged(bool canRaise); void canSetFullscreenChanged(bool canSetFullscreen); void desktopEntryChanged(const QString &desktopEntry); void fullscreenChanged(bool fullscreen); void hasTrackListChanged(bool hasTrackList); void identityChanged(const QString &identity); void supportedMimeTypesChanged(const QStringList &supportedMimeTypes); void supportedUriSchemesChanged(const QStringList &supportedUriSchemes); private Q_SLOTS: void onPropertyChanged(const QString &propertyName, const QVariant &value); private: bool m_canQuit; bool m_canRaise; bool m_canSetFullscreen; QString m_desktopEntry; bool m_fullscreen; bool m_hasTrackList; QString m_identity; QStringList m_supportedUriSchemes; QStringList m_supportedMimeTypes; }; namespace org { namespace mpris { typedef ::MprisRootInterface MediaPlayer2; } } /* * Proxy class for interface org.mpris.MediaPlayer2 */ class MprisPlayerInterface: public DBusExtendedAbstractInterface { Q_OBJECT public: static inline const char *staticInterfaceName() { return "org.mpris.MediaPlayer2.Player"; } public: MprisPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); ~MprisPlayerInterface(); Q_PROPERTY(bool CanControl READ canControl NOTIFY canControlChanged) inline bool canControl() { return qvariant_cast< bool >(internalPropGet("CanControl", &m_canControl)); } Q_PROPERTY(bool CanGoNext READ canGoNext NOTIFY canGoNextChanged) inline bool canGoNext() { return qvariant_cast< bool >(internalPropGet("CanGoNext", &m_canGoNext)); } Q_PROPERTY(bool CanGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged) inline bool canGoPrevious() { return qvariant_cast< bool >(internalPropGet("CanGoPrevious", &m_canGoPrevious)); } Q_PROPERTY(bool CanPause READ canPause NOTIFY canPauseChanged) inline bool canPause() { return qvariant_cast< bool >(internalPropGet("CanPause", &m_canPause)); } Q_PROPERTY(bool CanPlay READ canPlay NOTIFY canPlayChanged) inline bool canPlay() { return qvariant_cast< bool >(internalPropGet("CanPlay", &m_canPlay)); } Q_PROPERTY(bool CanSeek READ canSeek NOTIFY canSeekChanged) inline bool canSeek() { return qvariant_cast< bool >(internalPropGet("CanSeek", &m_canSeek)); } Q_PROPERTY(QString LoopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged) inline QString loopStatus() { return qvariant_cast< QString >(internalPropGet("LoopStatus", &m_loopStatus)); } inline void setLoopStatus(const QString &value) { m_loopStatus = value; internalPropSet("LoopStatus", QVariant::fromValue(value), &m_loopStatus); } Q_PROPERTY(double MaximumRate READ maximumRate NOTIFY maximumRateChanged) inline double maximumRate() { return qvariant_cast< double >(internalPropGet("MaximumRate", &m_maximumRate)); } Q_PROPERTY(QVariantMap Metadata READ metadata NOTIFY metadataChanged) inline QVariantMap metadata() { return qvariant_cast< QVariantMap >(internalPropGet("Metadata", &m_metadata)); } Q_PROPERTY(double MinimumRate READ minimumRate NOTIFY minimumRateChanged) inline double minimumRate() { return qvariant_cast< double >(internalPropGet("MinimumRate", &m_minimumRate)); } Q_PROPERTY(QString PlaybackStatus READ playbackStatus NOTIFY playbackStatusChanged) inline QString playbackStatus() { return qvariant_cast< QString >(internalPropGet("PlaybackStatus", &m_playbackStatus)); } Q_PROPERTY(qlonglong Position READ position NOTIFY positionChanged) inline qlonglong position() { return qvariant_cast< qlonglong >(internalPropGet("Position", &m_position)); } Q_PROPERTY(double Rate READ rate WRITE setRate NOTIFY rateChanged) inline double rate() { return qvariant_cast< double >(internalPropGet("Rate", &m_rate)); } inline void setRate(double value) { m_rate = value; internalPropSet("Rate", QVariant::fromValue(value), &m_rate); } Q_PROPERTY(bool Shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged) inline bool shuffle() { return qvariant_cast< bool >(internalPropGet("Shuffle", &m_shuffle)); } inline void setShuffle(bool value) { m_shuffle = value; internalPropSet("Shuffle", QVariant::fromValue(value), &m_shuffle); } Q_PROPERTY(double Volume READ volume WRITE setVolume NOTIFY volumeChanged) inline double volume() { return qvariant_cast< double >(internalPropGet("Volume", &m_volume)); } inline void setVolume(double value) { m_volume = value; internalPropSet("Volume", QVariant::fromValue(value), &m_volume); } public Q_SLOTS: // METHODS inline QDBusPendingReply<> Next() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Next"), argumentList); } inline QDBusPendingReply<> OpenUri(const QString &Uri) { QList argumentList; argumentList << QVariant::fromValue(Uri); return asyncCallWithArgumentList(QLatin1String("OpenUri"), argumentList); } inline QDBusPendingReply<> Pause() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Pause"), argumentList); } inline QDBusPendingReply<> Play() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Play"), argumentList); } inline QDBusPendingReply<> PlayPause() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("PlayPause"), argumentList); } inline QDBusPendingReply<> Previous() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Previous"), argumentList); } inline QDBusPendingReply<> Seek(qlonglong Offset) { QList argumentList; argumentList << QVariant::fromValue(Offset); return asyncCallWithArgumentList(QLatin1String("Seek"), argumentList); } inline QDBusPendingReply<> SetPosition(const QDBusObjectPath &TrackId, qlonglong Position) { QList argumentList; argumentList << QVariant::fromValue(TrackId) << QVariant::fromValue(Position); return asyncCallWithArgumentList(QLatin1String("SetPosition"), argumentList); } inline QDBusPendingReply<> Stop() { QList argumentList; return asyncCallWithArgumentList(QLatin1String("Stop"), argumentList); } Q_SIGNALS: // SIGNALS void canControlChanged(bool canControl); void canGoNextChanged(bool canGoNext); void canGoPreviousChanged(bool canGoPrevious); void canPauseChanged(bool canPause); void canPlayChanged(bool canPlay); void canSeekChanged(bool canSeek); void loopStatusChanged(const QString &loopStatus); void maximumRateChanged(double maximumRate); void metadataChanged(const QVariantMap &metadata); void minimumRateChanged(double minimumRate); void playbackStatusChanged(const QString &playbackStatus); void positionChanged(qlonglong rate); void rateChanged(double rate); void shuffleChanged(bool shuffle); void volumeChanged(double volume); void seeked(qlonglong Position); private Q_SLOTS: void onPropertyChanged(const QString &propertyName, const QVariant &value); private: bool m_canControl; bool m_canGoNext; bool m_canGoPrevious; bool m_canPause; bool m_canPlay; bool m_canSeek; QString m_loopStatus; double m_maximumRate; QVariantMap m_metadata; double m_minimumRate; QString m_playbackStatus; qlonglong m_position; double m_rate; bool m_shuffle; double m_volume; }; namespace MediaPlayer2 { typedef ::MprisPlayerInterface Player; } #endif /* MPRISROOTINTERFACE_P_H */ qtmpris-0.1.0/src/mprismanager.cpp000066400000000000000000000521641331514374100172010ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mprismanager.h" #include "mpriscontroller.h" #include #include #include #include static const QString mprisNameSpace = QStringLiteral("org.mpris.MediaPlayer2.*"); static const QString dBusService = QStringLiteral("org.freedesktop.DBus"); static const QString dBusObjectPath = QStringLiteral("/org/freedesktop/DBus"); static const QString dBusInterface = QStringLiteral("org.freedesktop.DBus"); static const QString dBusNameOwnerChangedSignal = QStringLiteral("NameOwnerChanged"); MprisManager::MprisManager(QObject *parent) : QObject(parent) , m_singleService(false) , m_playbackStatusMapper(new QSignalMapper(this)) { QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.isConnected()) { qmlInfo(this) << "Failed attempting to connect to DBus"; return; } connection.connect(dBusService, dBusObjectPath, dBusInterface, dBusNameOwnerChangedSignal, QStringList(), QString(), this, SLOT(onNameOwnerChanged(QString, QString, QString))); QStringList serviceNames = connection.interface()->registeredServiceNames(); QStringList::const_iterator i = serviceNames.constBegin(); while (i != serviceNames.constEnd()) { QRegExp rx(mprisNameSpace); rx.setPatternSyntax(QRegExp::Wildcard); if (rx.exactMatch(*i)) { onServiceAppeared(*i); } ++i; } } MprisManager::~MprisManager() { } // Mpris2 Root Interface bool MprisManager::quit() const { return checkController(Q_FUNC_INFO) && m_currentController->quit(); } bool MprisManager::raise() const { return checkController(Q_FUNC_INFO) && m_currentController->raise(); } // Mpris2 Player Interface bool MprisManager::next() const { return checkController(Q_FUNC_INFO) && m_currentController->next(); } bool MprisManager::openUri(const QUrl &uri) const { return checkController(Q_FUNC_INFO) && m_currentController->openUri(uri); } bool MprisManager::pause() const { return checkController(Q_FUNC_INFO) && m_currentController->pause(); } bool MprisManager::play() const { return checkController(Q_FUNC_INFO) && m_currentController->play(); } bool MprisManager::playPause() const { return checkController(Q_FUNC_INFO) && m_currentController->playPause(); } bool MprisManager::previous() const { return checkController(Q_FUNC_INFO) && m_currentController->previous(); } bool MprisManager::seek(qlonglong offset) const { return checkController(Q_FUNC_INFO) && m_currentController->seek(offset); } bool MprisManager::setPosition(qlonglong position) const { return checkController(Q_FUNC_INFO) && m_currentController->setPosition(position); } bool MprisManager::setPosition(const QString &trackId, qlonglong position) const { return checkController(Q_FUNC_INFO) && m_currentController->setPosition(trackId, position); } bool MprisManager::stop() const { return checkController(Q_FUNC_INFO) && m_currentController->stop(); } // Slots bool MprisManager::singleService() const { return m_singleService; } void MprisManager::setSingleService(bool single) { if (m_singleService == single) { return; } m_singleService = single; emit singleServiceChanged(); } QString MprisManager::currentService() const { return m_currentController.isNull() ? QString() : m_currentController->service(); } void MprisManager::setCurrentService(const QString &service) { if (!m_currentController.isNull() && m_currentController->service() == service) { return; } QRegExp rx(mprisNameSpace); rx.setPatternSyntax(QRegExp::Wildcard); if (!rx.exactMatch(service)) { qmlInfo(this) << service << "is not a proper Mpris2 service"; return; } QSharedPointer controller = availableController(service); if (controller.isNull()) { controller = QSharedPointer(new MprisController(service, QDBusConnection::sessionBus(), this)); } else { m_availableControllers.move(m_availableControllers.indexOf(controller), 0); } setCurrentController(controller); } QStringList MprisManager::availableServices() const { QStringList result; QList< QSharedPointer >::const_iterator i = m_availableControllers.constBegin(); while (i != m_availableControllers.constEnd()) { const QSharedPointer controller = *i; result.append(controller->service()); ++i; } return result; } // Mpris2 Root Interface bool MprisManager::canQuit() const { return checkController(Q_FUNC_INFO) && m_currentController->canQuit(); } bool MprisManager::canRaise() const { return checkController(Q_FUNC_INFO) && m_currentController->canRaise(); } bool MprisManager::canSetFullscreen() const { return checkController(Q_FUNC_INFO) && m_currentController->canSetFullscreen(); } QString MprisManager::desktopEntry() const { return checkController(Q_FUNC_INFO) ? m_currentController->desktopEntry() : QString(); } bool MprisManager::fullscreen() const { return checkController(Q_FUNC_INFO) && m_currentController->fullscreen(); } void MprisManager::setFullscreen(bool fullscreen) { if (checkController(Q_FUNC_INFO)) { m_currentController->setFullscreen(fullscreen); } } bool MprisManager::hasTrackList() const { return checkController(Q_FUNC_INFO) && m_currentController->hasTrackList(); } QString MprisManager::identity() const { return checkController(Q_FUNC_INFO) ? m_currentController->identity() : QString(); } QStringList MprisManager::supportedUriSchemes() const { return checkController(Q_FUNC_INFO) ? m_currentController->supportedUriSchemes() : QStringList(); } QStringList MprisManager::supportedMimeTypes() const { return checkController(Q_FUNC_INFO) ? m_currentController->supportedMimeTypes() : QStringList(); } // Mpris2 Player Interface bool MprisManager::canControl() const { return checkController(Q_FUNC_INFO) && m_currentController->canControl(); } bool MprisManager::canGoNext() const { return checkController(Q_FUNC_INFO) && m_currentController->canGoNext(); } bool MprisManager::canGoPrevious() const { return checkController(Q_FUNC_INFO) && m_currentController->canGoPrevious(); } bool MprisManager::canPause() const { return checkController(Q_FUNC_INFO) && m_currentController->canPause(); } bool MprisManager::canPlay() const { return checkController(Q_FUNC_INFO) && m_currentController->canPlay(); } bool MprisManager::canSeek() const { return checkController(Q_FUNC_INFO) && m_currentController->canSeek(); } Mpris::LoopStatus MprisManager::loopStatus() const { return checkController(Q_FUNC_INFO) ? m_currentController->loopStatus() : Mpris::None; } void MprisManager::setLoopStatus(Mpris::LoopStatus loopStatus) { if (checkController(Q_FUNC_INFO)) { m_currentController->setLoopStatus(loopStatus); } } double MprisManager::maximumRate() const { return checkController(Q_FUNC_INFO) ? m_currentController->maximumRate() : 1; } QVariantMap MprisManager::metadata() const { return checkController(Q_FUNC_INFO) ? m_currentController->metadata() : QVariantMap(); } double MprisManager::minimumRate() const { return checkController(Q_FUNC_INFO) ? m_currentController->minimumRate() : 1; } Mpris::PlaybackStatus MprisManager::playbackStatus() const { return checkController(Q_FUNC_INFO) ? m_currentController->playbackStatus() : Mpris::Stopped; } qlonglong MprisManager::position() const { return checkController(Q_FUNC_INFO) ? m_currentController->position() : 0; } void MprisManager::requestPosition() const { if (checkController(Q_FUNC_INFO)) { m_currentController->requestPosition(); } } double MprisManager::rate() const { return checkController(Q_FUNC_INFO) ? m_currentController->rate() : 1; } void MprisManager::setRate(double rate) { if (checkController(Q_FUNC_INFO)) { m_currentController->setRate(rate); } } bool MprisManager::shuffle() const { return checkController(Q_FUNC_INFO) && m_currentController->shuffle(); } void MprisManager::setShuffle(bool shuffle) { if (checkController(Q_FUNC_INFO)) { m_currentController->setShuffle(shuffle); } } double MprisManager::volume() const { return checkController(Q_FUNC_INFO) ? m_currentController->volume() : 0; } void MprisManager::setVolume(double volume) { if (checkController(Q_FUNC_INFO)) { m_currentController->setVolume(volume); } } // Private void MprisManager::onNameOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner) { // Unfortunately, QDBus doesn't allow flexible signal watchers. // Would it allow them, we could pass the filter "arg0namespace='org.mpris.MediaPlayer2'" // Therefore, we will receive here all the name changes in the // bus, not just the ones for our name space of interest, and we // will have to filter on our own :( QRegExp rx(mprisNameSpace); rx.setPatternSyntax(QRegExp::Wildcard); if (!rx.exactMatch(service)) { return; } if (oldOwner.isEmpty()) { onServiceAppeared(service); return; } if (newOwner.isEmpty()) { onServiceVanished(service); return; } // Service changed owner. Nothing to do ... } void MprisManager::onServiceAppeared(const QString &service) { QSharedPointer controller = availableController(service); if (!controller.isNull()) { Q_ASSERT(m_availableControllers.contains(controller)); m_availableControllers.removeOne(controller); m_otherPlayingControllers.removeOne(controller); } else { if (!m_currentController.isNull() && service == m_currentController->service()) { controller = m_currentController; } else { controller = QSharedPointer(new MprisController(service, QDBusConnection::sessionBus(), this)); } connect(controller.data(), SIGNAL(playbackStatusChanged()), m_playbackStatusMapper, SLOT(map())); m_playbackStatusMapper->setMapping(controller.data(), controller->service()); connect(m_playbackStatusMapper, SIGNAL(mapped(QString)), this, SLOT(onAvailableControllerPlaybackStatusChanged(QString))); } if (m_currentController.isNull()) { setCurrentController(controller); } if (controller == m_currentController) { m_availableControllers.prepend(controller); emit availableServicesChanged(); return; } if (!m_singleService && m_currentController->playbackStatus() != Mpris::Playing) { m_availableControllers.prepend(controller); setCurrentController(controller); } else { m_availableControllers.insert(1, controller); if (controller->playbackStatus() == Mpris::Playing) { m_otherPlayingControllers.prepend(controller); } } emit availableServicesChanged(); } void MprisManager::onServiceVanished(const QString &service) { QSharedPointer controller = availableController(service); if (!controller.isNull()) { Q_ASSERT(m_availableControllers.contains(controller)); m_availableControllers.removeOne(controller); m_otherPlayingControllers.removeOne(controller); } if (!m_currentController.isNull() && service == m_currentController->service()) { if (m_singleService) { emit availableServicesChanged(); return; } if (!m_availableControllers.isEmpty()) { setCurrentController(m_availableControllers[0]); } else { setCurrentController(QSharedPointer()); } } emit availableServicesChanged(); } void MprisManager::onAvailableControllerPlaybackStatusChanged(const QString &service) { QSharedPointer controller = availableController(service); Q_ASSERT(!controller.isNull()); if (m_currentController == controller) { if (m_currentController->playbackStatus() == Mpris::Playing) { return; } if (!m_otherPlayingControllers.isEmpty()) { QSharedPointer currentController = m_otherPlayingControllers.takeFirst(); m_availableControllers.move(m_availableControllers.indexOf(currentController), 0); setCurrentController(currentController); } } else { if (controller->playbackStatus() != Mpris::Playing) { m_otherPlayingControllers.removeOne(controller); return; } if (!m_singleService && m_currentController->playbackStatus() != Mpris::Playing) { setCurrentController(controller); } else { m_availableControllers.move(m_availableControllers.indexOf(controller), 1); m_otherPlayingControllers.removeOne(controller); // Just in case, shouldn't be needed m_otherPlayingControllers.prepend(controller); } } } QSharedPointer MprisManager::availableController(const QString &service) { QList< QSharedPointer >::iterator i = m_availableControllers.begin(); while (i != m_availableControllers.end()) { QSharedPointer controller = *i; if (!controller.isNull() && controller->service() == service) { return controller; } ++i; } return QSharedPointer(); } void MprisManager::setCurrentController(QSharedPointer controller) { if (controller == m_currentController) { return; } if (!m_currentController.isNull()) { // Mpris Root Interface disconnect(m_currentController.data(), &MprisController::canQuitChanged, this, &MprisManager::canQuitChanged); disconnect(m_currentController.data(), &MprisController::canRaiseChanged, this, &MprisManager::canRaiseChanged); disconnect(m_currentController.data(), &MprisController::canSetFullscreenChanged, this, &MprisManager::canSetFullscreenChanged); disconnect(m_currentController.data(), &MprisController::desktopEntryChanged, this, &MprisManager::desktopEntryChanged); disconnect(m_currentController.data(), &MprisController::fullscreenChanged, this, &MprisManager::fullscreenChanged); disconnect(m_currentController.data(), &MprisController::hasTrackListChanged, this, &MprisManager::hasTrackListChanged); disconnect(m_currentController.data(), &MprisController::identityChanged, this, &MprisManager::identityChanged); disconnect(m_currentController.data(), &MprisController::supportedUriSchemesChanged, this, &MprisManager::supportedUriSchemesChanged); disconnect(m_currentController.data(), &MprisController::supportedMimeTypesChanged, this, &MprisManager::supportedMimeTypesChanged); // Mpris Player Interface disconnect(m_currentController.data(), &MprisController::canControlChanged, this, &MprisManager::canControlChanged); disconnect(m_currentController.data(), &MprisController::canGoNextChanged, this, &MprisManager::canGoNextChanged); disconnect(m_currentController.data(), &MprisController::canGoPreviousChanged, this, &MprisManager::canGoPreviousChanged); disconnect(m_currentController.data(), &MprisController::canPauseChanged, this, &MprisManager::canPauseChanged); disconnect(m_currentController.data(), &MprisController::canPlayChanged, this, &MprisManager::canPlayChanged); disconnect(m_currentController.data(), &MprisController::canSeekChanged, this, &MprisManager::canSeekChanged); disconnect(m_currentController.data(), &MprisController::loopStatusChanged, this, &MprisManager::loopStatusChanged); disconnect(m_currentController.data(), &MprisController::maximumRateChanged, this, &MprisManager::maximumRateChanged); disconnect(m_currentController.data(), &MprisController::metadataChanged, this, &MprisManager::metadataChanged); disconnect(m_currentController.data(), &MprisController::minimumRateChanged, this, &MprisManager::minimumRateChanged); disconnect(m_currentController.data(), &MprisController::playbackStatusChanged, this, &MprisManager::playbackStatusChanged); disconnect(m_currentController.data(), &MprisController::positionChanged, this, &MprisManager::positionChanged); disconnect(m_currentController.data(), &MprisController::rateChanged, this, &MprisManager::rateChanged); disconnect(m_currentController.data(), &MprisController::shuffleChanged, this, &MprisManager::shuffleChanged); disconnect(m_currentController.data(), &MprisController::volumeChanged, this, &MprisManager::volumeChanged); disconnect(m_currentController.data(), &MprisController::seeked, this, &MprisManager::seeked); if (m_currentController->playbackStatus() == Mpris::Playing) { m_otherPlayingControllers.prepend(m_currentController); } } m_currentController = controller; if (!m_currentController.isNull()) { // Mpris Root Interface connect(m_currentController.data(), &MprisController::canQuitChanged, this, &MprisManager::canQuitChanged); connect(m_currentController.data(), &MprisController::canRaiseChanged, this, &MprisManager::canRaiseChanged); connect(m_currentController.data(), &MprisController::canSetFullscreenChanged, this, &MprisManager::canSetFullscreenChanged); connect(m_currentController.data(), &MprisController::desktopEntryChanged, this, &MprisManager::desktopEntryChanged); connect(m_currentController.data(), &MprisController::fullscreenChanged, this, &MprisManager::fullscreenChanged); connect(m_currentController.data(), &MprisController::hasTrackListChanged, this, &MprisManager::hasTrackListChanged); connect(m_currentController.data(), &MprisController::identityChanged, this, &MprisManager::identityChanged); connect(m_currentController.data(), &MprisController::supportedUriSchemesChanged, this, &MprisManager::supportedUriSchemesChanged); connect(m_currentController.data(), &MprisController::supportedMimeTypesChanged, this, &MprisManager::supportedMimeTypesChanged); connect(m_currentController.data(), &MprisController::canControlChanged, this, &MprisManager::canControlChanged); // Mpris Player Interface connect(m_currentController.data(), &MprisController::canGoNextChanged, this, &MprisManager::canGoNextChanged); connect(m_currentController.data(), &MprisController::canGoPreviousChanged, this, &MprisManager::canGoPreviousChanged); connect(m_currentController.data(), &MprisController::canPauseChanged, this, &MprisManager::canPauseChanged); connect(m_currentController.data(), &MprisController::canPlayChanged, this, &MprisManager::canPlayChanged); connect(m_currentController.data(), &MprisController::canSeekChanged, this, &MprisManager::canSeekChanged); connect(m_currentController.data(), &MprisController::loopStatusChanged, this, &MprisManager::loopStatusChanged); connect(m_currentController.data(), &MprisController::maximumRateChanged, this, &MprisManager::maximumRateChanged); connect(m_currentController.data(), &MprisController::metadataChanged, this, &MprisManager::metadataChanged); connect(m_currentController.data(), &MprisController::minimumRateChanged, this, &MprisManager::minimumRateChanged); connect(m_currentController.data(), &MprisController::playbackStatusChanged, this, &MprisManager::playbackStatusChanged); connect(m_currentController.data(), &MprisController::rateChanged, this, &MprisManager::rateChanged); connect(m_currentController.data(), &MprisController::shuffleChanged, this, &MprisManager::shuffleChanged); connect(m_currentController.data(), &MprisController::volumeChanged, this, &MprisManager::volumeChanged); connect(m_currentController.data(), &MprisController::seeked, this, &MprisManager::seeked); if (m_currentController->playbackStatus() == Mpris::Playing) { m_otherPlayingControllers.removeOne(m_currentController); } } emit currentServiceChanged(); } bool MprisManager::checkController(const char *callerName) const { if (m_currentController.isNull()) { qWarning() << callerName << "None service available/selected"; return false; } return true; } qtmpris-0.1.0/src/mprismanager.h000066400000000000000000000163701331514374100166450ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRISMANAGER_H #define MPRISMANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include class QSignalMapper; class MPRIS_QT_EXPORT MprisManager : public QObject { Q_OBJECT Q_PROPERTY(bool singleService READ singleService WRITE setSingleService NOTIFY singleServiceChanged) Q_PROPERTY(QString currentService READ currentService WRITE setCurrentService NOTIFY currentServiceChanged) Q_PROPERTY(QStringList availableServices READ availableServices NOTIFY availableServicesChanged) // Mpris2 Root Interface Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged) Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged) Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged) Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged) Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) Q_PROPERTY(bool hasTrackList READ hasTrackList NOTIFY hasTrackListChanged) Q_PROPERTY(QString identity READ identity NOTIFY identityChanged) Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged) Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged) // Mpris2 Player Interface Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged) Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged) Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged) Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged) Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged) Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged) Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged) Q_PROPERTY(double maximumRate READ maximumRate NOTIFY maximumRateChanged) Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged) Q_PROPERTY(double minimumRate READ minimumRate NOTIFY minimumRateChanged) Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus NOTIFY playbackStatusChanged) Q_PROPERTY(qlonglong position READ position) Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged) Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged) Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged) public: MprisManager(QObject *parent = 0); ~MprisManager(); // Mpris2 Root Interface Q_INVOKABLE bool quit() const; Q_INVOKABLE bool raise() const; // Mpris2 Player Interface Q_INVOKABLE bool next() const; Q_INVOKABLE bool openUri(const QUrl &uri) const; Q_INVOKABLE bool pause() const; Q_INVOKABLE bool play() const; Q_INVOKABLE bool playPause() const; Q_INVOKABLE bool previous() const; Q_INVOKABLE bool seek(qlonglong offset) const; Q_INVOKABLE bool setPosition(qlonglong position) const; Q_INVOKABLE bool setPosition(const QString &trackId, qlonglong position) const; Q_INVOKABLE bool stop() const; public slots: bool singleService() const; void setSingleService(bool single); QString currentService() const; void setCurrentService(const QString &service); QStringList availableServices() const; // Mpris2 Root Interface bool canQuit() const; bool canRaise() const; bool canSetFullscreen() const; QString desktopEntry() const; bool fullscreen() const; void setFullscreen(bool fullscreen); bool hasTrackList() const; QString identity() const; QStringList supportedUriSchemes() const; QStringList supportedMimeTypes() const; // Mpris2 Player Interface bool canControl() const; bool canGoNext() const; bool canGoPrevious() const; bool canPause() const; bool canPlay() const; bool canSeek() const; Mpris::LoopStatus loopStatus() const; void setLoopStatus(Mpris::LoopStatus loopStatus); double maximumRate() const; QVariantMap metadata() const; double minimumRate() const; Mpris::PlaybackStatus playbackStatus() const; qlonglong position() const; void requestPosition() const; double rate() const; void setRate(double rate); bool shuffle() const; void setShuffle(bool shuffle); double volume() const; void setVolume(double volume); signals: void singleServiceChanged(); void currentServiceChanged(); void availableServicesChanged(); // Mpris2 Root Interface void canQuitChanged(); void canRaiseChanged(); void canSetFullscreenChanged(); void desktopEntryChanged(); void fullscreenChanged(); void hasTrackListChanged(); void identityChanged(); void supportedUriSchemesChanged(); void supportedMimeTypesChanged(); // Mpris2 Player Interface void canControlChanged(); void canGoNextChanged(); void canGoPreviousChanged(); void canPauseChanged(); void canPlayChanged(); void canSeekChanged(); void loopStatusChanged(); void maximumRateChanged(); void metadataChanged(); void minimumRateChanged(); void playbackStatusChanged(); void positionChanged(qlonglong position); void rateChanged(); void shuffleChanged(); void volumeChanged(); void seeked(qlonglong position); private Q_SLOTS: void onNameOwnerChanged(const QString &service, const QString &oldOwner, const QString& newOwner); void onServiceAppeared(const QString &service); void onServiceVanished(const QString &service); void onAvailableControllerPlaybackStatusChanged(const QString &service); private: QSharedPointer availableController(const QString &service); void setCurrentController(QSharedPointer controller); bool checkController(const char *callerName) const; bool m_singleService; QSharedPointer m_currentController; QList< QSharedPointer > m_availableControllers; QList< QSharedPointer > m_otherPlayingControllers; QSignalMapper *m_playbackStatusMapper; }; #endif /* MPRISMANAGER_H */ qtmpris-0.1.0/src/mprisplayer.cpp000066400000000000000000000311221331514374100170520ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mprisplayer.h" #include "mprisplayer_p.h" #include #include #include #include #include #include static const QString serviceNamePrefix = QStringLiteral("org.mpris.MediaPlayer2."); static const QString mprisObjectPath = QStringLiteral("/org/mpris/MediaPlayer2"); static const QString dBusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties"); static const QString dBusPropertiesChangedSignal = QStringLiteral("PropertiesChanged"); MprisPlayer::MprisPlayer(QObject *parent) : QObject(parent) , QDBusContext() , m_mprisRootAdaptor(new MprisRootAdaptor(this)) , m_mprisPlayerAdaptor(new MprisPlayerAdaptor(this)) , m_canQuit(false) , m_canRaise(false) , m_canSetFullscreen(false) , m_fullscreen(false) , m_hasTrackList(false) , m_canControl(false) , m_canGoNext(false) , m_canGoPrevious(false) , m_canPause(false) , m_canPlay(false) , m_canSeek(false) , m_loopStatus(Mpris::None) , m_maximumRate(1) , m_minimumRate(1) , m_playbackStatus(Mpris::Stopped) , m_position(0) , m_rate(1) , m_shuffle(false) , m_volume(0) { QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.isConnected()) { qmlInfo(this) << "Failed attempting to connect to DBus"; } else if (!connection.registerObject(mprisObjectPath, this)) { qmlInfo(this) << "Failed attempting to register object path. Already registered?"; } } MprisPlayer::~MprisPlayer() { unregisterService(); } QString MprisPlayer::serviceName() const { return m_serviceName; } void MprisPlayer::setServiceName(const QString &serviceName) { if (m_serviceName == serviceName) { return; } unregisterService(); m_serviceName = serviceName; registerService(); emit serviceNameChanged(); } // Mpris2 Root Interface bool MprisPlayer::canQuit() const { return m_canQuit; } void MprisPlayer::setCanQuit(bool canQuit) { if (m_canQuit == canQuit) { return; } m_canQuit = canQuit; emit canQuitChanged(); } bool MprisPlayer::canRaise() const { return m_canRaise; } void MprisPlayer::setCanRaise(bool canRaise) { if (m_canRaise == canRaise) { return; } m_canRaise = canRaise; emit canRaiseChanged(); } bool MprisPlayer::canSetFullscreen() const { return m_canSetFullscreen; } void MprisPlayer::setCanSetFullscreen(bool canSetFullscreen) { if (m_canSetFullscreen == canSetFullscreen) { return; } m_canSetFullscreen = canSetFullscreen; emit canSetFullscreenChanged(); } QString MprisPlayer::desktopEntry() const { return m_desktopEntry; } void MprisPlayer::setDesktopEntry(const QString &desktopEntry) { if (m_desktopEntry == desktopEntry) { return; } m_desktopEntry = desktopEntry; emit desktopEntryChanged(); } bool MprisPlayer::fullscreen() const { return m_fullscreen; } void MprisPlayer::setFullscreen(bool fullscreen) { if (m_fullscreen == fullscreen) { return; } m_fullscreen = fullscreen; emit fullscreenChanged(); } bool MprisPlayer::hasTrackList() const { return m_hasTrackList; } void MprisPlayer::setHasTrackList(bool hasTrackList) { if (m_hasTrackList == hasTrackList) { return; } m_hasTrackList = hasTrackList; emit hasTrackListChanged(); } QString MprisPlayer::identity() const { return m_identity; } void MprisPlayer::setIdentity(const QString &identity) { if (m_identity == identity) { return; } m_identity = identity; emit identityChanged(); } QStringList MprisPlayer::supportedUriSchemes() const { return m_supportedUriSchemes; } void MprisPlayer::setSupportedUriSchemes(const QStringList &supportedUriSchemes) { if (m_supportedUriSchemes == supportedUriSchemes) { return; } m_supportedUriSchemes = supportedUriSchemes; emit supportedUriSchemesChanged(); } QStringList MprisPlayer::supportedMimeTypes() const { return m_supportedMimeTypes; } void MprisPlayer::setSupportedMimeTypes(const QStringList &supportedMimeTypes) { if (m_supportedMimeTypes == supportedMimeTypes) { return; } m_supportedMimeTypes = supportedMimeTypes; emit supportedMimeTypesChanged(); } // Mpris2 Player Interface bool MprisPlayer::canControl() const { return m_canControl; } void MprisPlayer::setCanControl(bool canControl) { if (m_canControl == canControl) { return; } m_canControl = canControl; emit canControlChanged(); } bool MprisPlayer::canGoNext() const { return m_canGoNext; } void MprisPlayer::setCanGoNext(bool canGoNext) { if (m_canGoNext == canGoNext) { return; } m_canGoNext = canGoNext; emit canGoNextChanged(); } bool MprisPlayer::canGoPrevious() const { return m_canGoPrevious; } void MprisPlayer::setCanGoPrevious(bool canGoPrevious) { if (m_canGoPrevious == canGoPrevious) { return; } m_canGoPrevious = canGoPrevious; emit canGoPreviousChanged(); } bool MprisPlayer::canPause() const { return m_canPause; } void MprisPlayer::setCanPause(bool canPause) { if (m_canPause == canPause) { return; } m_canPause = canPause; emit canPauseChanged(); } bool MprisPlayer::canPlay() const { return m_canPlay; } void MprisPlayer::setCanPlay(bool canPlay) { if (m_canPlay == canPlay) { return; } m_canPlay = canPlay; emit canPlayChanged(); } bool MprisPlayer::canSeek() const { return m_canSeek; } void MprisPlayer::setCanSeek(bool canSeek) { if (m_canSeek == canSeek) { return; } m_canSeek = canSeek; emit canSeekChanged(); } Mpris::LoopStatus MprisPlayer::loopStatus() const { return m_loopStatus; } void MprisPlayer::setLoopStatus(Mpris::LoopStatus loopStatus) { if (m_loopStatus == loopStatus) { return; } m_loopStatus = loopStatus; emit loopStatusChanged(); } double MprisPlayer::maximumRate() const { return m_maximumRate; } void MprisPlayer::setMaximumRate(double maximumRate) { if (m_maximumRate == maximumRate) { return; } m_maximumRate = maximumRate; emit maximumRateChanged(); } QVariantMap MprisPlayer::metadata() const { return m_typedMetadata; } void MprisPlayer::setMetadata(const QVariantMap &metadata) { if (m_metadata == metadata) { return; } m_metadata = metadata; m_typedMetadata = typeMetadata(metadata); emit metadataChanged(); } double MprisPlayer::minimumRate() const { return m_minimumRate; } void MprisPlayer::setMinimumRate(double minimumRate) { if (m_minimumRate == minimumRate) { return; } m_minimumRate = minimumRate; emit minimumRateChanged(); } Mpris::PlaybackStatus MprisPlayer::playbackStatus() const { return m_playbackStatus; } void MprisPlayer::setPlaybackStatus(Mpris::PlaybackStatus playbackStatus) { if (m_playbackStatus == playbackStatus) { return; } m_playbackStatus = playbackStatus; emit playbackStatusChanged(); } qlonglong MprisPlayer::position() const { return m_position; } void MprisPlayer::setPosition(qlonglong position) { if (m_position == position) { return; } m_position = position; emit positionChanged(); } double MprisPlayer::rate() const { return m_rate; } void MprisPlayer::setRate(double rate) { if (m_rate == rate) { return; } m_rate = rate; emit rateChanged(); } bool MprisPlayer::shuffle() const { return m_shuffle; } void MprisPlayer::setShuffle(bool shuffle) { if (m_shuffle == shuffle) { return; } m_shuffle= shuffle; emit shuffleChanged(); } double MprisPlayer::volume() const { return m_volume; } void MprisPlayer::setVolume(double volume) { if (m_volume == volume) { return; } m_volume = volume; emit volumeChanged(); } // Private QVariantMap MprisPlayer::typeMetadata(const QVariantMap &aMetadata) { QVariantMap metadata; QVariantMap::const_iterator i = aMetadata.constBegin(); while (i != aMetadata.constEnd()) { switch (Mpris::enumerationFromString(i.key())) { case Mpris::TrackId: metadata.insert(i.key(), QVariant::fromValue(QDBusObjectPath(i.value().toString()))); break; case Mpris::Length: metadata.insert(i.key(), QVariant::fromValue(i.value().toLongLong())); break; case Mpris::ArtUrl: case Mpris::Url: metadata.insert(i.key(), QVariant::fromValue(i.value().toUrl().toString())); break; case Mpris::Album: case Mpris::AsText: case Mpris::Title: metadata.insert(i.key(), QVariant::fromValue(i.value().toString())); break; case Mpris::AlbumArtist: case Mpris::Artist: case Mpris::Comment: case Mpris::Composer: case Mpris::Genre: case Mpris::Lyricist: metadata.insert(i.key(), QVariant::fromValue(i.value().toStringList())); break; case Mpris::AudioBPM: case Mpris::DiscNumber: case Mpris::TrackNumber: case Mpris::UseCount: metadata.insert(i.key(), QVariant::fromValue(i.value().toInt())); break; case Mpris::AutoRating: case Mpris::UserRating: metadata.insert(i.key(), QVariant::fromValue(i.value().toFloat())); break; case Mpris::ContentCreated: case Mpris::FirstUsed: case Mpris::LastUsed: metadata.insert(i.key(), QVariant::fromValue(i.value().toDate().toString(Qt::ISODate))); break; case Mpris::InvalidMetadata: // Passing with the original type and hoping the user used // a type supported by DBus metadata.insert(i.key(), i.value()); break; default: // Nothing to do break; } ++i; } return metadata; } void MprisPlayer::registerService() { if (m_serviceName.isEmpty()) { qmlInfo(this) << "Failed to register service: empty service name"; return; } QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.isConnected()) { qmlInfo(this) << "Failed attempting to connect to DBus"; return; } if (!connection.registerService(QString(serviceNamePrefix).append(m_serviceName))) { qmlInfo(this) << "Failed attempting to register service: " << m_serviceName << " Already taken?"; } return; } void MprisPlayer::unregisterService() { if (!m_serviceName.isEmpty()) { QDBusConnection connection = QDBusConnection::sessionBus(); connection.unregisterService(QString(serviceNamePrefix).append(m_serviceName)); } } void MprisPlayer::notifyPropertiesChanged(const QString& interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) const { if (m_serviceName.isEmpty()) { return; } QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.isConnected()) { qmlInfo(this) << "Failed attempting to connect to DBus"; return; } QDBusMessage message = QDBusMessage::createSignal(mprisObjectPath, dBusPropertiesInterface, dBusPropertiesChangedSignal); QList arguments; arguments << QVariant(interfaceName) << QVariant(changedProperties) << QVariant(invalidatedProperties); message.setArguments(arguments); if (!connection.send(message)) { qmlInfo(this) << "Failed to send DBus property notification signal"; } } qtmpris-0.1.0/src/mprisplayer.h000066400000000000000000000205561331514374100165300ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRISPLAYER_H #define MPRISPLAYER_H #include #include #include #include #include class MprisRootAdaptor; class MprisPlayerAdaptor; class MPRIS_QT_EXPORT MprisPlayer : public QObject, protected QDBusContext { Q_OBJECT Q_PROPERTY(QString serviceName READ serviceName WRITE setServiceName NOTIFY serviceNameChanged) // Mpris2 Root Interface Q_PROPERTY(bool canQuit READ canQuit WRITE setCanQuit NOTIFY canQuitChanged) Q_PROPERTY(bool canRaise READ canRaise WRITE setCanRaise NOTIFY canRaiseChanged) Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen WRITE setCanSetFullscreen NOTIFY canSetFullscreenChanged) Q_PROPERTY(QString desktopEntry READ desktopEntry WRITE setDesktopEntry NOTIFY desktopEntryChanged) Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) Q_PROPERTY(bool hasTrackList READ hasTrackList WRITE setHasTrackList NOTIFY hasTrackListChanged) Q_PROPERTY(QString identity READ identity WRITE setIdentity NOTIFY identityChanged) Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes WRITE setSupportedUriSchemes NOTIFY supportedUriSchemesChanged) Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes WRITE setSupportedMimeTypes NOTIFY supportedMimeTypesChanged) // Mpris2 Player Interface Q_PROPERTY(bool canControl READ canControl WRITE setCanControl NOTIFY canControlChanged) Q_PROPERTY(bool canGoNext READ canGoNext WRITE setCanGoNext NOTIFY canGoNextChanged) Q_PROPERTY(bool canGoPrevious READ canGoPrevious WRITE setCanGoPrevious NOTIFY canGoPreviousChanged) Q_PROPERTY(bool canPause READ canPause WRITE setCanPause NOTIFY canPauseChanged) Q_PROPERTY(bool canPlay READ canPlay WRITE setCanPlay NOTIFY canPlayChanged) Q_PROPERTY(bool canSeek READ canSeek WRITE setCanSeek NOTIFY canSeekChanged) Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged) Q_PROPERTY(double maximumRate READ maximumRate WRITE setMaximumRate NOTIFY maximumRateChanged) Q_PROPERTY(QVariantMap metadata READ metadata WRITE setMetadata NOTIFY metadataChanged) Q_PROPERTY(double minimumRate READ minimumRate WRITE setMinimumRate NOTIFY minimumRateChanged) Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus WRITE setPlaybackStatus NOTIFY playbackStatusChanged) Q_PROPERTY(qlonglong position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged) Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged) Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged) public: MprisPlayer(QObject *parent = 0); ~MprisPlayer(); public slots: QString serviceName() const; void setServiceName(const QString &serviceName); // Mpris2 Root Interface bool canQuit() const; void setCanQuit(bool canQuit); bool canRaise() const; void setCanRaise(bool canRaise); bool canSetFullscreen() const; void setCanSetFullscreen(bool canSetFullscreen); QString desktopEntry() const; void setDesktopEntry(const QString &desktopEntry); bool fullscreen() const; void setFullscreen(bool fullscreen); bool hasTrackList() const; void setHasTrackList(bool hasTrackList); QString identity() const; void setIdentity(const QString &identity); QStringList supportedUriSchemes() const; void setSupportedUriSchemes(const QStringList &supportedUriSchemes); QStringList supportedMimeTypes() const; void setSupportedMimeTypes(const QStringList &supportedMimeTypes); // Mpris2 Player Interface bool canControl() const; void setCanControl(bool canControl); bool canGoNext() const; void setCanGoNext(bool canGoNext); bool canGoPrevious() const; void setCanGoPrevious(bool canGoPrevious); bool canPause() const; void setCanPause(bool canPause); bool canPlay() const; void setCanPlay(bool canPlay); bool canSeek() const; void setCanSeek(bool canSeek); Mpris::LoopStatus loopStatus() const; void setLoopStatus(Mpris::LoopStatus loopStatus); double maximumRate() const; void setMaximumRate(double maximumRate); QVariantMap metadata() const; void setMetadata(const QVariantMap &metadata); double minimumRate() const; void setMinimumRate(double minimumRate); Mpris::PlaybackStatus playbackStatus() const; void setPlaybackStatus(Mpris::PlaybackStatus playbackStatus); qlonglong position() const; void setPosition(qlonglong position); double rate() const; void setRate(double rate); bool shuffle() const; void setShuffle(bool shuffle); double volume() const; void setVolume(double volume); signals: void serviceNameChanged(); // Mpris2 Root Interface void canQuitChanged(); void canRaiseChanged(); void canSetFullscreenChanged(); void desktopEntryChanged(); void fullscreenChanged(); void hasTrackListChanged(); void identityChanged(); void supportedUriSchemesChanged(); void supportedMimeTypesChanged(); void fullscreenRequested(bool fullscreen); void quitRequested(); void raiseRequested(); // Mpris2 Player Interface void canControlChanged(); void canGoNextChanged(); void canGoPreviousChanged(); void canPauseChanged(); void canPlayChanged(); void canSeekChanged(); void loopStatusChanged(); void maximumRateChanged(); void metadataChanged(); void minimumRateChanged(); void playbackStatusChanged(); void positionChanged(); void rateChanged(); void shuffleChanged(); void volumeChanged(); void loopStatusRequested(Mpris::LoopStatus loopStatus); void rateRequested(double rate); void shuffleRequested(bool shuffle); void volumeRequested(double volume); void nextRequested(); void openUriRequested(const QUrl &url); void pauseRequested(); void playRequested(); void playPauseRequested(); void previousRequested(); void seekRequested(qlonglong offset); void seeked(qlonglong position); void setPositionRequested(const QDBusObjectPath &trackId, qlonglong position); void stopRequested(); private: static QVariantMap typeMetadata(const QVariantMap &aMetadata); void registerService(); void unregisterService(); void notifyPropertiesChanged(const QString& interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) const; MprisRootAdaptor *m_mprisRootAdaptor; MprisPlayerAdaptor *m_mprisPlayerAdaptor; QString m_serviceName; // Mpris2 Root Interface bool m_canQuit; bool m_canRaise; bool m_canSetFullscreen; QString m_desktopEntry; bool m_fullscreen; bool m_hasTrackList; QString m_identity; QStringList m_supportedUriSchemes; QStringList m_supportedMimeTypes; // Mpris2 Player Interface bool m_canControl; bool m_canGoNext; bool m_canGoPrevious; bool m_canPause; bool m_canPlay; bool m_canSeek; Mpris::LoopStatus m_loopStatus; double m_maximumRate; QVariantMap m_metadata; QVariantMap m_typedMetadata; double m_minimumRate; Mpris::PlaybackStatus m_playbackStatus; qlonglong m_position; double m_rate; bool m_shuffle; double m_volume; friend class MprisRootAdaptor; friend class MprisPlayerAdaptor; }; #endif /* MPRISPLAYER_H */ qtmpris-0.1.0/src/mprisplayer_p.h000066400000000000000000000210651331514374100170430ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // // W A R N I N G // ------------- // // This file is not part of the public API. This header file may // change from version to version without notice, or even be // removed. // // We mean it. // // #ifndef MPRISPLAYER_P_H #define MPRISPLAYER_P_H #include #include QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE class MprisPlayer; /* * Adaptor class for interface org.mpris.MediaPlayer2 */ class MprisRootAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: MprisRootAdaptor(MprisPlayer *parent); virtual ~MprisRootAdaptor(); public: // PROPERTIES Q_PROPERTY(bool CanQuit READ canQuit) bool canQuit() const; Q_PROPERTY(bool CanRaise READ canRaise) bool canRaise() const; Q_PROPERTY(bool CanSetFullscreen READ canSetFullscreen) bool canSetFullscreen() const; Q_PROPERTY(QString DesktopEntry READ desktopEntry) QString desktopEntry() const; Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen) bool fullscreen() const; void setFullscreen(bool value); Q_PROPERTY(bool HasTrackList READ hasTrackList) bool hasTrackList() const; Q_PROPERTY(QString Identity READ identity) QString identity() const; Q_PROPERTY(QStringList SupportedMimeTypes READ supportedMimeTypes) QStringList supportedMimeTypes() const; Q_PROPERTY(QStringList SupportedUriSchemes READ supportedUriSchemes) QStringList supportedUriSchemes() const; public Q_SLOTS: // METHODS void Quit(); void Raise(); Q_SIGNALS: // SIGNALS private Q_SLOTS: void onCanQuitChanged() const; void onCanRaiseChanged() const; void onCanSetFullscreenChanged() const; void onDesktopEntryChanged() const; void onFullscreenChanged() const; void onHasTrackListChanged() const; void onIdentityChanged() const; void onSupportedUriSchemesChanged() const; void onSupportedMimeTypesChanged() const; }; /* * Adaptor class for interface org.mpris.MediaPlayer2.Player */ class MprisPlayerAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.Player") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: MprisPlayerAdaptor(MprisPlayer *parent); virtual ~MprisPlayerAdaptor(); public: // PROPERTIES Q_PROPERTY(bool CanControl READ canControl) bool canControl() const; Q_PROPERTY(bool CanGoNext READ canGoNext) bool canGoNext() const; Q_PROPERTY(bool CanGoPrevious READ canGoPrevious) bool canGoPrevious() const; Q_PROPERTY(bool CanPause READ canPause) bool canPause() const; Q_PROPERTY(bool CanPlay READ canPlay) bool canPlay() const; Q_PROPERTY(bool CanSeek READ canSeek) bool canSeek() const; Q_PROPERTY(QString LoopStatus READ loopStatus WRITE setLoopStatus) QString loopStatus() const; void setLoopStatus(const QString &value); Q_PROPERTY(double MaximumRate READ maximumRate) double maximumRate() const; Q_PROPERTY(QVariantMap Metadata READ metadata) QVariantMap metadata() const; Q_PROPERTY(double MinimumRate READ minimumRate) double minimumRate() const; Q_PROPERTY(QString PlaybackStatus READ playbackStatus) QString playbackStatus() const; Q_PROPERTY(qlonglong Position READ position) qlonglong position() const; Q_PROPERTY(double Rate READ rate WRITE setRate) double rate() const; void setRate(double value); Q_PROPERTY(bool Shuffle READ shuffle WRITE setShuffle) bool shuffle() const; void setShuffle(bool value); Q_PROPERTY(double Volume READ volume WRITE setVolume) double volume() const; void setVolume(double value); public Q_SLOTS: // METHODS void Next(); void OpenUri(const QString &Uri); void Pause(); void Play(); void PlayPause(); void Previous(); void Seek(qlonglong Offset); void SetPosition(const QDBusObjectPath &TrackId, qlonglong Position); void Stop(); Q_SIGNALS: // SIGNALS void Seeked(qlonglong Position); private Q_SLOTS: void onCanControlChanged() const; void onCanGoNextChanged() const; void onCanGoPreviousChanged() const; void onCanPauseChanged() const; void onCanPlayChanged() const; void onCanSeekChanged() const; void onLoopStatusChanged() const; void onMaximumRateChanged() const; void onMetadataChanged() const; void onMinimumRateChanged() const; void onPlaybackStatusChanged() const; void onRateChanged() const; void onShuffleChanged() const; void onVolumeChanged() const; }; #endif /* MPRISPLAYER_P_H */ qtmpris-0.1.0/src/mprisplayeradaptor.cpp000066400000000000000000000473411331514374100204370ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mprisplayer_p.h" #include "mprisplayer.h" #include #include #include #include #include #include #include #include #include /* * Implementation of adaptor class MprisPlayerAdaptor */ static const QString mprisPlayerInterface = QStringLiteral("org.mpris.MediaPlayer2.Player"); MprisPlayerAdaptor::MprisPlayerAdaptor(MprisPlayer *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(false); connect(parent, SIGNAL(canControlChanged()), this, SLOT(onCanControlChanged())); connect(parent, SIGNAL(canGoNextChanged()), this, SLOT(onCanGoNextChanged())); connect(parent, SIGNAL(canGoPreviousChanged()), this, SLOT(onCanGoPreviousChanged())); connect(parent, SIGNAL(canPauseChanged()), this, SLOT(onCanPauseChanged())); connect(parent, SIGNAL(canPlayChanged()), this, SLOT(onCanPlayChanged())); connect(parent, SIGNAL(canSeekChanged()), this, SLOT(onCanSeekChanged())); connect(parent, SIGNAL(loopStatusChanged()), this, SLOT(onLoopStatusChanged())); connect(parent, SIGNAL(maximumRateChanged()), this, SLOT(onMaximumRateChanged())); connect(parent, SIGNAL(metadataChanged()), this, SLOT(onMetadataChanged())); connect(parent, SIGNAL(minimumRateChanged()), this, SLOT(onMinimumRateChanged())); connect(parent, SIGNAL(playbackStatusChanged()), this, SLOT(onPlaybackStatusChanged())); // PositionChanged signal is not forwarded through DBus ... connect(parent, SIGNAL(rateChanged()), this, SLOT(onRateChanged())); connect(parent, SIGNAL(shuffleChanged()), this, SLOT(onShuffleChanged())); connect(parent, SIGNAL(volumeChanged()), this, SLOT(onVolumeChanged())); connect(parent, SIGNAL(seeked(qlonglong)), this, SIGNAL(Seeked(qlonglong))); } MprisPlayerAdaptor::~MprisPlayerAdaptor() { // destructor } bool MprisPlayerAdaptor::canControl() const { return static_cast(parent())->canControl(); } bool MprisPlayerAdaptor::canGoNext() const { MprisPlayer * const player = static_cast(parent()); return player->canControl() && player->canGoNext(); } bool MprisPlayerAdaptor::canGoPrevious() const { MprisPlayer * const player = static_cast(parent()); return player->canControl() && player->canGoPrevious(); } bool MprisPlayerAdaptor::canPause() const { MprisPlayer * const player = static_cast(parent()); return player->canControl() && player->canPause(); } bool MprisPlayerAdaptor::canPlay() const { MprisPlayer * const player = static_cast(parent()); return player->canControl() && player->canPlay(); } bool MprisPlayerAdaptor::canSeek() const { MprisPlayer * const player = static_cast(parent()); return player->canControl() && player->canSeek(); } QString MprisPlayerAdaptor::loopStatus() const { return Mpris::enumerationToString(static_cast(parent())->loopStatus()); } void MprisPlayerAdaptor::setLoopStatus(const QString &value) { MprisPlayer * const player = static_cast(parent()); if (player->canControl()) { emit player->loopStatusRequested(Mpris::enumerationFromString(value)); return; } // We cannot send an error reply in a property setter so we just // complain here qDebug() << Q_FUNC_INFO << "Requested to modify the loop status but it is not supported."; } double MprisPlayerAdaptor::maximumRate() const { return static_cast(parent())->maximumRate(); } QVariantMap MprisPlayerAdaptor::metadata() const { return static_cast(parent())->metadata(); } double MprisPlayerAdaptor::minimumRate() const { return static_cast(parent())->minimumRate(); } QString MprisPlayerAdaptor::playbackStatus() const { return Mpris::enumerationToString(static_cast(parent())->playbackStatus()); } qlonglong MprisPlayerAdaptor::position() const { return static_cast(parent())->position(); } double MprisPlayerAdaptor::rate() const { return static_cast(parent())->rate(); } void MprisPlayerAdaptor::setRate(double value) { MprisPlayer * const player = static_cast(parent()); QString errorMessage; if (!player->canControl()) { errorMessage = QStringLiteral("Requested to modify the rate but it is not supported."); } else if (player->minimumRate() > value) { errorMessage = QStringLiteral("Requested to modify the rate under its minimum allowed value."); } else if (player->maximumRate() < value) { errorMessage = QStringLiteral("Requested to modify the rate over its maximum allowed value."); } if (errorMessage.isEmpty()) { if (value == 0) { emit player->pauseRequested(); } else { emit player->rateRequested(value); } return; } // We cannot send an error reply in a property setter so we just // complain here qDebug() << Q_FUNC_INFO << errorMessage; } bool MprisPlayerAdaptor::shuffle() const { return static_cast(parent())->shuffle(); } void MprisPlayerAdaptor::setShuffle(bool value) { MprisPlayer * const player = static_cast(parent()); if (player->canControl()) { emit player->shuffleRequested(value); return; } // We cannot send an error reply in a property setter so we just // complain here qDebug() << Q_FUNC_INFO << "Requested to modify the shuffle but it is not supported."; } double MprisPlayerAdaptor::volume() const { return static_cast(parent())->volume(); } void MprisPlayerAdaptor::setVolume(double value) { MprisPlayer * const player = static_cast(parent()); if (player->canControl()) { emit player->volumeRequested(value < 0 ? 0 : value); return; } // We cannot send an error reply in a property setter so we just // complain here qDebug() << Q_FUNC_INFO << "Requested to modify the volume but it is not supported."; } void MprisPlayerAdaptor::Next() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to next track but it is not supported.")); return; } if (!player->canGoNext()) { return; } emit player->nextRequested(); } void MprisPlayerAdaptor::OpenUri(const QString &Uri) { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but it is not supported.")); return; } QUrl url(Uri, QUrl::StrictMode); if (!url.isValid()) { player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to open an url but the url is invalid.")); } if (!player->supportedUriSchemes().contains(url.scheme())) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but the scheme is not supported.")); } QMimeDatabase db; QMimeType mime; if (url.isLocalFile()) { mime = db.mimeTypeForFile(url.toLocalFile()); } else { mime = db.mimeTypeForFile(url.fileName(), QMimeDatabase::MatchExtension); } QStringList mimeNames = mime.aliases(); mimeNames.prepend(mime.name()); for (int i = 0; i < mimeNames.size(); i++) { if (player->supportedMimeTypes().contains(mimeNames[i])) { emit player->openUriRequested(url); return; } } player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but the mime type is not supported.")); } void MprisPlayerAdaptor::Pause() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to pause but it is not supported.")); return; } if (!player->canPause()) { return; } switch (player->playbackStatus()) { case Mpris::Playing: case Mpris::Stopped: emit player->pauseRequested(); break; case Mpris::Paused: default: // Nothing to do break; } } void MprisPlayerAdaptor::Play() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play but it is not supported.")); return; } if (!player->canPlay()) { return; } switch (player->playbackStatus()) { case Mpris::Stopped: case Mpris::Paused: emit player->playRequested(); break; case Mpris::Playing: default: // Nothing to do break; } } void MprisPlayerAdaptor::PlayPause() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play or pause but it is not supported.")); return; } switch (player->playbackStatus()) { case Mpris::Playing: if (!player->canPause()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to pause but it is not supported.")); return; } emit player->pauseRequested(); break; case Mpris::Stopped: case Mpris::Paused: if (!player->canPlay()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play but it is not supported.")); return; } emit player->playRequested(); break; default: // Nothing to do break; } } void MprisPlayerAdaptor::Previous() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to previous track but it is not supported.")); return; } if (!player->canGoPrevious()) { return; } emit player->previousRequested(); } void MprisPlayerAdaptor::Seek(qlonglong Offset) { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to seek but it is not supported.")); return; } if (!player->canSeek() || Offset == 0) { return; } if (Offset < 0) { emit player->seekRequested(Offset); return; } QVariantMap metadata = player->metadata(); QVariant length = metadata[Mpris::metadataToString(Mpris::Length)]; if (length.isValid() && (player->position() + Offset) > length.toLongLong()) { emit player->nextRequested(); return; } emit player->seekRequested(Offset); } void MprisPlayerAdaptor::SetPosition(const QDBusObjectPath &TrackId, qlonglong Position) { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to position but it is not supported.")); return; } if (!player->canSeek()) { return; } QVariantMap metadata = player->metadata(); QVariant trackId = metadata[Mpris::metadataToString(Mpris::TrackId)]; QVariant length = metadata[Mpris::metadataToString(Mpris::Length)]; if (!trackId.isValid() || !length.isValid()) { return; } if (trackId.value() != TrackId) { player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to move to position but the TrackId is not the current one.")); return; } if (Position > length.toLongLong()) { player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to move to position but the position is off range.")); return; } emit player->setPositionRequested(TrackId, Position); } void MprisPlayerAdaptor::Stop() { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to stop but it is not supported.")); return; } switch (player->playbackStatus()) { case Mpris::Playing: case Mpris::Paused: emit player->stopRequested(); break; case Mpris::Stopped: default: // Nothing to do break; } } // Private void MprisPlayerAdaptor::onCanControlChanged() const { MprisPlayer * const player = static_cast(parent()); // canControlChanged signal is not forwarded through DBus, but // we can notify about the rest of "Can*" properties QVariantMap changedProperties; if (player->canGoNext()) { changedProperties[QStringLiteral("CanGoNext")] = QVariant(player->canControl()); } if (player->canGoPrevious()) { changedProperties[QStringLiteral("CanGoPrevious")] = QVariant(player->canControl()); } if (player->canPause()) { changedProperties[QStringLiteral("CanPause")] = QVariant(player->canControl()); } if (player->canPlay()) { changedProperties[QStringLiteral("CanPlay")] = QVariant(player->canControl()); } if (player->canSeek()) { changedProperties[QStringLiteral("CanSeek")] = QVariant(player->canControl()); } if (changedProperties.isEmpty()) { return; } player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onCanGoNextChanged() const { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { return; } QVariantMap changedProperties; changedProperties[QStringLiteral("CanGoNext")] = QVariant(player->canGoNext()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onCanGoPreviousChanged() const { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { return; } QVariantMap changedProperties; changedProperties[QStringLiteral("CanGoPrevious")] = QVariant(player->canGoPrevious()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onCanPauseChanged() const { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { return; } QVariantMap changedProperties; changedProperties[QStringLiteral("CanPause")] = QVariant(player->canPause()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onCanPlayChanged() const { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { return; } QVariantMap changedProperties; changedProperties[QStringLiteral("CanPlay")] = QVariant(player->canPlay()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onCanSeekChanged() const { MprisPlayer * const player = static_cast(parent()); if (!player->canControl()) { return; } QVariantMap changedProperties; changedProperties[QStringLiteral("CanSeek")] = QVariant(player->canSeek()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onLoopStatusChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("LoopStatus")] = QVariant(Mpris::enumerationToString(player->loopStatus())); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onMaximumRateChanged() const { MprisPlayer * const player = static_cast(parent()); if (player->maximumRate() < 1) { qmlInfo(this) << "Maximum rate should be equal or above 1"; return; } QVariantMap changedProperties; changedProperties[QStringLiteral("MaximumRate")] = QVariant(player->maximumRate()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onMetadataChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("Metadata")] = QVariant(player->metadata()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onMinimumRateChanged() const { MprisPlayer * const player = static_cast(parent()); if (player->minimumRate() > 1) { qmlInfo(this) << "Minimum rate should be equal or less than 1"; return; } QVariantMap changedProperties; changedProperties[QStringLiteral("MinimumRate")] = QVariant(player->minimumRate() < 0 ? 0 : player->minimumRate()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onPlaybackStatusChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("PlaybackStatus")] = QVariant(Mpris::enumerationToString(player->playbackStatus())); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onRateChanged() const { MprisPlayer * const player = static_cast(parent()); if (player->rate() <= 0 || player->rate() < player->minimumRate() || player->rate() > player->maximumRate()) { qmlInfo(this) << "Rate should never be negative or out of the minimum and maximum limits"; return; } QVariantMap changedProperties; changedProperties[QStringLiteral("Rate")] = QVariant(player->rate()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onShuffleChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("Shuffle")] = QVariant(player->shuffle()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } void MprisPlayerAdaptor::onVolumeChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("Volume")] = QVariant(player->volume() < 0 ? 0 : player->volume()); player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList()); } qtmpris-0.1.0/src/mprisplayerinterface.cpp000066400000000000000000000130401331514374100207320ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mpriscontroller_p.h" #include "mpris.h" #include /* * Implementation of interface class MprisPlayerInterface */ MprisPlayerInterface::MprisPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) , m_canControl(false) , m_canGoNext(false) , m_canGoPrevious(false) , m_canPause(false) , m_canPlay(false) , m_canSeek(false) , m_loopStatus(Mpris::None) , m_maximumRate(1) , m_minimumRate(1) , m_playbackStatus(Mpris::Stopped) , m_position(0) , m_rate(1) , m_shuffle(false) , m_volume(0) { connect(this, SIGNAL(propertyChanged(QString, QVariant)), this, SLOT(onPropertyChanged(QString, QVariant))); } MprisPlayerInterface::~MprisPlayerInterface() { } void MprisPlayerInterface::onPropertyChanged(const QString &propertyName, const QVariant &value) { if (propertyName == QStringLiteral("CanControl")) { bool canControl = value.toBool(); if (m_canControl != canControl) { m_canControl = canControl; emit canControlChanged(m_canControl); } } else if (propertyName == QStringLiteral("CanGoNext")) { bool canGoNext = value.toBool(); if (m_canGoNext != canGoNext) { m_canGoNext = canGoNext; emit canGoNextChanged(m_canGoNext); } } else if (propertyName == QStringLiteral("CanGoPrevious")) { bool canGoPrevious = value.toBool(); if (m_canGoPrevious != canGoPrevious) { m_canGoPrevious = canGoPrevious; emit canGoPreviousChanged(m_canGoPrevious); } } else if (propertyName == QStringLiteral("CanPause")) { bool canPause = value.toBool(); if (m_canPause != canPause) { m_canPause = canPause; emit canPauseChanged(m_canPause); } } else if (propertyName == QStringLiteral("CanPlay")) { bool canPlay = value.toBool(); if (m_canPlay != canPlay) { m_canPlay = canPlay; emit canPlayChanged(m_canPlay); } } else if (propertyName == QStringLiteral("CanSeek")) { bool canSeek = value.toBool(); if (m_canSeek != canSeek) { m_canSeek = canSeek; emit canSeekChanged(m_canSeek); } } else if (propertyName == QStringLiteral("LoopStatus")) { QString loopStatus = value.toString(); if (m_loopStatus != loopStatus) { m_loopStatus = loopStatus; emit loopStatusChanged(m_loopStatus); } } else if (propertyName == QStringLiteral("MaximumRate")) { bool maximumRate = value.toDouble(); if (m_maximumRate != maximumRate) { m_maximumRate = maximumRate; emit maximumRateChanged(m_maximumRate); } } else if (propertyName == QStringLiteral("Metadata")) { QVariantMap metadata = value.toMap(); if (m_metadata != metadata) { m_metadata = metadata; emit metadataChanged(m_metadata); } } else if (propertyName == QStringLiteral("MinimumRate")) { double minimumRate = value.toDouble(); if (m_minimumRate != minimumRate) { m_minimumRate = minimumRate; emit minimumRateChanged(m_minimumRate); } } else if (propertyName == QStringLiteral("PlaybackStatus")) { QString playbackStatus = value.toString(); if (m_playbackStatus != playbackStatus) { m_playbackStatus = playbackStatus; emit playbackStatusChanged(m_playbackStatus); } } else if (propertyName == QStringLiteral("Position")) { qlonglong position = value.toLongLong(); if (m_position != position) { m_position = position; emit positionChanged(m_position); } } else if (propertyName == QStringLiteral("Rate")) { double rate = value.toDouble(); if (m_rate != rate) { m_rate = rate; emit rateChanged(m_rate); } } else if (propertyName == QStringLiteral("Shuffle")) { bool shuffle = value.toBool(); if (m_shuffle != shuffle) { m_shuffle = shuffle; emit shuffleChanged(m_shuffle); } } else if (propertyName == QStringLiteral("Volume")) { double volume = value.toDouble(); if (m_volume != volume) { m_volume = volume; emit volumeChanged(m_volume); } } else { qWarning() << Q_FUNC_INFO << "Received PropertyChanged signal from unknown property: " << propertyName; } } qtmpris-0.1.0/src/mprisqt.h000066400000000000000000000021151331514374100156470ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPRIS_QT_H #define MPRIS_QT_H #if defined(MPRIS_QT_LIBRARY) # define MPRIS_QT_EXPORT Q_DECL_EXPORT #else # define MPRIS_QT_EXPORT Q_DECL_IMPORT #endif #endif /* MPRIS_QT_H */ qtmpris-0.1.0/src/mprisrootadaptor.cpp000066400000000000000000000170131331514374100201170ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mprisplayer_p.h" #include "mprisplayer.h" #include #include #include #include #include #include #include #include #include /* * Implementation of adaptor class MprisRootAdaptor */ static const QString mprisRootInterface = QStringLiteral("org.mpris.MediaPlayer2"); MprisRootAdaptor::MprisRootAdaptor(MprisPlayer *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(false); connect(parent, SIGNAL(canQuitChanged()), this, SLOT(onCanQuitChanged())); connect(parent, SIGNAL(canRaiseChanged()), this, SLOT(onCanRaiseChanged())); connect(parent, SIGNAL(canSetFullscreenChanged()), this, SLOT(onCanSetFullscreenChanged())); connect(parent, SIGNAL(desktopEntryChanged()), this, SLOT(onDesktopEntryChanged())); connect(parent, SIGNAL(fullscreenChanged()), this, SLOT(onFullscreenChanged())); connect(parent, SIGNAL(hasTrackListChanged()), this, SLOT(onHasTrackListChanged())); connect(parent, SIGNAL(identityChanged()), this, SLOT(onIdentityChanged())); connect(parent, SIGNAL(supportedUriSchemesChanged()), this, SLOT(onSupportedUriSchemesChanged())); connect(parent, SIGNAL(supportedMimeTypesChanged()), this, SLOT(onSupportedMimeTypesChanged())); } MprisRootAdaptor::~MprisRootAdaptor() { // destructor } bool MprisRootAdaptor::canQuit() const { return static_cast(parent())->canQuit(); } bool MprisRootAdaptor::canRaise() const { return static_cast(parent())->canRaise(); } bool MprisRootAdaptor::canSetFullscreen() const { return static_cast(parent())->canSetFullscreen(); } QString MprisRootAdaptor::desktopEntry() const { return static_cast(parent())->desktopEntry(); } bool MprisRootAdaptor::fullscreen() const { return static_cast(parent())->fullscreen(); } void MprisRootAdaptor::setFullscreen(bool value) { MprisPlayer * const player = static_cast(parent()); if (player->canSetFullscreen()) { emit player->fullscreenRequested(value); return; } // We cannot send an error reply in a property setter so we just // complain here if (value) { qDebug() << Q_FUNC_INFO << "Requested to fullscreen, but not supported"; } else { qDebug() << Q_FUNC_INFO << "Requested to unfullscreen, but not supported"; } } bool MprisRootAdaptor::hasTrackList() const { return static_cast(parent())->hasTrackList(); } QString MprisRootAdaptor::identity() const { return static_cast(parent())->identity(); } QStringList MprisRootAdaptor::supportedMimeTypes() const { return static_cast(parent())->supportedMimeTypes(); } QStringList MprisRootAdaptor::supportedUriSchemes() const { return static_cast(parent())->supportedUriSchemes(); } void MprisRootAdaptor::Quit() { MprisPlayer * const player = static_cast(parent()); if (player->canQuit()) { emit player->quitRequested(); return; } player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Quit requested but not supported.")); } void MprisRootAdaptor::Raise() { MprisPlayer * const player = static_cast(parent()); if (player->canRaise()) { emit player->raiseRequested(); return; } player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Raise requested but not supported.")); } // Private void MprisRootAdaptor::onCanQuitChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("CanQuit")] = QVariant(player->canQuit()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onCanRaiseChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("CanRaise")] = QVariant(player->canRaise()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onCanSetFullscreenChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("CanSetFullscreen")] = QVariant(player->canSetFullscreen()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onDesktopEntryChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("DesktopEntry")] = QVariant(player->desktopEntry()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onFullscreenChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("Fullscreen")] = QVariant(player->fullscreen()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onHasTrackListChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("HasTrackList")] = QVariant(player->hasTrackList()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onIdentityChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("Identity")] = QVariant(player->identity()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onSupportedUriSchemesChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("SupportedUriSchemes")] = QVariant(player->supportedUriSchemes()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } void MprisRootAdaptor::onSupportedMimeTypesChanged() const { MprisPlayer * const player = static_cast(parent()); QVariantMap changedProperties; changedProperties[QStringLiteral("SupportedMimeTypes")] = QVariant(player->supportedMimeTypes()); player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList()); } qtmpris-0.1.0/src/mprisrootinterface.cpp000066400000000000000000000102151331514374100204220ustar00rootroot00000000000000// -*- c++ -*- /*! * * Copyright (C) 2015 Jolla Ltd. * * Contact: Valerio Valerio * Author: Andres Gomez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mpriscontroller_p.h" #include /* * Implementation of interface class MprisRootInterface */ MprisRootInterface::MprisRootInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) , m_canQuit(false) , m_canRaise(false) , m_canSetFullscreen(false) , m_fullscreen(false) , m_hasTrackList(false) { connect(this, SIGNAL(propertyChanged(QString, QVariant)), this, SLOT(onPropertyChanged(QString, QVariant))); } MprisRootInterface::~MprisRootInterface() { } void MprisRootInterface::onPropertyChanged(const QString &propertyName, const QVariant &value) { if (propertyName == QStringLiteral("CanQuit")) { bool canQuit = value.toBool(); if (m_canQuit != canQuit) { m_canQuit = canQuit; emit canQuitChanged(m_canQuit); } } else if (propertyName == QStringLiteral("CanRaise")) { bool canRaise = value.toBool(); if (m_canRaise != canRaise) { m_canRaise = canRaise; emit canRaiseChanged(m_canRaise); } } else if (propertyName == QStringLiteral("CanSetFullscreen")) { bool canSetFullscreen = value.toBool(); if (m_canSetFullscreen != canSetFullscreen) { m_canSetFullscreen = canSetFullscreen; emit canSetFullscreenChanged(m_canSetFullscreen); } } else if (propertyName == QStringLiteral("DesktopEntry")) { QString desktopEntry = value.toString(); if (m_desktopEntry != desktopEntry) { m_desktopEntry = desktopEntry; emit desktopEntryChanged(m_desktopEntry); } } else if (propertyName == QStringLiteral("Fullscreen")) { bool fullscreen = value.toBool(); if (m_fullscreen != fullscreen) { m_fullscreen = fullscreen; emit fullscreenChanged(m_fullscreen); } } else if (propertyName == QStringLiteral("HasTrackList")) { bool hasTrackList = value.toBool(); if (m_hasTrackList != hasTrackList) { m_hasTrackList = hasTrackList; emit hasTrackListChanged(m_hasTrackList); } } else if (propertyName == QStringLiteral("Identity")) { QString identity= value.toString(); if (m_identity != identity) { m_identity = identity; emit identityChanged(m_identity); } } else if (propertyName == QStringLiteral("SupportedMimeTypes")) { QStringList supportedUriSchemes = value.toStringList(); if (m_supportedUriSchemes != supportedUriSchemes) { m_supportedUriSchemes = supportedUriSchemes; emit supportedMimeTypesChanged(m_supportedUriSchemes); } } else if (propertyName == QStringLiteral("SupportedUriSchemes")) { QStringList supportedMimeTypes = value.toStringList(); if (m_supportedMimeTypes != supportedMimeTypes) { m_supportedMimeTypes = supportedMimeTypes; emit supportedUriSchemesChanged(m_supportedMimeTypes); } } else { qWarning() << Q_FUNC_INFO << "Received PropertyChanged signal from unknown property: " << propertyName; } } qtmpris-0.1.0/src/org.mpris.MediaPlayer2.Player.xml000066400000000000000000000406531331514374100221620ustar00rootroot00000000000000 qtmpris-0.1.0/src/org.mpris.MediaPlayer2.xml000066400000000000000000000151061331514374100207220ustar00rootroot00000000000000 qtmpris-0.1.0/src/src.pro000066400000000000000000000026741331514374100153220ustar00rootroot00000000000000include(../common.pri) TEMPLATE = lib CONFIG += qt link_pkgconfig QT = core dbus qml PKGCONFIG = dbusextended-qt5 TARGET = $${MPRISQTLIB} QMAKE_SUBSTITUTES = $${TARGET}.prf.in DEFINES += MPRIS_QT_LIBRARY # Generate pkg-config support by default # Note that we HAVE TO also create prl config as QMake implementation # mixes both of them together. CONFIG += create_pc create_prl no_install_prl SOURCES += \ mpris.cpp \ mprisrootadaptor.cpp \ mprisplayeradaptor.cpp \ mprisplayer.cpp \ mpriscontroller.cpp \ mprismanager.cpp \ mprisplayerinterface.cpp \ mprisrootinterface.cpp HEADERS += \ mprisqt.h \ mpris.h \ mprisplayer.h \ mprisplayer_p.h \ mpriscontroller.h \ mpriscontroller_p.h \ mprismanager.h INSTALL_HEADERS = \ MprisQt \ Mpris \ MprisPlayer \ MprisController \ MprisManager \ mprisqt.h \ mpris.h \ mprisplayer.h \ mpriscontroller.h \ mprismanager.h OTHER_FILES += org.mpris.MediaPlayer2.xml \ org.mpris.MediaPlayer2.Player.xml target.path = $$[QT_INSTALL_LIBS] headers.files = $$INSTALL_HEADERS headers.path = $$[QT_INSTALL_HEADERS]/MprisQt prf.files = $${TARGET}.prf prf.path = $$[QMAKE_MKSPECS]/features INSTALLS += target headers prf QMAKE_PKGCONFIG_REQUIRES = Qt5Core Qt5DBus dbusextended-qt5 QMAKE_PKGCONFIG_LIBDIR = $$target.path QMAKE_PKGCONFIG_INCDIR = $$headers.path QMAKE_PKGCONFIG_DESTDIR = pkgconfig QMAKE_PKGCONFIG_NAME = MprisQt