gecko/toolkit/mozapps/downloads/DownloadTaskbarProgress.jsm
Jim Blandy 4d6a633bba Bug 914753: Make Emacs file variable header lines correct, or at least consistent. DONTBUILD r=ehsan
The -*- file variable lines -*- establish per-file settings that Emacs will
pick up. This patch makes the following changes to those lines (and touches
nothing else):

 - Never set the buffer's mode.

   Years ago, Emacs did not have a good JavaScript mode, so it made sense
   to use Java or C++ mode in .js files. However, Emacs has had js-mode for
   years now; it's perfectly serviceable, and is available and enabled by
   default in all major Emacs packagings.

   Selecting a mode in the -*- file variable line -*- is almost always the
   wrong thing to do anyway. It overrides Emacs's default choice, which is
   (now) reasonable; and even worse, it overrides settings the user might
   have made in their '.emacs' file for that file extension. It's only
   useful when there's something specific about that particular file that
   makes a particular mode appropriate.

 - Correctly propagate settings that establish the correct indentation
   level for this file: c-basic-offset and js2-basic-offset should be
   js-indent-level. Whatever value they're given should be preserved;
   different parts of our tree use different indentation styles.

 - We don't use tabs in Mozilla JS code. Always set indent-tabs-mode: nil.
   Remove tab-width: settings, at least in files that don't contain tab
   characters.

 - Remove js2-mode settings that belong in the user's .emacs file, like
   js2-skip-preprocessor-directives.
2014-06-24 22:12:07 -07:00

