[tbb-commits] [tor-launcher/master] Bug 23261: implement configuration portion of new Tor Launcher UI

gk at torproject.org gk at torproject.org
Thu Nov 9 08:33:31 UTC 2017


commit 4f07910c678fe2179f200ea4dc777782e006fe0a
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Mon Oct 30 15:43:52 2017 -0400

    Bug 23261: implement configuration portion of new Tor Launcher UI
    
    Eliminate several wizard pages and include all of the bridge and
      proxy settings on one page.
    Use the new Tor Browser logo.
    Reuse Mozilla's help button from the Firefox hamburger menu and add
      help for the proxy settings..
    In the wizard, use a "pageshow" event listener to show page-specific
      titles and to hide/show the navigation buttons as needed.
    After the user chooses to restart the tor process, display the
      "Waiting for Tor to start" panel.
    When tor is restarted by the user, disable networking so that
      bootstrapping does not begin right away; this allows the user to
      make configuration choices first.
    Do not try to connect to the control port if tor is not running.
---
 src/chrome/content/localePicker.xul             |   8 +-
 src/chrome/content/network-settings-overlay.xul | 204 ++++++------
 src/chrome/content/network-settings-wizard.xul  | 172 +++-------
 src/chrome/content/network-settings.js          | 405 ++++++++++++------------
 src/chrome/content/network-settings.xul         |  29 +-
 src/chrome/locale/en/network-settings.dtd       |  58 ++--
 src/chrome/locale/en/torlauncher.properties     |   3 +-
 src/chrome/skin/network-settings.css            |  87 +++--
 src/chrome/skin/tbb-logo.png                    | Bin 20231 -> 0 bytes
 src/chrome/skin/tbb-logo.svg                    | 139 ++++++++
 src/components/tl-process.js                    |  33 +-
 11 files changed, 594 insertions(+), 544 deletions(-)

diff --git a/src/chrome/content/localePicker.xul b/src/chrome/content/localePicker.xul
index 5b93825..2017baa 100644
--- a/src/chrome/content/localePicker.xul
+++ b/src/chrome/content/localePicker.xul
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
-   - Copyright (c) 2015, The Tor Project, Inc.
+   - Copyright (c) 2017, The Tor Project, Inc.
    - See LICENSE for licensing information.
    - vim: set sw=2 sts=2 ts=8 et syntax=xml:
   -->
@@ -26,10 +26,8 @@
           src="chrome://torlauncher/content/network-settings.js"/>
 
   <wizardpage pageid="localePicker">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
+    <hbox class="tbb-header" pack="center">
+      <image class="tbb-logo"/>
     </hbox>
     <separator />
     <vbox>
diff --git a/src/chrome/content/network-settings-overlay.xul b/src/chrome/content/network-settings-overlay.xul
index 10751d1..8f1bc45 100644
--- a/src/chrome/content/network-settings-overlay.xul
+++ b/src/chrome/content/network-settings-overlay.xul
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
-   - Copyright (c) 2016, The Tor Project, Inc.
+   - Copyright (c) 2017, The Tor Project, Inc.
    - See LICENSE for licensing information.
    - vim: set sw=2 sts=2 ts=8 et syntax=xml:
   -->
@@ -11,59 +11,73 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml">
 
-  <groupbox id="proxySpecificSettings">
-    <grid flex="1">
-      <columns>
-        <column/>
-        <column/>
-      </columns>
-      <rows>
-        <row align="center">
-          <label value="&torsettings.useProxy.type;" control="proxyType"
-                 style="text-align:right" />
-          <hbox align="center">
-            <menulist id="proxyType" oncommand="onProxyTypeChange()">
-              <menupopup id="proxyType_menuPopup">
-                <menuitem label="-" value="" selected="true" />
-                <menuitem label="&torsettings.useProxy.type.socks4;"
-                          value="SOCKS4"/>
-                <menuitem label="&torsettings.useProxy.type.socks5;"
-                          value="SOCKS5"/>
-                <menuitem label="&torsettings.useProxy.type.http;"
-                          value="HTTP"/>
-              </menupopup>
-            </menulist>
-          </hbox>
-        </row>
-        <row align="center">
-          <label value="&torsettings.useProxy.address;" control="proxyAddr"
-                 style="text-align:right" />
-          <hbox align="center">
-            <textbox id="proxyAddr" size="20" flex="1"
-                     placeholder="&torsettings.useProxy.address.placeholder;" />
-            <separator orient="vertical" />
-            <label value="&torsettings.useProxy.port;" control="proxyPort"/>
-            <textbox id="proxyPort" size="4" />
-          </hbox>
-        </row>
-        <row align="center">
-          <label id="proxyUsernameLabel"
-                 value="&torsettings.useProxy.username;"
-                 control="proxyUsername" style="text-align:right" />
-          <hbox align="center">
-            <textbox id="proxyUsername" size="14" flex="1"
-                     placeholder="&torsettings.optional;" />
-            <separator orient="vertical" />
-            <label id="proxyPasswordLabel"
-                   value="&torsettings.useProxy.password;"
-                   control="proxyPassword"/>
-            <textbox id="proxyPassword" size="14" type="password"
-                     placeholder="&torsettings.optional;" />
-          </hbox>
-        </row>
-      </rows>
-    </grid>
-  </groupbox>
+  <vbox id="proxySettings">
+    <hbox align="center">
+      <checkbox id="useProxy" groupboxID="proxySpecificSettings"
+                  label="&torsettings.useProxy.checkbox;"
+                  oncommand="toggleElemUI(this)"/>
+      <button class="helpButton" oncommand="onOpenHelp('proxyHelpContent')"/>
+    </hbox>
+    <groupbox id="proxySpecificSettings">
+      <grid flex="1">
+        <columns>
+          <column/>
+          <column/>
+        </columns>
+        <rows>
+          <row align="center">
+            <label value="&torsettings.useProxy.type;" control="proxyType"
+                   style="text-align:right"/>
+            <hbox align="center">
+              <menulist id="proxyType" sizetopopup="always"
+                        placeholder="&torsettings.useProxy.type.placeholder;"
+                        oncommand="onProxyTypeChange()">
+                <menupopup id="proxyType_menuPopup">
+                  <menuitem label="&torsettings.useProxy.type.socks4;"
+                            value="SOCKS4"/>
+                  <menuitem label="&torsettings.useProxy.type.socks5;"
+                            value="SOCKS5"/>
+                  <menuitem label="&torsettings.useProxy.type.http;"
+                            value="HTTP"/>
+                </menupopup>
+              </menulist>
+            </hbox>
+          </row>
+          <row align="center">
+            <label value="&torsettings.useProxy.address;" control="proxyAddr"
+                   style="text-align:right"/>
+            <hbox align="center">
+              <textbox id="proxyAddr" size="20" flex="1"
+                       placeholder="&torsettings.useProxy.address.placeholder;"/>
+              <separator orient="vertical"/>
+              <label value="&torsettings.useProxy.port;" control="proxyPort"/>
+              <textbox id="proxyPort" size="4"/>
+            </hbox>
+          </row>
+          <row align="center">
+            <label id="proxyUsernameLabel"
+                   value="&torsettings.useProxy.username;"
+                   control="proxyUsername" style="text-align:right"/>
+            <hbox align="center">
+              <textbox id="proxyUsername" size="14" flex="1"
+                       placeholder="&torsettings.optional;"/>
+              <separator orient="vertical"/>
+              <label id="proxyPasswordLabel"
+                     value="&torsettings.useProxy.password;"
+                     control="proxyPassword"/>
+              <textbox id="proxyPassword" size="14" type="password"
+                       placeholder="&torsettings.optional;"/>
+            </hbox>
+          </row>
+        </rows>
+      </grid>
+    </groupbox>
+  </vbox>
+
+  <vbox id="proxyHelpContent">
+    <hbox align="middle"><label>&torsettings.proxyHelpTitle;</label></hbox>
+    <description>&torsettings.proxyHelp1;</description>
+  </vbox>
 
   <groupbox id="firewallSpecificSettings">
     <hbox align="center">
@@ -73,59 +87,47 @@
     </hbox>
   </groupbox>
 
-  <groupbox id="bridgeSpecificSettings">
-    <hbox align="end" pack="end">
-      <radiogroup id="bridgeTypeRadioGroup" flex="1" style="margin: 0px"
-                  oncommand="onBridgeTypeRadioChange()">
-        <radio id="bridgeRadioDefault"
-               label="&torsettings.useBridges.default;" selected="true" />
-        <hbox id="bridgeDefaultEntry" align="baseline" style="margin-top: -5px">
-          <label id="defaultBridgeTypeLabel"
-                 value="&torsettings.useBridges.type;"
-                 control="defaultBridgeType"/>
-          <menulist id="defaultBridgeType">
-            <menupopup id="defaultBridgeType_menuPopup" />
-          </menulist>
-          <spring/>
-        </hbox>
-        <spacer style="height: 0.5em" />
+  <vbox id="bridgeSettings">
+    <checkbox id="useBridges" groupboxID="bridgeSpecificSettings"
+                label="&torsettings.useBridges.checkbox;"
+                oncommand="toggleElemUI(this);"/>
+    <groupbox id="bridgeSpecificSettings">
+      <hbox align="end" pack="end">
+        <radiogroup id="bridgeTypeRadioGroup" flex="1" style="margin: 0px"
+                    oncommand="onBridgeTypeRadioChange()">
+          <hbox align="center">
+            <radio id="bridgeRadioDefault"
+                   label="&torsettings.useBridges.default;" selected="true"/>
+            <button class="helpButton"
+                    oncommand="onOpenHelp('bridgeHelpContent')"/>
+            <spacer style="width: 3em"/>
+            <menulist id="defaultBridgeType" sizetopopup="always"
+                  placeholder="&torsettings.useBridges.default.placeholder;">
+              <menupopup id="defaultBridgeType_menuPopup"/>
+            </menulist>
+            <spring/>
+          </hbox>
 
