home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / components / sbGlobalHotkeys.js < prev    next >
Text File  |  2012-06-08  |  23KB  |  749 lines

  1. /*
  2.  *=BEGIN SONGBIRD GPL
  3.  *
  4.  * This file is part of the Songbird web player.
  5.  *
  6.  * Copyright(c) 2005-2009 POTI, Inc.
  7.  * http://www.songbirdnest.com
  8.  *
  9.  * This file may be licensed under the terms of of the
  10.  * GNU General Public License Version 2 (the ``GPL'').
  11.  *
  12.  * Software distributed under the License is distributed
  13.  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
  14.  * express or implied. See the GPL for the specific language
  15.  * governing rights and limitations.
  16.  *
  17.  * You should have received a copy of the GPL along with this
  18.  * program. If not, go to http://www.gnu.org/licenses/gpl.html
  19.  * or write to the Free Software Foundation, Inc.,
  20.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21.  *
  22.  *=END SONGBIRD GPL
  23.  */
  24.  
  25. const Cc = Components.classes;
  26. const Ci = Components.interfaces;
  27. const Cu = Components.utils;
  28. const Cr = Components.results;
  29.  
  30. const SB_HOTKEY_SERVICE_CLASSNAME  = "sbHotkeyService"
  31. const SB_HOTKEY_SERVICE_DESC       = "Songbird Global Hotkey Service";
  32. const SB_HOTKEY_SERVICE_CONTRACTID = "@songbirdnest.com/Songbird/HotkeyService;1";
  33. const SB_HOTKEY_SERVICE_CID        = "{8264dc94-1dd2-11b2-ab4a-8b3dfb1072fb}";
  34.  
  35. const SB_DEFGLOBALHKACTIONS_CLASSNAME  = "sbDefaultGlobalHotkeyActions";
  36. const SB_DEFGLOBALHKACTIONS_DESC       = "Songbird Default Global Hotkey Actions";
  37. const SB_DEFGLOBALHKACTIONS_CONTRACTID = "@songbirdnest.com/Songbird/DefaultGlobalHotkeyActions;1";
  38. const SB_DEFGLOBALHKACTIONS_CID        = "{76512c09-7f02-48f5-86c0-c3a8670ead3f}";
  39.  
  40. const SB_HOTKEY_CONFIGURATION_CLASSNAME  = "sbHotkeyConfiguration";
  41. const SB_HOTKEY_CONFIGURATION_DESC       = "Songbird Hotkey Configuration";
  42. const SB_HOTKEY_CONFIGURATION_CONTRACTID = "@songbirdnest.com/Songbird/HotkeyConfiguration;1";
  43. const SB_HOTKEY_CONFIGURATION_CID        = "{5c6b204c-1dd2-11b2-8005-83725e03a0d0}";
  44.  
  45. const SB_HOTKEYMANAGER_CONTRACTID = "@songbirdnest.com/Songbird/GlobalHotkeys;1";
  46. const SB_HOTKEYACTIONS_CONTRACTID = "@songbirdnest.com/Songbird/HotkeyActions;1";
  47. const SB_COMMANDLINE_CONTRACTID   = "@songbirdnest.com/commandlinehandler/general-startup;1?type=songbird";
  48.  
  49. const STARTUP_TOPIC  = "final-ui-startup";
  50. const SHUTDOWN_TOPIC = "quit-application";
  51.  
  52. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  53. Cu.import("resource://app/jsmodules/SBDataRemoteUtils.jsm");
  54. Cu.import("resource://app/jsmodules/SBTimer.jsm");
  55.  
  56. /**
  57.  * Global getter for the Global Hotkey Manager
  58.  */
  59. __defineGetter__("HotkeyManager", function() {
  60.   delete HotkeyManager;
  61.  
  62.   if (SB_HOTKEYMANAGER_CONTRACTID in Cc) {
  63.     HotkeyManager = Cc[SB_HOTKEYMANAGER_CONTRACTID]
  64.                       .getService(Ci.sbIGlobalHotkeys);
  65.   } else {
  66.     HotkeyManager = null;
  67.   }
  68.  
  69.   return HotkeyManager;
  70. });
  71.  
  72. /**
  73.  * Global getter for Global Hotkey Actions Service
  74.  */
  75. __defineGetter__("HotkeyActions", function() {
  76.   delete HotkeyActions;
  77.  
  78.   if (SB_HOTKEYACTIONS_CONTRACTID in Cc) {
  79.     HotkeyActions = Cc[SB_HOTKEYACTIONS_CONTRACTID]
  80.                       .getService(Ci.sbIHotkeyActions);
  81.   } else {
  82.     HotkeyActions = null;
  83.   }
  84.  
  85.   return HotkeyActions;
  86. });
  87.  
  88. /**
  89.  * Global getter for the Command Line Service
  90.  */
  91.  __defineGetter__("CommandLine", function() {
  92.    delete CommandLine;
  93.  
  94.    if (SB_COMMANDLINE_CONTRACTID in Cc) {
  95.     CommandLine = Cc[SB_COMMANDLINE_CONTRACTID]
  96.                     .getService(Ci.nsICommandLineHandler)
  97.                     .QueryInterface(Ci.sbICommandLineManager);
  98.    } else {
  99.     CommandLine = null;
  100.    }
  101.  
  102.    return CommandLine;
  103. });
  104.  
  105. /**
  106.  * Global getter for Observer Service
  107.  */
  108. __defineGetter__("ObserverService", function() {
  109.   delete ObserverService;
  110.   ObserverService = Cc["@mozilla.org/observer-service;1"]
  111.                       .getService(Ci.nsIObserverService);
  112.   return ObserverService;
  113. });
  114.  
  115.  
  116.  
  117. function sbHotkeyService() {
  118.   ObserverService.addObserver(this, STARTUP_TOPIC, false);
  119. }
  120.  
  121. sbHotkeyService.prototype =
  122. {
  123.   _dataRemoteHotkeysChanged: null,
  124.   _dataRemoteHotkeysEnabled: null,
  125.   _dataRemoteObserver: null,
  126.   _platform: null,
  127.   _metaKeyString: null,
  128.   _hotkeyHandler: null,
  129.  
  130.   ///////////////////////////////////////////////////////////////////
  131.   // nsIObserver
  132.   ///////////////////////////////////////////////////////////////////
  133.   observe: function(aSubject, aTopic, aData) {
  134.     switch(aTopic) {
  135.       case STARTUP_TOPIC: {
  136.         ObserverService.removeObserver(this, STARTUP_TOPIC);
  137.         this._init();
  138.       }
  139.       break;
  140.       case SHUTDOWN_TOPIC: {
  141.         ObserverService.removeObserver(this, SHUTDOWN_TOPIC);
  142.         this._shutdown();
  143.       }
  144.       break;
  145.     }
  146.   },
  147.  
  148.   ///////////////////////////////////////////////////////////////////
  149.   // sbIHotkeyService
  150.   ///////////////////////////////////////////////////////////////////
  151.   getHotkeys: function() {
  152.     var count = SBDataGetIntValue("globalhotkeys.count");
  153.     var hotkeyConfigList = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  154.                              .createInstance(Ci.nsIMutableArray);
  155.     for (var i = 0; i < count; i++) {
  156.       var hotkeyConfig = Cc[SB_HOTKEY_CONFIGURATION_CONTRACTID]
  157.                            .createInstance(Ci.sbIHotkeyConfiguration);
  158.  
  159.       var keyBase = "globalhotkey." + i + ".";
  160.       hotkeyConfig.key = SBDataGetStringValue(keyBase + "key");
  161.       hotkeyConfig.keyReadable = SBDataGetStringValue(keyBase + "key.readable");
  162.       hotkeyConfig.action = SBDataGetStringValue(keyBase + "action");
  163.  
  164.       if (!this._configListContainsKey(hotkeyConfigList, hotkeyConfig.key))
  165.         hotkeyConfigList.appendElement(hotkeyConfig, false);
  166.     }
  167.  
  168.     return hotkeyConfigList;
  169.   },
  170.  
  171.   getHotkey: function(aKey) {
  172.     var hotkeyConfigList = this.getHotkeys();
  173.     for (var i = 0; i < hotkeyConfigList.length; i++) {
  174.       var hotkeyConfig =
  175.             hotkeyConfigList.queryElementAt(i, Ci.sbIHotkeyConfiguration);
  176.       if (hotkeyConfig.key == aKey)
  177.         return hotkeyConfig;
  178.     }
  179.  
  180.     return null;
  181.   },
  182.  
  183.   setHotkeys: function(aHotkeyConfigList) {
  184.     SBDataDeleteBranch("globalhotkey");
  185.     for (var i = 0; i < aHotkeyConfigList.length; i++) {
  186.       var hotkeyConfig =
  187.             aHotkeyConfigList.queryElementAt(i, Ci.sbIHotkeyConfiguration);
  188.  
  189.       var keyBase = "globalhotkey." + i + ".";
  190.       SBDataSetStringValue(keyBase + "key", hotkeyConfig.key);
  191.       SBDataSetStringValue(keyBase + "key.readable", hotkeyConfig.keyReadable);
  192.       SBDataSetStringValue(keyBase + "action", hotkeyConfig.action);
  193.     }
  194.     SBDataSetIntValue("globalhotkeys.count", aHotkeyConfigList.length);
  195.     this._loadHotkeysFromPrefs();
  196.   },
  197.  
  198.   addHotkey: function(aHotkeyConfig) {
  199.     var hotkeyConfigList = this.getHotkeys();
  200.     this._removeHotkeyFromConfigList(hotkeyConfigList, aHotkeyConfig.key);
  201.     hotkeyConfigList.appendElement(aHotkeyConfig, false);
  202.     this.setHotkeys(hotkeyConfigList);
  203.   },
  204.  
  205.   removeHotkeyByKey: function(aKey) {
  206.     var hotkeyConfigList = this.getHotkeys();
  207.     this._removeHotkeyFromConfigList(hotkeyConfigList, aKey);
  208.     this.setHotkeys(hotkeyConfigList);
  209.   },
  210.  
  211.   removeHotkeysByAction: function(aAction) {
  212.     var hotkeyConfigList = this.getHotkeys();
  213.     for (var i = hotkeyConfigList.length - 1; i >= 0; i--) {
  214.       var hotkeyConfig =
  215.             hotkeyConfigList.queryElementAt(i, Ci.sbIHotkeyConfiguration);
  216.       if (hotkeyConfig.action == aAction)
  217.         hotkeyConfigList.removeElementAt(i);
  218.     }
  219.     this.setHotkeys(hotkeyConfigList);
  220.   },
  221.  
  222.   get hotkeysEnabled() {
  223.     return SBDataGetBoolValue("globalhotkeys.enabled");
  224.   },
  225.  
  226.   set hotkeysEnabled(aEnabled) {
  227.     SBDataSetBoolValue("globalhotkeys.enabled", aEnabled);
  228.     this._loadHotkeysFromPrefs();
  229.   },
  230.  
  231.   get hotkeysEnabledDRKey() {
  232.     return "globalhotkeys.enabled";
  233.   },
  234.  
  235.   ///////////////////////////////////////////////////////////////////
  236.   // Internal Methods
  237.   ///////////////////////////////////////////////////////////////////
  238.   _init: function() {
  239.     if(!HotkeyManager) {
  240.       Cu.reportError("Global Hotkey Manager is not available.");
  241.       return;
  242.     }
  243.  
  244.     this._initPlatform();
  245.     this._initMetaKeyString();
  246.     this._initHotkeyHandler();
  247.  
  248.     this._loadDefaultHotkeys();
  249.  
  250.     this._loadHotkeysFromPrefs();
  251.  
  252.     if(!HotkeyActions) {
  253.       Cu.reportError("Global Hotkey Actions Service is not available.");
  254.       return;
  255.     }
  256.  
  257.     // Register the default set of actions.
  258.     var defaultActions = Cc[SB_DEFGLOBALHKACTIONS_CONTRACTID]
  259.                            .createInstance(Ci.sbIHotkeyActionBundle);
  260.     HotkeyActions.registerHotkeyActionBundle(defaultActions);
  261.  
  262.     // Register observer for application shutdown to clean up.
  263.     ObserverService.addObserver(this, SHUTDOWN_TOPIC, false);
  264.  
  265.     // Indicate that the service is ready.
  266.     var serviceManager = Cc["@songbirdnest.com/Songbird/ServiceManager;1"]
  267.                            .getService(Ci.sbIServiceManager);
  268.     serviceManager.setServiceReady(SB_HOTKEY_SERVICE_CONTRACTID, true);
  269.   },
  270.  
  271.   _shutdown: function() {
  272.     // Indicate that the service is no longer ready.
  273.     var serviceManager = Cc["@songbirdnest.com/Songbird/ServiceManager;1"]
  274.                            .getService(Ci.sbIServiceManager);
  275.     serviceManager.setServiceReady(SB_HOTKEY_SERVICE_CONTRACTID, false);
  276.  
  277.     if (CommandLine) {
  278.       CommandLine.removeFlagHandler(this._hotkeyHandler, "hotkey");
  279.     }
  280.  
  281.     this._hotkeyHandler = null;
  282.  
  283.     if (HotkeyManager) {
  284.       HotkeyManager.removeAllHotkeys();
  285.     }
  286.   },
  287.  
  288.   _initPlatform: function() {
  289.     try {
  290.       var sysInfo =
  291.         Components.classes["@mozilla.org/system-info;1"]
  292.                   .getService(Components.interfaces.nsIPropertyBag2);
  293.       this._platform = sysInfo.getProperty("name");
  294.     }
  295.     catch (e) {
  296.       Cu.reportError(e);
  297.  
  298.       var user_agent = navigator.userAgent;
  299.       if (user_agent.indexOf("Windows") != -1)
  300.         this._platform = "Windows_NT";
  301.       else if (user_agent.indexOf("Mac OS X") != -1)
  302.         this._platform = "Darwin";
  303.       else if (user_agent.indexOf("Linux") != -1)
  304.         this._platform = "Linux";
  305.       else if (user_agent.indexOf("SunOS") != -1)
  306.         this._platform = "SunOS";
  307.     }
  308.   },
  309.  
  310.   _initMetaKeyString: function() {
  311.     switch(this._platform) {
  312.       case "Windows_NT": this._metaKeyString = "win"; break;
  313.       case "Darwin": this._metaKeyString = "command"; break;
  314.       case "Linux": this._metaKeyString = "meta"; break;
  315.       default: this._metaKeyString = "meta";
  316.     }
  317.   },
  318.  
  319.   _initHotkeyHandler: function() {
  320.     if (!CommandLine) {
  321.       Cu.reportError("Command Line Handler is not available.");
  322.       return;
  323.     }
  324.  
  325.     if (!this._hotkeyHandler) {
  326.       /**
  327.        * The default hotkey handler
  328.        */
  329.       this._hotkeyHandler = {
  330.         onHotkey: function (aHotkeyId) {
  331.           aHotkeyId = aHotkeyId.toLowerCase();
  332.           // look through the action bundles to find the right action to trigger
  333.           for (var i = 0;i < HotkeyActions.bundleCount; i++)
  334.           {
  335.             var bundle = HotkeyActions.enumBundle(i);
  336.             for (var j=0;j<bundle.actionCount;j++)
  337.             {
  338.               var id = bundle.enumActionID(j);
  339.               if (id.toLowerCase() == aHotkeyId) {
  340.                 bundle.onAction(j);
  341.                 return;
  342.               }
  343.             }
  344.           }
  345.         },
  346.  
  347.         handleFlag: function(aFlag, aParam)
  348.         {
  349.           var ids = aParam.split(",");
  350.           for (var i = 0; i < ids.length; i++) {
  351.             this.onHotkey(ids[i]);
  352.           }
  353.  
  354.           return true;
  355.         },
  356.  
  357.         QueryInterface : XPCOMUtils.generateQI([Ci.sbIGlobalHotkeyCallback,
  358.                                                 Ci.sbICommandLineFlagHandler,
  359.                                                 Ci.nsISupportsWeakReference])
  360.       };
  361.     }
  362.  
  363.     CommandLine.addFlagHandler(this._hotkeyHandler, "hotkey");
  364.   },
  365.  
  366.   /**
  367.    * \brief Load the hotkeys saved in the users prefs
  368.    */
  369.   _loadHotkeysFromPrefs: function() {
  370.     this._removeHotkeyBindings();
  371.  
  372.     var enabled = SBDataGetBoolValue("globalhotkeys.enabled");
  373.  
  374.     if (!enabled) {
  375.       return;
  376.     }
  377.  
  378.     var count = SBDataGetIntValue("globalhotkeys.count");
  379.     for (var i = 0;i < count; i++) {
  380.       // Read hotkey binding from user preferences
  381.       let root = "globalhotkey." + i + ".";
  382.       let keycombo = SBDataGetStringValue(root + "key");
  383.       let action = SBDataGetStringValue(root + "action");
  384.  
  385.       // Split key combination string
  386.       let keys = keycombo.split("-");
  387.  
  388.       // Parse its components
  389.       let alt = false;
  390.       let ctrl = false;
  391.       let shift = false;
  392.       let meta = false;
  393.       let keyCode = 0;
  394.  
  395.       for (var j = 0; j < keys.length; j++) {
  396.         keys[j] = keys[j].toLowerCase();
  397.         switch (keys[j]) {
  398.           case "alt": alt = true; break;
  399.           case "shift": shift = true; break;
  400.           case "ctrl": ctrl = true; break;
  401.           case "meta": meta = true; break;
  402.           default: keyCode = this._stringToKeyCode(keys[j]);
  403.         }
  404.       }
  405.  
  406.       // If we had a key code (and possibly modifiers), register the corresponding action for it
  407.       if (keyCode != 0) {
  408.         HotkeyManager.addHotkey(keyCode,
  409.                                 alt,
  410.                                 ctrl,
  411.                                 shift,
  412.                                 meta,
  413.                                 action,
  414.                                 this._hotkeyHandler);
  415.       }
  416.     }
  417.  
  418.   },
  419.  
  420.   /**
  421.    * \brief Load the default set of hotkeys
  422.    */
  423.   _loadDefaultHotkeys: function() {
  424.     // Global Hotkeys have already changed, don't load the default set.
  425.     if (SBDataGetBoolValue("globalhotkeys.changed")) {
  426.       return;
  427.     }
  428.  
  429.     // Indicate that the global hotkeys have changed and are enabled
  430.     SBDataSetBoolValue("globalhotkeys.changed", true);
  431.     SBDataSetBoolValue("globalhotkeys.enabled", true);
  432.  
  433.     // Hot key list
  434.     var metaKey = this._metaKeyString;
  435.     var hotkeyConfigList =
  436.     [
  437.       // Media keys
  438.       { key:         "$176",
  439.         keyReadable: "nexttrack",
  440.         action:      "playback.nexttrack" },
  441.  
  442.       { key:         "$177",
  443.         keyReadable: "prevtrack",
  444.         action:      "playback.previoustrack" },
  445.  
  446.       { key:         "$179",
  447.         keyReadable: "playpause",
  448.         action:      "playback.playpause" },
  449.  
  450.       // Regular keys
  451.       { key:         "meta-$190",
  452.         keyReadable: metaKey + " - .",
  453.         action:      "playback.volumeup" },
  454.  
  455.       { key:         "meta-$188",
  456.         keyReadable: metaKey + " - ,",
  457.         action:      "playback.volumedown" },
  458.  
  459.       { key:         "meta-$221",
  460.         keyReadable: metaKey + " - ]",
  461.         action:      "playback.nexttrack" },
  462.  
  463.       { key:         "meta-$219",
  464.         keyReadable: metaKey + " - [",
  465.         action:      "playback.previoustrack" },
  466.  
  467.       { key:         "meta-$220",
  468.         keyReadable: metaKey + " - \\",
  469.         action:      "playback.playpause" },
  470.  
  471.       { key:         "$178",
  472.         keyReadable: "stop",
  473.         action:      "playback.stop" }
  474.     ];
  475.  
  476.     // Build an array of hot key configurations
  477.     var hotkeyConfigArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  478.                               .createInstance(Ci.nsIMutableArray);
  479.     for (var i = 0; i < hotkeyConfigList.length; i++) {
  480.       var hotkeyConfiguration = Cc[SB_HOTKEY_CONFIGURATION_CONTRACTID]
  481.                                   .createInstance(Ci.sbIHotkeyConfiguration);
  482.       hotkeyConfiguration.key =         hotkeyConfigList[i].key;
  483.       hotkeyConfiguration.keyReadable = hotkeyConfigList[i].keyReadable;
  484.       hotkeyConfiguration.action =      hotkeyConfigList[i].action;
  485.       hotkeyConfigArray.appendElement(hotkeyConfiguration, false);
  486.     }
  487.  
  488.     // Set the default hot keys
  489.     this.setHotkeys(hotkeyConfigArray);
  490.   },
  491.  
  492.   /**
  493.    * \brief Remove all hotkeys currently bound
  494.    */
  495.   _removeHotkeyBindings: function() {
  496.     if (HotkeyManager) {
  497.       HotkeyManager.removeAllHotkeys();
  498.     }
  499.   },
  500.  
  501.   _stringToKeyCode: function(aStr) {
  502.     if (aStr.slice(0, 1) == '$') {
  503.       return aStr.slice(1);
  504.     }
  505.  
  506.     return 0;
  507.   },
  508.  
  509.   _configListContainsKey: function(aHotkeyConfigList, aKey) {
  510.     for (var i = 0; i < aHotkeyConfigList.length; i++) {
  511.       var hotkeyConfig =
  512.             aHotkeyConfigList.queryElementAt(i, Ci.sbIHotkeyConfiguration);
  513.       if (hotkeyConfig.key == aKey)
  514.         return true;
  515.     }
  516.  
  517.     return false;
  518.   },
  519.  
  520.   _removeHotkeyFromConfigList: function(aHotkeyConfigList, aKey) {
  521.     for (var i = aHotkeyConfigList.length - 1; i >= 0; i--) {
  522.       var hotkeyConfig =
  523.             aHotkeyConfigList.queryElementAt(i, Ci.sbIHotkeyConfiguration);
  524.       if (hotkeyConfig.key == aKey)
  525.         aHotkeyConfigList.removeElementAt(i);
  526.     }
  527.   },
  528.  
  529.   className: SB_HOTKEY_SERVICE_CLASSNAME,
  530.   classDescription: SB_HOTKEY_SERVICE_DESC,
  531.   classID: Components.ID(SB_HOTKEY_SERVICE_CID),
  532.   contractID: SB_HOTKEY_SERVICE_CONTRACTID,
  533.   _xpcom_categories: [
  534.     {
  535.       category: "app-startup",
  536.       entry:    SB_HOTKEY_SERVICE_DESC,
  537.       value:    "service," + SB_HOTKEY_SERVICE_CONTRACTID
  538.     }
  539.   ],
  540.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
  541.                                          Ci.sbIHotkeyService])
  542. };
  543.  
  544.  
  545. function sbDefaultGlobalHotkeyActions() {
  546. }
  547.  
  548. sbDefaultGlobalHotkeyActions.prototype =
  549. {
  550.   /**
  551.    * You should change these to match your own actions, strings, and
  552.    * stringbundle (ie, you will need to ship your own translations with
  553.    * your extension since the description string you use will probably
  554.    * not be in the standard songbird string bundle)
  555.    */
  556.   _packagename: "playback",
  557.  
  558.   _actions: [ "volumeup",
  559.               "volumedown",
  560.               "nexttrack",
  561.               "previoustrack",
  562.               "playpause",
  563.               "pause",
  564.               "stop" ],
  565.   /**
  566.    * The string bundle to use to get the localized strings
  567.    * (ie, hotkeys.actions.playback, hotkeys.actions.playback.volumeup,
  568.    * hotkeys.actions.playback.volumedown, etc).
  569.    */
  570.   _stringbundle: "chrome://songbird/locale/songbird.properties",
  571.  
  572.   /**
  573.    * Internal data
  574.    */
  575.   _localpackagename: null,
  576.   _sbs: null,
  577.   _songbirdStrings: null,
  578.  
  579.   /**
  580.    * This enumerates the actions, their localized display strings,
  581.    * and their internal ids, so that the hotkey action manager may list them
  582.    * in the hotkeys preference pane.
  583.    */
  584.   get actionCount() {
  585.     return this._actions.length;
  586.   },
  587.  
  588.   enumActionLocaleDescription: function (aIndex) {
  589.     return this._getLocalizedPackageName() +
  590.            ": " +
  591.            this._getLocalizedActionName(this._actions[aIndex]);
  592.   },
  593.  
  594.   enumActionID: function(aIndex) {
  595.     return this._packagename + "." + this._actions[aIndex];
  596.   },
  597.  
  598.   /**
  599.    * This is called when an action has been triggered
  600.    */
  601.   onAction: function(aIndex) {
  602.     switch (aIndex) {
  603.       case 0: this._hotkey_volumeUp(); break;
  604.       case 1: this._hotkey_volumeDown(); break;
  605.       case 2: this._hotkey_nextTrack(); break;
  606.       case 3: this._hotkey_previousTrack(); break;
  607.       case 4: this._hotkey_playPause(); break;
  608.       case 5: this._hotkey_pause(); break;
  609.       case 6: this._hotkey_stop(); break;
  610.     }
  611.   },
  612.  
  613.   get _mm() {
  614.     return Cc["@songbirdnest.com/Songbird/Mediacore/Manager;1"]
  615.              .getService(Ci.sbIMediacoreManager);
  616.   },
  617.  
  618.   _hotkey_volumeUp: function() {
  619.     var volume = this._mm.volumeControl.volume + 0.03;
  620.     if (volume > 1) volume = 1;
  621.     this._mm.volumeControl.volume = volume;
  622.   },
  623.  
  624.   _hotkey_volumeDown: function() {
  625.     var volume = this._mm.volumeControl.volume - 0.03;
  626.     if (volume < 0) volume = 0;
  627.     this._mm.volumeControl.volume = volume;
  628.   },
  629.  
  630.   _hotkey_nextTrack: function() {
  631.     this._mm.sequencer.next();
  632.   },
  633.  
  634.   _hotkey_previousTrack: function() {
  635.     this._mm.sequencer.previous();
  636.   },
  637.  
  638.   _hotkey_playPause: function() {
  639.     try {
  640.       // If we are already playing something just pause/unpause playback
  641.       if (this._mm.status.state == Ci.sbIMediacoreStatus.STATUS_PLAYING ||
  642.           this._mm.status.state == Ci.sbIMediacoreStatus.STATUS_BUFFERING) {
  643.           this._mm.playbackControl.pause();
  644.       }
  645.       else if(this._mm.status.state == Ci.sbIMediacoreStatus.STATUS_PAUSED) {
  646.           this._mm.playbackControl.play();
  647.       }
  648.       // Otherwise just have the root application controller figure it out
  649.       else {
  650.         // If we have no context, initiate playback
  651.         // via the root application controller
  652.         var app = Cc["@songbirdnest.com/Songbird/ApplicationController;1"]
  653.                     .getService(Ci.sbIApplicationController);
  654.         app.playDefault();
  655.       }
  656.     } catch (e) {
  657.       Cu.reportError(e);
  658.     }
  659.   },
  660.  
  661.   _hotkey_pause: function() {
  662.     this._mm.playbackControl.pause();
  663.   },
  664.  
  665.   _hotkey_stop: function() {
  666.     this._mm.playbackControl.stop();
  667.   },
  668.  
  669.   _getLocalizedString: function(str, defaultstr) {
  670.     var r = defaultstr;
  671.     if (!this._sbs) {
  672.       this._sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  673.                     .getService(Ci.nsIStringBundleService);
  674.       this._songbirdStrings = this._sbs.createBundle(this._stringbundle);
  675.     }
  676.     try {
  677.       r = this._songbirdStrings.GetStringFromName(str);
  678.     } catch (e) { /* we have a default */ }
  679.  
  680.     return r;
  681.   },
  682.  
  683.   /**
  684.    * The local package name is taken from the specified string bundle,
  685.    * using the key "hotkeys.actions.package", where package is
  686.    * the internal name of the package, as specified in this._packagename.
  687.    */
  688.   _getLocalizedPackageName: function() {
  689.     if (!this._localpackage)
  690.       this._localpackage = this._getLocalizedString("hotkeys.actions." +
  691.                                                     this._packagename,
  692.                                                     this._packagename);
  693.     return this._localpackage;
  694.   },
  695.  
  696.   /**
  697.    * the local action name is taken from the specified string bundle, using
  698.    * the key "hotkeys.actions.package.action", where package
  699.    * is the internal name of the package, as specified in this._packagename,
  700.    * and action is the internal name of the action, as specified in the
  701.    * this._actions array.
  702.    */
  703.   _getLocalizedActionName: function(action) {
  704.     return this._getLocalizedString("hotkeys.actions." +
  705.                                     this._packagename +
  706.                                     "." +
  707.                                     action,
  708.                                     action);
  709.   },
  710.  
  711.   className: SB_DEFGLOBALHKACTIONS_CLASSNAME,
  712.   classDescription: SB_DEFGLOBALHKACTIONS_DESC,
  713.   classID: Components.ID(SB_DEFGLOBALHKACTIONS_CID),
  714.   contractID: SB_DEFGLOBALHKACTIONS_CONTRACTID,
  715.   QueryInterface: XPCOMUtils.generateQI([Ci.sbIHotkeyActionBundle,
  716.                                          Ci.nsISupportsWeakReference,
  717.                                          Ci.nsISupports])
  718. };
  719.  
  720.  
  721. function sbHotkeyConfiguration() {
  722. }
  723.  
  724. sbHotkeyConfiguration.prototype =
  725. {
  726.   key: null,
  727.   keyReadable: null,
  728.   action: null,
  729.  
  730.   className: SB_HOTKEY_CONFIGURATION_CLASSNAME,
  731.   classDescription: SB_HOTKEY_CONFIGURATION_DESC,
  732.   classID: Components.ID(SB_HOTKEY_CONFIGURATION_CID),
  733.   contractID: SB_HOTKEY_CONFIGURATION_CONTRACTID,
  734.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
  735.                                          Ci.sbIHotkeyConfiguration])
  736. };
  737.  
  738.  
  739. //------------------------------------------------------------------------------
  740. // XPCOM Registration
  741.  
  742. function NSGetModule(compMgr, fileSpec)
  743. {
  744.   return XPCOMUtils.generateModule([sbHotkeyService,
  745.                                     sbDefaultGlobalHotkeyActions,
  746.                                     sbHotkeyConfiguration]);
  747. }
  748.  
  749.