Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | const Cc = Components.classes; |
michael@0 | 7 | const Ci = Components.interfaces; |
michael@0 | 8 | const Cu = Components.utils; |
michael@0 | 9 | const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService; |
michael@0 | 10 | |
michael@0 | 11 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 12 | Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 13 | |
michael@0 | 14 | function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) { |
michael@0 | 15 | let argString = null; |
michael@0 | 16 | if (aArgs && !(aArgs instanceof Ci.nsISupportsArray)) { |
michael@0 | 17 | argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); |
michael@0 | 18 | argString.data = aArgs; |
michael@0 | 19 | } |
michael@0 | 20 | |
michael@0 | 21 | return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, argString || aArgs); |
michael@0 | 22 | } |
michael@0 | 23 | |
michael@0 | 24 | function resolveURIInternal(aCmdLine, aArgument) { |
michael@0 | 25 | let uri = aCmdLine.resolveURI(aArgument); |
michael@0 | 26 | |
michael@0 | 27 | if (!(uri instanceof Ci.nsIFileURL)) |
michael@0 | 28 | return uri; |
michael@0 | 29 | |
michael@0 | 30 | try { |
michael@0 | 31 | if (uri.file.exists()) |
michael@0 | 32 | return uri; |
michael@0 | 33 | } catch (e) { |
michael@0 | 34 | Cu.reportError(e); |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | try { |
michael@0 | 38 | let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); |
michael@0 | 39 | uri = urifixup.createFixupURI(aArgument, 0); |
michael@0 | 40 | } catch (e) { |
michael@0 | 41 | Cu.reportError(e); |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | return uri; |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | /** |
michael@0 | 48 | * Determines whether a home page override is needed. |
michael@0 | 49 | * Returns: |
michael@0 | 50 | * "new profile" if this is the first run with a new profile. |
michael@0 | 51 | * "new version" if this is the first run with a build with a different |
michael@0 | 52 | * Gecko milestone (i.e. right after an upgrade). |
michael@0 | 53 | * "none" otherwise. |
michael@0 | 54 | */ |
michael@0 | 55 | function needHomepageOverride() { |
michael@0 | 56 | let savedmstone = null; |
michael@0 | 57 | try { |
michael@0 | 58 | savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone"); |
michael@0 | 59 | } catch (e) {} |
michael@0 | 60 | |
michael@0 | 61 | if (savedmstone == "ignore") |
michael@0 | 62 | return "none"; |
michael@0 | 63 | |
michael@0 | 64 | let ourmstone = Services.appinfo.platformVersion; |
michael@0 | 65 | |
michael@0 | 66 | if (ourmstone != savedmstone) { |
michael@0 | 67 | Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone); |
michael@0 | 68 | |
michael@0 | 69 | return (savedmstone ? "new version" : "new profile"); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | return "none"; |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | function getHomePage() { |
michael@0 | 76 | let url = "about:newtab"; |
michael@0 | 77 | try { |
michael@0 | 78 | url = Services.prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data; |
michael@0 | 79 | } catch (e) { } |
michael@0 | 80 | |
michael@0 | 81 | return url; |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | function showPanelWhenReady(aWindow, aPage) { |
michael@0 | 85 | aWindow.addEventListener("UIReadyDelayed", function(aEvent) { |
michael@0 | 86 | aWindow.PanelUI.show(aPage); |
michael@0 | 87 | }, false); |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | function haveSystemLocale() { |
michael@0 | 91 | let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService); |
michael@0 | 92 | let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE"); |
michael@0 | 93 | return isLocaleAvailable(systemLocale); |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | function checkCurrentLocale() { |
michael@0 | 97 | if (Services.prefs.prefHasUserValue("general.useragent.locale")) { |
michael@0 | 98 | // if the user has a compatible locale from a different buildid, we need to update |
michael@0 | 99 | var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).platformBuildID; |
michael@0 | 100 | let localeBuildID = Services.prefs.getCharPref("extensions.compatability.locales.buildid"); |
michael@0 | 101 | if (buildID != localeBuildID) |
michael@0 | 102 | return false; |
michael@0 | 103 | |
michael@0 | 104 | let currentLocale = Services.prefs.getCharPref("general.useragent.locale"); |
michael@0 | 105 | return isLocaleAvailable(currentLocale); |
michael@0 | 106 | } |
michael@0 | 107 | return true; |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | function isLocaleAvailable(aLocale) { |
michael@0 | 111 | let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); |
michael@0 | 112 | chrome.QueryInterface(Ci.nsIToolkitChromeRegistry); |
michael@0 | 113 | let availableLocales = chrome.getLocalesForPackage("browser"); |
michael@0 | 114 | |
michael@0 | 115 | let locale = aLocale.split("-")[0]; |
michael@0 | 116 | let localeRegEx = new RegExp("^" + locale); |
michael@0 | 117 | |
michael@0 | 118 | while (availableLocales.hasMore()) { |
michael@0 | 119 | let locale = availableLocales.getNext(); |
michael@0 | 120 | if (localeRegEx.test(locale)) |
michael@0 | 121 | return true; |
michael@0 | 122 | } |
michael@0 | 123 | return false; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | function BrowserCLH() { } |
michael@0 | 127 | |
michael@0 | 128 | BrowserCLH.prototype = { |
michael@0 | 129 | // |
michael@0 | 130 | // nsICommandLineHandler |
michael@0 | 131 | // |
michael@0 | 132 | handle: function fs_handle(aCmdLine) { |
michael@0 | 133 | #ifdef DEBUG |
michael@0 | 134 | for (var idx = 0; idx < aCmdLine.length; idx++) { |
michael@0 | 135 | dump(aCmdLine.getArgument(idx) + "\n"); |
michael@0 | 136 | } |
michael@0 | 137 | #endif |
michael@0 | 138 | // Instantiate the search service so the search engine cache is created now |
michael@0 | 139 | // instead when the application is running. The install process will register |
michael@0 | 140 | // this component by using the -silent command line flag, thereby creating |
michael@0 | 141 | // the cache during install, not runtime. |
michael@0 | 142 | // NOTE: This code assumes this CLH is run before the nsDefaultCLH, which |
michael@0 | 143 | // consumes the "-silent" flag. |
michael@0 | 144 | if (aCmdLine.findFlag("silent", false) > -1) { |
michael@0 | 145 | let searchService = Services.search; |
michael@0 | 146 | let autoComplete = Cc["@mozilla.org/autocomplete/search;1?name=history"]. |
michael@0 | 147 | getService(Ci.nsIAutoCompleteSearch); |
michael@0 | 148 | return; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | // Handle chrome windows loaded via commandline |
michael@0 | 152 | let chromeParam = aCmdLine.handleFlagWithParam("chrome", false); |
michael@0 | 153 | if (chromeParam) { |
michael@0 | 154 | try { |
michael@0 | 155 | // Only load URIs which do not inherit chrome privs |
michael@0 | 156 | let features = "chrome,dialog=no,all"; |
michael@0 | 157 | let uri = resolveURIInternal(aCmdLine, chromeParam); |
michael@0 | 158 | let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil); |
michael@0 | 159 | if (!netutil.URIChainHasFlags(uri, Ci.nsIHttpProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) { |
michael@0 | 160 | openWindow(null, uri.spec, "_blank", features, null); |
michael@0 | 161 | |
michael@0 | 162 | // Stop the normal commandline processing from continuing |
michael@0 | 163 | aCmdLine.preventDefault = true; |
michael@0 | 164 | } |
michael@0 | 165 | } catch (e) { |
michael@0 | 166 | Cu.reportError(e); |
michael@0 | 167 | } |
michael@0 | 168 | return; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | // Check and remove the alert flag here, but we'll handle it a bit later - see below |
michael@0 | 172 | let alertFlag = aCmdLine.handleFlagWithParam("alert", false); |
michael@0 | 173 | |
michael@0 | 174 | // Check and remove the webapp param |
michael@0 | 175 | let appFlag = aCmdLine.handleFlagWithParam("webapp", false); |
michael@0 | 176 | let appURI; |
michael@0 | 177 | if (appFlag) |
michael@0 | 178 | appURI = resolveURIInternal(aCmdLine, appFlag); |
michael@0 | 179 | |
michael@0 | 180 | // Keep an array of possible URL arguments |
michael@0 | 181 | let uris = []; |
michael@0 | 182 | |
michael@0 | 183 | // Check for the "url" flag |
michael@0 | 184 | let uriFlag = aCmdLine.handleFlagWithParam("url", false); |
michael@0 | 185 | if (uriFlag) { |
michael@0 | 186 | let uri = resolveURIInternal(aCmdLine, uriFlag); |
michael@0 | 187 | if (uri) |
michael@0 | 188 | uris.push(uri); |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | // Check for the "search" flag |
michael@0 | 192 | let searchParam = aCmdLine.handleFlagWithParam("search", false); |
michael@0 | 193 | if (searchParam) { |
michael@0 | 194 | var ss = Components.classes["@mozilla.org/browser/search-service;1"] |
michael@0 | 195 | .getService(nsIBrowserSearchService); |
michael@0 | 196 | var submission = ss.defaultEngine.getSubmission(searchParam.replace("\"", "", "g")); |
michael@0 | 197 | uris.push(submission.uri); |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | for (let i = 0; i < aCmdLine.length; i++) { |
michael@0 | 201 | let arg = aCmdLine.getArgument(i); |
michael@0 | 202 | if (!arg || arg[0] == '-') |
michael@0 | 203 | continue; |
michael@0 | 204 | |
michael@0 | 205 | let uri = resolveURIInternal(aCmdLine, arg); |
michael@0 | 206 | if (uri) |
michael@0 | 207 | uris.push(uri); |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | // Open the main browser window, if we don't already have one |
michael@0 | 211 | let browserWin; |
michael@0 | 212 | try { |
michael@0 | 213 | let localeWin = Services.wm.getMostRecentWindow("navigator:localepicker"); |
michael@0 | 214 | if (localeWin) { |
michael@0 | 215 | localeWin.focus(); |
michael@0 | 216 | aCmdLine.preventDefault = true; |
michael@0 | 217 | return; |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | browserWin = Services.wm.getMostRecentWindow("navigator:browser"); |
michael@0 | 221 | if (!browserWin) { |
michael@0 | 222 | // Default to the saved homepage |
michael@0 | 223 | let defaultURL = getHomePage(); |
michael@0 | 224 | |
michael@0 | 225 | // Override the default if we have a URL passed on command line |
michael@0 | 226 | if (uris.length > 0) { |
michael@0 | 227 | defaultURL = uris[0].spec; |
michael@0 | 228 | uris = uris.slice(1); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | // Show the locale selector if we have a new profile, or if the selected locale is no longer compatible |
michael@0 | 232 | let showLocalePicker = Services.prefs.getBoolPref("browser.firstrun.show.localepicker"); |
michael@0 | 233 | if ((needHomepageOverride() == "new profile" && showLocalePicker && !haveSystemLocale())) { // || !checkCurrentLocale()) { |
michael@0 | 234 | browserWin = openWindow(null, "chrome://browser/content/localePicker.xul", "_blank", "chrome,dialog=no,all", defaultURL); |
michael@0 | 235 | aCmdLine.preventDefault = true; |
michael@0 | 236 | return; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", defaultURL); |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | browserWin.focus(); |
michael@0 | 243 | |
michael@0 | 244 | // Stop the normal commandline processing from continuing. We just opened the main browser window |
michael@0 | 245 | aCmdLine.preventDefault = true; |
michael@0 | 246 | } catch (e) { |
michael@0 | 247 | Cu.reportError(e); |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | // Assumption: All remaining command line arguments have been sent remotely (browser is already running) |
michael@0 | 251 | // Action: Open any URLs we find into an existing browser window |
michael@0 | 252 | |
michael@0 | 253 | // First, get a browserDOMWindow object |
michael@0 | 254 | while (!browserWin.browserDOMWindow) |
michael@0 | 255 | Services.tm.currentThread.processNextEvent(true); |
michael@0 | 256 | |
michael@0 | 257 | // Open any URIs into new tabs |
michael@0 | 258 | for (let i = 0; i < uris.length; i++) |
michael@0 | 259 | browserWin.browserDOMWindow.openURI(uris[i], null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); |
michael@0 | 260 | |
michael@0 | 261 | if (appURI) |
michael@0 | 262 | browserWin.browserDOMWindow.openURI(appURI, null, browserWin.OPEN_APPTAB, Ci.nsIBrowserDOMWindow.OPEN_NEW); |
michael@0 | 263 | |
michael@0 | 264 | // Handle the notification, if called from it |
michael@0 | 265 | if (alertFlag) { |
michael@0 | 266 | if (alertFlag == "update-app") { |
michael@0 | 267 | // Notification was already displayed and clicked, skip it next time |
michael@0 | 268 | Services.prefs.setBoolPref("app.update.skipNotification", true); |
michael@0 | 269 | |
michael@0 | 270 | var updateService = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService); |
michael@0 | 271 | var updateTimerCallback = updateService.QueryInterface(Ci.nsITimerCallback); |
michael@0 | 272 | updateTimerCallback.notify(null); |
michael@0 | 273 | } |
michael@0 | 274 | } |
michael@0 | 275 | }, |
michael@0 | 276 | |
michael@0 | 277 | // QI |
michael@0 | 278 | QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), |
michael@0 | 279 | |
michael@0 | 280 | // XPCOMUtils factory |
michael@0 | 281 | classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}"), |
michael@0 | 282 | }; |
michael@0 | 283 | |
michael@0 | 284 | var components = [ BrowserCLH ]; |
michael@0 | 285 | this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); |