-        <radio align="start" id="bridgeRadioCustom"
-               label="&torsettings.useBridges.custom;" />
-      </radiogroup>
-      <button dlgtype="help" oncommand="onOpenHelp()" />
-    </hbox>
-    <vbox id="bridgeCustomEntry">
-      <label id="bridgeListLabel" style="margin-top:0px;"
-             value="&torsettings.useBridges.label;" control="bridgeList"/>
-      <textbox id="bridgeList" multiline="true" rows="3" wrap="off"
-               oninput="onCustomBridgesTextInput();"
-               placeholder="&torsettings.useBridges.placeholder;" />
-    </vbox>
-  </groupbox>
+          <radio align="start" id="bridgeRadioCustom"
+                 label="&torsettings.useBridges.custom;"/>
+        </radiogroup>
+      </hbox>
+      <vbox id="bridgeCustomEntry">
+        <label id="bridgeListLabel" style="margin-top:0px;"
+               value="&torsettings.useBridges.label;" control="bridgeList"/>
+        <textbox id="bridgeList" multiline="true" rows="3" wrap="off"
+                 oninput="onCustomBridgesTextInput();"
+                 placeholder="&torsettings.useBridges.placeholder;"/>
+      </vbox>
+    </groupbox>
+  </vbox>
 
   <vbox id="bridgeHelpContent">
     <hbox align="middle"><label>&torsettings.bridgeHelpTitle;</label></hbox>
     <description>&torsettings.bridgeHelp1;</description>
-    <description class="prelist">&torsettings.bridgeHelp1B;</description>
-    <html:ol>
-      <html:li>
-        <html:div class="heading">&torsettings.bridgeHelp2Heading;</html:div>
-        <html:div>&torsettings.bridgeHelp2;</html:div>
-      </html:li>
-      <html:li>
-        <html:div class="heading">&torsettings.bridgeHelp3Heading;</html:div>
-        <html:div>&torsettings.bridgeHelp3.emailDesc;</html:div>
-        <html:div>&torsettings.bridgeHelp3.emailList;</html:div>
-      </html:li>
-<!-- As of April 2016, no one is responding to help desk email. Hopefully this will change soon.
-      <html:li>
-        <html:div class="heading">&torsettings.bridgeHelp4Heading;</html:div>
-        <html:div class="endOfHelp">&torsettings.bridgeHelp4;</html:div>
-      </html:li>
--->
-    </html:ol>
+    <description>&torsettings.bridgeHelp2;</description>
   </vbox>
+
   <panel id="copyLogFeedbackPanel" type="arrow" fade="slow"
          onclick="closeCopyLogFeedbackPanel()">
      <description flex="1" />
diff --git a/src/chrome/content/network-settings-wizard.xul b/src/chrome/content/network-settings-wizard.xul
index 56217c5..5d76331 100644
--- a/src/chrome/content/network-settings-wizard.xul
+++ b/src/chrome/content/network-settings-wizard.xul
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
-   - Copyright (c) 2015, The Tor Project, Inc.
+   - Copyright (c) 2017, The Tor Project, Inc.
    - See LICENSE for licensing information.
    - vim: set sw=2 sts=2 ts=8 et syntax=xml:
   -->
@@ -15,7 +15,7 @@
 
 <wizard id="TorNetworkSettings"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        title="&torsettings.dialog.title;"
+        defaulttitle="&torsettings.wizard.title.default;"
         windowtype="TorLauncher:NetworkSettings"
         persist="screenX screenY"
         buttonlabelextra2="&torsettings.copyLog;"
@@ -27,132 +27,39 @@
   <script type="application/x-javascript"
           src="chrome://torlauncher/content/network-settings.js"/>
 
-  <!-- This page requires a setTimeout for onpageshow because it may be
-       shown first -->
-  <wizardpage pageid="first" next="proxy" onextra2="onCopyLog();"
-              onpageshow="setTimeout(function() { showWizardNavButtons(false); }, 0);">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
-      <separator class="tbb-logo-separator" orient="vertical" />
-      <groupbox flex="1">
-        <description>&torsettings.prompt;</description>
-      </groupbox>
+  <wizardpage pageid="first" next="configureSettings" onextra2="onCopyLog();"
+              torShowNavButtons="false">
+    <hbox class="tbb-header" pack="center">
+      <image class="tbb-logo"/>
     </hbox>
-    <separator />
-    <vbox class="firstResponses" align="start">
-      <label class="question">&torSettings.firstQuestion;</label>
-      <separator/>
-      <label>&torSettings.connectPrompt2;</label>
-      <label>&torSettings.connectPrompt3;</label>
-      <button label="&torSettings.connect;"
-              oncommand="onWizardFirstPanelConnect();"/>
-      <separator class="tall"/>
-      <label>&torSettings.configurePrompt1;</label>
-      <label>&torSettings.configurePrompt2;</label>
-      <button label="&torSettings.configure;" oncommand="onWizardConfigure();"/>
-    </vbox>
-  </wizardpage>
 
-  <wizardpage pageid="bridges" next="proxy" onextra2="onCopyLog();"
-              onpageshow="showWizardNavButtons(true);"
-              onpageadvanced="return onWizardUseBridgesNext(this)">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
-      <separator class="tbb-logo-separator" orient="vertical" />
-      <vbox pack="end">
-        <label class="tbb-wizardpage-title" value="&torSettings.bridgePageTitle;"/>
-      </vbox>
-    </hbox>
-    <separator />
-    <hbox>
-      <vbox flex="1">
-        <label class="question">&torSettings.bridgeQuestion;</label>
-        <radiogroup id="useBridgesRadioGroup">
-          <radio id="bridgesRadioYes" label="&torSettings.yes;" />
-          <radio id="bridgesRadioNo" label="&torSettings.no;" selected="true" />
-        </radiogroup>
-        <description class="questionHelp">&torSettings.bridgeExplanation1;
-        </description>
-        <description class="questionHelp">&torSettings.bridgeExplanation2;
-        </description>
-      </vbox>
-    </hbox>
-  </wizardpage>
-
-  <wizardpage pageid="bridgeSettings" next="proxy" onextra2="onCopyLog();"
-              onpageshow="onWizardBridgeSettingsShow();">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
-      <separator class="tbb-logo-separator" orient="vertical" />
-      <vbox pack="end">
-        <label class="tbb-wizardpage-title" value="&torSettings.bridgePageTitle;"/>
-      </vbox>
-    </hbox>
-    <separator />
-    <vbox>
-      <label id="bridgeSettingsPrompt"
-             class="question">&torSettings.bridgeSettingsPrompt; 
-&torsettings.useBridges.note;</label>
-      <groupbox id="bridgeSpecificSettings" />
+    <separator class="tall"/>
+    <vbox class="firstResponses" align="center">
+      <label>&torSettings.connectPrompt;</label>
+      <label>&torSettings.configurePrompt;</label>
+      <separator/>
+      <hbox>
+        <button label="&torSettings.connect;"
+                oncommand="onWizardFirstPanelConnect();"/>
+        <button label="&torSettings.configure;"
+                oncommand="onWizardConfigure();"/>
+      </hbox>
     </vbox>
   </wizardpage>
 
-  <wizardpage pageid="proxy" onextra2="onCopyLog();"
-              onpageshow="onWizardUseProxyRadioChange()"
-              onpageadvanced="return onWizardProxyNext(this);">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
-      <separator class="tbb-logo-separator" orient="vertical" />
-      <vbox pack="end">
-        <label class="tbb-wizardpage-title" value="&torSettings.proxyPageTitle;"/>
-      </vbox>
-    </hbox>
-    <separator />
-    <hbox>
-      <vbox flex="1">
-        <label class="question">&torSettings.proxyQuestion;</label>
-        <radiogroup id="proxyRadioGroup"
-                    oncommand="onWizardUseProxyRadioChange()">
-          <radio id="proxyRadioYes" label="&torSettings.yes;" />
-          <radio id="proxyRadioNo" label="&torSettings.no;" selected="true" />
-        </radiogroup>
-        <description class="questionHelp">&torSettings.proxyExplanation1;
-        </description>
-        <description class="questionHelp">&torSettings.proxyExplanation2;
-        </description>
-      </vbox>
-    </hbox>
+  <wizardpage pageid="configureSettings" onextra2="onCopyLog();"
+              windowtitle="&torsettings.wizard.title.configure;"
+              torShowNavButtons="true">
+    <separator class="tall"/>
+    <vbox id="bridgeSettings"/>
+    <separator/>
+    <vbox id="proxySettings"/>
   </wizardpage>
 
-  <wizardpage pageid="proxyYES" onextra2="onCopyLog();"
-              onpageshow="onWizardProxySettingsShow()"
-              onpageadvanced="return (getAndValidateProxySettings() != null)">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
-      <separator class="tbb-logo-separator" orient="vertical" />
-      <vbox pack="end">
-        <label class="tbb-wizardpage-title" value="&torSettings.proxyPageTitle;"/>
-      </vbox>
+  <wizardpage pageid="startingTor" next="notUsed" torShowNavButtons="false">
+    <hbox class="tbb-header" pack="center">
+      <image class="tbb-logo"/>
     </hbox>
-    <separator />
-    <label class="instructions">&torSettings.enterProxy;</label>
-    <groupbox id="proxySpecificSettings" />
-  </wizardpage>
-
-  <!-- This page requires a setTimeout for onpageshow because it may be
-       shown first -->
-  <wizardpage pageid="startingTor" next="notUsed"
-              onpageshow="setTimeout(function() { showWizardNavButtons(false); }, 0);">
     <spring flex="1" />
     <hbox>
       <spring flex="1" />
@@ -162,8 +69,7 @@
     <spring flex="1" />
   </wizardpage>
 
-  <wizardpage pageid="errorPanel" next="notUsed"
-              onpageshow="showWizardNavButtons(false);"
+  <wizardpage pageid="errorPanel" next="notUsed" torShowNavButtons="false"
               onextra2="onCopyLog();">
     <spring flex="1" />
     <hbox>
@@ -183,35 +89,29 @@
     <spring flex="1" />
   </wizardpage>
 
-  <wizardpage pageid="discardSettings" next="notUsed"
-              onpageshow="showWizardNavButtons(false);"
+  <wizardpage pageid="discardSettings" next="notUsed" torShowNavButtons="false"
               onextra2="onCopyLog();">
-    <hbox class="tbb-header">
-      <vbox class="tbb-logo-box" align="start">
-        <image class="tbb-logo" />
-      </vbox>
+    <hbox class="tbb-header" pack="center">
+      <image class="tbb-logo"/>
     </hbox>
     <spring flex="1" />
