aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorConor Curran <conor.curran@canonical.com>2011-01-09 16:31:12 +0000
committerConor Curran <conor.curran@canonical.com>2011-01-09 16:31:12 +0000
commitc49d87b94dc4a8fe3ccb2c150ad1cd34404630f2 (patch)
tree8824cfe53ae0fea3a90f6489e3eed8610e74da86 /src
parentce996a8b02131d9711cc3dee67f6c3844e55b8e8 (diff)
parent33e8e6c2ac125ba3806032ea3ef730bd5c782ac8 (diff)
downloadayatana-indicator-sound-c49d87b94dc4a8fe3ccb2c150ad1cd34404630f2.tar.gz
ayatana-indicator-sound-c49d87b94dc4a8fe3ccb2c150ad1cd34404630f2.tar.bz2
ayatana-indicator-sound-c49d87b94dc4a8fe3ccb2c150ad1cd34404630f2.zip
mpris interface introspection working nicel to determine playlist support
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/freedesktop-interfaces.vala47
-rw-r--r--src/mpris2-controller.vala55
-rw-r--r--src/mpris2-interfaces.vala4
-rw-r--r--src/mpris2-watcher.vala125
-rw-r--r--src/music-player-bridge.vala17
-rw-r--r--src/player-controller.vala19
7 files changed, 188 insertions, 83 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 82830e1..7fe7e0f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,7 @@ music_bridge_VALASOURCES = \
player-item.vala \
settings-manager.vala \
playlists-menu-item.vala \
+ freedesktop-interfaces.vala \
fetch-file.vala
@@ -81,7 +82,8 @@ music_bridge_VALAFLAGS = \
--pkg common-defs \
--pkg gio-2.0 \
--pkg gio-unix-2.0 \
- --pkg gdk-pixbuf-2.0
+ --pkg gdk-pixbuf-2.0 \
+ --pkg libxml-2.0
$(MAINTAINER_VALAFLAGS)
diff --git a/src/freedesktop-interfaces.vala b/src/freedesktop-interfaces.vala
new file mode 100644
index 0000000..4d75044
--- /dev/null
+++ b/src/freedesktop-interfaces.vala
@@ -0,0 +1,47 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+[DBus (name = "org.freedesktop.DBus")]
+public interface FreeDesktopObject: Object {
+ public abstract async string[] list_names() throws IOError;
+ public abstract signal void name_owner_changed ( string name,
+ string old_owner,
+ string new_owner );
+}
+
+[DBus (name = "org.freedesktop.DBus.Introspectable")]
+public interface FreeDesktopIntrospectable: Object {
+ public abstract string Introspect() throws IOError;
+}
+
+[DBus (name = "org.freedesktop.DBus.Properties")]
+public interface FreeDesktopProperties : Object{
+ public signal void PropertiesChanged (string source, HashTable<string, Variant?> changed_properties,
+ string[] invalid );
+}
+
+public errordomain XmlError {
+ FILE_NOT_FOUND,
+ XML_DOCUMENT_EMPTY
+}
+
+const string FREEDESKTOP_SERVICE = "org.freedesktop.DBus";
+const string FREEDESKTOP_OBJECT = "/org/freedesktop/DBus";
+
+
diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala
index 5f98541..fc61c12 100644
--- a/src/mpris2-controller.vala
+++ b/src/mpris2-controller.vala
@@ -18,12 +18,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Dbusmenu;
-[DBus (name = "org.freedesktop.DBus.Properties")]
-public interface FreeDesktopProperties : Object{
- public signal void PropertiesChanged (string source, HashTable<string, Variant?> changed_properties,
- string[] invalid );
-}
-
/*
This class will entirely replace mpris-controller.vala hence why there is no
point in trying to get encorporate both into the same object model.
@@ -50,10 +44,11 @@ public class Mpris2Controller : GLib.Object
this.player = Bus.get_proxy_sync ( BusType.SESSION,
this.owner.dbus_name,
"/org/mpris/MediaPlayer2" );
- this.playlists = Bus.get_proxy_sync ( BusType.SESSION,
- this.owner.dbus_name,
- "/org/mpris/MediaPlayer2" );
-
+ if ( this.owner.use_playlists == true ){
+ this.playlists = Bus.get_proxy_sync ( BusType.SESSION,
+ this.owner.dbus_name,
+ "/org/mpris/MediaPlayer2" );
+ }
this.properties_interface = Bus.get_proxy_sync ( BusType.SESSION,
"org.freedesktop.Properties.PropertiesChanged",
"/org/mpris/MediaPlayer2" );
@@ -70,7 +65,7 @@ public class Mpris2Controller : GLib.Object
{
debug("properties-changed for interface %s and owner %s", interface_source, this.owner.dbus_name);
if ( changed_properties == null ||
- interface_source.has_prefix ( Mpris2Watcher.MPRIS_PREFIX ) == false ){
+ interface_source.has_prefix ( MPRIS_PREFIX ) == false ){
warning("Property-changed hash is null or this is an interface that doesn't concerns us");
return;
}
@@ -95,19 +90,10 @@ public class Mpris2Controller : GLib.Object
metadata.populated(MetadataMenuitem.attributes_format()));
}
Variant? playlist_v = changed_properties.lookup("ActivePlaylist");
- if ( playlist_v != null ){
+ if ( playlist_v != null && this.owner.use_playlists == true ){
this.fetch_active_playlist();
- //Timeout.add ( 200, fetch_active_playlist );
}
}
-
- public bool playlists_support_exist()
- {
- if (this.playlists == null) return false;
- uint32? count = this.playlists.PlaylistCount;
- if ( count == null || count <= 0 ) return false;
- return true;
- }
private bool ensure_correct_playback_status(){
debug("TEST playback status = %s", this.player.PlaybackStatus);
@@ -154,8 +140,11 @@ public class Mpris2Controller : GLib.Object
GLib.HashTable<string, Value?>? cleaned_metadata = this.clean_metadata();
this.owner.custom_items[PlayerController.widget_order.METADATA].update(cleaned_metadata,
MetadataMenuitem.attributes_format());
- this.fetch_playlists();
- this.fetch_active_playlist();
+
+ if ( this.owner.use_playlists == true ){
+ this.fetch_playlists();
+ this.fetch_active_playlist();
+ }
}
public void transport_update(TransportMenuitem.action command)
@@ -174,8 +163,6 @@ public class Mpris2Controller : GLib.Object
public void fetch_playlists()
{
- if (this.playlists == null) return;
-
PlaylistDetails[] current_playlists = this.playlists.GetPlaylists(0,
10,
"Alphabetical",
@@ -185,13 +172,17 @@ public class Mpris2Controller : GLib.Object
PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem;
playlists_item.update(current_playlists);
}
+ else{
+ warning(" Playlists are on but its returning no current_playlists" );
+ this.owner.use_playlists = false;
+ }
return;
}
private void fetch_active_playlist()
- {
- if (this.playlists == null && this.playlists.ActivePlaylist.valid == false){
- warning("Playlists object is null or we don't have an active playlist");
+ {
+ if (this.playlists.ActivePlaylist.valid == false){
+ debug("We don't have an active playlist");
}
PlaylistsMenuitem playlists_item = this.owner.custom_items[PlayerController.widget_order.PLAYLISTS] as PlaylistsMenuitem;
playlists_item.update_active_playlist ( this.playlists.ActivePlaylist.details );
@@ -202,7 +193,7 @@ public class Mpris2Controller : GLib.Object
{
return (this.player != null && this.mpris2_root != null);
}
-
+
public void expose()
{
if(this.connected() == true){
@@ -212,15 +203,11 @@ public class Mpris2Controller : GLib.Object
public void activate_playlist (ObjectPath path)
{
- if(this.playlists == null){
- warning("playlists mpris instance is null !");
- return;
- }
try{
this.playlists.ActivatePlaylist.begin(path);
}
catch(IOError e){
debug("Could not activate playlist %s because %s", (string)path, e.message);
}
- }
+ }
} \ No newline at end of file
diff --git a/src/mpris2-interfaces.vala b/src/mpris2-interfaces.vala
index 88610e6..9d0b8c9 100644
--- a/src/mpris2-interfaces.vala
+++ b/src/mpris2-interfaces.vala
@@ -16,6 +16,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/>.
*/
+const string MPRIS_PREFIX = "org.mpris.MediaPlayer2.";
+const string MPRIS_MEDIA_PLAYER_PATH = "/org/mpris/MediaPlayer2";
[DBus (name = "org.mpris.MediaPlayer2")]
public interface MprisRoot : Object {
@@ -24,7 +26,7 @@ public interface MprisRoot : Object {
public abstract bool CanQuit{owned get; set;}
public abstract bool CanRaise{owned get; set;}
public abstract string Identity{owned get; set;}
- public abstract string DesktopEntry{owned get; set;}
+ public abstract string DesktopEntry{owned get; set;}
// methods
public abstract async void Quit() throws IOError;
public abstract async void Raise() throws IOError;
diff --git a/src/mpris2-watcher.vala b/src/mpris2-watcher.vala
index 7814975..c20b04b 100644
--- a/src/mpris2-watcher.vala
+++ b/src/mpris2-watcher.vala
@@ -17,30 +17,21 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-[DBus (name = "org.freedesktop.DBus")]
-public interface FreeDesktopObject: Object {
- public abstract async string[] list_names() throws IOError;
- public abstract signal void name_owner_changed ( string name,
- string old_owner,
- string new_owner );
-}
+using Xml;
public class Mpris2Watcher : GLib.Object
{
- private const string FREEDESKTOP_SERVICE = "org.freedesktop.DBus";
- private const string FREEDESKTOP_OBJECT = "/org/freedesktop/DBus";
- public const string MPRIS_PREFIX = "org.mpris.MediaPlayer2.";
- private const string MPRIS_MEDIA_PLAYER_PATH = "/org/mpris/MediaPlayer2";
-
FreeDesktopObject fdesktop_obj;
- 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 +48,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 +79,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 +106,66 @@ 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();
+ FreeDesktopIntrospectable introspectable;
+
+ 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.
+ */
+ 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
diff --git a/src/music-player-bridge.vala b/src/music-player-bridge.vala
index c7391cf..7587684 100644
--- a/src/music-player-bridge.vala
+++ b/src/music-player-bridge.vala
@@ -59,8 +59,9 @@ public class MusicPlayerBridge : GLib.Object
null,
this.fetch_icon_name(desktop),
calculate_menu_position(),
+ null,
PlayerController.state.OFFLINE );
- this.registered_clients.set(mpris_key, ctrl);
+ this.registered_clients.set(mpris_key, ctrl);
}
}
@@ -74,7 +75,9 @@ public class MusicPlayerBridge : GLib.Object
}
}
- public void client_has_become_available ( string desktop, string dbus_name )
+ public void client_has_become_available ( string desktop,
+ string dbus_name,
+ bool use_playlists )
{
if (desktop == null || desktop == ""){
warning("Client %s attempting to register without desktop entry being set on the mpris root",
@@ -82,8 +85,9 @@ public class MusicPlayerBridge : GLib.Object
return;
}
if (desktop in this.settings_manager.fetch_blacklist()) {
- debug ("Client %s attempting to register but it has been blacklisted",
+ debug ("Client %s attempting to register but I'm afraid it is blacklisted",
desktop);
+ return;
}
debug ( "client_has_become_available %s", desktop );
@@ -103,6 +107,7 @@ public class MusicPlayerBridge : GLib.Object
dbus_name,
this.fetch_icon_name(desktop),
this.calculate_menu_position(),
+ use_playlists,
PlayerController.state.READY );
this.registered_clients.set ( mpris_key, ctrl );
debug ( "Have not seen this %s before, new controller created.", desktop );
@@ -110,6 +115,7 @@ public class MusicPlayerBridge : GLib.Object
debug ( "application added to the interested list" );
}
else{
+ this.registered_clients[mpris_key].use_playlists = use_playlists;
this.registered_clients[mpris_key].update_state ( PlayerController.state.READY );
this.registered_clients[mpris_key].activate ( dbus_name );
debug("Application has already registered - awaken the hibernation: %s \n", dbus_name );
@@ -118,7 +124,8 @@ public class MusicPlayerBridge : GLib.Object
public void client_has_vanished ( string mpris_root_interface )
{
- debug("MusicPlayerBridge -> on_server_removed with value %s", mpris_root_interface);
+ debug("MusicPlayerBridge -> client with dbus interface %s has vanished",
+ mpris_root_interface );
if (root_menu != null){
debug("attempt to remove %s", mpris_root_interface);
var mpris_key = determine_key ( mpris_root_interface );
@@ -128,7 +135,7 @@ public class MusicPlayerBridge : GLib.Object
}
}
}
-
+
public void set_root_menu_item ( Dbusmenu.Menuitem menu )
{
this.root_menu = menu;
diff --git a/src/player-controller.vala b/src/player-controller.vala
index 3922ecf..adefb65 100644
--- a/src/player-controller.vala
+++ b/src/player-controller.vala
@@ -45,19 +45,22 @@ public class PlayerController : GLib.Object
private Dbusmenu.Menuitem root_menu;
public string dbus_name { get; set;}
- public ArrayList<PlayerItem> custom_items;
+ public ArrayList<PlayerItem> custom_items;
public Mpris2Controller mpris_bridge;
public AppInfo? app_info { get; set;}
public int menu_offset { get; set;}
public string icon_name { get; set; }
-
+ public bool? use_playlists;
+
public PlayerController(Dbusmenu.Menuitem root,
GLib.AppInfo app,
string? dbus_name,
string icon_name,
int offset,
+ bool? use_playlists,
state initial_state)
{
+ this.use_playlists = use_playlists;
this.root_menu = root;
this.app_info = app;
this.dbus_name = dbus_name;
@@ -67,7 +70,7 @@ public class PlayerController : GLib.Object
this.menu_offset = offset;
this.construct_widgets();
this.establish_mpris_connection();
- this.update_layout();
+ this.update_layout();
}
public void update_state(state new_state)
@@ -81,7 +84,7 @@ public class PlayerController : GLib.Object
public void activate( string dbus_name )
{
this.dbus_name = dbus_name;
- this.establish_mpris_connection();
+ this.establish_mpris_connection();
}
/*
@@ -109,6 +112,9 @@ public class PlayerController : GLib.Object
debug("establish_mpris_connection - Not ready to connect");
return;
}
+ debug ( " establish mpris connection - use playlists value = %s ",
+ this.use_playlists.to_string() );
+
this.mpris_bridge = new Mpris2Controller(this);
this.determine_state();
}
@@ -148,7 +154,7 @@ public class PlayerController : GLib.Object
this.custom_items[widget_order.TRANSPORT].property_set_bool(MENUITEM_PROP_VISIBLE,
true);
playlists_menuitem.root_item.property_set_bool ( MENUITEM_PROP_VISIBLE,
- this.mpris_bridge.playlists_support_exist() );
+ this.use_playlists );
}
private void construct_widgets()
@@ -181,9 +187,8 @@ public class PlayerController : GLib.Object
root_menu.child_add_position(playlists_menuitem.root_item, this.menu_offset + this.custom_items.index_of(item));
}
}
- }
+ }
-
private static string format_player_name(owned string app_info_name)
{
string result = app_info_name.down().strip();