404 lines
13 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
* vim: sw=2 ts=2 sts=2 et filetype=javascript
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = [
"DownloadTaskbarProgress",
];
////////////////////////////////////////////////////////////////////////////////
//// Constants
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
const kTaskbarIDWin = "@mozilla.org/windows-taskbar;1";
const kTaskbarIDMac = "@mozilla.org/widget/macdocksupport;1";
////////////////////////////////////////////////////////////////////////////////
//// DownloadTaskbarProgress Object
this.DownloadTaskbarProgress =
{
init: function DTP_init()
{
if (DownloadTaskbarProgressUpdater) {
DownloadTaskbarProgressUpdater._init();
}
},
/**
* Called when a browser window appears. This has an effect only when we
* don't already have an active window.
*
* @param aWindow
* The browser window that we'll potentially use to display the
* progress.
*/
onBrowserWindowLoad: function DTP_onBrowserWindowLoad(aWindow)
{
this.init();
if (!DownloadTaskbarProgressUpdater) {
return;
}
if (!DownloadTaskbarProgressUpdater._activeTaskbarProgress) {
DownloadTaskbarProgressUpdater._setActiveWindow(aWindow, false);
}
},
/**
* Called when the download window appears. The download window will take
* over as the active window.
*/
onDownloadWindowLoad: function DTP_onDownloadWindowLoad(aWindow)
{
if (!DownloadTaskbarProgressUpdater) {
return;
}
DownloadTaskbarProgressUpdater._setActiveWindow(aWindow, true);
},
/**
* Getters for internal DownloadTaskbarProgressUpdater values
*/
get activeTaskbarProgress() {
if (!DownloadTaskbarProgressUpdater) {
return null;
}
return DownloadTaskbarProgressUpdater._activeTaskbarProgress;
},
get activeWindowIsDownloadWindow() {
if (!DownloadTaskbarProgressUpdater) {
return null;
}
return DownloadTaskbarProgressUpdater._activeWindowIsDownloadWindow;
},
get taskbarState() {
if (!DownloadTaskbarProgressUpdater) {
return null;
}
return DownloadTaskbarProgressUpdater._taskbarState;
},
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadTaskbarProgressUpdater Object
var DownloadTaskbarProgressUpdater =
{
/// Whether the taskbar is initialized.
_initialized: false,
/// Reference to the taskbar.
_taskbar: null,
/// Reference to the download manager.
_dm: null,
/**
* Initialize and register ourselves as a download progress listener.
*/
_init: function DTPU_init()
{
if (this._initialized) {
return; // Already initialized
}
this._initialized = true;
if (kTaskbarIDWin in Cc) {
this._taskbar = Cc[kTaskbarIDWin].getService(Ci.nsIWinTaskbar);
if (!this._taskbar.available) {
// The Windows version is probably too old
DownloadTaskbarProgressUpdater = null;
return;
}
} else if (kTaskbarIDMac in Cc) {
this._activeTaskbarProgress = Cc[kTaskbarIDMac].
getService(Ci.nsITaskbarProgress);
} else {
DownloadTaskbarProgressUpdater = null;
return;
}
this._taskbarState = Ci.nsITaskbarProgress.STATE_NO_PROGRESS;
this._dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
this._dm.addPrivacyAwareListener(this);
this._os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
this._os.addObserver(this, "quit-application-granted", false);
this._updateStatus();
// onBrowserWindowLoad/onDownloadWindowLoad are going to set the active
// window, so don't do it here.
},
/**
* Unregisters ourselves as a download progress listener.
*/
_uninit: function DTPU_uninit() {
this._dm.removeListener(this);
this._os.removeObserver(this, "quit-application-granted");
this._activeTaskbarProgress = null;
this._initialized = false;
},
/**
* This holds a reference to the taskbar progress for the window we're
* working with. This window would preferably be download window, but can be
* another window if it isn't open.
*/
_activeTaskbarProgress: null,
/// Whether the active window is the download window
_activeWindowIsDownloadWindow: false,
/**
* Sets the active window, and whether it's the download window. This takes
* care of clearing out the previous active window's taskbar item, updating
* the taskbar, and setting an onunload listener.
*
* @param aWindow
* The window to set as active.
* @param aIsDownloadWindow
* Whether this window is a download window.
*/
_setActiveWindow: function DTPU_setActiveWindow(aWindow, aIsDownloadWindow)
{
#ifdef XP_WIN
// Clear out the taskbar for the old active window. (If there was no active
// window, this is a no-op.)
this._clearTaskbar();
this._activeWindowIsDownloadWindow = aIsDownloadWindow;
if (aWindow) {
// Get the taskbar progress for this window
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebNavigation).
QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIXULWindow).docShell;
let taskbarProgress = this._taskbar.getTaskbarProgress(docShell);
this._activeTaskbarProgress = taskbarProgress;
this._updateTaskbar();
// _onActiveWindowUnload is idempotent, so we don't need to check whether
// we've already set this before or not.
aWindow.addEventListener("unload", function () {
DownloadTaskbarProgressUpdater._onActiveWindowUnload(taskbarProgress);
}, false);
}
else {
this._activeTaskbarProgress = null;
}
#endif
},
/// Current state displayed on the active window's taskbar item
_taskbarState: null,
_totalSize: 0,
_totalTransferred: 0,
_shouldSetState: function DTPU_shouldSetState()
{
#ifdef XP_WIN
// If the active window is not the download manager window, set the state
// only if it is normal or indeterminate.
return this._activeWindowIsDownloadWindow ||
(this._taskbarState == Ci.nsITaskbarProgress.STATE_NORMAL ||
this._taskbarState == Ci.nsITaskbarProgress.STATE_INDETERMINATE);
#else
return true;
#endif
},
/**
* Update the active window's taskbar indicator with the current state. There
* are two cases here:
* 1. If the active window is the download window, then we always update
* the taskbar indicator.
* 2. If the active window isn't the download window, then we update only if
* the status is normal or indeterminate. i.e. one or more downloads are
* currently progressing or in scan mode. If we aren't, then we clear the
* indicator.
*/
_updateTaskbar: function DTPU_updateTaskbar()
{
if (!this._activeTaskbarProgress) {
return;
}
if (this._shouldSetState()) {
this._activeTaskbarProgress.setProgressState(this._taskbarState,
this._totalTransferred,
this._totalSize);
}
// Clear any state otherwise
else {
this._clearTaskbar();
}
},
/**
* Clear taskbar state. This is needed:
* - to transfer the indicator off a window before transferring it onto
* another one
* - whenever we don't want to show it for a non-download window.
*/
_clearTaskbar: function DTPU_clearTaskbar()
{
if (this._activeTaskbarProgress) {
this._activeTaskbarProgress.setProgressState(
Ci.nsITaskbarProgress.STATE_NO_PROGRESS
);
}
},
/**
* Update this._taskbarState, this._totalSize and this._totalTransferred.
* This is called when the download manager is initialized or when the
* progress or state of a download changes.
* We compute the number of active and paused downloads, and the total size
* and total amount already transferred across whichever downloads we have
* the data for.
* - If there are no active downloads, then we don't want to show any
* progress.
* - If the number of active downloads is equal to the number of paused
* downloads, then we show a paused indicator if we know the size of at
* least one download, and no indicator if we don't.
* - If the number of active downloads is more than the number of paused
* downloads, then we show a "normal" indicator if we know the size of at
* least one download, and an indeterminate indicator if we don't.
*/
_updateStatus: function DTPU_updateStatus()
{
let numActive = this._dm.activeDownloadCount + this._dm.activePrivateDownloadCount;
let totalSize = 0, totalTransferred = 0;
if (numActive == 0) {
this._taskbarState = Ci.nsITaskbarProgress.STATE_NO_PROGRESS;
}
else {
let numPaused = 0, numScanning = 0;
// Enumerate all active downloads
[this._dm.activeDownloads, this._dm.activePrivateDownloads].forEach(function(downloads) {
while (downloads.hasMoreElements()) {
let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
// Only set values if we actually know the download size
if (download.percentComplete != -1) {
totalSize += download.size;
totalTransferred += download.amountTransferred;
}
// We might need to display a paused state, so track this
if (download.state == this._dm.DOWNLOAD_PAUSED) {
numPaused++;
} else if (download.state == this._dm.DOWNLOAD_SCANNING) {
numScanning++;
}
}
}.bind(this));
// If all downloads are paused, show the progress as paused, unless we
// don't have any information about sizes, in which case we don't
// display anything
if (numActive == numPaused) {
if (totalSize == 0) {
this._taskbarState = Ci.nsITaskbarProgress.STATE_NO_PROGRESS;
totalTransferred = 0;
}
else {
this._taskbarState = Ci.nsITaskbarProgress.STATE_PAUSED;
}
}
// If at least one download is not paused, and we don't have any
// information about download sizes, display an indeterminate indicator
else if (totalSize == 0 || numActive == numScanning) {
this._taskbarState = Ci.nsITaskbarProgress.STATE_INDETERMINATE;
totalSize = 0;
totalTransferred = 0;
}
// Otherwise display a normal progress bar
else {
this._taskbarState = Ci.nsITaskbarProgress.STATE_NORMAL;
}
}
this._totalSize = totalSize;
this._totalTransferred = totalTransferred;
},
/**
* Called when a window that at one point has been an active window is
* closed. If this window is currently the active window, we need to look for
* another window and make that our active window.
*
* This function is idempotent, so multiple calls for the same window are not
* a problem.
*
* @param aTaskbarProgress
* The taskbar progress for the window that is being unloaded.
*/
_onActiveWindowUnload: function DTPU_onActiveWindowUnload(aTaskbarProgress)
{
if (this._activeTaskbarProgress == aTaskbarProgress) {
let windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
let windows = windowMediator.getEnumerator(null);
let newActiveWindow = null;
if (windows.hasMoreElements()) {
newActiveWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
}
// We aren't ever going to reach this point while the download manager is
// open, so it's safe to assume false for the second operand
this._setActiveWindow(newActiveWindow, false);
}
},
//////////////////////////////////////////////////////////////////////////////
//// nsIDownloadProgressListener
/**
* Update status if a download's progress has changed.
*/
onProgressChange: function DTPU_onProgressChange()
{
this._updateStatus();
this._updateTaskbar();
},
/**
* Update status if a download's state has changed.
*/
onDownloadStateChange: function DTPU_onDownloadStateChange()
{
this._updateStatus();
this._updateTaskbar();
},
onSecurityChange: function() { },
onStateChange: function() { },
observe: function DTPU_observe(aSubject, aTopic, aData) {
if (aTopic == "quit-application-granted") {
this._uninit();
}
}
};