-    <hbox>
-      <spring flex="1" />
+    <hbox pack="center">
       <description flex="1">&torsettings.discardSettings.prompt;</description>
-      <spring flex="1" />
     </hbox>
     <separator/>
-    <hbox>
-      <spring flex="1" />
+    <hbox pack="center">
       <button id="discardSettingsGoBack" oncommand="showPanel();"/>
       <separator/>
       <button label="&torsettings.discardSettings.proceed;"
               oncommand="removeSettingsAndConnect()" />
-      <spring flex="1" />
     </hbox>
     <spring flex="1" />
   </wizardpage>
 
-  <wizardpage class="help" pageid="bridgeHelp" next="notUsed"
+  <wizardpage class="help" pageid="helpPanel" next="notUsed"
               onpageadvanced="closeHelp(); return false;">
-    <vbox id="bridgeHelpContent" />
+    <vbox id="bridgeHelpContent" hidden="true"/>
+    <vbox id="proxyHelpContent" hidden="true"/>
   </wizardpage>
 
   <hbox pack="start">
diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js
index 830ef31..f8dcb3b 100644
--- a/src/chrome/content/network-settings.js
+++ b/src/chrome/content/network-settings.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2016, The Tor Project, Inc.
+// Copyright (c) 2017, The Tor Project, Inc.
 // See LICENSE for licensing information.
 //
 // vim: set sw=2 sts=2 ts=8 et syntax=javascript:
@@ -19,6 +19,7 @@ const kPrefPromptForLocale = "extensions.torlauncher.prompt_for_locale";
 const kPrefLocale = "general.useragent.locale";
 const kPrefMatchOSLocale = "intl.locale.matchOS";
 
+// The recommended type is listed first in the dropdown menu.
 const kPrefDefaultBridgeRecommendedType =
                    "extensions.torlauncher.default_bridge_recommended_type";
 const kPrefDefaultBridgeType = "extensions.torlauncher.default_bridge_type";
@@ -34,9 +35,6 @@ const kTorOpenProgressTopic = "TorOpenProgressDialog";
 const kTorBootstrapErrorTopic = "TorBootstrapError";
 const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
 
-const kWizardProxyRadioGroup = "proxyRadioGroup";
-const kWizardUseBridgesRadioGroup = "useBridgesRadioGroup";
-
 const kWizardFirstPageID = "first";
 
 const kLocaleList = "localeList";
@@ -67,17 +65,16 @@ const kTorConfKeyBridgeList = "Bridge";
 var gProtocolSvc = null;
 var gTorProcessService = null;
 var gObsService = null;
-var gHasQuitButton = false;
 var gIsInitialBootstrap = false;
+var gInitialPanelID = undefined;
 var gIsBootstrapComplete = false;
 var gRestoreAfterHelpPanelID = null;
+var gIsPostRestartBootstrapNeeded = false;
 var gActiveTopics = [];  // Topics for which an observer is currently installed.
 
 
 function initDialogCommon(aHasQuitButton)
 {
-  gHasQuitButton = aHasQuitButton;
-
   gObsService = Cc["@mozilla.org/observer-service;1"]
                   .getService(Ci.nsIObserverService);
 
@@ -140,9 +137,8 @@ function initDialog()
   gIsInitialBootstrap = window.arguments[0];
   initDialogCommon(gIsInitialBootstrap);
 
-  var startAtPanel;
   if (window.arguments.length > 1)
-    startAtPanel = window.arguments[1];
+    gInitialPanelID = window.arguments[1];
 
   if (gIsInitialBootstrap)
   {
@@ -187,22 +183,12 @@ function initDialog()
       showCopyLogButton(true);
     }
 
-    // Use "Connect" as the finish button label (on the last wizard page)..
+    // Use "Connect" as the finish button label (on the last wizard page).
     var finishBtn = document.documentElement.getButton("finish");
     if (finishBtn)
-      finishBtn.label = TorLauncherUtil.getLocalizedString("connect");
-
-    // Add label and access key to Help button.
-    var helpBtn = document.documentElement.getButton("help");
-    if (helpBtn)
     {
-      var strBundle = Cc["@mozilla.org/intl/stringbundle;1"]
-                    .getService(Ci.nsIStringBundleService)
-                    .createBundle("chrome://global/locale/dialog.properties");
-      helpBtn.setAttribute("label", strBundle.GetStringFromName("button-help"));
-      var accessKey = strBundle.GetStringFromName("accesskey-help");
-      if (accessKey)
-        helpBtn.setAttribute("accesskey", accessKey);
+      finishBtn.label = TorLauncherUtil.getLocalizedString("connect");
+      finishBtn.removeAttribute("default"); // We do not want a default button.
     }
 
     // Set Discard Settings back button label to match the wizard Back button.
@@ -232,12 +218,14 @@ function initDialog()
   }
   else
   {
-    readTorSettings();
+    onTorStarted();
+  }
 
-    if (startAtPanel)
-      advanceToWizardPanel(startAtPanel);
-    else
-      showPanel();
+  if (haveWizard)
+  {
+    onWizardPageShow();
+    document.addEventListener("pageshow",
+                              aEvent => { onWizardPageShow(); }, false);
   }
 
   resizeDialogToFitContent();
@@ -368,7 +356,7 @@ function maxWidthOfContent()
 
   // Show all buttons so we can get an accurate width measurement.
   // They will be hidden, as necessary, by the wizard.
-  let buttons = "back,next,cancel,extra2,help".split(',');
+  let buttons = "back,next,cancel,extra2".split(',');
   for (let i = 0; i < buttons.length; ++i)
     showOrHideButton(buttons[i], true, false);
 
@@ -385,6 +373,28 @@ function maxWidthOfContent()
 }
 
 
