miniPlayer.js
Go to the documentation of this file.
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 if (typeof(Ci) == "undefined")
26  var Ci = Components.interfaces;
27 if (typeof(Cc) == "undefined")
28  var Cc = Components.classes;
29 if (typeof(Cr) == "undefined")
30  var Cr = Components.results;
31 if (typeof(Cu) == "undefined")
32  var Cu = Components.utils;
33 
34 Cu.import("resource://app/jsmodules/sbLibraryUtils.jsm");
35 Cu.import("resource://app/jsmodules/ArrayConverter.jsm");
36 
41 var gMiniplayer = {
42 
43 
45  // Window Event Handling //
47 
52  onLoad: function onLoad()
53  {
54  dump("\nMiniplayer." + arguments.callee.name + "\n");
55 
56  window.focus();
57 
58  // Note, most listeners are hardcoded in miniplayer.xul
59 
60  // Prevent window from being resized inappropriately
61  this._setMinMaxCallback();
62 
63  // Set tooltip for feather switch button
64  var nextLayout = this._getNextLayout();
65  var button = document.getElementById("miniplayer_feathers_button");
66  var switchToString =
67  SBFormattedString("feathers.switchto", [nextLayout.name],
68  SBString("feathers.switchfeathers", "Switch Feathers"));
69  button.setAttribute("tooltiptext", switchToString);
70 
71  // Set attributes on the Window element so we can use them in CSS.
72  var windowElement = document.getElementsByTagName("window")[0];
73  windowElement.setAttribute("hasTitlebar",this._hasTitlebar());
74 
75  initializeDocumentPlatformAttribute();
76 
77  // Add resizer listeners
78  this._miniPlayerMinWidth = parseInt(getComputedStyle(
79  document.documentElement, "").minWidth);
80  this._miniPlayerMinHeight = parseInt(getComputedStyle(
81  document.documentElement, "").minHeight);
82 
83  // Set to initialized to properly resize on load.
84  this._initialized = false;
85  var resizer = document.getElementById("miniplayer_resizer_right");
86  resizer.addEventListener("mousemove", gMiniplayer.resizeHandler, false);
87 
88  },
89 
90  resizeHandler: function miniPlayer_resizeHandler(e) {
91  var windowElement = document.getElementsByTagName("window")[0],
92  width = windowElement.boxObject.width;
93 
94  // Opening a window with hidechrome=true does not initially size the window
95  // properly. The result is residual whitespace in place of chrome, titlebar.
96  // For reference, see https://bugzilla.mozilla.org/show_bug.cgi?id=392509.
97  // In order to circumvent the issue, when opened, the window resize handler
98  // will be triggered, sizing the window to its respective width and minimum
99  // height.
100  if (!this._initialized) {
101  this._initialized = true;
102  window.resizeTo(width,
103  gMiniplayer._miniPlayerMinHeight);
104  }
105 
106  if (e.type == "mousemove") {
107  if (!gMiniplayer._mouseDown || (gMiniplayer._mouseDown == false) ||
108  e.clientX < gMiniplayer._miniPlayerMinWidth)
109  {
110  if (e.clientX < gMiniplayer._miniPlayerMinWidth)
111  window.resizeTo(gMiniplayer._miniPlayerMinWidth,
112  gMiniplayer._miniPlayerMinHeight);
113  e.preventDefault();
114  e.stopPropagation();
115  return;
116  }
117  } else if (gMiniplayer._cancelResize && gMiniplayer._cancelResize == true) {
118  gMiniplayer._cancelResize = false;
119  e.preventDefault();
120  e.stopPropagation();
121  return;
122  }
123  if (width < gMiniplayer._miniPlayerMinWidth) {
124  setTimeout(function() {
125  window.resizeTo(gMiniplayer._miniPlayerMinWidth,
126  gMiniplayer._miniPlayerMinHeight);
127  }, 0);
128  }
129 
130  var ratings = document.getElementById("faceplate-tool");
131  var faceplate = document.getElementById("faceplate");
132  var autoscroll = document.getElementById("sb-faceplate-autoscroll-box");
133 
134  // At <500px we drop the ratings
135  if (width < 500 && ratings.style.visibility != "collapse") {
136  ratings.style.visibility = "collapse";
137  } else if (width >= 500 && ratings.style.visibility != "visible") {
138  ratings.style.visibility = "visible";
139  }
140 
141  // <315px we drop the autoscroll
142  if (width < 315 && autoscroll.style.visibility != "collapse") {
143  autoscroll.style.visibility = "collapse";
144  } else if (width >= 315 && autoscroll.style.visibility != "visible") {
145  autoscroll.style.visibility = "visible";
146  }
147 
148  // <308px we drop the faceplate in its entirety
149  if (width < 308 && faceplate.style.visibility != "collapse") {
150  faceplate.style.visibility = "collapse";
151  } else if (width >= 308 && faceplate.style.visibility != "visible") {
152  faceplate.style.visibility = "visible";
153  }
154 
155  var resizerBoundaryPassed = (e.type == "mousemove" && e.clientX > 308);
156  if (width < 308 && !resizerBoundaryPassed) {
157  setTimeout(function() {
158  window.resizeTo(gMiniplayer._miniPlayerMinWidth,
159  gMiniplayer._miniPlayerMinHeight);
160  }, 0);
161  } else {
162  gMiniplayer._cancelResize = true;
163  if (width < gMiniplayer._miniPlayerMinWidth && resizerBoundaryPassed) {
164  setTimeout(function() {
165  window.resizeTo(gMiniplayer._miniPlayerMinWidth,
166  gMiniplayer._miniPlayerMinHeight);
167  }, 0);
168  }
169  }
170 
171  },
172 
176  onUnload: function onUnload()
177  {
178  var resizer = document.getElementById("miniplayer_resizer_right");
179  resizer.removeEventListener("mousemove", gMiniplayer.resizeHandler, false);
180 
181  dump("\nMiniplayer." + arguments.callee.name + "\n");
182 
183  this._resetMinMaxCallback();
184 
185  },
186 
190  onKeypress: function onKeypress( evt )
191  {
192  dump("\nMiniplayer." + arguments.callee.name + "\n");
193 
194  dump("\nChecking for quit key\n");
195  // Check if the user wishes to quit.
196  checkQuitKey(evt);
197 
198  // TODO Does this not interfere with global hotkeys?
199  // Should this be a consistent thing that anyone can use?
200  var sbIMediacoreStatus = Components.interfaces.sbIMediacoreStatus;
201  switch ( evt.keyCode )
202  {
203  case 37: // Arrow Left
204  gMM.sequencer.previous();
205  break;
206  case 39: // Arrow Right
207  gMM.sequencer.next();
208  break;
209  case 40: // Arrow Down
210  case 13: // Return
211  if ( gMM.status.state == sbIMediacoreStatus.STATUS_PLAYING ||
212  gMM.status.state == sbIMediacoreStatus.STATUS_BUFFERING )
213  gMM.playbackControl.pause();
214  else if(gMM.primaryCore)
215  gMM.playbackControl.play();
216  else
217  // If we have no context, initiate playback
218  // via the root application controller
219  var app = Components.classes["@songbirdnest.com/Songbird/ApplicationController;1"]
220  .getService(Components.interfaces.sbIApplicationController);
221  app.playDefault();
222  break;
223  }
224  switch ( evt.charCode )
225  {
226  case 32: // Space
227  if ( gMM.status.state == sbIMediacoreStatus.STATUS_PLAYING ||
228  gMM.status.state == sbIMediacoreStatus.STATUS_BUFFERING )
229  gMM.playbackControl.pause();
230  else
231  gMM.playbackControl.play();
232  break;
233  }
234  },
235 
236 
241  onDblClick: function onDblClick( evt )
242  {
243  dump("\nMiniplayer." + arguments.callee.name + "\n");
244  if (evt.target.localName == 'sb-draggable') {
245  this.revertFeathers();
246  }
247  },
248 
249 
253  revertFeathers: function revertFeathers()
254  {
255  // Attempt to switch to the next layout available for the current skin
256  try {
257  var feathersMgr = Cc['@songbirdnest.com/songbird/feathersmanager;1']
258  .getService(Ci.sbIFeathersManager);
259  var skinName = feathersMgr.currentSkinName;
260  var layoutURL = feathersMgr.currentLayoutURL;
261  var nextLayout = this._getNextLayout();
262 
263  // If it is actually going to do anything, switch to the
264  // next layout
265  if (nextLayout.url != layoutURL) {
266  feathersMgr.switchFeathers(nextLayout.url, skinName);
267  }
268  } catch (e) {
269  dump("revertFeathers(): Unable to switch to the " +
270  "next layout for the current skin.\n\n" +
271  " Error: " + e.toString() + "\n");
272  }
273  },
274 
275  _getNextLayout: function getNextLayout()
276  {
277  var feathersMgr = Cc['@songbirdnest.com/songbird/feathersmanager;1']
278  .getService(Ci.sbIFeathersManager);
279  var skinName = feathersMgr.currentSkinName;
280  var layoutURL = feathersMgr.currentLayoutURL;
281 
282  // Find the layout that comes after the current layout, if one doesn't
283  // exist, then we'll just fallback to the default layout for this skin
284  var enum = feathersMgr.getLayoutsForSkin(skinName);
285  var switchLayout;
286  while (enum.hasMoreElements()) {
287  var nextLayout = enum.getNext();
288  if (!switchLayout)
289  switchLayout = nextLayout;
290  if (nextLayout.QueryInterface(Ci.sbILayoutDescription).url == layoutURL
291  && enum.hasMoreElements())
292  {
293  switchlayout = enum.getNext().QueryInterface(Ci.sbILayoutDescription);
294  }
295  }
296  return switchLayout;
297  },
298 
299 
301  // Window Min/Max Support //
303 
304 
305 
310  _minMaxHandler: {
311 
312  GetMinWidth: function()
313  {
314  var minWidth = getComputedStyle(document.documentElement, "").minWidth;
315  return (minWidth == "none") ? -1 : parseInt(minWidth);
316  },
317 
318  GetMinHeight: function()
319  {
320  var minHeight = getComputedStyle(document.documentElement, "").minHeight;
321  return (minHeight == "none") ? -1 : parseInt(minHeight);
322  },
323 
324  GetMaxWidth: function()
325  {
326  var maxWidth = getComputedStyle(document.documentElement, "").maxWidth;
327  return (maxWidth == "none") ? -1 : parseInt(maxWidth);
328  },
329 
330  GetMaxHeight: function()
331  {
332  var maxHeight = getComputedStyle(document.documentElement, "").maxHeight;
333  return (maxHeight == "none") ? -1 : parseInt(maxHeight);
334  },
335 
336  OnWindowClose: function()
337  {
338  setTimeout(quitApp, 0);
339  },
340 
341  QueryInterface : function(aIID)
342  {
343  if (!aIID.equals(Components.interfaces.sbIWindowMinMaxCallback) &&
344  !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
345  !aIID.equals(Components.interfaces.nsISupports))
346  {
347  throw Components.results.NS_ERROR_NO_INTERFACE;
348  }
349 
350  return this;
351  }
352  },
353 
354 
355 
357  // Helper Functions //
359 
360 
365  _setMinMaxCallback: function _setMinMaxCallback()
366  {
367  var platform = getPlatformString();
368 
369  try {
370 
371  if (platform == "Windows_NT") {
372  var windowMinMax = Components.classes["@songbirdnest.com/Songbird/WindowMinMax;1"];
373  var service = windowMinMax.getService(Components.interfaces.sbIWindowMinMax);
374 
375  service.setCallback(document, this._minMaxHandler);
376  return;
377  } else if (platform == "Darwin") {
378  var nativeWinMgr =
379  Cc["@songbirdnest.com/integration/native-window-manager;1"]
380  .getService(Ci.sbINativeWindowManager);
381  if (nativeWinMgr.supportsMinimumWindowSize) {
382  var minWidth = this._minMaxHandler.GetMinWidth();
383  var minHeight = this._minMaxHandler.GetMinHeight();
384  dump("min: " + minWidth + " x " + minHeight + "\n");
385  var cstyle = window.getComputedStyle(document.documentElement, '');
386  dump ("document min: " + cstyle.minWidth + "\n");
387  nativeWinMgr.setMinimumWindowSize(window, minWidth, minHeight);
388  }
389  }
390  }
391  catch (err) {
392  // No component
393  dump("Error. songbird_hack.js:setMinMaxCallback() \n " + err + "\n");
394  }
395  return;
396  },
397 
398  _resetMinMaxCallback: function _resetMinMaxCallback()
399  {
400  var platform = getPlatformString();
401 
402  try
403  {
404  if (platform == "Windows_NT") {
405  var windowMinMax = Components.classes["@songbirdnest.com/Songbird/WindowMinMax;1"];
406  var service = windowMinMax.getService(Components.interfaces.sbIWindowMinMax);
407  service.resetCallback(document);
408 
409  return;
410  }
411 
412  }
413  catch(err) {
414  dump("Error. songbird_hack.js: SBUnitialize() \n" + err + "\n");
415  }
416 
417  return;
418  },
419 
423  // XXXpvh: can this be removed and replaced with the GetPlatformString used everywhere else?
424  _getPlatform: function _getPlatform() {
425  var platform;
426  try {
427  var sysInfo =
428  Components.classes["@mozilla.org/system-info;1"]
429  .getService(Components.interfaces.nsIPropertyBag2);
430  platform = sysInfo.getProperty("name");
431  }
432  catch (e) {
433  dump("System-info not available, trying the user agent string.\n");
434  var user_agent = navigator.userAgent;
435  if (user_agent.indexOf("Mac OS X") != -1)
436  platform = "Darwin";
437  }
438  return platform;
439  },
440 
441 
445  _hasTitlebar: function _hasTitlebar() {
446 
447  // Jump through some hoops to get at nsIWebBrowserChrome.chromeFlags
448  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
449  var webnav = window.getInterface(Components.interfaces.nsIWebNavigation);
450  var treeItem = webnav.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
451  var treeOwner = treeItem.treeOwner;
452  var requestor = treeOwner.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
453  var windowChrome = requestor.getInterface(Components.interfaces.nsIWebBrowserChrome);
454 
455  // Phew... now, do we have a titlebar?
456  return windowChrome.chromeFlags & windowChrome.CHROME_TITLEBAR;
457  }
458 } // End of gMiniplayer
const Cu
const Cc
var gMM
Definition: windowUtils.js:62
id service()
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
function getPlatformString()
Get the name of the platform we are running on.
sbOSDControlService prototype QueryInterface
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
function width(ele) rect(ele).width
let window
Lastfm onLoad
Definition: mini.js:36
aWindow setTimeout(function(){_this.restoreHistory(aWindow, aTabs, aTabData, aIdMap);}, 0)
return!aWindow arguments!aWindow arguments[0]
SimpleArrayEnumerator prototype hasMoreElements
const Cr
const Ci
function onUnload()
onUnload - called when the cover preview window unloads.
Definition: coverPreview.js:36