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

  1. /*
  2.  *=BEGIN SONGBIRD GPL
  3.  *
  4.  * This file is part of the Songbird web player.
  5.  *
  6.  * Copyright(c) 2005-2010 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. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  26.  
  27. if (typeof(Cc) == "undefined")
  28.   var Cc = Components.classes;
  29. if (typeof(Ci) == "undefined")
  30.   var Ci = Components.interfaces;
  31. if (typeof(Cu) == "undefined")
  32.   var Cu = Components.utils;
  33. if (typeof(Cr) == "undefined")
  34.   var Cr = Components.results;
  35.  
  36.  
  37. //------------------------------------------------------------------------------
  38. // Constants
  39.  
  40. const SB_OSDHIDE_DELAY = 3000;
  41. const MAX_OSD_WIDTH    = 502;
  42. const OSD_HEIGHT       = 70;
  43. const OSD_PADDING      = 18;  // 9 on each side.
  44.  
  45.  
  46. //==============================================================================
  47. //
  48. // @interface sbOSDControlService
  49. // @brief Service to provide on-screen-display controls for video playback.
  50. //
  51. //==============================================================================
  52.  
  53. function sbOSDControlService()
  54. {
  55.   this._cloakService = Cc["@songbirdnest.com/Songbird/WindowCloak;1"]
  56.                          .getService(Ci.sbIWindowCloak);
  57.   this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  58.  
  59.   // Ask the window chrome service (if available) if it supports window
  60.   // composition to enable transparent graphics for the OSD.
  61.   this._useTransparentGraphics = true;
  62.   if ("@songbirdnest.com/Songbird/WindowChromeService;1" in Cc) {
  63.     var winChromeService =
  64.       Cc["@songbirdnest.com/Songbird/WindowChromeService;1"]
  65.         .getService(Ci.sbIWindowChromeService);
  66.     this._useTransparentGraphics = winChromeService.isCompositionEnabled;
  67.   }
  68. }
  69.  
  70. sbOSDControlService.prototype =
  71. {
  72.   _videoWindow:            null,
  73.   _osdWindow:              null,
  74.   _cloakService:           null,
  75.   _timer:                  null,
  76.   _osdControlsShowing:     false,
  77.   _useTransparentGraphics: false,
  78.   
  79.   _videoWinHasFocus:      false,
  80.   _osdWinHasFocus:        false,
  81.   _mouseDownOnOSD:        false,
  82.   
  83.   _fadeInterval: null,
  84.   _fadeContinuation: null,
  85.  
  86.  
  87.   _recalcOSDPosition: function() {
  88.     // Compute the position of the OSD controls using the video windows local
  89.     // and screen coordinates.
  90.     var osdY = this._videoWindow.screenY +
  91.       (this._videoWindow.outerHeight * 0.95 - this._osdWindow.outerHeight);
  92.  
  93.     // Resize the osd window as needed. (after move if needed)
  94.     var newOSDWidth = this._osdWindow.innerWidth;
  95.     if (this._videoWindow.innerWidth + OSD_PADDING > MAX_OSD_WIDTH) {
  96.       newOSDWidth = MAX_OSD_WIDTH;
  97.     }
  98.     else {
  99.       newOSDWidth = this._videoWindow.innerWidth - OSD_PADDING;
  100.     }
  101.  
  102.     // Now compute X position.
  103.     var osdX = this._videoWindow.screenX +
  104.       (this._videoWindow.innerWidth / 2) - (newOSDWidth / 2);
  105.  
  106.     // Move to the new (x,y) coordinates.
  107.     this._osdWindow.moveTo(osdX, osdY);
  108.  
  109.     // Now finally resize the osd window.
  110.     this._osdWindow.resizeTo(newOSDWidth, OSD_HEIGHT);
  111.   },
  112.  
  113.   //----------------------------------------------------------------------------
  114.   // sbIOSDControlService
  115.  
  116.   onVideoWindowOpened: function(aVideoWindow) {
  117.     // For now, just open the OSD control pane thingy.
  118.     this._videoWindow = aVideoWindow.QueryInterface(Ci.nsIDOMWindowInternal);
  119.  
  120.     // Create a OSD overlay window.
  121.     this._osdWindow = this._videoWindow.openDialog(
  122.         "chrome://songbird/content/xul/videoWindowControls.xul",
  123.         "Songbird OSD Control Window",
  124.         "chrome,dependent,modal=no,titlebar=no",
  125.         null);
  126.     this._osdWindow.QueryInterface(Ci.nsIDOMWindowInternal);
  127.  
  128.     // Cloak the window right now.
  129.     this._cloakService.cloak(this._osdWindow);
  130.  
  131.     try {
  132.       // Not all platforms have this service.
  133.       var winMoveService =
  134.         Cc["@songbirdnest.com/integration/window-move-resize-service;1"]
  135.         .getService(Ci.sbIWindowMoveService);
  136.  
  137.       winMoveService.startWatchingWindow(this._videoWindow, this);
  138.     }
  139.     catch (e) {
  140.       // No window move service on this platform.
  141.     }
  142.  
  143.     // Listen for blur and focus events for determing when both the video
  144.     // window and the OSD controls loose focus.
  145.     var self = this;
  146.     this._osdWinBlurListener = function(aEvent) {
  147.       self._onOSDWinBlur(aEvent);
  148.     };
  149.     this._videoWinBlurListener = function(aEvent) {
  150.       self._onVideoWinBlur(aEvent);
  151.     };
  152.     this._osdWinFocusListener = function(aEvent) {
  153.       self._onOSDWinFocus(aEvent);
  154.     };
  155.     this._videoWinFocusListener = function(aEvent) {
  156.       self._onVideoWinFocus(aEvent);
  157.     };
  158.     this._osdWinMousemoveListener = function(aEvent) {
  159.       self._onOSDWinMousemove(aEvent);
  160.     };
  161.     this._osdWinMousedownListener = function(aEvent) {
  162.       self._onOSDWinMousedown(aEvent);
  163.     };
  164.     this._osdWinMouseupListener = function(aEvent) {
  165.       self._onOSDWinMouseup(aEvent);
  166.     };
  167.     this._osdWinKeypressListener = function(aEvent) {
  168.       self._onOSDWinKeypress(aEvent);
  169.     };
  170.     this._osdWindow.addEventListener("blur",
  171.                                      this._osdWinBlurListener,
  172.                                      false);
  173.     this._osdWindow.addEventListener("focus",
  174.                                      this._osdWinFocusListener,
  175.                                      false);
  176.     this._osdWindow.addEventListener("mousemove",
  177.                                      this._osdWinMousemoveListener,
  178.                                      false);
  179.     this._videoWindow.addEventListener("mousemove",
  180.                                        this._osdWinMousemoveListener,
  181.                                        false);
  182.     this._osdWindow.addEventListener("mousedown",
  183.                                      this._osdWinMousedownListener,
  184.                                      false);
  185.     this._osdWindow.addEventListener("mouseup",
  186.                                      this._osdWinMouseupListener,
  187.                                      false);
  188.     this._osdWindow.addEventListener("keypress",
  189.                                      this._osdWinKeypressListener,
  190.                                      false);
  191.     this._videoWindow.addEventListener("blur",
  192.                                        this._videoWinBlurListener,
  193.                                        false);
  194.     this._videoWindow.addEventListener("focus",
  195.                                        this._videoWinFocusListener,
  196.                                        false);
  197.   },
  198.  
  199.   onVideoWindowWillClose: function() {
  200.     try {
  201.       // Not all platforms have this service.
  202.       var winMoveService =
  203.         Cc["@songbirdnest.com/integration/window-move-resize-service;1"]
  204.         .getService(Ci.sbIWindowMoveService);
  205.  
  206.       winMoveService.stopWatchingWindow(this._videoWindow, this);
  207.     }
  208.     catch (e) {
  209.       // No window move service on this platform.
  210.     }
  211.     
  212.     this._timer.cancel();
  213.     this._osdWindow.removeEventListener("blur",
  214.                                         this._osdWinBlurListener,
  215.                                         false);
  216.     this._osdWindow.removeEventListener("focus",
  217.                                         this._osdWinFocusListener,
  218.                                         false);
  219.     this._osdWindow.removeEventListener("mousemove",
  220.                                         this._osdWinMousemoveListener,
  221.                                         false);
  222.     this._osdWindow.removeEventListener("mousedown",
  223.                                         this._osdWinMousedownListener,
  224.                                         false);
  225.     this._osdWindow.removeEventListener("mouseup",
  226.                                         this._osdWinMouseupListener,
  227.                                         false);
  228.     this._osdWindow.removeEventListener("keypress",
  229.                                         this._osdWinKeypressListener,
  230.                                         false);
  231.     this._videoWindow.removeEventListener("blur",
  232.                                           this._videoWinBlurListener,
  233.                                           false);
  234.     this._videoWindow.removeEventListener("focus",
  235.                                           this._videoWinFocusListener,
  236.                                           false);
  237.     this._osdWindow.close();
  238.     this._osdWindow = null;
  239.     this._videoWindow = null;
  240.   },
  241.  
  242.   onVideoWindowResized: function() {
  243.     this._recalcOSDPosition();
  244.   },
  245.   
  246.   onVideoWindowFullscreenChanged: function(aFullscreen) {
  247.     var outterBox = 
  248.       this._osdWindow.document.getElementById("osd_wrapper_hbox");
  249.     var fullscreenButton =
  250.       this._osdWindow.document.getElementById("full_screen_button");
  251.     
  252.     if(outterBox) {
  253.       if(aFullscreen) {
  254.         outterBox.setAttribute("fullscreen", true);
  255.         fullscreenButton.setAttribute("fullscreen", true);
  256.       }
  257.       else {
  258.         outterBox.removeAttribute("fullscreen");
  259.         fullscreenButton.removeAttribute("fullscreen");
  260.       }
  261.     }
  262.   },
  263.  
  264.   hideOSDControls: function(aTransitionType) {
  265.     var self = this;
  266.     // Don't hide the window while the user is dragging
  267.     if (this._mouseDownOnOSD)
  268.       return;
  269.  
  270.     this._timer.cancel();
  271.  
  272.     var transition;
  273.     switch (aTransitionType) {
  274.       case Ci.sbIOSDControlService.TRANSITION_FADE:
  275.         transition = this._fadeOut;
  276.         break;
  277.  
  278.       case Ci.sbIOSDControlService.TRANSITION_NONE:
  279.         transition = this._hideInstantly;
  280.         break;
  281.  
  282.       default:
  283.         Components.utils.reportError(
  284.             "Invalid transition type passed into hideOSDControls()!");
  285.  
  286.         // Just fall back to hiding instantly.
  287.         transition = this._hideInstantly; 
  288.     }
  289.  
  290.     if (!this._useTransparentGraphics) {
  291.       transition = this._hideInstantly;
  292.     }
  293.  
  294.     transition.call(this, function() {
  295.       // The OSD controls are no longer showing. The order of events
  296.       // here is critical; surprisingly, the cloaking must happen
  297.       // last.
  298.       self._osdControlsShowing = false;
  299.  
  300.       if (!self._cloakService.isCloaked(self._osdWindow)) {
  301.         if (self._osdWinHasFocus) {
  302.           self._videoWindow.focus();
  303.         }
  304.         self._cloakService.cloak(self._osdWindow);
  305.       }
  306.     });
  307.   },
  308.  
  309.   showOSDControls: function(aTransitionType) {
  310.     if (!this._videoWinHasFocus &&
  311.         !this._osdWinHasFocus)
  312.     {
  313.       // Don't bother showing the controls if the video and the OSD window have
  314.       // lost focus. This prevents floating the OSD controls ontop of every
  315.       // other window in the OS.
  316.       return;
  317.     }
  318.  
  319.     if (this._osdSurpressed)
  320.       return;
  321.  
  322.     this._timer.cancel();
  323.     this._timer.initWithCallback(this,
  324.                                  SB_OSDHIDE_DELAY,
  325.                                  Ci.nsITimer.TYPE_ONE_SHOT);
  326.  
  327.     // if the osd is already visible, then all we need to do is reset the timer
  328.     // and make sure the controls are focused.
  329.     if (this._osdControlsShowing) {
  330.       this._osdWindow.focus();
  331.       return;
  332.     }
  333.     
  334.     // Controls are showing
  335.     this._osdControlsShowing = true;
  336.     this._recalcOSDPosition();
  337.  
  338.     // Show the controls if they are currently hidden.
  339.     if (this._cloakService.isCloaked(this._osdWindow)) {
  340.       this._cloakService.uncloak(this._osdWindow);
  341.     }
  342.  
  343.     var transition;
  344.     switch (aTransitionType) {
  345.       case Ci.sbIOSDControlService.TRANSITION_FADE:
  346.         transition = this._fadeIn;
  347.         break;
  348.  
  349.       case Ci.sbIOSDControlService.TRANSITION_NONE:
  350.         transition = this._showInstantly;
  351.         break;
  352.  
  353.       default:
  354.         Components.utils.reportError(
  355.             "Invalid transition type passed into showOSDControls()!");
  356.  
  357.         // Just fall back to show instantly.
  358.         transition = this._showInstantly;
  359.     }
  360.  
  361.     if (!this._useTransparentGraphics) {
  362.       transition = this._showInstantly;
  363.     }
  364.     
  365.     transition.call(this);
  366.   },
  367.  
  368.   _fade: function(start, end, func) {
  369.     var self = this;
  370.     this._fadeCancel();
  371.     this._fadeContinuation = func;
  372.     var node = this._osdWindow.document.getElementById("osd_wrapper_hbox");
  373.     var opacity = start;
  374.     var delta = (end - start) / 10;
  375.     var step = 1;
  376.  
  377.     self._fadeInterval = self._osdWindow.setInterval(function() {
  378.       opacity += delta;
  379.       node.style.opacity = opacity;
  380.  
  381.       if (step++ >= 9) {
  382.         self._fadeCancel();
  383.         node = null;
  384.       }
  385.     }, 50);
  386.   },
  387.   
  388.   _fadeCancel: function() {
  389.     this._osdWindow.clearInterval(this._fadeInterval);
  390.     if (this._fadeContinuation) {
  391.        this._fadeContinuation();
  392.     }
  393.     this._fadeContinuation = null;
  394.   },
  395.  
  396.   _showInstantly: function(func) {
  397.     this._fadeCancel();
  398.     var node = this._osdWindow.document.getElementById("osd_wrapper_hbox");
  399.     if (node) {
  400.       node.style.opacity = 1;
  401.     }
  402.     if (func) {
  403.        func();
  404.     }
  405.   },
  406.  
  407.   _hideInstantly: function(func) {
  408.     this._fadeCancel();
  409.     if (func) {
  410.        func();
  411.     }
  412.   },
  413.  
  414.   // fade from 100% opaque to 0% opaque 
  415.   _fadeOut: function(func) {
  416.     this._fade(1, 0, func);
  417.   },
  418.  
  419.   // fade from 0% opaque to 100% opaque 
  420.   _fadeIn: function(func) {
  421.     this._fade(0, 1, func);
  422.   },
  423.  
  424.   _onOSDWinBlur: function(aEvent) {
  425.     this._osdWinHasFocus = false;
  426.   },
  427.  
  428.   _onOSDWinFocus: function(aEvent) {
  429.     this._osdWinHasFocus = true;
  430.   },
  431.  
  432.   _onVideoWinBlur: function(aEvent) {
  433.     this._videoWinHasFocus = false;
  434.   },
  435.  
  436.   _onVideoWinFocus: function(aEvent) {
  437.     this._videoWinHasFocus = true;
  438.   },
  439.  
  440.   _onOSDWinMousemove: function(aEvent) {
  441.     // The user has the mouse over the OSD controls, ensure that the controls
  442.     // are visible.
  443.     this.showOSDControls(Ci.sbIOSDControlService.TRANSITION_NONE);
  444.   },
  445.  
  446.   _onOSDWinMousedown: function(aEvent) {
  447.     if (aEvent.button == 0) {
  448.       this._mouseDownOnOSD = true;
  449.     }
  450.   },
  451.  
  452.   _onOSDWinMouseup: function(aEvent) {
  453.     if (aEvent.button == 0) {
  454.       // User released the mouse button, reset the timer
  455.       this._mouseDownOnOSD = false;
  456.       this.showOSDControls(Ci.sbIOSDControlService.TRANSITION_NONE);
  457.     }
  458.   },
  459.  
  460.   _onOSDWinKeypress: function(aEvent) {
  461.     if (!aEvent.getPreventDefault())
  462.     {
  463.       let event = this._videoWindow.document.createEvent("KeyboardEvent");
  464.       event.initKeyEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable,
  465.                          this._videoWindow, aEvent.ctrlKey, aEvent.altKey,
  466.                          aEvent.shiftKey, aEvent.metaKey, aEvent.keyCode,
  467.                          aEvent.charCode);
  468.       this._videoWindow.dispatchEvent(event);
  469.     }
  470.   },
  471.  
  472.   //----------------------------------------------------------------------------
  473.   // sbIWindowMoveListener
  474.  
  475.   onMoveStarted: function() {
  476.     this._osdSurpressed = true;
  477.     this._showOSDControlsOnStop = this._osdControlsShowing;
  478.     this.hideOSDControls(Ci.sbIOSDControlService.TRANSITION_NONE);
  479.   },
  480.  
  481.   onMoveStopped: function() {
  482.     this._osdSurpressed = false;
  483.     if (this._showOSDControlsOnStop) {
  484.       this.showOSDControls(Ci.sbIOSDControlService.TRANSITION_NONE);
  485.     }
  486.     this._showOSDControlsOnStop = false;
  487.   },
  488.  
  489.   //----------------------------------------------------------------------------
  490.   // nsITimerCallback
  491.  
  492.   notify: function(aTimer) {
  493.     if (aTimer == this._timer) {
  494.       this.hideOSDControls(Ci.sbIOSDControlService.TRANSITION_FADE);
  495.     }
  496.   },
  497. };
  498.  
  499. //------------------------------------------------------------------------------
  500. // XPCOM Registration
  501.  
  502. sbOSDControlService.prototype.classDescription =
  503.   "Songbird OSD Control Service";
  504. sbOSDControlService.prototype.className =
  505.   "sbOSDControlService";
  506. sbOSDControlService.prototype.classID =
  507.   Components.ID("{03F78779-FCB7-4442-9A0C-E8547B4F1368}");
  508. sbOSDControlService.prototype.contractID =
  509.   "@songbirdnest.com/mediacore/osd-control-service;1";
  510. sbOSDControlService.prototype.QueryInterface =
  511.   XPCOMUtils.generateQI([Ci.sbIOSDControlService,
  512.                          Ci.sbIWindowMoveListener,
  513.                          Ci.nsITimerCallback]);
  514.  
  515. function NSGetModule(compMgr, fileSpec)
  516. {
  517.   return XPCOMUtils.generateModule([sbOSDControlService]);
  518. }
  519.  
  520.