+function onWizardPageShow()
+{
+  let wizardElem = getWizard();
+  // Update page title.
+  let title = wizardElem.currentPage.getAttribute("windowtitle");
+  if (!title)
+    title = wizardElem.getAttribute("defaulttitle");
+  document.title = title;
+
+  // Hide or show navigation buttons as appropriate.
+  // setTimeout() is needed for the first panel that is displayed.
+  let val = wizardElem.currentPage.getAttribute("torShowNavButtons");
+  setTimeout(function() {
+      showOrHideButton("back", (val == "true"), false);
+
+      // The "next" button is only used by the bridgeHelp wizard panel.
+      let isShowingHelp = (wizardElem.currentPage.pageid == "helpPanel");
+      showOrHideButton("next", isShowingHelp, false);
+  }, 0);
+}
+
+
 function getWizard()
 {
   let elem = document.getElementById("TorNetworkSettings");
@@ -415,62 +425,7 @@ function removeSettingsAndConnect()
 
 function onWizardConfigure()
 {
-  getWizard().advance("bridges");
-}
-
-
-function onWizardProxyNext(aWizPage)
-{
-  if (aWizPage)
-  {
-    var hasProxy = getElemValue("proxyRadioYes", false);
-    aWizPage.next = (hasProxy) ? "proxyYES" : "";
-  }
-
-  return true;
-}
-
-
-function onWizardUseProxyRadioChange()
-{
-  var wizard = getWizard();
-  if (wizard && wizard.currentPage)
-  {
-    var hasProxy = getElemValue("proxyRadioYes", false);
-    wizard.setAttribute("lastpage", !hasProxy);
-    wizard._wizardButtons.onPageChange();
-  }
-}
-
-
-function onWizardProxySettingsShow()
-{
-  var wizard = getWizard();
-  if (wizard)
-  {
-    wizard.setAttribute("lastpage", true);
-    wizard._wizardButtons.onPageChange();
-  }
-}
-
-
-function onWizardUseBridgesNext(aWizPage)
-{
-  if (aWizPage)
-  {
-    var useBridges = getElemValue("bridgesRadioYes", false);
-    aWizPage.next = (useBridges) ? "bridgeSettings" : "proxy";
-  }
-
-  return true;
-}
-
-
-function onWizardBridgeSettingsShow()
-{
-  var btn = document.documentElement.getButton("next");
-  if (btn)
-    btn.focus();
+  getWizard().advance("configureSettings");
 }
 
 
@@ -486,8 +441,8 @@ function onCustomBridgesTextInput()
 function onBridgeTypeRadioChange()
 {
   var useCustom = getElemValue(kCustomBridgesRadio, false);
-  enableElemWithLabel(kDefaultBridgeTypeMenuList, !useCustom);
-  enableElemWithLabel(kBridgeList + "Label", useCustom);
+  setBoolAttrForElemWithLabel(kDefaultBridgeTypeMenuList, "hidden", useCustom);
+  setBoolAttrForElemWithLabel(kBridgeList, "hidden", !useCustom);
   var focusElemID = (useCustom) ? kBridgeList : kDefaultBridgeTypeMenuList;
   var elem = document.getElementById(focusElemID);
   if (elem)
@@ -495,13 +450,6 @@ function onBridgeTypeRadioChange()
 }
 
 
-function showWizardNavButtons(aShowBtns)
-{
-  showOrHideButton("back", aShowBtns, false);
-  showOrHideButton("next", aShowBtns, false);
-}
-
-
 var gObserver = {
   observe: function(aSubject, aTopic, aData)
   {
@@ -516,11 +464,7 @@ var gObserver = {
     {
       removeObserver(kTorProcessReadyTopic);
       removeObserver(kTorProcessDidNotStartTopic);
-      var haveWizard = (getWizard() != null);
-      showPanel();
-      if (haveWizard)
-        showWizardNavButtons(true);
-      readTorSettings();
+      onTorStarted();
     }
     else if (kTorProcessDidNotStartTopic == aTopic)
     {
@@ -577,7 +521,7 @@ function readTorSettings()
   TorLauncherLogger.log(2, "readTorSettings " +
                             "----------------------------------------------");
 
-  var didSucceed = false;
+  let didSucceed = false;
   try
   {
     // TODO: retrieve > 1 key at one time inside initProxySettings() et al.
@@ -593,15 +537,28 @@ function readTorSettings()
 
     setTimeout(function()
         {
-          var details = TorLauncherUtil.getLocalizedString(
+          let details = TorLauncherUtil.getLocalizedString(
                                           "ensure_tor_is_running");
-          var s = TorLauncherUtil.getFormattedLocalizedString(
+          let s = TorLauncherUtil.getFormattedLocalizedString(
                                       "failed_to_get_settings", [details], 1);
           TorLauncherUtil.showAlert(window, s);
           close();
         }, 0);
   }
-  TorLauncherLogger.log(2, "readTorSettings done");
+
+  TorLauncherLogger.log(2, "readTorSettings done; didSucceed: " + didSucceed);
+  return didSucceed;
+}
+
+
+function onTorStarted()
+{
+  if (readTorSettings())
+  {
+    showPanel();
+    if (gInitialPanelID)
+      advanceToWizardPanel(gInitialPanelID);
+  }
 }
 
 
@@ -618,9 +575,6 @@ function showPanel(aPanelID)
   else if (wizard.currentPage.pageid != aPanelID)
     wizard.goTo(aPanelID);
 
-  if (wizard && (aPanelID == kWizardFirstPageID))
-    setTimeout( function() { showWizardNavButtons(false); }, 0);
-
   showOrHideButton("accept", (aPanelID == "settings"), true);
 }
 
@@ -648,10 +602,6 @@ function advanceToWizardPanel(aPanelID)
 
 function showStartingTorPanel()
 {
-  var haveWizard = (getWizard() != null);
-  if (haveWizard)
-    showWizardNavButtons(false);
-
   showPanel("startingTor");
 }
 
@@ -693,10 +643,6 @@ function showErrorMessage(aTorExited, aErrorMsg, aShowReconfigButton)
 
   showPanel("errorPanel");
 
-  var haveWizard = (getWizard() != null);
-  if (haveWizard)
-    showWizardNavButtons(false);
-
   var haveErrorOrWarning = (gTorProcessService.TorBootstrapErrorOccurred ||
                             gProtocolSvc.TorLogHasWarnOrErr)
   showCopyLogButton(haveErrorOrWarning);
@@ -775,8 +721,8 @@ function setButtonAttr(aID, aAttr, aValue)
 }
 
 
-// Enables / disables aID as well as optional aID+"Label" element.
-function enableElemWithLabel(aID, aEnable)
+// Sets or removes aAttr for aID as well as optional aID+"Label" element.
+function setBoolAttrForElemWithLabel(aID, aAttr, aValue)
 {
   if (!aID)
     return;
@@ -785,24 +731,31 @@ function enableElemWithLabel(aID, aEnable)
   if (elem)
   {
     var label = document.getElementById(aID + "Label");
-    if (aEnable)
+    if (aValue)
     {
       if (label)
-        label.removeAttribute("disabled");
+        label.setAttribute(aAttr, true);
 
-      elem.removeAttribute("disabled");
+      elem.setAttribute(aAttr, true);
     }
     else
     {
       if (label)
-        label.setAttribute("disabled", true);
+        label.removeAttribute(aAttr);
 
-      elem.setAttribute("disabled", true);
+      elem.removeAttribute(aAttr);
     }
   }
 }
 
 
+// Enables / disables aID as well as optional aID+"Label" element.
+function enableElemWithLabel(aID, aEnable)
+{
+  setBoolAttrForElemWithLabel(aID, "disabled", !aEnable);
+}
+
+
 // Removes placeholder text when disabled.
 function enableTextBox(aID, aEnable)
 {
@@ -825,6 +778,19 @@ function enableTextBox(aID, aEnable)
 }
 
 
+function showMenuListPlaceholderText(aElemID)
+{
+  let menu = document.getElementById(aElemID);
+  if (menu)
+  {
+    menu.selectedItem = undefined;
+    let placeholder = menu.getAttribute("placeholder");
+    if (placeholder)
+      menu.setAttribute("label", placeholder);
+  }
+}
+
+
 function overrideButtonLabel(aID, aLabelKey)
 {
   var btn = document.documentElement.getButton(aID);
@@ -889,8 +855,11 @@ function onRestartTor()
   addObserver(kTorProcessDidNotStartTopic);
   addObserver(kTorProcessExitedTopic);
 
-  gTorProcessService._startTor();
-  gTorProcessService._controlTor();
+  // Start tor with networking disabled so that the user has a chance to
+  // make configuration changes before bootstrapping begins.
+  gIsPostRestartBootstrapNeeded = true;
+  showStartingTorPanel();
+  gTorProcessService.TorStartAndControlTor(true);
 }
 
 
@@ -898,10 +867,6 @@ function onWizardReconfig()
 {
   showPanel(kWizardFirstPageID);
   onWizardConfigure();
-  // Because a similar delayed call is used to hide the buttons when the
-  // first wizard page is displayed, we use setTimeout() here to ensure
-  // that the navigation buttons are visible.
-  window.setTimeout(function() { showWizardNavButtons(true); }, 0);
 }
 
 
@@ -913,15 +878,37 @@ function onCancel()
     return false;
   }
 
-  if (gHasQuitButton) try
+  // If this is a wizard (initial config or locale picker), the cancel
+  // button is "Quit"
+  if (getWizard())
   {
-    gObsService.notifyObservers(null, "TorUserRequestedQuit", null);
-  } catch (e) {}
+    try
+    {
+      gObsService.notifyObservers(null, "TorUserRequestedQuit", null);
+    } catch (e) {}
+  }
+  else if (gIsPostRestartBootstrapNeeded)
+  {
+    useSettings();
+    return false;
+  }
 
   return true;
 }
 
 
+function onNetworkSettingsFinish()
+{
+  if (gRestoreAfterHelpPanelID) // Is help open?
+  {
+    closeHelp();
+    return false;
+  }
+
+  return applySettings(false);
+}
+
+
 function onCopyLog()
 {
   // Copy tor log messages to the system clipboard.
@@ -931,14 +918,13 @@ function onCopyLog()
   chSvc.copyString(gProtocolSvc.TorGetLog(countObj));
 
   // Display a feedback popup that fades away after a few seconds.
-  let forAssistance = document.getElementById("forAssistance");
+  let copyLogBtn = document.documentElement.getButton("extra2");
   let panel = document.getElementById("copyLogFeedbackPanel");
-  if (forAssistance && panel)
+  if (copyLogBtn && panel)
   {
     panel.firstChild.textContent = TorLauncherUtil.getFormattedLocalizedString(
                                      "copiedNLogMessages", [countObj.value], 1);
-    let rectObj = forAssistance.getBoundingClientRect();
-    panel.openPopup(null, null, rectObj.left, rectObj.top, false, false);
+    panel.openPopup(copyLogBtn, "before_start", 0, 0, false, false);
   }
 }
 
@@ -951,7 +937,7 @@ function closeCopyLogFeedbackPanel()
 }
 
 
-function onOpenHelp()
+function onOpenHelp(aHelpContentID)
 {
   if (gRestoreAfterHelpPanelID) // Already open?
     return;
@@ -962,7 +948,11 @@ function onOpenHelp()
   else
     gRestoreAfterHelpPanelID = getWizard().currentPage.pageid;
 
-  showPanel("bridgeHelp");
+  let contentElem = document.getElementById(aHelpContentID);
+  if (contentElem)
+    contentElem.removeAttribute("hidden");
+
+  showPanel("helpPanel");
 
   showOrHideButton("extra2", false, false); // Hide "Copy Tor Log To Clipboard"
 
@@ -971,6 +961,7 @@ function onOpenHelp()
     showOrHideButton("cancel", false, false);
     showOrHideButton("back", false, false);
     overrideButtonLabel("next", "done");
+    showOrHideButton("next", true, false);
     var forAssistance = document.getElementById("forAssistance");
     if (forAssistance)
       forAssistance.setAttribute("hidden", true);
@@ -989,30 +980,41 @@ function closeHelp()
 
   restoreCopyLogVisibility();
 
-  if (getWizard())
+  let helpPanel;
+  let wizardElem = getWizard();
+  if (wizardElem)
   {
     showOrHideButton("cancel", true, false);
     showOrHideButton("back", true, false);
+    showOrHideButton("next", false, false);
     restoreButtonLabel("next");
     var forAssistance = document.getElementById("forAssistance");
     if (forAssistance)
       forAssistance.removeAttribute("hidden");
+    helpPanel = wizardElem.currentPage;
   }
   else
   {
     restoreButtonLabel("cancel");
+    helpPanel = document.getElementById("helpPanel");
   }
 
   showPanel(gRestoreAfterHelpPanelID);
   gRestoreAfterHelpPanelID = null;
+
+  for (let childElem = helpPanel.firstChild; childElem;
+       childElem = childElem.nextSibling)
+  {
+    childElem.setAttribute("hidden", true);
+  }
 }
 
 
 // Returns true if successful.
 function initProxySettings()
 {
-  var proxyType, proxyAddrPort, proxyUsername, proxyPassword;
-  var reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null);
+  let proxyType, proxyAddrPort, proxyUsername, proxyPassword;
+  let reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null);
   if (!gProtocolSvc.TorCommandSucceeded(reply))
     return false;
 
@@ -1023,7 +1025,7 @@ function initProxySettings()
   }
   else
   {
-    var reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null);
+    reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null);
     if (!gProtocolSvc.TorCommandSucceeded(reply))
       return false;
 
@@ -1031,14 +1033,12 @@ function initProxySettings()
     {
       proxyType = "SOCKS5";
       proxyAddrPort = reply.retVal;
-      var reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername,
-                                             null);
+      reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername, null);
       if (!gProtocolSvc.TorCommandSucceeded(reply))
         return false;
 
       proxyUsername = reply.retVal;
-      var reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword,
-                                             null);
+      reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword, null);
       if (!gProtocolSvc.TorCommandSucceeded(reply))
         return false;
 
@@ -1046,7 +1046,7 @@ function initProxySettings()
     }
     else
     {
-      var reply = gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null);
+      reply = gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null);
       if (!gProtocolSvc.TorCommandSucceeded(reply))
         return false;
 
@@ -1054,28 +1054,30 @@ function initProxySettings()
       {
         proxyType = "HTTP";
         proxyAddrPort = reply.retVal;
-        var reply = gProtocolSvc.TorGetConfStr(
+        reply = gProtocolSvc.TorGetConfStr(
                                    kTorConfKeyHTTPSProxyAuthenticator, null);
         if (!gProtocolSvc.TorCommandSucceeded(reply))
           return false;
 
-        var values = parseColonStr(reply.retVal);
+        let values = parseColonStr(reply.retVal);
         proxyUsername = values[0];
         proxyPassword = values[1];
       }
     }
   }
 
