aboutsummaryrefslogtreecommitdiff
path: root/.pc/lp_992262.patch/src/music-player-bridge.vala
diff options
context:
space:
mode:
authorKen VanDine <ken.vandine@canonical.com>2012-05-03 09:07:19 -0700
committerPackage Import Robot <package-import@ubuntu.com>2012-05-03 09:07:19 -0700
commit8c3919c60a789f650a35a72a0891daa340f9e809 (patch)
tree1d7bbe5414203e473a5e78ae4b4e2176280dbe04 /.pc/lp_992262.patch/src/music-player-bridge.vala
parent3b1ebd8c79d394fa65b53ee23255617440e2fec4 (diff)
parentb68112634c6721221dc7b82e04f798378e26bb9e (diff)
downloadayatana-indicator-sound-8c3919c60a789f650a35a72a0891daa340f9e809.tar.gz
ayatana-indicator-sound-8c3919c60a789f650a35a72a0891daa340f9e809.tar.bz2
ayatana-indicator-sound-8c3919c60a789f650a35a72a0891daa340f9e809.zip
* debian/patches/lp_992262.patch
- fix sound indicator not working after amarok close (LP: #992262) * debian/patches/lp_902715.patch - Partial fix which sets the accessibility property on the volume slider menu item. Previously this was achieved by sending a signal on the indicator object but now it seems the way to update orca is to set/update the appropriate property on the menuitem. Orca doesn't broadcast volume updates on slider movement but at least it updates when the user moves to the item on the menu, previously it was entirely silent. (LP: #902715)
Diffstat (limited to '.pc/lp_992262.patch/src/music-player-bridge.vala')
-rw-r--r--.pc/lp_992262.patch/src/music-player-bridge.vala298
1 files changed, 298 insertions, 0 deletions
diff --git a/.pc/lp_992262.patch/src/music-player-bridge.vala b/.pc/lp_992262.patch/src/music-player-bridge.vala
new file mode 100644
index 0000000..18f1c40
--- /dev/null
+++ b/.pc/lp_992262.patch/src/music-player-bridge.vala
@@ -0,0 +1,298 @@
+/*
+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/>.
+*/
+
+using Dbusmenu;
+using Gee;
+using GLib;
+
+public class MusicPlayerBridge : GLib.Object
+{
+ const int DEVICE_ITEMS_COUNT = 3;
+
+ private SettingsManager settings_manager;
+ private Dbusmenu.Menuitem root_menu;
+ private HashMap<string, PlayerController> registered_clients;
+ private HashMap<string, string> file_monitors;
+ private Mpris2Watcher watcher;
+
+ public MusicPlayerBridge()
+ {
+ }
+
+ construct{
+ this.registered_clients = new HashMap<string, PlayerController> ();
+ this.file_monitors = new HashMap<string, string> ();
+ this.settings_manager = new SettingsManager();
+ this.settings_manager.blacklist_updates.connect ( this.on_blacklist_update );
+ }
+
+ private void on_blacklist_update ( string[] blacklist )
+ {
+ debug("some blacklist update");
+
+ foreach(var s in blacklist){
+ string key = this.determine_key (s);
+ if (this.registered_clients.has_key (key)){
+ debug ("Apparently %s is now blacklisted - remove thy self", key);
+ this.registered_clients[key].remove_from_menu();
+ this.registered_clients.unset (key);
+ }
+ }
+ // double check present players to ensure dynamic removal/addition
+ this.watcher.check_for_active_clients.begin();
+ }
+
+ private void try_to_add_inactive_familiar_clients()
+ {
+ foreach ( string desktop in this.settings_manager.fetch_interested()){
+ debug ( "interested client found : %s", desktop );
+ AppInfo? app_info = create_app_info ( desktop.concat( ".desktop" ) );
+ if ( app_info == null ){
+ warning ( "Could not create app_info for path %s \n Getting out of here ",
+ desktop );
+ continue;
+ }
+ var mpris_key = determine_key ( desktop );
+ PlayerController ctrl = new PlayerController ( this.root_menu,
+ app_info,
+ null,
+ this.fetch_icon_name(desktop),
+ calculate_menu_position(),
+ null,
+ PlayerController.state.OFFLINE );
+ this.registered_clients.set(mpris_key, ctrl);
+ this.establish_file_monitoring (app_info, mpris_key);
+ }
+ }
+
+ private void establish_file_monitoring (AppInfo info, string mpris_key){
+ DesktopAppInfo desktop_info = info as DesktopAppInfo;
+ var file_path = desktop_info.get_filename ();
+ File f = File.new_for_path (file_path);
+ try {
+ FileMonitor monitor = f.monitor (FileMonitorFlags.SEND_MOVED, null);
+ unowned FileMonitor weak_monitor = monitor;
+ monitor.changed.connect ((desktop_file, other_file, event_type) => {
+ this.relevant_desktop_file_changed (desktop_file, other_file, event_type, weak_monitor);
+ });
+ monitor.ref(); // will be unref()ed by relevant_desktop_file_changed()
+ GLib.debug ("monitoring file '%s'", file_path);
+ this.file_monitors.set (file_path, mpris_key);
+ }
+ catch (Error e){
+ warning ("Unable to create a file monitor for %s", info.get_name());
+ return;
+ }
+ }
+
+ private void relevant_desktop_file_changed (File desktop_file,
+ File? other_file,
+ FileMonitorEvent event_type,
+ FileMonitor monitor)
+ {
+ if (event_type != FileMonitorEvent.DELETED)
+ return;
+
+ string? path = desktop_file.get_path ();
+ if (path == null){
+ warning ("relevant_desktop_file_changed is returning a file with no path !");
+ return;
+ }
+ if (!this.file_monitors.has_key (path)){
+ warning ("relevant_desktop_file_changed is returning a file which we know nothing about - %s",
+ path);
+ return;
+ }
+
+ var mpris_key = this.file_monitors[path];
+ GLib.debug ("file \"%s\" was removed; stopping monitoring \"%s\"", path, mpris_key);
+ this.registered_clients[mpris_key].remove_from_menu();
+ this.settings_manager.remove_interested (mpris_key);
+ this.registered_clients.unset (mpris_key);
+ monitor.cancel ();
+ monitor.unref();
+ }
+
+ private int calculate_menu_position()
+ {
+ if(this.registered_clients.size == 0){
+ return DEVICE_ITEMS_COUNT;
+ }
+ else{
+ return (DEVICE_ITEMS_COUNT + (this.registered_clients.size * PlayerController.WIDGET_QUANTITY));
+ }
+ }
+
+ 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",
+ dbus_name);
+ return;
+ }
+ if (desktop in this.settings_manager.fetch_blacklist()) {
+ debug ("Client %s attempting to register but I'm afraid it is blacklisted",
+ desktop);
+ return;
+ }
+
+ debug ( "client_has_become_available %s", desktop );
+ AppInfo? app_info = create_app_info ( desktop.concat( ".desktop" ) );
+ if ( app_info == null ){
+ warning ( "Could not create app_info for path %s \n Getting out of here ",
+ desktop );
+ return;
+ }
+
+ var mpris_key = determine_key ( desktop );
+ // Are we sure clients will appear like this with the new registration method in place.
+ if ( this.registered_clients.has_key (mpris_key) == false ){
+ debug("New client has registered that we have not seen before: %s", dbus_name );
+ PlayerController ctrl = new PlayerController ( this.root_menu,
+ app_info,
+ 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 );
+ this.settings_manager.add_interested ( desktop );
+ this.establish_file_monitoring (app_info, mpris_key);
+ 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 with playlists %s \n", dbus_name, use_playlists.to_string() );
+ }
+ }
+
+ public void client_has_vanished ( string 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 );
+ if ( mpris_key != null && this.registered_clients.has_key(mpris_key)){
+ registered_clients[mpris_key].hibernate();
+ debug("Successively offlined client %s", mpris_key);
+ }
+ }
+ }
+
+ public void set_root_menu_item ( Dbusmenu.Menuitem menu )
+ {
+ this.root_menu = menu;
+ this.try_to_add_inactive_familiar_clients();
+ this.watcher = new Mpris2Watcher ();
+ this.watcher.client_appeared.connect (this.client_has_become_available);
+ this.watcher.client_disappeared.connect (this.client_has_vanished);
+ }
+
+ public void enable_player_specific_items_for_client (string object_path,
+ string desktop_id)
+ {
+ var mpris_key = determine_key ( desktop_id );
+ if (this.registered_clients.has_key (mpris_key) == false){
+ warning ("we don't have a client with desktop id %s registered", desktop_id);
+ return;
+ }
+ this.registered_clients[mpris_key].enable_player_specific_items(object_path);
+ }
+
+ public void enable_track_specific_items_for_client (string object_path,
+ string desktop_id)
+ {
+ var mpris_key = determine_key ( desktop_id );
+ if (this.registered_clients.has_key (mpris_key) == false){
+ warning ("we don't have a client with desktop id %s registered", desktop_id);
+ return;
+ }
+ this.registered_clients[mpris_key].enable_track_specific_items(object_path);
+ }
+
+ private static AppInfo? create_app_info ( string desktop )
+ {
+ DesktopAppInfo info = new DesktopAppInfo ( desktop );
+ if ( desktop == null || info == null ){
+ warning ( "Could not create a desktopappinfo instance from app: %s", desktop );
+ return null;
+ }
+ GLib.AppInfo app_info = info as GLib.AppInfo;
+ return app_info;
+ }
+
+ private static string? fetch_icon_name(string desktop)
+ {
+ // We know the appinfo is good because it was loaded in the previous reg step.
+ DesktopAppInfo info = new DesktopAppInfo ( desktop.concat( ".desktop" ) ) ;
+ KeyFile desktop_keyfile = new KeyFile ();
+ try{
+ desktop_keyfile.load_from_file (info.get_filename(), KeyFileFlags.NONE);
+ }
+ catch(GLib.FileError error){
+ warning("Error loading keyfile - FileError");
+ return null;
+ }
+ catch(GLib.KeyFileError error){
+ warning("Error loading keyfile - KeyFileError");
+ return null;
+ }
+
+ try{
+ return desktop_keyfile.get_string (KeyFileDesktop.GROUP,
+ KeyFileDesktop.KEY_ICON);
+ }
+ catch(GLib.KeyFileError error){
+ warning("Error trying to fetch the icon name from the keyfile");
+ return null;
+ }
+ }
+
+ /*
+ Messy but necessary method to consolidate desktop filesnames and mpris dbus
+ names into the one single word string (used as the key in the players hash).
+ So this means that we can determine the key for the players_hash from the
+ dbus interface name or the desktop file name, at startup offline/online and
+ shutdown.
+ */
+ private static string? determine_key(owned string desktop_or_interface)
+ {
+ var result = desktop_or_interface;
+ var tokens = desktop_or_interface.split( "." );
+ if (tokens != null && tokens.length > 1){
+ result = tokens[tokens.length - 1];
+ }
+ var temp = result.split("-");
+ if (temp != null && temp.length > 1){
+ result = temp[0];
+ }
+ return result;
+ }
+
+}
+
+
+
+