Bug 1219725 - Add a button for session restore to the tab bar. r=jaws, r=Gijs, ui-r=shorlander draft
authorerica <ewright@mozilla.com>
Wed, 22 Jun 2016 12:58:26 -0400
changeset 394306 fb148017b2188b535c2d1bbe9cbee1461d90eec3
parent 393861 9ec789c0ee5bd3a5e765513c21027fdad953b022
child 526792 85d739dd5ff361f0893a658b58961bd2141115c6
push id24551
push userbmo:ewright@mozilla.com
push dateFri, 29 Jul 2016 15:22:55 +0000
reviewersjaws, Gijs, shorlander
bugs1219725
milestone50.0a1
Bug 1219725 - Add a button for session restore to the tab bar. r=jaws, r=Gijs, ui-r=shorlander MozReview-Commit-ID: F5fVFSzi6xc
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/base/content/test/tabbrowser/browser.ini
browser/base/content/test/tabbrowser/browser_tabbar_sessionrestore_button.js
browser/base/moz.build
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/shared/tabs.inc.css
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -134,16 +134,21 @@ tabbrowser {
 #tabbrowser-tabs:not([overflow="true"]) ~ #alltabs-button,
 #tabbrowser-tabs:not([overflow="true"]) + #new-tab-button,
 #tabbrowser-tabs[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
 #TabsToolbar[currentset]:not([currentset*="tabbrowser-tabs,new-tab-button"]) > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
 #TabsToolbar[customizing="true"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
   visibility: collapse;
 }
 