-  var haveProxy = (proxyType != undefined);
-  setYesNoRadioValue(kWizardProxyRadioGroup, haveProxy);
+  let haveProxy = (proxyType != undefined);
   setElemValue(kUseProxyCheckbox, haveProxy);
   setElemValue(kProxyTypeMenulist, proxyType);
+  if (!proxyType)
+    showMenuListPlaceholderText(kProxyTypeMenulist);
+
   onProxyTypeChange();
 
-  var proxyAddr, proxyPort;
+  let proxyAddr, proxyPort;
   if (proxyAddrPort)
   {
-    var values = parseColonStr(proxyAddrPort);
+    let values = parseColonStr(proxyAddrPort);
     proxyAddr = values[0];
     proxyPort = values[1];
   }
@@ -1128,24 +1130,26 @@ function initFirewallSettings()
 // Returns true if successful.
 function initBridgeSettings()
 {
-  var typeList = TorLauncherUtil.defaultBridgeTypes;
-  var canUseDefaultBridges = (typeList && (typeList.length > 0));
-  var defaultType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType);
-  var useDefault = canUseDefaultBridges && !!defaultType;
+  let typeList = TorLauncherUtil.defaultBridgeTypes;
+  let canUseDefaultBridges = (typeList && (typeList.length > 0));
+  let defaultType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType);
+  let useDefault = canUseDefaultBridges && !!defaultType;
 
   // If not configured to use a default set of bridges, get UseBridges setting
   // from tor.
-  var useBridges = useDefault;
+  let useBridges = useDefault;
   if (!useDefault)
   {
-    var reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
+    showMenuListPlaceholderText(kDefaultBridgeTypeMenuList);
+
+    let reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
     if (!gProtocolSvc.TorCommandSucceeded(reply))
       return false;
 
     useBridges = reply.retVal;
 
     // Get bridge list from tor.
-    var bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
+    let bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
     if (!gProtocolSvc.TorCommandSucceeded(bridgeReply))
       return false;
 
@@ -1159,21 +1163,16 @@ function initBridgeSettings()
   }
 
   setElemValue(kUseBridgesCheckbox, useBridges);
-  setYesNoRadioValue(kWizardUseBridgesRadioGroup, useBridges);
 
   if (!canUseDefaultBridges)
   {
-    var label = document.getElementById("bridgeSettingsPrompt");
-    if (label)
-      label.setAttribute("hidden", true);
-
     var radioGroup = document.getElementById("bridgeTypeRadioGroup");
     if (radioGroup)
       radioGroup.setAttribute("hidden", true);
   }
 
-  var radioID = (useDefault) ? "bridgeRadioDefault" : "bridgeRadioCustom";
-  var radio = document.getElementById(radioID);
+  let radioID = (useDefault) ? "bridgeRadioDefault" : "bridgeRadioCustom";
+  let radio = document.getElementById(radioID);
   if (radio)
     radio.control.selectedItem = radio;
   onBridgeTypeRadioChange();
@@ -1213,6 +1212,8 @@ function useSettings()
   if (!didApply)
     return;
 
+  gIsPostRestartBootstrapNeeded = false;
+
   gProtocolSvc.TorSendCommand("SAVECONF");
   gTorProcessService.TorClearBootstrapError();
 
@@ -1272,7 +1273,7 @@ function applyProxySettings(aUseDefaults)
   if (!settings)
     return false;
 
-  return setConfAndReportErrors(settings, "proxyYES");
+  return setConfAndReportErrors(settings, "configureSettings");
 }
 
 
@@ -1344,8 +1345,7 @@ function getAndValidateProxySettings()
 
 function isProxyConfigured()
 {
-  return (getWizard()) ? getYesNoRadioValue(kWizardProxyRadioGroup)
-                       : getElemValue(kUseProxyCheckbox, false);
+  return getElemValue(kUseProxyCheckbox, false);
 }
 
 
@@ -1451,34 +1451,44 @@ function constructFirewallSettings(aAllowedPorts)
 
 function initDefaultBridgeTypeMenu()
 {
-  var menu = document.getElementById(kDefaultBridgeTypeMenuList);
+  let menu = document.getElementById(kDefaultBridgeTypeMenuList);
   if (!menu)
     return;
 
   menu.removeAllItems();
 
-  var typeArray = TorLauncherUtil.defaultBridgeTypes;
+  let typeArray = TorLauncherUtil.defaultBridgeTypes;
   if (!typeArray || typeArray.length == 0)
     return;
 
-  var recommendedType = TorLauncherUtil.getCharPref(
+  // Move the recommended type to the top of the list.
+  let recommendedType = TorLauncherUtil.getCharPref(
                                       kPrefDefaultBridgeRecommendedType, null);
-  var selectedType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType, null);
-  if (!selectedType)
-    selectedType = recommendedType;
-
-  for (var i=0; i < typeArray.length; i++)
+  if (recommendedType)
   {
-    var bridgeType = typeArray[i];
-
-    var menuItemLabel = bridgeType;
-    if (bridgeType == recommendedType)
+    for (let i = 0; i < typeArray.length; i++)
     {
-      const key = "recommended_bridge";
-      menuItemLabel += " " + TorLauncherUtil.getLocalizedString(key);
+      if (typeArray[i] == recommendedType)
+      {
+        typeArray.splice(i, 1);             // remove
+        typeArray.unshift(recommendedType); // add to the beginning
+        break;
+      }
     }
+  }
+
+  // Build the popup menu.
+  let selectedType = TorLauncherUtil.getCharPref(kPrefDefaultBridgeType, null);
+  for (let i = 0; i < typeArray.length; i++)
+  {
+    let bridgeType = typeArray[i];
+    let menuItemLabel = bridgeType;
+    let key = "bridge_suffix." + bridgeType;
+    let suffix = TorLauncherUtil.getLocalizedString(key);
+    if (suffix != key)
+      menuItemLabel += " " + suffix;
 
-    var mi = menu.appendItem(menuItemLabel, bridgeType);
+    let mi = menu.appendItem(menuItemLabel, bridgeType);
     if (bridgeType == selectedType)
       menu.selectedItem = mi;
   }
@@ -1496,7 +1506,7 @@ function applyBridgeSettings(aUseDefaults)
   if (aUseDefaults)
     TorLauncherUtil.setCharPref(kPrefDefaultBridgeType, "");
 
-  return setConfAndReportErrors(settings, "bridgeSettings");
+  return setConfAndReportErrors(settings, "configureSettings");
 }
 
 
@@ -1561,8 +1571,7 @@ function getAndValidateBridgeSettings()
 
 function isBridgeConfigured()
 {
-  return (getWizard()) ? getElemValue("bridgesRadioYes", false)
-                       : getElemValue(kUseBridgesCheckbox, false);
+  return getElemValue(kUseBridgesCheckbox, false);
 }
 
 
@@ -1715,34 +1724,20 @@ function getElemValue(aID, aDefaultValue)
 }
 
 
-// This assumes that first radio button is yes.
-function setYesNoRadioValue(aGroupID, aIsYes)
-{
-  var elem = document.getElementById(aGroupID);
-  if (elem)
-    elem.selectedIndex = (aIsYes) ? 0 : 1;
-}
-
-
-// This assumes that first radio button is yes.
-function getYesNoRadioValue(aGroupID)
-{
-  var elem = document.getElementById(aGroupID);
-  return (elem) ? (0 == elem.selectedIndex) : false;
-}
-
-
+// Hide and show groupbox based on aElem's checked state. aElem may be a
+// checkbox or radio element.
 function toggleElemUI(aElem)
 {
   if (!aElem)
     return;
 
-  var gbID = aElem.getAttribute("groupboxID");
+  let gbID = aElem.getAttribute("groupboxID");
   if (gbID)
   {
-    var gb = document.getElementById(gbID);
+    let isOn = getElemValue(aElem.id, false);
+    let gb = document.getElementById(gbID);
     if (gb)
-      gb.hidden = !aElem.checked;
+      gb.hidden = !isOn;
   }
 }
 
diff --git a/src/chrome/content/network-settings.xul b/src/chrome/content/network-settings.xul
index 727e7f6..e6d3531 100644
--- a/src/chrome/content/network-settings.xul
+++ b/src/chrome/content/network-settings.xul
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
-   - Copyright (c) 2015, The Tor Project, Inc.
+   - Copyright (c) 2017, The Tor Project, Inc.
    - See LICENSE for licensing information.
    - vim: set sw=2 sts=2 ts=8 et syntax=xml:
   -->
@@ -18,12 +18,11 @@
         title="&torsettings.dialog.title;"
         windowtype="TorLauncher:NetworkSettings"
         persist="screenX screenY"
-        buttons="accept,cancel,extra2,help"
+        buttons="accept,cancel,extra2"
         buttonlabelextra2="&torsettings.copyLog;"
-        ondialogaccept="return applySettings(false);"
+        ondialogaccept="return onNetworkSettingsFinish();"
         ondialogcancel="return onCancel();"
         ondialogextra2="onCopyLog();"
-        ondialoghelp="onOpenHelp();"
         onload="initDialog();"
         onunload="deinitDialog();">
 
@@ -32,20 +31,9 @@
 
   <deck id="deck">
     <vbox id="settings">
-      <vbox>
-        <checkbox id="useBridges" groupboxID="bridgeSpecificSettings"
-                  label="&torsettings.useBridges.checkbox;"
-                  oncommand="toggleElemUI(this);" />
-        <groupbox id="bridgeSpecificSettings" />
-      </vbox>
-
-      <vbox>
-        <separator orient="horizontal" class="thin" />
-        <checkbox id="useProxy" groupboxID="proxySpecificSettings"
-                  label="&torsettings.useProxy.checkbox;"
-                  oncommand="toggleElemUI(this)"/>
-        <groupbox id="proxySpecificSettings" />
-      </vbox>
+      <vbox id="bridgeSettings"/>
+      <separator orient="horizontal" class="thin"/>
+      <vbox id="proxySettings"/>
 
       <vbox>
         <checkbox id="useFirewallPorts" groupboxID="firewallSpecificSettings"
@@ -79,8 +67,9 @@
       </hbox>
       <spring flex="1" />
     </vbox>
