browser/components/downloads/src/DownloadsTaskbar.jsm

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /**
michael@0 8 * Handles the download progress indicator in the taskbar.
michael@0 9 */
michael@0 10
michael@0 11 "use strict";
michael@0 12
michael@0 13 this.EXPORTED_SYMBOLS = [
michael@0 14 "DownloadsTaskbar",
michael@0 15 ];
michael@0 16
michael@0 17 ////////////////////////////////////////////////////////////////////////////////
michael@0 18 //// Globals
michael@0 19
michael@0 20 const Cc = Components.classes;
michael@0 21 const Ci = Components.interfaces;
michael@0 22 const Cu = Components.utils;
michael@0 23 const Cr = Components.results;
michael@0 24
michael@0 25 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 26
michael@0 27 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
michael@0 28 "resource://gre/modules/Downloads.jsm");
michael@0 29 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
michael@0 30 "resource:///modules/RecentWindow.jsm");
michael@0 31 XPCOMUtils.defineLazyModuleGetter(this, "Services",
michael@0 32 "resource://gre/modules/Services.jsm");
michael@0 33
michael@0 34 XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function () {
michael@0 35 if (!("@mozilla.org/windows-taskbar;1" in Cc)) {
michael@0 36 return null;
michael@0 37 }
michael@0 38 let winTaskbar = Cc["@mozilla.org/windows-taskbar;1"]
michael@0 39 .getService(Ci.nsIWinTaskbar);
michael@0 40 return winTaskbar.available && winTaskbar;
michael@0 41 });
michael@0 42
michael@0 43 XPCOMUtils.defineLazyGetter(this, "gMacTaskbarProgress", function () {
michael@0 44 return ("@mozilla.org/widget/macdocksupport;1" in Cc) &&
michael@0 45 Cc["@mozilla.org/widget/macdocksupport;1"]
michael@0 46 .getService(Ci.nsITaskbarProgress);
michael@0 47 });
michael@0 48
michael@0 49 ////////////////////////////////////////////////////////////////////////////////
michael@0 50 //// DownloadsTaskbar
michael@0 51
michael@0 52 /**
michael@0 53 * Handles the download progress indicator in the taskbar.
michael@0 54 */
michael@0 55 this.DownloadsTaskbar = {
michael@0 56 /**
michael@0 57 * Underlying DownloadSummary providing the aggregate download information, or
michael@0 58 * null if the indicator has never been initialized.
michael@0 59 */
michael@0 60 _summary: null,
michael@0 61
michael@0 62 /**
michael@0 63 * nsITaskbarProgress object to which download information is dispatched.
michael@0 64 * This can be null if the indicator has never been initialized or if the
michael@0 65 * indicator is currently hidden on Windows.
michael@0 66 */
michael@0 67 _taskbarProgress: null,
michael@0 68
michael@0 69 /**
michael@0 70 * This method is called after a new browser window is opened, and ensures
michael@0 71 * that the download progress indicator is displayed in the taskbar.
michael@0 72 *
michael@0 73 * On Windows, the indicator is attached to the first browser window that
michael@0 74 * calls this method. When the window is closed, the indicator is moved to
michael@0 75 * another browser window, if available, in no particular order. When there
michael@0 76 * are no browser windows visible, the indicator is hidden.
michael@0 77 *
michael@0 78 * On Mac OS X, the indicator is initialized globally when this method is
michael@0 79 * called for the first time. Subsequent calls have no effect.
michael@0 80 *
michael@0 81 * @param aBrowserWindow
michael@0 82 * nsIDOMWindow object of the newly opened browser window to which the
michael@0 83 * indicator may be attached.
michael@0 84 */
michael@0 85 registerIndicator: function (aBrowserWindow)
michael@0 86 {
michael@0 87 if (!this._taskbarProgress) {
michael@0 88 if (gMacTaskbarProgress) {
michael@0 89 // On Mac OS X, we have to register the global indicator only once.
michael@0 90 this._taskbarProgress = gMacTaskbarProgress;
michael@0 91 // Free the XPCOM reference on shutdown, to prevent detecting a leak.
michael@0 92 Services.obs.addObserver(() => {
michael@0 93 this._taskbarProgress = null;
michael@0 94 gMacTaskbarProgress = null;
michael@0 95 }, "quit-application-granted", false);
michael@0 96 } else if (gWinTaskbar) {
michael@0 97 // On Windows, the indicator is currently hidden because we have no
michael@0 98 // previous browser window, thus we should attach the indicator now.
michael@0 99 this._attachIndicator(aBrowserWindow);
michael@0 100 } else {
michael@0 101 // The taskbar indicator is not available on this platform.
michael@0 102 return;
michael@0 103 }
michael@0 104 }
michael@0 105
michael@0 106 // Ensure that the DownloadSummary object will be created asynchronously.
michael@0 107 if (!this._summary) {
michael@0 108 Downloads.getSummary(Downloads.ALL).then(summary => {
michael@0 109 // In case the method is re-entered, we simply ignore redundant
michael@0 110 // invocations of the callback, instead of keeping separate state.
michael@0 111 if (this._summary) {
michael@0 112 return;
michael@0 113 }
michael@0 114 this._summary = summary;
michael@0 115 return this._summary.addView(this);
michael@0 116 }).then(null, Cu.reportError);
michael@0 117 }
michael@0 118 },
michael@0 119
michael@0 120 /**
michael@0 121 * On Windows, attaches the taskbar indicator to the specified browser window.
michael@0 122 */
michael@0 123 _attachIndicator: function (aWindow)
michael@0 124 {
michael@0 125 // Activate the indicator on the specified window.
michael@0 126 let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 127 .getInterface(Ci.nsIWebNavigation)
michael@0 128 .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
michael@0 129 .QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 130 .getInterface(Ci.nsIXULWindow).docShell;
michael@0 131 this._taskbarProgress = gWinTaskbar.getTaskbarProgress(docShell);
michael@0 132
michael@0 133 // If the DownloadSummary object has already been created, we should update
michael@0 134 // the state of the new indicator, otherwise it will be updated as soon as
michael@0 135 // the DownloadSummary view is registered.
michael@0 136 if (this._summary) {
michael@0 137 this.onSummaryChanged();
michael@0 138 }
michael@0 139
michael@0 140 aWindow.addEventListener("unload", () => {
michael@0 141 // Locate another browser window, excluding the one being closed.
michael@0 142 let browserWindow = RecentWindow.getMostRecentBrowserWindow();
michael@0 143 if (browserWindow) {
michael@0 144 // Move the progress indicator to the other browser window.
michael@0 145 this._attachIndicator(browserWindow);
michael@0 146 } else {
michael@0 147 // The last browser window has been closed. We remove the reference to
michael@0 148 // the taskbar progress object so that the indicator will be registered
michael@0 149 // again on the next browser window that is opened.
michael@0 150 this._taskbarProgress = null;
michael@0 151 }
michael@0 152 }, false);
michael@0 153 },
michael@0 154
michael@0 155 //////////////////////////////////////////////////////////////////////////////
michael@0 156 //// DownloadSummary view
michael@0 157
michael@0 158 onSummaryChanged: function ()
michael@0 159 {
michael@0 160 // If the last browser window has been closed, we have no indicator anymore.
michael@0 161 if (!this._taskbarProgress) {
michael@0 162 return;
michael@0 163 }
michael@0 164
michael@0 165 if (this._summary.allHaveStopped || this._summary.progressTotalBytes == 0) {
michael@0 166 this._taskbarProgress.setProgressState(
michael@0 167 Ci.nsITaskbarProgress.STATE_NO_PROGRESS, 0, 0);
michael@0 168 } else {
michael@0 169 // For a brief moment before completion, some download components may
michael@0 170 // report more transferred bytes than the total number of bytes. Thus,
michael@0 171 // ensure that we never break the expectations of the progress indicator.
michael@0 172 let progressCurrentBytes = Math.min(this._summary.progressTotalBytes,
michael@0 173 this._summary.progressCurrentBytes);
michael@0 174 this._taskbarProgress.setProgressState(
michael@0 175 Ci.nsITaskbarProgress.STATE_NORMAL,
michael@0 176 progressCurrentBytes,
michael@0 177 this._summary.progressTotalBytes);
michael@0 178 }
michael@0 179 },
michael@0 180 };

mercurial