diff options
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/control | 4 | ||||
-rwxr-xr-x | debian/rules | 1 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/mpris2-controller.vala | 48 | ||||
-rw-r--r-- | src/mpris2-watcher.vala | 124 | ||||
-rw-r--r-- | src/music-player-bridge.vala | 17 | ||||
-rw-r--r-- | src/player-controller.vala | 19 |
9 files changed, 160 insertions, 66 deletions
diff --git a/configure.ac b/configure.ac index c9227cd..928ffff 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,8 @@ PKG_CHECK_MODULES(SOUNDSERVICE, dbusmenu-glib >= $DBUSMENUGLIB_REQUIRED_VERSION indicator >= $INDICATOR_REQUIRED_VERSION indicate >= $INDICATE_REQUIRED_VERSION gee-1.0 - gio-unix-2.0) + gio-unix-2.0 + libxml-2.0) AC_SUBST(SOUNDSERVICE_CFLAGS) AC_SUBST(SOUNDERVICE_LIBS) diff --git a/debian/changelog b/debian/changelog index 0572e06..c694a7d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,7 +7,12 @@ indicator-sound (0.5.4-0ubuntu1) UNRELEASED; urgency=low - The players list should be customizable (LP: #685725) - gio-unix-2.0 checks (LP: #694828) - Desktop file loading should not manually use full path (LP: #693824) - + * debian/control + - Added build depends for libxml2-dev + - Added build depends for dh-autoreconf + * debian/rules + - Added autoreconf.mk + -- Ken VanDine <ken.vandine@canonical.com> Tue, 11 Jan 2011 14:38:36 -0600 indicator-sound (0.5.3-0ubuntu1) natty; urgency=low diff --git a/debian/control b/debian/control index dab145b..b6a62ad 100644 --- a/debian/control +++ b/debian/control @@ -18,7 +18,9 @@ Build-Depends: debhelper (>= 7), libgconf2-dev, libgee-dev, libindicate-dev (>= 0.4.1), - valac + libxml2-dev, + dh-autoreconf, + valac-0.12 Standards-Version: 3.9.1 Homepage: https://launchpad.net/indicator-sound diff --git a/debian/rules b/debian/rules index 0bae2ff..d778ba1 100755 --- a/debian/rules +++ b/debian/rules @@ -3,6 +3,7 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/gnome.mk include /usr/share/cdbs/1/rules/simple-patchsys.mk +include /usr/share/cdbs/1/rules/autoreconf.mk # List any files which are not installed include /usr/share/cdbs/1/rules/utils.mk diff --git a/src/Makefile.am b/src/Makefile.am index 82830e1..57f52d4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -81,7 +81,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/mpris2-controller.vala b/src/mpris2-controller.vala index 5f98541..c43f5fe 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -50,10 +50,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" ); @@ -95,19 +96,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 +146,12 @@ 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 ){ + debug ("it thinks that there is a valid playlist interface"); + this.fetch_playlists(); + this.fetch_active_playlist(); + } } public void transport_update(TransportMenuitem.action command) @@ -174,8 +170,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 +179,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 +200,7 @@ public class Mpris2Controller : GLib.Object { return (this.player != null && this.mpris2_root != null); } - + public void expose() { if(this.connected() == true){ @@ -212,15 +210,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-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 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(); |