-    <vbox id="bridgeHelp" class="help">
-      <vbox id="bridgeHelpContent" />
+    <vbox id="helpPanel" class="help">
+      <vbox id="bridgeHelpContent" hidden="true"/>
+      <vbox id="proxyHelpContent" hidden="true"/>
     </vbox>
   </deck>
   <spring flex="1" />
diff --git a/src/chrome/locale/en/network-settings.dtd b/src/chrome/locale/en/network-settings.dtd
index 0d2e9dc..dc666dd 100644
--- a/src/chrome/locale/en/network-settings.dtd
+++ b/src/chrome/locale/en/network-settings.dtd
@@ -1,4 +1,7 @@
 <!ENTITY torsettings.dialog.title "Tor Network Settings">
+<!ENTITY torsettings.wizard.title.default "Connect to Tor">
+<!ENTITY torsettings.wizard.title.configure "Tor Network Settings">
+<!ENTITY torsettings.wizard.title.connecting "Establishing a Connection">
 
 <!-- For locale picker: -->
 <!ENTITY torlauncher.localePicker.title "Tor Browser Language">
@@ -6,31 +9,11 @@
 
 <!-- For "first run" wizard: -->
 
-<!ENTITY torsettings.prompt "Before you connect to the Tor network, you need to provide information about this computer's Internet connection.">
-
-<!ENTITY torSettings.yes "Yes">
-<!ENTITY torSettings.no "No">
-
-<!ENTITY torSettings.firstQuestion "Which of the following best describes your situation?">
-<!ENTITY torSettings.configurePrompt1 "This computer's Internet connection is censored or proxied.">
-<!ENTITY torSettings.configurePrompt2 "I need to configure bridge or local proxy settings before I connect to the Tor network.">
+<!ENTITY torSettings.connectPrompt "Click “Connect” to connect to Tor.">
+<!ENTITY torSettings.configurePrompt "Click “Configure” to adjust network settings if you are in a country that censors Tor (such as China, Iran, Syria) or if you are connecting from a private network that requires a proxy.">
 <!ENTITY torSettings.configure "Configure">
-<!ENTITY torSettings.connectPrompt2 "I would like to make a direct connection to the Tor network.">
-<!ENTITY torSettings.connectPrompt3 "This will work in most situations.">
 <!ENTITY torSettings.connect "Connect">
 
-<!ENTITY torSettings.proxyPageTitle "Local Proxy Configuration">
-<!ENTITY torSettings.proxyQuestion "Does this computer need to use a local proxy to access the Internet?">
-<!-- see https://www.torproject.org/docs/proxychain.html.en -->
-<!ENTITY torSettings.proxyExplanation1 "In most cases a local proxy is not needed, but it may be required when connecting through a company, school, or university network.">
-<!ENTITY torSettings.proxyExplanation2 "If you are not sure how to answer this question, look at the Internet settings in another browser or check your system's network settings to see whether a local proxy is needed.">
-<!ENTITY torSettings.enterProxy "Enter the proxy settings.">
-<!ENTITY torSettings.bridgePageTitle "Tor Bridges Configuration">
-<!ENTITY torSettings.bridgeQuestion "Does your Internet Service Provider (ISP) block or otherwise censor connections to the Tor Network?">
-<!ENTITY torSettings.bridgeExplanation1 "If you are not sure how to answer this question, choose No (if you are unable to connect to the Tor network without a bridge, you can add one later).">
-<!ENTITY torSettings.bridgeExplanation2 "If you choose Yes, you will be asked to configure Tor Bridges, which are unlisted relays that make it more difficult to block connections to the Tor Network.">
-<!ENTITY torSettings.bridgeSettingsPrompt "You may use the provided set of bridges or you may obtain and enter a custom set of bridges.">
-
 <!-- Other: -->
 
 <!ENTITY torsettings.startingTor "Waiting for Tor to start…">
@@ -42,8 +25,9 @@
 
 <!ENTITY torsettings.optional "Optional">
 
-<!ENTITY torsettings.useProxy.checkbox "This computer needs to use a local proxy to access the Internet">
+<!ENTITY torsettings.useProxy.checkbox "I use a proxy to connect to the Internet">
 <!ENTITY torsettings.useProxy.type "Proxy Type:">
+<!ENTITY torsettings.useProxy.type.placeholder "select a proxy type">
 <!ENTITY torsettings.useProxy.address "Address:">
 <!ENTITY torsettings.useProxy.address.placeholder "IP address or hostname">
 <!ENTITY torsettings.useProxy.port "Port:">
@@ -54,22 +38,18 @@
 <!ENTITY torsettings.useProxy.type.http "HTTP / HTTPS">
 <!ENTITY torsettings.firewall.checkbox "This computer goes through a firewall that only allows connections to certain ports">
 <!ENTITY torsettings.firewall.allowedPorts "Allowed Ports:">
-<!ENTITY torsettings.useBridges.checkbox "My Internet Service Provider (ISP) blocks connections to the Tor network">
-<!ENTITY torsettings.useBridges.default "Connect with provided bridges">
-<!ENTITY torsettings.useBridges.note "Each type of bridge uses a different method to avoid censorship.  If one bridge does not work, try again using a different one.">
-<!ENTITY torsettings.useBridges.type "Transport type:">
-<!ENTITY torsettings.useBridges.custom "Enter custom bridges">
-<!ENTITY torsettings.useBridges.label "Enter one or more bridge relays (one per line).">
-<!ENTITY torsettings.useBridges.placeholder "type address:port">
+<!ENTITY torsettings.useBridges.checkbox "Tor is censored in my country">
+<!ENTITY torsettings.useBridges.default "Select a built-in bridge">
+<!ENTITY torsettings.useBridges.default.placeholder "select a bridge">
+<!ENTITY torsettings.useBridges.custom "Provide a bridge I know">
+<!ENTITY torsettings.useBridges.label "Enter bridge information from a trusted source.">
+<!ENTITY torsettings.useBridges.placeholder "type address:port (one per line)">
 
 <!ENTITY torsettings.copyLog "Copy Tor Log To Clipboard">
+
+<!ENTITY torsettings.proxyHelpTitle "Proxy Help">
+<!ENTITY torsettings.proxyHelp1 "A local proxy is needed when connecting through a company, school, or university network. If you are not sure how to answer this question, look at the Internet settings in another browser or check your system's network settings to see whether a proxy is needed.">
+
 <!ENTITY torsettings.bridgeHelpTitle "Bridge Relay Help">
-<!ENTITY torsettings.bridgeHelp1 "If you are unable to connect to the Tor network, it could be that your Internet Service Provider (ISP) or another agency is blocking Tor.  Often, you can work around this problem by using Tor Bridges, which are unlisted relays that are more difficult to block.">
-<!ENTITY torsettings.bridgeHelp1B "You may use the preconfigured, provided set of bridge addresses or you may obtain a custom set of addresses by using one of these methods:">
-<!ENTITY torsettings.bridgeHelp2Heading "Through the Web">
-<!ENTITY torsettings.bridgeHelp2 "Use a web browser to visit https://bridges.torproject.org">
-<!ENTITY torsettings.bridgeHelp3Heading "Through the Email Autoresponder">
-<!ENTITY torsettings.bridgeHelp3.emailDesc "Send email to bridges at torproject.org with the line 'get bridges' by itself in the body of the message.  However, to make it harder for an attacker to learn a lot of bridge addresses, you must send this request from one of the following email providers (listed in order of preference):">
-<!ENTITY torsettings.bridgeHelp3.emailList "https://www.riseup.net, https://mail.google.com, or https://mail.yahoo.com">
-<!ENTITY torsettings.bridgeHelp4Heading "Through the Help Desk">
-<!ENTITY torsettings.bridgeHelp4 "As a last resort, you can request bridge addresses by sending a polite email message to help at rt.torproject.org.  Please note that a person will need to respond to each request.">
+<!ENTITY torsettings.bridgeHelp1 "Bridges are unlisted relays that make it more difficult to block connections to the Tor Network.  Each type of bridge uses a different method to avoid censorship.  The obfs ones make your traffic look like random noise, and the meek ones make your traffic look like it's connecting to that service instead of Tor.">
+<!ENTITY torsettings.bridgeHelp2 "Because of how certain countries try to block Tor, certain bridges work in certain countries but not others.  If you are unsure about which bridges work in your country, visit torproject.org/about/contact.html#support">
diff --git a/src/chrome/locale/en/torlauncher.properties b/src/chrome/locale/en/torlauncher.properties
index 24bb4d6..b09753e 100644
--- a/src/chrome/locale/en/torlauncher.properties
+++ b/src/chrome/locale/en/torlauncher.properties
@@ -28,7 +28,8 @@ torlauncher.error_bridges_missing=You must specify one or more bridges.
 torlauncher.error_default_bridges_type_missing=You must select a transport type for the provided bridges.
 torlauncher.error_bridge_bad_default_type=No provided bridges that have the transport type %S are available. Please adjust your settings.
 
-torlauncher.recommended_bridge=(recommended)
+torlauncher.bridge_suffix.meek-amazon=(works in China)
+torlauncher.bridge_suffix.meek-azure=(works in China)
 
 torlauncher.connect=Connect
 torlauncher.restart_tor=Restart Tor
diff --git a/src/chrome/skin/network-settings.css b/src/chrome/skin/network-settings.css
index 20d3528..3b6faba 100644
--- a/src/chrome/skin/network-settings.css
+++ b/src/chrome/skin/network-settings.css
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Tor Project, Inc.
+ * Copyright (c) 2017, The Tor Project, Inc.
  * See LICENSE for licensing information.
  *
  * vim: set sw=2 sts=2 ts=8 et syntax=css:
