author | Robert Strong <robert.bugzilla@gmail.com> |
Thu, 23 Sep 2010 21:02:08 -0700 | |
changeset 54611 | 78c90846f8c76e57d7ef25216bc33e12b0e822d0 |
parent 54610 | 7cd8c313dfc5d9651bf34494a521fb1f8f6e1ea5 |
child 54612 | c7ed283dda27f26e020bed851a77ab34ecdce41b |
push id | 15953 |
push user | rstrong@mozilla.com |
push date | Fri, 24 Sep 2010 04:02:44 +0000 |
treeherder | mozilla-central@78c90846f8c7 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dtownsend, beltzner, blocking2.0-beta7 |
bugs | 596813 |
milestone | 2.0b7pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -83,16 +83,21 @@ pref("browser.dictionaries.download.url" // default=10 minutes pref("app.update.timer", 600000); // App-specific update preferences // The interval to check for updates (app.update.interval) is defined in // firefox-branding.js +// Alternative windowtype for an application update user interface window. When +// a window with this windowtype is open the application update service won't +// open the normal application update user interface window. +pref("app.update.altwindowtype", "Browser:About"); + // Enables some extra Application Update Logging (can reduce performance) pref("app.update.log", false); // The number of general background check failures to allow before notifying the // user of the failure. User initiated update checks always notify the user of // the failure. pref("app.update.backgroundMaxErrors", 10);
--- a/browser/base/content/aboutDialog.css +++ b/browser/base/content/aboutDialog.css @@ -47,23 +47,44 @@ #distribution, #distributionId { font-weight: bold; display: none; margin-top: 0; margin-bottom: 0; } -#checkForUpdatesButton, .text-blurb { margin-bottom: 10px; -moz-margin-start: 0; -moz-padding-start: 0; } +#updateBox { + margin-bottom: 10px; +} + +#updateButton, +#updateDeck > hbox > label { + -moz-margin-start: 0; + -moz-padding-start: 0; +} + +#updateDeck > hbox > label:not([class="text-link"]) { + color: #909090; + font-style:italic; +} + +.update-throbber { + width: 16px; + min-height: 16px; + -moz-margin-end: 3px; + list-style-image: url("chrome://global/skin/icons/loading_16.png"); +} + .trademark-label, .text-link, .text-link:focus { margin: 0px; padding: 0px; } .bottom-link,
--- a/browser/base/content/aboutDialog.js +++ b/browser/base/content/aboutDialog.js @@ -16,16 +16,17 @@ # The Initial Developer of the Original Code is # Blake Ross (blaker@netscape.com). # Portions created by the Initial Developer are Copyright (C) 2002 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Ehsan Akhgari <ehsan.akhgari@gmail.com> # Margaret Leibovic <margaret.leibovic@gmail.com> +# Robert Strong <robert.bugzilla@gmail.com> # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your @@ -60,30 +61,478 @@ function init(aEvent) distroIdField.style.display = "block"; } } catch (e) { // Pref is unset } #ifdef MOZ_UPDATER - initUpdates(); + gAppUpdater = new appUpdater(); #endif #ifdef XP_MACOSX // it may not be sized at this point, and we need its width to calculate its position window.sizeToContent(); window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5); #endif } #ifdef MOZ_UPDATER -/** - * Sets up "Check for Updates..." button. - */ -function initUpdates() +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); +Components.utils.import("resource://gre/modules/AddonManager.jsm"); + +var gAppUpdater; + +function onUnload(aEvent) { + if (gAppUpdater.isChecking) + gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK); + // Safe to call even when there isn't a download in progress. + gAppUpdater.removeDownloadListener(); + gAppUpdater = null; +} + + +function appUpdater() +{ + this.updateDeck = document.getElementById("updateDeck"); + + // Hide the update deck when there is already an update window open to avoid + // syncing issues between them. + if (Services.wm.getMostRecentWindow("Update:Wizard")) { + this.updateDeck.hidden = true; + return; + } + + XPCOMUtils.defineLazyServiceGetter(this, "aus", + "@mozilla.org/updates/update-service;1", + "nsIApplicationUpdateService"); + XPCOMUtils.defineLazyServiceGetter(this, "checker", + "@mozilla.org/updates/update-checker;1", + "nsIUpdateChecker"); + XPCOMUtils.defineLazyServiceGetter(this, "um", + "@mozilla.org/updates/update-manager;1", + "nsIUpdateManager"); + XPCOMUtils.defineLazyServiceGetter(this, "bs", + "@mozilla.org/extensions/blocklist;1", + "nsIBlocklistService"); + + this.bundle = Services.strings. + createBundle("chrome://browser/locale/browser.properties"); + + this.updateBtn = document.getElementById("updateButton"); + + // The button label value must be set so its height is correct. + this.setupUpdateButton("update.checkInsideButton"); + + let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual"); + let manualLink = document.getElementById("manualLink"); + manualLink.value = manualURL; + manualLink.href = manualURL; + document.getElementById("failedLink").href = manualURL; + + if (this.updateDisabledAndLocked) { + this.selectPanel("adminDisabled"); + return; + } + + if (this.isPending) { + this.setupUpdateButton("update.restart." + + (this.isMajor ? "upgradeButton" : "applyButton")); + return; + } + + if (this.isDownloading) { + this.startDownload(); + return; + } + + if (this.updateEnabled && this.updateAuto) { + this.selectPanel("checkingForUpdates"); + this.isChecking = true; + this.checker.checkForUpdates(this.updateCheckListener, true); + return; + } +} + +appUpdater.prototype = { - var browserBundle = Services.strings. - createBundle("chrome://browser/locale/browser.properties"); - var checkForUpdates = document.getElementById("checkForUpdatesButton"); - setupCheckForUpdates(checkForUpdates, browserBundle); -} + // true when there is an update check in progress. + isChecking: false, + + // true when there is an update already staged / ready to be applied. + get isPending() { + if (this.update) + return this.update.state == "pending"; + return this.um.activeUpdate && this.um.activeUpdate.state == "pending"; + }, + + // true when there is an update download in progress. + get isDownloading() { + if (this.update) + return this.update.state == "downloading"; + return this.um.activeUpdate && + this.um.activeUpdate.state == "downloading"; + }, + + // true when the update type is major. + get isMajor() { + if (this.update) + return this.update.type == "major"; + return this.um.activeUpdate.type == "major"; + }, + + // true when updating is disabled by an administrator. + get updateDisabledAndLocked() { + return !this.updateEnabled && + Services.prefs.prefIsLocked("app.update.enabled"); + }, + + // true when updating is enabled. + get updateEnabled() { + try { + return Services.prefs.getBoolPref("app.update.enabled"); + } + catch (e) { } + return true; // Firefox default is true + }, + + // true when updating is automatic. + get updateAuto() { + try { + return Services.prefs.getBoolPref("app.update.auto"); + } + catch (e) { } + return true; // Firefox default is true + }, + + /** + * Sets the deck's selected panel. + * + * @param aChildID + * The id of the deck's child to select. + */ + selectPanel: function(aChildID) { + this.updateDeck.selectedPanel = document.getElementById(aChildID); + }, + + /** + * Sets the update button's label and accesskey. + * + * @param aKeyPrefix + * The prefix for the properties file entry to use for setting the + * label and accesskey. + */ + setupUpdateButton: function(aKeyPrefix) { + this.updateBtn.label = this.bundle.GetStringFromName(aKeyPrefix + ".label"); + this.updateBtn.accessKey = this.bundle.GetStringFromName(aKeyPrefix + ".accesskey"); + if (!document.commandDispatcher.focusedElement || + document.commandDispatcher.focusedElement.isSameNode(this.updateBtn)) + this.updateBtn.focus(); + }, + + /** + * Handles oncommand for the update button. + */ + buttonOnCommand: function() { + if (this.isPending) { + // Notify all windows that an application quit has been requested. + let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]. + createInstance(Components.interfaces.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); + + // Something aborted the quit process. + if (cancelQuit.data) + return; + + // If already in safe mode restart in safe mode (bug 327119) + if (Services.appinfo.inSafeMode) { + let env = Components.classes["@mozilla.org/process/environment;1"]. + getService(Components.interfaces.nsIEnvironment); + env.set("MOZ_SAFE_MODE_RESTART", "1"); + } + + Components.classes["@mozilla.org/toolkit/app-startup;1"]. + getService(Components.interfaces.nsIAppStartup). + quit(Components.interfaces.nsIAppStartup.eAttemptQuit | + Components.interfaces.nsIAppStartup.eRestart); + return; + } + + const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul"; + // Firefox no longer displays a license for updates and the licenseURL check + // is just in case a distibution does. + if (this.update && (this.update.billboardURL || this.update.licenseURL || + this.addons.length != 0)) { + var ary = null; + ary = Components.classes["@mozilla.org/supports-array;1"]. + createInstance(Components.interfaces.nsISupportsArray); + ary.AppendElement(this.update); + var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no"; + Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary); + window.close(); + return; + } + + this.selectPanel("checkingForUpdates"); + this.isChecking = true; + this.checker.checkForUpdates(this.updateCheckListener, true); + }, + + /** + * Implements nsIUpdateCheckListener. The methods implemented by + * nsIUpdateCheckListener have to be in a different scope from + * nsIIncrementalDownload because both nsIUpdateCheckListener and + * nsIIncrementalDownload implement onProgress. + */ + updateCheckListener: { + /** + * See nsIUpdateService.idl + */ + onProgress: function(aRequest, aPosition, aTotalSize) { + }, + + /** + * See nsIUpdateService.idl + */ + onCheckComplete: function(aRequest, aUpdates, aUpdateCount) { + gAppUpdater.isChecking = false; + gAppUpdater.update = gAppUpdater.aus. + selectUpdate(aUpdates, aUpdates.length); + if (!gAppUpdater.update) { + gAppUpdater.selectPanel("noUpdatesFound"); + return; + } + + if (!gAppUpdater.aus.canApplyUpdates) { + gAppUpdater.selectPanel("manualUpdate"); + return; + } + + // Firefox no longer displays a license for updates and the licenseURL + // check is just in case a distibution does. + if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) { + gAppUpdater.selectPanel("updateButtonBox"); + gAppUpdater.setupUpdateButton("update.openUpdateUI." + + (this.isMajor ? "upgradeButton" + : "applyButton")); + return; + } + + if (!gAppUpdater.update.appVersion || + Services.vc.compare(gAppUpdater.update.appVersion, + Services.appinfo.version) == 0) { + gAppUpdater.startDownload(); + return; + } + + gAppUpdater.checkAddonCompatibility(); + }, + + /** + * See nsIUpdateService.idl + */ + onError: function(aRequest, aUpdate) { + // Errors in the update check are treated as no updates found. If the + // update check fails repeatedly without a success the user will be + // notified with the normal app update user interface so this is safe. + gAppUpdater.isChecking = false; + gAppUpdater.selectPanel("noUpdatesFound"); + return; + }, + + /** + * See nsISupports.idl + */ + QueryInterface: function(aIID) { + if (!aIID.equals(Components.interfaces.nsIUpdateCheckListener) && + !aIID.equals(Components.interfaces.nsISupports)) + throw Components.results.NS_ERROR_NO_INTERFACE; + return this; + } + }, + + /** + * Checks the compatibility of add-ons for the application update. + */ + checkAddonCompatibility: function() { + var self = this; + AddonManager.getAllAddons(function(aAddons) { + self.addons = []; + self.addonsCheckedCount = 0; + aAddons.forEach(function(aAddon) { + // If an add-on isn't appDisabled and isn't userDisabled then it is + // either active now or the user expects it to be active after the + // restart. If that is the case and the add-on is not installed by the + // application and is not compatible with the new application version + // then the user should be warned that the add-on will become + // incompatible. If an addon's type equals plugin it is skipped since + // checking plugins compatibility information isn't supported and + // getting the scope property of a plugin breaks in some environments + // (see bug 566787). + if (aAddon.type != "plugin" && + !aAddon.appDisabled && !aAddon.userDisabled && + aAddon.scope != AddonManager.SCOPE_APPLICATION && + aAddon.isCompatible && + !aAddon.isCompatibleWith(self.update.appVersion, + self.update.platformVersion)) + self.addons.push(aAddon); + }); + self.addonsTotalCount = self.addons.length; + if (self.addonsTotalCount == 0) { + self.startDownload(); + return; + } + + self.checkAddonsForUpdates(); + }); + }, + + /** + * Checks if there are updates for add-ons that are incompatible with the + * application update. + */ + checkAddonsForUpdates: function() { + this.addons.forEach(function(aAddon) { + aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED, + this.update.appVersion, + this.update.platformVersion); + }, this); + }, + + /** + * See XPIProvider.jsm + */ + onCompatibilityUpdateAvailable: function(aAddon) { + for (var i = 0; i < this.addons.length; ++i) { + if (this.addons[i].id == aAddon.id) { + this.addons.splice(i, 1); + break; + } + } + }, + + /** + * See XPIProvider.jsm + */ + onUpdateAvailable: function(aAddon, aInstall) { + if (!this.bs.isAddonBlocklisted(aAddon.id, aInstall.version, + this.update.appVersion, + this.update.platformVersion)) { + // Compatibility or new version updates mean the same thing here. + this.onCompatibilityUpdateAvailable(aAddon); + } + }, + + /** + * See XPIProvider.jsm + */ + onUpdateFinished: function(aAddon) { + ++this.addonsCheckedCount; + + if (this.addonsCheckedCount < this.addonsTotalCount) + return; + + if (this.addons.length == 0) { + // Compatibility updates or new version updates were found for all add-ons + this.startDownload(); + return; + } + + this.selectPanel("updateButtonBox"); + this.setupUpdateButton("update.openUpdateUI." + + (this.isMajor ? "upgradeButton" : "applyButton")); + }, + + /** + * Starts the download of an update mar. + */ + startDownload: function() { + if (!this.update) + this.update = this.um.activeUpdate; + this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag); + this.update.setProperty("foregroundDownload", "true"); + + this.aus.pauseDownload(); + let state = this.aus.downloadUpdate(this.update, false); + if (state == "failed") { + this.selectPanel("downloadFailed"); + return; + } + + this.downloadStatus = document.getElementById("downloadStatus"); + this.downloadStatus.value = + DownloadUtils.getTransferTotal(0, this.update.selectedPatch.size); + this.selectPanel("downloading"); + this.aus.addDownloadListener(this); + }, + + removeDownloadListener: function() { + this.aus.removeDownloadListener(this); + }, + + /** + * See nsIRequestObserver.idl + */ + onStartRequest: function(aRequest, aContext) { + }, + + /** + * See nsIRequestObserver.idl + */ + onStopRequest: function(aRequest, aContext, aStatusCode) { + switch (aStatusCode) { + case Components.results.NS_ERROR_UNEXPECTED: + if (this.update.selectedPatch.state == "download-failed" && + (this.update.isCompleteUpdate || this.update.patchCount != 2)) { + // Verification error of complete patch, informational text is held in + // the update object. + this.removeDownloadListener(); + this.selectPanel("downloadFailed"); + break; + } + // Verification failed for a partial patch, complete patch is now + // downloading so return early and do NOT remove the download listener! + break; + case Components.results.NS_BINDING_ABORTED: + // Do not remove UI listener since the user may resume downloading again. + break; + case Components.results.NS_OK: + this.removeDownloadListener(); + this.selectPanel("updateButtonBox"); + this.setupUpdateButton("update.restart." + + (this.isMajor ? "upgradeButton" : "applyButton")); + break; + default: + this.removeDownloadListener(); + this.selectPanel("downloadFailed"); + break; + } + + }, + + /** + * See nsIProgressEventSink.idl + */ + onStatus: function(aRequest, aContext, aStatus, aStatusArg) { + }, + + /** + * See nsIProgressEventSink.idl + */ + onProgress: function(aRequest, aContext, aProgress, aProgressMax) { + this.downloadStatus.value = + DownloadUtils.getTransferTotal(aProgress, aProgressMax); + }, + + /** + * See nsISupports.idl + */ + QueryInterface: function(aIID) { + if (!aIID.equals(Components.interfaces.nsIProgressEventSink) && + !aIID.equals(Components.interfaces.nsIRequestObserver) && + !aIID.equals(Components.interfaces.nsISupports)) + throw Components.results.NS_ERROR_NO_INTERFACE; + return this; + } +}; #endif
--- a/browser/base/content/aboutDialog.xul +++ b/browser/base/content/aboutDialog.xul @@ -18,16 +18,17 @@ # The Initial Developer of the Original Code is # Blake Ross (blaker@netscape.com). # Portions created by the Initial Developer are Copyright (C) 2002 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Ehsan Akhgari <ehsan.akhgari@gmail.com> # Margaret Leibovic <margaret.leibovic@gmail.com> +# Robert Strong <robert.bugzilla@gmail.com> # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your @@ -52,39 +53,67 @@ <?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?> #endif <window xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="aboutDialog" windowtype="Browser:About" onload="init(event);" +#ifdef MOZ_UPDATER + onunload="onUnload(event);" +#endif #ifdef XP_MACOSX inwindowmenu="false" #else title="&aboutDialog.title;" #endif > - <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/> <script type="application/javascript" src="chrome://browser/content/aboutDialog.js"/> <vbox> <hbox id="clientBox"> <vbox id="leftBox" flex="1"/> <vbox id="rightBox" flex="1"> #expand <label id="version" value="__MOZ_APP_VERSION__"/> <label id="distribution" class="text-blurb"/> <label id="distributionId" class="text-blurb"/> + <vbox id="updateBox"> #ifdef MOZ_UPDATER - <hbox> - <button id="checkForUpdatesButton" oncommand="checkForUpdates();" align="start"/> - <spacer flex="1"/> - </hbox> + <deck id="updateDeck" orient="vertical"> + <hbox id="updateButtonBox" align="center"> + <button id="updateButton" align="start" + oncommand="gAppUpdater.buttonOnCommand();"/> + <spacer flex="1"/> + </hbox> + <hbox id="checkingForUpdates" align="center"> + <image class="update-throbber"/><label>&update.checkingForUpdates;</label> + </hbox> + <hbox id="checkingAddonCompat" align="center"> + <image class="update-throbber"/><label>&update.checkingAddonCompat;</label> + </hbox> + <hbox id="downloading" align="center"> + <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label> + </hbox> + <hbox id="downloadFailed" align="center"> + <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label> + </hbox> + <hbox id="adminDisabled" align="center"> + <label>&update.adminDisabled;</label> + </hbox> + <hbox id="noUpdatesFound" align="center"> + <label>&update.noUpdatesFound;</label> + </hbox> + <hbox id="manualUpdate" align="center"> + <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label> + </hbox> + </deck> #endif + </vbox> <description class="text-blurb"> &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2; </description> <description class="text-blurb"> &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end; </description> </vbox> </hbox>
--- a/toolkit/mozapps/update/content/updates.js +++ b/toolkit/mozapps/update/content/updates.js @@ -1723,26 +1723,32 @@ var gFinishedPage = { // This prevents the user from switching back // to the Software Update dialog and clicking "Restart" or "Later" // when dealing with the "confirm close" prompts. // See bug #350299 for more details. gUpdates.wiz.getButton("finish").disabled = true; gUpdates.wiz.getButton("extra1").disabled = true; // Notify all windows that an application quit has been requested. - var os = CoC["@mozilla.org/observer-service;1"]. - getService(CoI.nsIObserverService); var cancelQuit = CoC["@mozilla.org/supports-PRBool;1"]. createInstance(CoI.nsISupportsPRBool); - os.notifyObservers(cancelQuit, "quit-application-requested", "restart"); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", + "restart"); // Something aborted the quit process. if (cancelQuit.data) return; + // If already in safe mode restart in safe mode (bug 327119) + if (Services.appinfo.inSafeMode) { + let env = CoC["@mozilla.org/process/environment;1"]. + getService(CoI.nsIEnvironment); + env.set("MOZ_SAFE_MODE_RESTART", "1"); + } + // Restart the application CoC["@mozilla.org/toolkit/app-startup;1"].getService(CoI.nsIAppStartup). quit(CoI.nsIAppStartup.eAttemptQuit | CoI.nsIAppStartup.eRestart); }, /** * When the user clicks the "Restart Later" instead of the Restart Now" button * in the wizard after an update has been downloaded.
--- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -46,16 +46,17 @@ Components.utils.import("resource://gre/ Components.utils.import("resource://gre/modules/FileUtils.jsm"); Components.utils.import("resource://gre/modules/AddonManager.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; +const PREF_APP_UPDATE_ALTWINDOWTYPE = "app.update.altwindowtype"; const PREF_APP_UPDATE_AUTO = "app.update.auto"; const PREF_APP_UPDATE_BACKGROUND_INTERVAL = "app.update.download.backgroundInterval"; const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors"; const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors"; const PREF_APP_UPDATE_CERTS_BRANCH = "app.update.certs."; const PREF_APP_UPDATE_CERT_CHECKATTRS = "app.update.cert.checkAttributes"; const PREF_APP_UPDATE_CERT_ERRORS = "app.update.cert.errors"; const PREF_APP_UPDATE_CERT_MAXERRORS = "app.update.cert.maxErrors"; @@ -2774,42 +2775,48 @@ Downloader.prototype = { */ function UpdatePrompt() { } UpdatePrompt.prototype = { /** * See nsIUpdateService.idl */ checkForUpdates: function UP_checkForUpdates() { + if (this._getAltUpdateWindow()) + return; + this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, UPDATE_WINDOW_NAME, null, null); }, /** * See nsIUpdateService.idl */ showUpdateAvailable: function UP_showUpdateAvailable(update) { if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false) || - this._getUpdateWindow()) + this._getUpdateWindow() || this._getAltUpdateWindow()) return; var stringsPrefix = "updateAvailable_" + update.type + "."; var title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [update.name], 1); var text = gUpdateBundle.GetStringFromName(stringsPrefix + "text"); var imageUrl = ""; this._showUnobtrusiveUI(null, URI_UPDATE_PROMPT_DIALOG, null, UPDATE_WINDOW_NAME, "updatesavailable", update, title, text, imageUrl); }, /** * See nsIUpdateService.idl */ showUpdateDownloaded: function UP_showUpdateDownloaded(update, background) { + if (this._getAltUpdateWindow()) + return; + if (background) { if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false)) return; var stringsPrefix = "updateDownloaded_" + update.type + "."; var title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [update.name], 1); var text = gUpdateBundle.GetStringFromName(stringsPrefix + "text"); @@ -2847,17 +2854,18 @@ UpdatePrompt.prototype = { Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, null, openFeatures, arg); } }, /** * See nsIUpdateService.idl */ showUpdateError: function UP_showUpdateError(update) { - if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false)) + if (getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false) || + this._getAltUpdateWindow()) return; // In some cases, we want to just show a simple alert dialog: if (update.state == STATE_FAILED && update.errorCode == WRITE_ERROR) { var title = gUpdateBundle.GetStringFromName("updaterIOErrorTitle"); var text = gUpdateBundle.formatStringFromName("updaterIOErrorMsg", [Services.appinfo.name, Services.appinfo.name], 2); @@ -2888,16 +2896,28 @@ UpdatePrompt.prototype = { /** * Returns the update window if present. */ _getUpdateWindow: function UP__getUpdateWindow() { return Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME); }, /** + * Returns an alternative update window if present. When a window with this + * windowtype is open the application update service won't open the normal + * application update user interface window. + */ + _getAltUpdateWindow: function UP__getAltUpdateWindow() { + let windowType = getPref("getCharPref", PREF_APP_UPDATE_ALTWINDOWTYPE, null); + if (!windowType) + return null; + return Services.wm.getMostRecentWindow(windowType); + }, + + /** * Initiate a less obtrusive UI, starting with a non-modal notification alert * @param parent * A parent window, can be null * @param uri * The URI string of the dialog to show * @param name * The Window Name of the dialog to show, in case it is already open * and can merely be focused
--- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -44,16 +44,17 @@ #include "nsXULAppAPI.h" #include "nsAppRunner.h" #include "nsILocalFile.h" #include "nsCOMPtr.h" #include "nsString.h" #include "nsPrintfCString.h" #include "prproces.h" #include "prlog.h" +#include "prenv.h" #include "nsVersionComparator.h" #ifdef XP_MACOSX #include "nsILocalFileMac.h" #include "nsCommandLineServiceMac.h" #endif #if defined(XP_WIN) @@ -468,16 +469,20 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up for (int i = 1; i < appArgc; ++i) argv[4 + i] = appArgv[i]; argv[4 + appArgc] = nsnull; } else { argv[3] = nsnull; argc = 3; } + if (gSafeMode) { + PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); + } + LOG(("spawning updater process [%s]\n", updaterPath.get())); #if defined(USE_EXECV) chdir(applyToDir.get()); execv(updaterPath.get(), argv); #elif defined(XP_WIN) _wchdir(applyToDir.get());