aboutsummaryrefslogtreecommitdiff
path: root/src/mpris2-watcher.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/mpris2-watcher.vala')
-rw-r--r--src/mpris2-watcher.vala124
1 files changed, 101 insertions, 23 deletions
diff --git a/src/mpris2-watcher.vala b/src/mpris2-watcher.vala
index 7814975..9ef9b2f 100644
--- a/src/mpris2-watcher.vala
+++ b/src/mpris2-watcher.vala
@@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+using Xml;
+
[DBus (name = "org.freedesktop.DBus")]
public interface FreeDesktopObject: Object {
public abstract async string[] list_names() throws IOError;
@@ -25,6 +27,16 @@ public interface FreeDesktopObject: Object {
string new_owner );
}
+[DBus (name = "org.freedesktop.DBus.Introspectable")]
+public interface FreeDesktopIntrospectable: Object {
+ public abstract string Introspect() throws IOError;
+}
+
+public errordomain XmlError {
+ FILE_NOT_FOUND,
+ XML_DOCUMENT_EMPTY
+}
+
public class Mpris2Watcher : GLib.Object
{
private const string FREEDESKTOP_SERVICE = "org.freedesktop.DBus";
@@ -33,14 +45,17 @@ public class Mpris2Watcher : GLib.Object
private const string MPRIS_MEDIA_PLAYER_PATH = "/org/mpris/MediaPlayer2";
FreeDesktopObject fdesktop_obj;
+ FreeDesktopIntrospectable introspectable;
- public signal void client_appeared ( string desktop_file_name, string dbus_name );
+ public signal void client_appeared ( string desktop_file_name,
+ string dbus_name,
+ bool use_playlists );
public signal void client_disappeared ( string dbus_name );
public Mpris2Watcher ()
{
}
-
+
construct
{
try {
@@ -57,6 +72,29 @@ public class Mpris2Watcher : GLib.Object
}
}
+ // At startup check to see if there are clients up that we are interested in
+ // More relevant for development and daemon's like mpd.
+ private async void check_for_active_clients()
+ {
+ string[] interfaces;
+ try{
+ interfaces = yield this.fdesktop_obj.list_names();
+ }
+ catch ( IOError e) {
+ warning( "Mpris2watcher could fetch active interfaces at startup: %s",
+ e.message );
+ return;
+ }
+ foreach (var address in interfaces) {
+ if (address.has_prefix (MPRIS_PREFIX)){
+ MprisRoot? mpris2_root = this.create_mpris_root(address);
+ if (mpris2_root == null) return;
+ bool use_playlists = this.supports_playlists ( address );
+ client_appeared (mpris2_root.DesktopEntry, address, use_playlists);
+ }
+ }
+ }
+
private void name_changes_detected ( FreeDesktopObject dbus_obj,
string name,
string previous_owner,
@@ -65,24 +103,25 @@ public class Mpris2Watcher : GLib.Object
MprisRoot? mpris2_root = this.create_mpris_root(name);
if (mpris2_root == null) return;
-
+
if (previous_owner != "" && current_owner == "") {
debug ("Client '%s' gone down", name);
client_disappeared (name);
}
else if (previous_owner == "" && current_owner != "") {
debug ("Client '%s' has appeared", name);
- client_appeared (mpris2_root.DesktopEntry, name);
+ bool use_playlists = this.supports_playlists ( name );
+ client_appeared (mpris2_root.DesktopEntry, name, use_playlists);
}
}
- private MprisRoot? create_mpris_root(string name){
+ private MprisRoot? create_mpris_root ( string name ){
MprisRoot mpris2_root = null;
if ( name.has_prefix (MPRIS_PREFIX) ){
try {
mpris2_root = Bus.get_proxy_sync ( BusType.SESSION,
- name,
- MPRIS_MEDIA_PLAYER_PATH );
+ name,
+ MPRIS_MEDIA_PLAYER_PATH );
}
catch (IOError e){
warning( "Mpris2watcher could not create a root interface: %s",
@@ -91,26 +130,65 @@ public class Mpris2Watcher : GLib.Object
}
return mpris2_root;
}
-
- // At startup check to see if there are clients up that we are interested in
- // More relevant for development and daemon's like mpd.
- private async void check_for_active_clients()
+
+ private bool supports_playlists ( string name )
{
- string[] interfaces;
- try{
- interfaces = yield this.fdesktop_obj.list_names();
+ try {
+ /* The dbusproxy flag parameter is needed to ensure Banshee does not
+ blow up. I suspect the issue is that if you
+ try to instantiate a dbus object which does not have any properties
+ associated with it, gdbus will attempt to fetch the properties (this is
+ in the documentation) but the banshee mpris dbus object more than likely
+ causes a crash because it doesn't check for the presence of properties
+ before attempting to access them.
+ */
+ this.introspectable = Bus.get_proxy_sync ( BusType.SESSION,
+ name,
+ MPRIS_MEDIA_PLAYER_PATH,
+ GLib.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES);
+
+ var results = introspectable.Introspect();
+ return this.parse_interfaces (results);
}
- catch ( IOError e) {
- warning( "Mpris2watcher could fetch active interfaces at startup: %s",
+ catch (IOError e){
+ warning( "Could not create an introspectable object: %s",
e.message );
- return;
}
- foreach (var address in interfaces) {
- if (address.has_prefix (MPRIS_PREFIX)){
- MprisRoot? mpris2_root = this.create_mpris_root(address);
- if (mpris2_root == null) return;
- client_appeared (mpris2_root.DesktopEntry, address);
+ return false;
+ }
+
+ private bool parse_interfaces( string interface_info )
+ {
+ //parse the document from path
+ bool result = false;
+ Xml.Doc* xml_doc = Parser.parse_doc (interface_info);
+ if (xml_doc == null) {
+ warning ("Mpris2Watcher - parse-interfaces - failed to instantiate xml doc");
+ return false;
+ }
+ //get the root node. notice the dereferencing operator -> instead of .
+ Xml.Node* root_node = xml_doc->get_root_element ();
+ if (root_node == null) {
+ //free the document manually before throwing because the garbage collector can't work on pointers
+ delete xml_doc;
+ warning ("Mpris2Watcher - the interface info xml is empty");
+ return false;
+ }
+
+ //let's parse those nodes
+ for (Xml.Node* iter = root_node->children; iter != null; iter = iter->next) {
+ //spaces btw. tags are also nodes, discard them
+ if (iter->type != ElementType.ELEMENT_NODE){
+ continue;
+ }
+ Xml.Attr* attributes = iter->properties; //get the node's name
+ string interface_name = attributes->children->content;
+ debug ( "this dbus object has interface %s ", interface_name );
+ if ( interface_name == MPRIS_PREFIX.concat("Playlists")){
+ result = true;
}
}
- }
+ delete xml_doc;
+ return result;
+ }
} \ No newline at end of file