@@ -18,14 +18,14 @@ dialog.os-windows {
 
 wizard {
   width: 45em;
-  height: 35em;
+  height: 36em;
   font: -moz-dialog;
   padding-top: 0px;
 }
 
 wizard.os-windows {
   width: 49em;
-  height: 41em;
+  height: 42em;
 }
 
 .wizard-page-box {
@@ -57,9 +57,14 @@ wizard radiogroup {
   margin-bottom: 0px;
 }
 
+.firstResponses label {
+  text-align: center;
+  margin-top: 1.2em;
+}
+
 .firstResponses button {
   min-width: 85px;
-  margin-top: 9px;
+  margin: 9px 40px;
 }
 
 separator.tall {
@@ -71,31 +76,17 @@ separator.tall {
   font-weight: bold;
 }
 
-.questionHelp {
-  margin: 0px 0px 12px 20px;
-}
-
-.instructions {
-  margin-bottom: 8px;
-}
-
 button.firstAnswer {
   margin-top: 0px;
 }
 
-.tbb-logo-box {
-  height: 80px;
-}
-
 .tbb-logo {
-  list-style-image: url("chrome://torlauncher/skin/tbb-logo.png");
-  width: 115px;
-  height: 80px;
-  margin-right: 20px;
+  list-style-image: url("chrome://torlauncher/skin/tbb-logo.svg");
+  width: 40em;
+  height: 60px;
 }
 
-wizard[tor_hide_browser_logo="true"] .tbb-logo,
-wizard[tor_hide_browser_logo="true"] .tbb-logo-separator {
+wizard[tor_hide_browser_logo="true"] .tbb-logo {
   display: none;
 }
 
@@ -104,9 +95,12 @@ wizard#TorLauncherLocalePicker button[dlgtype="next"] {
   display: none;
 }
 
-.tbb-wizardpage-title {
-  font-size: 115%;
-  font-weight: bold;
+/* Show menulist placeholder text in gray. */
+#defaultBridgeType:not([value]) .menulist-label,
+#defaultBridgeType[value=""] .menulist-label,
+#proxyType:not([value]) .menulist-label,
+#proxyType[value=""] .menulist-label {
+  color: #777;
 }
 
 #bridgeNote,
@@ -120,6 +114,49 @@ wizard.os-mac #bridgeList {
   font-size: 90%;
 }
 
+/* reuse Mozilla's help button from the Firefox hamburger menu */
+.helpButton {
+  list-style-image: url(chrome://browser/skin/menuPanel-help.png);
+  -moz-image-region: rect(0, 16px, 16px, 0);
+  -moz-appearance: none;
+  height: 16px;
+  width: 16px;
+  min-height: 16px;
+  min-width: 16px;
+  margin: 0;
+  border: none;
+  box-shadow: none;
+}
+
+.helpButton .button-box {
+  padding: 0;
+  margin: 0;
+  border: none;
+}
+
+.helpButton:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.helpButton:hover:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+ at media (min-resolution: 8.1dppx) {
+  .helpButton {
+    list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
+    -moz-image-region: rect(0, 32px, 32px, 0);
+  }
+
+  .helpButton:hover {
+    -moz-image-region: rect(0, 64px, 32px, 32px);
+  }
+
+  .helpButton:hover:active {
+    -moz-image-region: rect(0, 96px, 32px, 64px);
+  }
+}
+
 wizardpage[pageid="startingTor"] description,
 wizardpage[pageid="errorPanel"] description,
 #errorPanel description,
diff --git a/src/chrome/skin/tbb-logo.png b/src/chrome/skin/tbb-logo.png
deleted file mode 100644
index 5499203..0000000
Binary files a/src/chrome/skin/tbb-logo.png and /dev/null differ
diff --git a/src/chrome/skin/tbb-logo.svg b/src/chrome/skin/tbb-logo.svg
new file mode 100644
index 0000000..26cd158
--- /dev/null
+++ b/src/chrome/skin/tbb-logo.svg
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 328.6 66.3" enable-background="new 0 0 328.6 66.3" xml:space="preserve">
+<g>
+	<g>
+		<g>
+			<path fill="#68B044" d="M138.8,28.3h11.9c7.6,0,13.3,2.3,13.3,9.2c0,3.5-2,7-6.4,8.1v0.2c5.4,0.9,8.4,3.8,8.4,8.8
+				c0,7.5-6.1,10.9-14.3,10.9h-12.9V28.3z M150.1,43.7c5.2,0,7.4-2,7.4-5.5c0-3.4-2.4-4.8-7.2-4.8h-4.8v10.3H150.1z M151,60.4
+				c5.5,0,8.5-2.1,8.5-6.3c0-3.9-3-5.7-8.5-5.7h-5.6v12H151z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M170.7,37.6h5.4l0.5,5h0.2c2-3.6,5-5.6,7.9-5.6c1.4,0,2.3,0.2,3.2,0.6l-1.1,5.7c-1-0.3-1.7-0.5-2.9-0.5
+				c-2.2,0-4.9,1.5-6.6,5.8v17.1h-6.6V37.6z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M201.4,36.9c7,0,13.3,5.4,13.3,14.7c0,9.3-6.3,14.7-13.3,14.7c-7,0-13.3-5.4-13.3-14.7
+				C188.1,42.2,194.5,36.9,201.4,36.9z M201.4,60.9c4.1,0,6.6-3.7,6.6-9.3c0-5.6-2.5-9.4-6.6-9.4s-6.6,3.7-6.6,9.4
+				C194.9,57.2,197.3,60.9,201.4,60.9z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M216.7,37.6h6.6l3.4,14.5c0.6,2.7,1,5.3,1.5,8h0.2c0.5-2.7,1.1-5.4,1.8-8l3.6-14.5h6l3.7,14.5
+				c0.7,2.7,1.3,5.3,1.9,8h0.2c0.5-2.7,1-5.4,1.5-8l3.4-14.5h6.2l-7.1,28h-7.8l-3.3-13.1c-0.6-2.6-1.1-5.2-1.7-8.2h-0.2
+				c-0.5,3-1,5.6-1.7,8.2l-3.2,13h-7.5L216.7,37.6z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M261,58.2c2.5,1.9,4.9,3.1,7.8,3.1c3,0,4.4-1.4,4.4-3.4c0-2.3-3-3.4-6-4.5c-3.7-1.4-7.9-3.5-7.9-8.2
+				c0-4.9,3.9-8.4,10.2-8.4c3.9,0,7,1.6,9.3,3.4l-3,4c-1.9-1.4-3.9-2.4-6.2-2.4c-2.8,0-4.1,1.3-4.1,3.1c0,2.2,2.8,3.1,5.8,4.2
+				c3.8,1.4,8,3.3,8,8.5c0,4.8-3.8,8.7-10.9,8.7c-3.8,0-7.9-1.7-10.6-3.9L261,58.2z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M294.9,36.9c7.6,0,11.6,5.5,11.6,13.3c0,1.3-0.1,2.4-0.3,3.1h-17.8c0.6,5.1,3.8,7.9,8.3,7.9
+				c2.4,0,4.4-0.7,6.5-2.1l2.2,4.1c-2.7,1.8-6,3-9.6,3c-7.8,0-13.8-5.4-13.8-14.7C282,42.5,288.4,36.9,294.9,36.9z M300.8,49.1
+				c0-4.4-1.9-7.1-5.7-7.1c-3.3,0-6.2,2.5-6.7,7.1H300.8z"/>
+		</g>
+		<g>
+			<path fill="#68B044" d="M311.4,37.6h5.4l0.5,5h0.2c2-3.6,5-5.6,7.9-5.6c1.4,0,2.3,0.2,3.2,0.6l-1.1,5.7c-1-0.3-1.7-0.5-2.9-0.5
+				c-2.2,0-4.9,1.5-6.6,5.8v17.1h-6.6V37.6z"/>
+		</g>
+	</g>
+	<g>
+		<g>
+			<rect x="120.4" y="6.2" fill="#494949" width="3" height="58"/>
+		</g>
+	</g>
+	<g>
+		<g>
+			<g id="layer3_17_" transform="translate(-92,-63.999774)">
+				<g id="layer5_17_">
+					<g id="path2554_28_">
+						<g>
+							<path fill="#68B044" d="M152.1,68.8l-1.7,6.8c2.4-4.8,6.3-8.4,10.7-11.6c-3.2,3.8-6.2,7.5-8,11.3c3.1-4.3,7.2-6.7,11.8-8.2
+								c-6.2,5.5-11,11.4-14.8,17.3l-3-1.3C147.7,78.3,149.5,73.5,152.1,68.8L152.1,68.8z"/>
+						</g>
+					</g>
+					<g id="path2534_7_">
+						<g>
+							<path fill="#F5F8DE" d="M144.2,81.8l5.6,2.3c0,1.4-0.1,5.8,0.8,7.1c9.4,12.1,7.8,36.2-1.9,36.8c-14.7,0-20.4-10-20.4-19.2
+								c0-8.4,10.1-14,16.1-18.9C146,88.6,145.7,85.6,144.2,81.8L144.2,81.8z"/>
+						</g>
+					</g>
+					<g id="path2536_18_">
+						<g>
+							<path fill="#7E4798" d="M149.9,84l2,1c-0.2,1.3,0.1,4.3,1.4,5.1c5.9,3.7,11.5,7.7,13.7,11.7c7.8,14.1-5.5,27.2-17,25.9
+								c6.2-4.6,8.1-14.1,5.7-24.5c-1-4.1-2.4-7.7-5.1-11.9C149.6,89.4,150,86.9,149.9,84L149.9,84z"/>
+						</g>
+					</g>
+				</g>
+				<g id="layer4_17_">
+					<g id="path2540_18_">
+						<g>
+							<path fill="#010101" d="M147.6,90.8c-0.4,2.2-0.9,6.2-2.8,7.6c-0.8,0.6-1.6,1.1-2.5,1.7c-3.4,2.3-6.9,4.5-8.4,10.2
+								c-0.3,1.2,0,2.5,0.2,3.7c0.9,3.4,3.3,7.2,5.2,9.3c0,0.1,0.4,0.3,0.4,0.4c1.6,1.9,2.1,2.4,8,3.7l-0.1,0.7
+								c-3.6-1-6.5-1.8-8.4-4c0,0-0.3-0.4-0.3-0.4c-2-2.3-4.4-6.1-5.3-9.7c-0.3-1.4-0.6-2.5-0.2-4c1.6-5.8,5.2-8.1,8.7-10.5
+								c0.8-0.5,1.8-1,2.5-1.6C146,96.8,146.8,93.5,147.6,90.8L147.6,90.8z"/>
+						</g>
+					</g>
+					<g id="path2542_18_">
+						<g>
+							<path fill="#010101" d="M149.1,99.9c0,2.5-0.2,3.7,0.4,5.5c0.4,1,1.7,2.5,2.1,3.9c0.5,1.9,1.1,3.9,1,5.2c0,1.4-0.1,4.1-0.7,7
+								c-0.5,2.4-1.6,4.4-3.4,5.5c-1.9-0.4-4.1-1-5.4-2.2c-2.5-2.2-4.8-5.9-5.1-9.1c-0.2-2.6,2.2-6.5,5.6-8.4
+								c2.9-1.7,3.5-3.6,4.1-6.6c-0.9,2.7-1.7,4.9-4.4,6.3c-4,2.1-6.1,5.6-5.9,9c0.3,4.3,2,7.2,5.4,9.5c1.4,1,4.1,2.1,5.8,2.3v-0.2
+								c1.3-0.2,2.9-2.3,3.7-5.1c0.7-2.5,1-5.8,0.9-7.8c0-1.2-0.6-3.8-1.5-6.1c-0.5-1.3-1.3-2.6-1.9-3.5
+								C149.4,104.2,149.4,102.2,149.1,99.9z"/>
+						</g>
+					</g>
+					<g id="path2544_18_">
+						<g>
+							<path fill="#010101" d="M148.7,109.7c0,1.7,0.7,3.8,1,6c0.2,1.6,0.1,3.3,0.1,4.7c0,1.7-0.6,4.6-1.4,6.1
+								c-0.7-0.3-1-0.7-1.5-1.3c-0.6-0.8-1-1.6-1.3-2.6c-0.3-0.7-0.6-1.5-0.8-2.5c-0.2-1.4-0.1-3.7,1.5-6c1.2-1.8,1.5-2,2-4
+								c-0.6,1.9-1,2-2.3,3.6c-1.5,1.7-1.7,4.2-1.7,6.3c0,0.9,0.3,1.8,0.7,2.7c0.4,1,0.7,1.9,1.2,2.6c0.8,1.2,1.8,1.8,2.3,1.9
+								c0,0,0,0,0,0c0,0,0,0,0,0v-0.1c0.9-1,1.5-2.1,1.7-3.1c0.2-1.2,0.3-2.5,0.4-4c0.1-1.2,0-2.9-0.3-4.6
+								C149.8,113.4,149,111.2,148.7,109.7L148.7,109.7z"/>
+						</g>
+					</g>
+					<g id="path2550_18_">
+						<g>
+							<path fill="#010101" d="M149,88.7c0,2.5,0.2,7.1,0.9,8.9c0.2,0.6,2,3.3,3.2,6.6c0.9,2.3,1,4.4,1.2,5
+								c0.6,2.7-0.1,7.3-1.1,11.6c-0.5,2.3-2.1,5.2-4,6.4l-0.4,0.7c1,0,3.6-2.6,4.5-5.7c1.5-5.3,2.1-7.8,1.4-13.7
+								c-0.1-0.6-0.3-2.5-1.2-4.6c-1.3-3.2-3.2-6.2-3.5-6.9C149.7,96,149.1,91.7,149,88.7L149,88.7z"/>
+						</g>
+					</g>
+					<g id="path2552_18_">
+						<g>
+							<path fill="#010101" d="M149.9,84.3c-0.1,2.5-0.2,4.6,0.3,6.4c0.5,2.1,3.2,5,4.3,8.4c2.1,6.5,1.6,15,0,21.6
+								c-0.6,2.3-3.3,5.7-6,6.8l2,0.5c1.1,0,3.9-2.7,5-5.7c1.8-4.7,2.1-10.3,1.4-16.3c0-0.6-1-5.7-1.9-7.8c-1.3-3.2-3.3-5.4-4.1-7.4
+								c-0.6-1.5-0.8-5.4-0.4-6.3L149.9,84.3z"/>
+						</g>
+					</g>
+				</g>
+			</g>
+			<g id="path2528_14_">
+				<g>
+					<path fill="#7E4798" d="M2.7,6.2H41c1.4,0,2.7,1.2,2.7,2.7v11.3c0,1.5-1.2,2.7-2.7,2.7h-7.9c-1.8,0-2.5,1-2.5,2.1v37
+						c0,1.2-1,2.2-2.2,2.2h-13c-1.2,0-2.1-1-2.1-2.2V24.7c0-1.1-1-1.8-1.9-1.8H2.7c-1.5,0-2.7-1.2-2.7-2.7V8.9
+						C0,7.4,1.2,6.2,2.7,6.2z"/>
+				</g>
+			</g>
+			<g id="path2532_14_">
+				<g>
+					<path fill="#7E4798" d="M100.9,21.2h3.4c1.2,0,2.2,1,2.2,2.2v12.1c0,1.6,0.1,2.2-1.8,2.2c-3.8,0-5.5,2-5.5,4.2v20.5
+						c0,1-0.9,1.8-2,1.8H85.1c-1.1,0-2-0.8-2-1.8V39.1c0-0.4,0-1,0-1.3c0.7-8.6,7.4-15.5,16-16.4C99.4,21.3,100.5,21.2,100.9,21.2
+						L100.9,21.2z"/>
+				</g>
+			</g>
+		</g>
+		<g>
+			<g>
+				<path fill="#010101" d="M72,32.8c-2.1-1.9-4.6-3.4-7.3-4.9c-1.2-0.7-4.9-3.5-3.6-7.6l-9.3-3.8l-0.6,0.5c3.1,5.6,1.5,8.5,0,9.6
+					c-3.1,2.1-7.6,4.8-9.9,7.2c-4.3,4.4-5.6,8.7-5.2,14.3c0.4,7.2,5.6,13.1,12.6,15.5c3.1,1,5.9,1.1,9,1.1c5.1,0,10.3-1.3,14-4.5
+					c4-3.3,6.4-8.3,6.4-13.5C78.1,41.2,75.9,36.3,72,32.8z M70.6,58.9c-3.4,2.9-9.7,4.8-13,4.7c-3.7-0.2-7.3-0.8-10.4-2.3
+					c-5.6-2.7-9.3-8.5-9.5-13.3c-0.5-9.7,4.1-12.5,8.4-16c2.4-2,5.8-3,7.7-6.5c0.4-0.8,0.6-2.5,0.1-4.2c-0.2-0.6-1.1-2.8-1.4-3.2
+					l7,3.1c-0.9,3.2,1.8,6.5,3.9,7.7c2.1,1.2,5.5,3.4,7.5,5.3c3.6,3.2,5.5,7.7,5.5,12.5C76.3,51.2,74.3,55.8,70.6,58.9z"/>
+			</g>
+		</g>
+	</g>
+</g>
+</svg>
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index ca38e9c..317dbd7 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -95,7 +95,7 @@ TorProcessService.prototype =
 
       if (TorLauncherUtil.shouldOnlyConfigureTor)
       {
-        this._controlTor();
+        this._controlTor(true, false);
       }
       else if (TorLauncherUtil.shouldStartAndOwnTor)
       {
@@ -111,8 +111,7 @@ TorProcessService.prototype =
           TorLauncherUtil.setIntPref(kTorrcFixupPref, kTorrcFixupVersion);
         }
 
-        this._startTor();
-        this._controlTor();
+        this.TorStartAndControlTor(false);
       }
     }
     else if ("quit-application-granted" == aTopic)
@@ -195,8 +194,7 @@ TorProcessService.prototype =
         if (TorLauncherUtil.showConfirm(null, s, defaultBtnLabel, cancelBtnLabel)
             && !this.mIsQuitting)
         {
-          this._startTor();
-          this._controlTor();
+          this.TorStartAndControlTor(false);
         }
       }
     }