+/*#TabsToolbar[currentset*="tabbrowser-tabs,alltabs-button,new-tab-button"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
+#TabsToolbar[currentset*="tabbrowser-tabs,new-tab-button,alltabs-button"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
+  visibility: visible;
+}*/
+
 #tabbrowser-tabs:not([overflow="true"])[using-closing-tabs-spacer] ~ #alltabs-button {
   visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
 }
 
 .tabbrowser-tab {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7556,26 +7556,47 @@ function switchToTabHavingURI(aURI, aOpe
 
   return false;
 }
 
 var RestoreLastSessionObserver = {
   init: function () {
     if (SessionStore.canRestoreLastSession &&
         !PrivateBrowsingUtils.isWindowPrivate(window)) {
+      let restoreTabsButtonWrapper = document.getAnonymousElementByAttribute(gBrowser.tabContainer, "anonid", "restore-tabs-button-wrapper");
+      restoreTabsButtonWrapper.setAttribute("session-exists", "true");
+      gBrowser.tabContainer.updateSessionRestoreVisibility();
+
+      //once, remove the styling that hides the button after it has been measured, from now on we use hidden attr
+      restoreTabsButtonWrapper.style.position = "initial";
+      restoreTabsButtonWrapper.style.visibility = "visible";
+
+      gBrowser.tabContainer.addEventListener("TabOpen", this.fadeRestoreTabsButton.bind(this), false);
       Services.obs.addObserver(this, "sessionstore-last-session-cleared", true);
       goSetCommandEnabled("Browser:RestoreLastSession", true);
     }
   },
-
+  removeRestoreTabsButton: function () {
+    let restoreTabsButtonWrapper = document.getAnonymousElementByAttribute(gBrowser.tabContainer, "anonid", "restore-tabs-button-wrapper");
+    restoreTabsButtonWrapper.removeEventListener("transitionend", this.removeRestoreTabsButton, false);
+    restoreTabsButtonWrapper.hidden = true;
+  },
+  fadeRestoreTabsButton: function () {
+    let restoreTabsButtonWrapper = document.getAnonymousElementByAttribute(gBrowser.tabContainer, "anonid", "restore-tabs-button-wrapper");
+    gBrowser.tabContainer.removeEventListener("TabOpen", this.fadeRestoreTabsButton, false);
+    restoreTabsButtonWrapper.addEventListener("transitionend", this.removeRestoreTabsButton, false);
+    restoreTabsButtonWrapper.classList.add("restore-fade-out");
+  },
   observe: function () {
     // The last session can only be restored once so there's
     // no way we need to re-enable our menu item.
     Services.obs.removeObserver(this, "sessionstore-last-session-cleared");
     goSetCommandEnabled("Browser:RestoreLastSession", false);
+    gBrowser.tabContainer.removeEventListener("TabOpen", this.fadeRestoreTabsButton, false);
+    this.fadeRestoreTabsButton();
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 function restoreLastSession() {
   SessionStore.restoreLastSession();
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1,14 +1,19 @@
 <?xml version="1.0"?>
 
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
+<!DOCTYPE bindings [
+<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
+%browserDTD;
+]>
+
 <bindings id="tabBrowserBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="tabbrowser">
     <resources>
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
@@ -4923,16 +4928,25 @@
         <children/>
         <xul:toolbarbutton class="tabs-newtab-button"
                            anonid="tabs-newtab-button"
                            command="cmd_newNavigatorTab"
                            onclick="checkForMiddleClick(this, event);"
                            onmouseover="document.getBindingParent(this)._enterNewTab();"
                            onmouseout="document.getBindingParent(this)._leaveNewTab();"
                            tooltip="dynamic-shortcut-tooltip"/>
+
+        <xul:hbox class="restore-tabs-button-wrapper"
+                  anonid="restore-tabs-button-wrapper">
+          <xul:toolbarbutton anonid="restore-tabs-button"
+                             class="restore-tabs-button"
+                             onclick="SessionStore.restoreLastSession();"
+                             label="&restoreLastTabs.label;"/>
+        </xul:hbox>
+
         <xul:spacer class="closing-tabs-spacer" anonid="closing-tabs-spacer"
                     style="width: 0;"/>
       </xul:arrowscrollbox>
     </content>
 
     <implementation implements="nsIDOMEventListener">
       <constructor>
         <![CDATA[
@@ -4975,24 +4989,65 @@
 
       <field name="_firstTab">null</field>
       <field name="_lastTab">null</field>
       <field name="_afterSelectedTab">null</field>
       <field name="_beforeHoveredTab">null</field>
       <field name="_afterHoveredTab">null</field>
       <field name="_hoveredTab">null</field>
 
+      <field name="buttonWidth">
+        document.getAnonymousElementByAttribute(this, "anonid", "restore-tabs-button-wrapper").clientWidth;
+      </field>
+
       <property name="_isCustomizing" readonly="true">
         <getter>
           let root = document.documentElement;
           return root.getAttribute("customizing") == "true" ||
                  root.getAttribute("customize-exiting") == "true";
         </getter>
       </property>
 
+      <method name="updateSessionRestoreVisibility">
+        <body><![CDATA[
+          let shouldHide = true;
+          let buttonPadding = 10;
+
+          //measure the button width initially on the DOM - it changes due to localization
+          let buttonWidth = this.buttonWidth;
+          let wrapper = document.getAnonymousElementByAttribute(this, "anonid", "restore-tabs-button-wrapper");
+
+          // if there is a flex > 1 element in the TabToolbar then there will not be a visual
+          // jump when the button fades, so we can show it so long as there is some room.
+          if (!wrapper.classList.contains("restore-fade-out") && wrapper.getAttribute('session-exists') === "true") {
+            let toolbarNode = document.getElementById("TabsToolbar").firstChild;
+            while (toolbarNode && toolbarNode.nodeType === 1) {
+              if (toolbarNode.flex > 1) {
+                if ((wrapper.hidden === true && toolbarNode.boxObject.width >= (buttonWidth * 2.5)) || (wrapper.hidden !== true && toolbarNode.boxObject.width >= buttonWidth * 1.5)) {
+                  shouldHide = false;
+                }
+              }
+              toolbarNode = toolbarNode.nextElementSibling;
+            }
+
+            //there will only ever be one tab when the button is showing.
+            let firstTab = document.getElementById("tabbrowser-tabs").firstChild;
+            let newTabButton = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button");
+            let childNodesTotalWidth = firstTab.clientWidth + newTabButton.clientWidth + wrapper.clientWidth;
+
+            //if there is enough extra room in the flex-element "tabbrowser-tabs"
+            //then there is room for the button.
+            if ((wrapper.hidden && document.getElementById("tabbrowser-tabs").clientWidth - childNodesTotalWidth >= buttonWidth + buttonPadding) || (!wrapper.hidden === true && document.getElementById("tabbrowser-tabs").clientWidth - childNodesTotalWidth >= buttonPadding)) {
+              shouldHide = false;
+            }
+          }
+          wrapper.hidden = shouldHide;
+        ]]></body>
+      </method>
+
       <method name="_setPositionalAttributes">
         <body><![CDATA[
           let visibleTabs = this.tabbrowser.visibleTabs;
 
           if (!visibleTabs.length)
             return;
 
           let selectedIndex = visibleTabs.indexOf(this.selectedItem);
@@ -5416,16 +5471,17 @@
               TabsInTitlebar.updateAppearance();
 
               var width = this.mTabstrip.boxObject.width;
               if (width != this.mTabstripWidth) {
                 this.adjustTabstrip();
                 this._fillTrailingGap();
                 this._handleTabSelect();
                 this.mTabstripWidth = width;
+                this.updateSessionRestoreVisibility();
               }
 
               this.tabbrowser.updateWindowResizers();
               break;
             case "mouseout":
               // If the "related target" (the node to which the pointer went) is not
               // a child of the current document, the mouse just left the window.
               let relatedTarget = aEvent.relatedTarget;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabbrowser/browser.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[browser_tabbar_sessionrestore_button.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabbrowser/browser_tabbar_sessionrestore_button.js
@@ -0,0 +1,20 @@
+
+add_task(function* (){
+  let win = yield BrowserTestUtils.openNewBrowserWindow();
+  let tabBrowser = win.document.getElementById('tabbrowser-tabs');
+  let restoreTabsButtonWrapper = win.document.getAnonymousElementByAttribute(tabBrowser, "anonid", "restore-tabs-button-wrapper");
+
+  let new_tab_button = win.document.getAnonymousElementByAttribute(win.gBrowser.tabContainer, 'class', 'tabs-newtab-button');
+  is(new_tab_button.style.visibility !== 'collapse', true, 'new tab button is not visibility: collapse');
+
+  let resizedPromise = BrowserTestUtils.waitForEvent(win, 'resize');
+  win.resizeTo(335, 300);
+  yield resizedPromise;
+
+  is(win.innerWidth, 335, 'window has resized to 335 width');
+  is(restoreTabsButtonWrapper.hidden, true, 'restoreTabsButtonWrapper is hidden after resize small')
+
+
+  //cleanup
+  yield BrowserTestUtils.closeWindow(win);
+});
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -18,16 +18,17 @@ BROWSER_CHROME_MANIFESTS += [
     'content/test/alerts/browser.ini',
     'content/test/chat/browser.ini',
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/social/browser.ini',
+    'content/test/tabbrowser/browser.ini',
     'content/test/tabPrompts/browser.ini',
     'content/test/urlbar/browser.ini',
     'content/test/webrtc/browser.ini',
 ]
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -1,14 +1,14 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!-- LOCALIZATION NOTE : FILE This file contains the browser main menu items -->
-<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys --> 
+<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
 
 <!-- LOCALIZATION NOTE (mainWindow.title): DONT_TRANSLATE -->
 <!ENTITY mainWindow.title "&brandFullName;">
 <!-- LOCALIZATION NOTE (mainWindow.titlemodifier) : DONT_TRANSLATE -->
 <!ENTITY mainWindow.titlemodifier "&brandFullName;">
 <!-- LOCALIZATION NOTE (mainWindow.titlemodifiermenuseparator): DONT_TRANSLATE -->
 <!ENTITY mainWindow.titlemodifiermenuseparator " - ">
 <!-- LOCALIZATION NOTE (mainWindow.titlePrivateBrowsingSuffix): This will be appended to the window's title
@@ -230,17 +230,17 @@ These should match what Safari and other
 <!ENTITY urlbar.translateNotificationAnchor.label       "Translate this page">
 <!ENTITY urlbar.translatedNotificationAnchor.label      "Manage page translation">
 <!ENTITY urlbar.emeNotificationAnchor.label             "Manage use of DRM software">
 
 <!ENTITY urlbar.openHistoryPopup.tooltip                "Show history">
 
 <!ENTITY searchItem.title             "Search">
 
-<!-- Toolbar items --> 
+<!-- Toolbar items -->
 <!ENTITY homeButton.label             "Home">
 
 <!ENTITY bookmarksButton.label          "Bookmarks">
 <!ENTITY bookmarksCmd.commandkey "b">
 
 <!ENTITY bookmarksMenuButton.label          "Bookmarks">
 <!ENTITY bookmarksMenuButton.other.label "Other Bookmarks">
 <!ENTITY viewBookmarksSidebar2.label        "View Bookmarks Sidebar">
@@ -253,17 +253,17 @@ These should match what Safari and other
   -  shortcut keys on Linux. -->
 <!ENTITY bookmarksGtkCmd.commandkey "o">
 <!ENTITY bookmarksWinCmd.commandkey "i">
 
 <!ENTITY historyButton.label            "History">
 <!ENTITY historySidebarCmd.commandKey   "h">
 
 <!ENTITY toolsMenu.label              "Tools">
-<!ENTITY toolsMenu.accesskey          "T"> 
+<!ENTITY toolsMenu.accesskey          "T">
 
 <!ENTITY keywordfield.label           "Add a Keyword for this Search…">
 <!ENTITY keywordfield.accesskey       "K">
 
 <!ENTITY downloads.label              "Downloads">
 <!ENTITY downloads.accesskey          "D">
 <!ENTITY downloads.commandkey         "j">
 <!ENTITY downloadsUnix.commandkey     "y">
@@ -272,74 +272,75 @@ These should match what Safari and other
 <!ENTITY addons.commandkey            "A">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
 <!ENTITY inspectContextMenu.label     "Inspect Element">
 <!ENTITY inspectContextMenu.accesskey "Q">
 
-<!ENTITY fileMenu.label         "File"> 
+<!ENTITY fileMenu.label         "File">
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newUserContext.label             "New Container Tab">
 <!ENTITY newUserContext.accesskey         "C">
 <!ENTITY newNavigatorCmd.label        "New Window">
 <!ENTITY newNavigatorCmd.key        "N">
 <!ENTITY newNavigatorCmd.accesskey      "N">
 <!ENTITY newPrivateWindow.label     "New Private Window">
 <!ENTITY newPrivateWindow.accesskey "W">
 <!ENTITY newNonRemoteWindow.label   "New Non-e10s Window">
 
-<!ENTITY editMenu.label         "Edit"> 
-<!ENTITY editMenu.accesskey       "E"> 
-<!ENTITY undoCmd.label            "Undo">  
-<!ENTITY undoCmd.key            "Z">  
-<!ENTITY undoCmd.accesskey          "U"> 
-<!ENTITY redoCmd.label            "Redo">  
-<!ENTITY redoCmd.key            "Y">  
-<!ENTITY redoCmd.accesskey          "R"> 
-<!ENTITY cutCmd.label           "Cut">  
-<!ENTITY cutCmd.key             "X">  
-<!ENTITY cutCmd.accesskey         "t"> 
-<!ENTITY copyCmd.label            "Copy">  
-<!ENTITY copyCmd.key            "C">  
-<!ENTITY copyCmd.accesskey          "C"> 
-<!ENTITY pasteCmd.label           "Paste">  
-<!ENTITY pasteCmd.key           "V">  
-<!ENTITY pasteCmd.accesskey         "P"> 
-<!ENTITY deleteCmd.label          "Delete">  
-<!ENTITY deleteCmd.key            "D">  
-<!ENTITY deleteCmd.accesskey        "D"> 
-<!ENTITY selectAllCmd.label         "Select All">  
-<!ENTITY selectAllCmd.key         "A">  
-<!ENTITY selectAllCmd.accesskey       "A"> 
+<!ENTITY editMenu.label         "Edit">
+<!ENTITY editMenu.accesskey       "E">
+<!ENTITY undoCmd.label            "Undo">
+<!ENTITY undoCmd.key            "Z">
+<!ENTITY undoCmd.accesskey          "U">
+<!ENTITY redoCmd.label            "Redo">
+<!ENTITY redoCmd.key            "Y">
+<!ENTITY redoCmd.accesskey          "R">
+<!ENTITY cutCmd.label           "Cut">
+<!ENTITY cutCmd.key             "X">
+<!ENTITY cutCmd.accesskey         "t">
+<!ENTITY copyCmd.label            "Copy">
+<!ENTITY copyCmd.key            "C">
+<!ENTITY copyCmd.accesskey          "C">
+<!ENTITY pasteCmd.label           "Paste">
+<!ENTITY pasteCmd.key           "V">
+<!ENTITY pasteCmd.accesskey         "P">
+<!ENTITY deleteCmd.label          "Delete">
+<!ENTITY deleteCmd.key            "D">
+<!ENTITY deleteCmd.accesskey        "D">
+<!ENTITY selectAllCmd.label         "Select All">
+<!ENTITY selectAllCmd.key         "A">
+<!ENTITY selectAllCmd.accesskey       "A">
 <!ENTITY preferencesCmd2.label       "Options">
 <!ENTITY preferencesCmd2.accesskey     "O">
 <!ENTITY preferencesCmdUnix.label       "Preferences">
-<!ENTITY preferencesCmdUnix.accesskey     "n"> 
+<!ENTITY preferencesCmdUnix.accesskey     "n">
 
 <!ENTITY clearRecentHistory.label               "Clear Recent History…">
 
 <!ENTITY privateBrowsingCmd.commandkey          "P">
 
-<!ENTITY viewMenu.label         "View"> 
-<!ENTITY viewMenu.accesskey       "V"> 
-<!ENTITY viewToolbarsMenu.label       "Toolbars"> 
-<!ENTITY viewToolbarsMenu.accesskey     "T"> 
+<!ENTITY viewMenu.label         "View">
+<!ENTITY viewMenu.accesskey       "V">
+<!ENTITY viewToolbarsMenu.label       "Toolbars">
+<!ENTITY viewToolbarsMenu.accesskey     "T">
 <!ENTITY viewSidebarMenu.label "Sidebar">
 <!ENTITY viewSidebarMenu.accesskey "e">
-<!ENTITY viewCustomizeToolbar.label       "Customize…"> 
+<!ENTITY viewCustomizeToolbar.label       "Customize…">
 <!ENTITY viewCustomizeToolbar.accesskey     "C">
 
 <!ENTITY historyMenu.label "History">
 <!ENTITY historyMenu.accesskey "s">
 <!ENTITY historyUndoMenu.label "Recently Closed Tabs">
 <!-- LOCALIZATION NOTE (historyUndoWindowMenu): see bug 394759 -->
 <!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
 <!ENTITY historyRestoreLastSession.label "Restore Previous Session">
+<!ENTITY restoreLastTabs.label "Restore Tabs From Last Time">
 
 <!ENTITY showAllHistoryCmd2.label "Show All History">
 <!ENTITY showAllHistoryCmd.commandkey "H">
 
 <!ENTITY appMenuCustomize.label "Customize">
 <!ENTITY appMenuCustomize.tooltip "Customize the Menu and Toolbars">
 <!ENTITY appMenuCustomizeExit.label "Exit Customize">
 <!ENTITY appMenuCustomizeExit.tooltip "Finish Customizing">
@@ -370,17 +371,17 @@ These should match what Safari and other
 <!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
 <!ENTITY customizeMenu.addToToolbar.accesskey "A">
 <!ENTITY customizeMenu.addToPanel.label "Add to Menu">
 <!ENTITY customizeMenu.addToPanel.accesskey "M">
 <!ENTITY customizeMenu.moveToToolbar.label "Move to Toolbar">
 <!ENTITY customizeMenu.moveToToolbar.accesskey "o">
 <!-- LOCALIZATION NOTE (customizeMenu.moveToPanel.accesskey) can appear on the
      same context menu as menubarCmd and personalbarCmd, so they should have
-     different access keys. customizeMenu.moveToToolbar and 
+     different access keys. customizeMenu.moveToToolbar and
      customizeMenu.moveToPanel are mutually exclusive, so can share access
      keys.  -->
 <!ENTITY customizeMenu.moveToPanel.label "Move to Menu">
 <!ENTITY customizeMenu.moveToPanel.accesskey "o">
 <!ENTITY customizeMenu.removeFromToolbar.label "Remove from Toolbar">
 <!ENTITY customizeMenu.removeFromToolbar.accesskey "R">
 <!ENTITY customizeMenu.removeFromMenu.label "Remove from Menu">
 <!ENTITY customizeMenu.removeFromMenu.accesskey "R">
@@ -395,17 +396,17 @@ These should match what Safari and other
 <!ENTITY urlbar.searchSuggestionsNotification.question "Would you like to improve your search experience with suggestions?">
 <!ENTITY urlbar.searchSuggestionsNotification.learnMore "Learn more…">
 <!ENTITY urlbar.searchSuggestionsNotification.learnMore.accesskey "l">
 <!ENTITY urlbar.searchSuggestionsNotification.disable "No">
 <!ENTITY urlbar.searchSuggestionsNotification.disable.accesskey "n">
 <!ENTITY urlbar.searchSuggestionsNotification.enable "Yes">
 <!ENTITY urlbar.searchSuggestionsNotification.enable.accesskey "y">
 
-<!-- 
+<!--
   Comment duplicated from browser-sets.inc:
 
   Search Command Key Logic works like this:
 
   Unix: Ctrl+J (0.8, 0.9 support)
         Ctrl+K (cross platform binding)
   Mac:  Cmd+K (cross platform binding)
         Cmd+Opt+F (platform convention)
@@ -476,17 +477,17 @@ These should match what Safari and other
 <!ENTITY openLinkCmdInContainerTab.accesskey "z">
 <!ENTITY showOnlyThisFrameCmd.label     "Show Only This Frame">
 <!ENTITY showOnlyThisFrameCmd.accesskey "S">
 <!ENTITY reloadCmd.commandkey         "r">
 <!ENTITY reloadFrameCmd.label         "Reload Frame">
 <!ENTITY reloadFrameCmd.accesskey     "R">
 <!ENTITY viewPartialSourceForSelectionCmd.label "View Selection Source">
 <!ENTITY viewPartialSourceForMathMLCmd.label    "View MathML Source">
-<!-- LOCALIZATION NOTE (viewPartialSourceCmd.accesskey): This accesskey is used for both 
+<!-- LOCALIZATION NOTE (viewPartialSourceCmd.accesskey): This accesskey is used for both
          viewPartialSourceForSelectionCmd.label and viewPartialSourceForMathMLCmd.label -->
 <!ENTITY viewPartialSourceCmd.accesskey "e">
 <!ENTITY viewPageSourceCmd.label      "View Page Source">
 <!ENTITY viewPageSourceCmd.accesskey  "V">
 <!ENTITY viewFrameSourceCmd.label     "View Frame Source">
 <!ENTITY viewFrameSourceCmd.accesskey "V">
 <!ENTITY viewPageInfoCmd.label        "View Page Info">
 <!ENTITY viewPageInfoCmd.accesskey    "I">
@@ -542,17 +543,17 @@ These should match what Safari and other
 <!ENTITY playPluginCmd.accesskey      "c">
 <!ENTITY hidePluginCmd.label          "Hide this plugin">
 <!ENTITY hidePluginCmd.accesskey      "H">
 <!ENTITY copyLinkCmd.label            "Copy Link Location">
 <!ENTITY copyLinkCmd.accesskey        "a">
 <!ENTITY copyImageCmd.label           "Copy Image Location">
 <!ENTITY copyImageCmd.accesskey       "o">
 <!ENTITY copyImageContentsCmd.label   "Copy Image">
-<!ENTITY copyImageContentsCmd.accesskey  "y"> 
+<!ENTITY copyImageContentsCmd.accesskey  "y">
 <!ENTITY copyVideoURLCmd.label        "Copy Video Location">
 <!ENTITY copyVideoURLCmd.accesskey    "o">
 <!ENTITY copyAudioURLCmd.label        "Copy Audio Location">
 <!ENTITY copyAudioURLCmd.accesskey    "o">
 <!ENTITY copyEmailCmd.label           "Copy Email Address">
 <!ENTITY copyEmailCmd.accesskey       "E">
 <!ENTITY thisFrameMenu.label              "This Frame">
 <!ENTITY thisFrameMenu.accesskey          "h">
@@ -637,24 +638,24 @@ you can use these alternative items. Oth
 
 <!ENTITY sidebarCloseButton.tooltip     "Close sidebar">
 
 <!ENTITY quitApplicationCmdWin2.label       "Exit">
 <!ENTITY quitApplicationCmdWin2.accesskey   "x">
 <!ENTITY quitApplicationCmdWin2.tooltip     "Exit &brandShorterName;">
 <!ENTITY goBackCmd.commandKey "[">
 <!ENTITY goForwardCmd.commandKey "]">
-<!ENTITY quitApplicationCmd.label       "Quit"> 
+<!ENTITY quitApplicationCmd.label       "Quit">
 <!ENTITY quitApplicationCmd.accesskey   "Q">
 <!ENTITY quitApplicationCmdMac2.label   "Quit &brandShorterName;">
 <!-- LOCALIZATION NOTE(quitApplicationCmdUnix.key): This keyboard shortcut is used by both Linux and OSX builds. -->
 <!ENTITY quitApplicationCmdUnix.key     "Q">
 
-<!ENTITY closeCmd.label                 "Close">  
-<!ENTITY closeCmd.key                   "W">  
+<!ENTITY closeCmd.label                 "Close">
+<!ENTITY closeCmd.key                   "W">
 <!ENTITY closeCmd.accesskey             "C">
 
 <!ENTITY toggleMuteCmd.key              "M">
 
 <!ENTITY pageStyleMenu.label "Page Style">
 <!ENTITY pageStyleMenu.accesskey "y">
 <!ENTITY pageStyleNoStyle.label "No Style">
 <!ENTITY pageStyleNoStyle.accesskey "n">
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -3,17 +3,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
 :root {
   --tab-toolbar-navbar-overlap: 1px;
   --navbar-tab-toolbar-highlight-overlap: 1px;
   --tab-min-height: 31px;
+  --restore-tabs-button-color: hsla(0,0%,16%,.2);
 }
+
+:root[lwthemetextcolor="dark"] {
+  --restore-tabs-button-color: hsla(0,0%,16%,.2);
+}
+
+:root[lwthemetextcolor="bright"] {
+  --restore-tabs-button-color: hsl(0, 0%, 70%);
+}
+
 #TabsToolbar {
   --tab-stroke-background-size: auto 100%;
 }
 
 %define tabCurveWidth 30px
 %define tabCurveHalfWidth 15px
 
 /* image preloading hack */
@@ -557,8 +567,36 @@
   .tab-icon-image {
     list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
   }
 
   .tab-throbber[progress] {
     list-style-image: url("chrome://global/skin/icons/loading@2x.png");
   }
 }
+
+.restore-tabs-button > .toolbarbutton-icon {
+  display: none;
+}
+
+.restore-tabs-button-wrapper {
+  visibility: hidden;
+  position:fixed;
+  padding: 4px;
+  margin-left: 3px;
+  transition: opacity 300ms ease-out;
+}
+
+.restore-tabs-button > .toolbarbutton-text {
+  display: -moz-box;
+  font-size: .8em;
+  margin-bottom: 0;
+  padding: 0 5px;
+}
+
+.restore-tabs-button {
+  border: 1px solid var(--restore-tabs-button-color);
+  border-radius: 2px;
+}
+
+.restore-tabs-button-wrapper.restore-fade-out {
+  opacity: 0;
+}