@@ -301,6 +299,13 @@ TorProcessService.prototype =
     return this.mBootstrapErrorOccurred;
   },
 
+  TorStartAndControlTor: function(aForceDisableNetwork)
+  {
+    this._startTor(aForceDisableNetwork);
+    let isRunningTor = (this.mTorProcessStatus == this.kStatusStarting) ||
+                       (this.mTorProcessStatus == this.kStatusRunning);
+    this._controlTor(isRunningTor, aForceDisableNetwork);
+  },
 
   TorClearBootstrapError: function()
   {
@@ -328,7 +333,7 @@ TorProcessService.prototype =
 
 
   // Private Methods /////////////////////////////////////////////////////////
-  _startTor: function()
+  _startTor: function(aForceDisableNetwork)
   {
     this.mTorProcessStatus = this.kStatusUnknown;
 
@@ -457,7 +462,8 @@ TorProcessService.prototype =
         TorLauncherUtil.showAlert(null, err);
       }
 
-      if (TorLauncherUtil.shouldShowNetworkSettings || defaultBridgeType)
+      if (aForceDisableNetwork || TorLauncherUtil.shouldShowNetworkSettings ||
+          defaultBridgeType)
       {
         args.push("DisableNetwork");
         args.push("1");
@@ -511,7 +517,7 @@ TorProcessService.prototype =
     return "unix:" + this.mProtocolSvc.TorEscapeString(aIPCFile.path);
   },
 
-  _controlTor: function()
+  _controlTor: function(aIsRunningTor, aIsNetworkForceDisabled)
   {
     // Optionally prompt for locale.  Blocks until dialog is closed.
     if (TorLauncherUtil.shouldPromptForLocale)
@@ -526,7 +532,8 @@ TorProcessService.prototype =
 
     try
     {
-      this._monitorTorProcessStartup();
+      if (aIsRunningTor)
+        this._monitorTorProcessStartup();
 
       var bridgeConfigIsBad = (this._defaultBridgesStatus ==
                                this.kDefaultBridgesStatus_BadConfig);
@@ -535,14 +542,16 @@ TorProcessService.prototype =
         if (this.mProtocolSvc)
         {
           // Show network settings wizard.  Blocks until dialog is closed.
-          var panelID = (bridgeConfigIsBad) ? "bridgeSettings" : undefined;
+          var panelID = (bridgeConfigIsBad) ? "configureSettings" : undefined;
           this._openNetworkSettings(true, panelID);
         }
       }
       else if (this._networkSettingsWindow != null)
       {
-        // If network settings is open, open progress dialog via notification.
-        if (this.mObsSvc)
+        // The network settings window is open, which means the user asked
+        // for tor to be restarted. If networking is enabled, show the
+        // progress panel (since bootstrapping is underway).
+        if (!aIsNetworkForceDisabled && this.mObsSvc)
           this.mObsSvc.notifyObservers(null, "TorOpenProgressDialog", null);
       }
       else if (!this.TorIsBootstrapDone)





More information about the tbb-commits mailing list