Blob Blame History Raw
--- comm/suite/app/profile/suite-prefs.js.orig	2021-10-28 22:08:57.878222186 +0300
+++ comm/suite/app/profile/suite-prefs.js	2021-10-28 22:11:27.853233034 +0300
@@ -225,16 +225,17 @@ pref("browser.tabs.forceHide", false);
 pref("browser.tabs.closeWindowWithLastTab", true);
 pref("browser.tabs.warnOnClose", true);
 pref("browser.tabs.warnOnCloseOther", true);
 pref("browser.tabs.warnOnOpen", true);
 pref("browser.tabs.maxOpenBeforeWarn", 15);
 pref("browser.tabs.insertRelatedAfterCurrent", true);
 pref("browser.tabs.insertAllTabsAfterCurrent", false);
 pref("browser.tabs.avoidBrowserFocus", false);
+pref("browser.tabs.selectOwnerOnClose", true);
 
 // For future use
 pref("browser.tabs.loadBookmarksInBackground", false);
 
 // how many browsers can be saved in the DOM (by the tabbed browser)
 pref("browser.tabs.max_tabs_undo", 3);
 // should popups by saved in the DOM (by the tabbed browser)
 pref("browser.tabs.cache_popups", false);
--- comm/suite/base/content/utilityOverlay.js.orig	2021-10-26 19:51:22.000000000 +0300
+++ comm/suite/base/content/utilityOverlay.js	2021-10-28 22:08:57.879222179 +0300
@@ -1632,21 +1632,23 @@ function openLinkIn(url, where, params)
     // forces tab to be focused
     loadInBackground = true;
     // fall through
   case "tabshifted":
     loadInBackground = !loadInBackground;
     // fall through
   case "tab":
     var browser = w.getBrowser();
+    var owner = loadInBackground ? null : browser.selectedTab;
     var tab = browser.addTab(url, {
                 referrerURI: aReferrerURI,
                 referrerPolicy: aReferrerPolicy,
                 charset: aCharset,
                 postData: aPostData,
+                ownerTab: owner,
                 allowThirdPartyFixup: aAllowThirdPartyFixup,
                 relatedToCurrent: aRelatedToCurrent,
                 allowMixedContent: aAllowMixedContent,
                 noReferrer: aNoReferrer,
                 userContextId: aUserContextId,
                 originPrincipal: aPrincipal,
                 triggeringPrincipal: aTriggeringPrincipal,
               });
--- comm/suite/browser/tabbrowser.xml.orig	2021-10-26 19:51:22.000000000 +0300
+++ comm/suite/browser/tabbrowser.xml	2021-10-28 22:08:57.881222166 +0300
@@ -1154,16 +1154,28 @@
             newBrowser.docShellIsActive = this.mCurrentTab.linkedBrowser.docShellIsActive;
             if (this.mCurrentBrowser) {
               this.mCurrentBrowser.droppedLinkHandler = null;
               this.mCurrentBrowser.docShellIsActive = false;
               this.mCurrentBrowser.removeAttribute("primary");
               this.finder.mListeners.forEach(l => this.mCurrentBrowser.finder.removeResultListener(l));
             }
 
+            var oldTab = this.mCurrentTab;
+
+            // Preview mode should not reset the owner
+            if (!this._previewMode && !oldTab.selected)
+              oldTab.owner = null;
+
+            let lastRelatedTab = this.mLastRelatedIndex ? this.tabs[this.mLastRelatedIndex] : null;
+            if (lastRelatedTab) {
+              if (!lastRelatedTab.selected)
+                lastRelatedTab.owner = null;
+            }
+
             newBrowser.setAttribute("primary", "true");
             this.mCurrentBrowser = newBrowser;
             this.mCurrentTab = this.selectedTab;
             this.mCurrentTab.removeAttribute("unread");
             this.finder.mListeners.forEach(l => this.mCurrentBrowser.finder.addResultListener(l));
 
             var tabListener = this.mTabListeners[this.tabContainer.selectedIndex];
 
@@ -1449,16 +1461,19 @@
                 opener: null,
               };
             }
 
             params.focusNewTab = params.inBackground != null ?
                 !params.inBackground :
                 !Services.prefs.getBoolPref("browser.tabs.loadInBackground");
 
+            if (params.focusNewTab)
+              params.ownerTab = this.selectedTab;
+
             return this.addTab(aURI, params);
          ]]>
         </body>
       </method>
 
       <method name="loadTabs">
         <parameter name="aURIs"/>
         <parameter name="aLoadInBackground"/>
@@ -1560,43 +1575,49 @@
         <parameter name="aPostData"/>
         <parameter name="aFocusNewTab"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
           <![CDATA[
             var aTriggeringPrincipal;
             var aReferrerPolicy;
             var aFromExternal;
+            var aOwner;
             var aRelatedToCurrent;
             var aAllowMixedContent;
             var aNoReferrer;
             var aUserContextId;
             var aOriginPrincipal;
             var aOpener;
             if (arguments.length == 2 &&
                 arguments[1] != null &&
                 typeof arguments[1] == "object" &&
                 !(arguments[1] instanceof Ci.nsIURI)) {
               let params = arguments[1];
               aTriggeringPrincipal  = params.triggeringPrincipal;
               aReferrerURI          = params.referrerURI;
               aReferrerPolicy       = params.referrerPolicy;
               aCharset              = params.charset;
               aPostData             = params.postData;
+              aOwner                = params.ownerTab;
               aFocusNewTab          = params.focusNewTab;
               aAllowThirdPartyFixup = params.allowThirdPartyFixup;
               aFromExternal         = params.fromExternal;
               aRelatedToCurrent     = params.relatedToCurrent;
               aAllowMixedContent    = params.allowMixedContent;
               aNoReferrer           = params.noReferrer;
               aUserContextId        = params.userContextId;
               aOriginPrincipal      = params.originPrincipal;
               aOpener               = params.opener;
             }
 
+            // if we're adding tabs, we're past interrupt mode, ditch the owner
+            if (this.mCurrentTab.owner)
+              this.mCurrentTab.owner = null;
+
             this._browsers = null; // invalidate cache
 
             var t = this.referenceTab.cloneNode(true);
 
             var blank = !aURI || aURI == "about:blank";
 
             if (!blank)
               t.setAttribute("label", aURI);
@@ -1654,16 +1675,20 @@
 
             // We start our browsers out as inactive.
             b.docShellIsActive = false;
 
             this.mStrip.collapsed = false;
 
             Services.prefs.setBoolPref("browser.tabs.forceHide", false);
 
+            // If this new tab is owned by another, assert that relationship
+            if (aOwner)
+              t.owner = aOwner;
+
             // wire up a progress listener for the new browser object.
             var position = this.tabs.length - 1;
             var tabListener = this.mTabProgressListener(t, b, blank);
             const filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
                              .createInstance(Ci.nsIWebProgress);
             filter.addProgressListener(tabListener, Ci.nsIWebProgress.NOTIFY_ALL);
             b.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
             this.mTabListeners[position] = tabListener;
@@ -1703,16 +1728,20 @@
             // aReferrerURI is null or undefined if the tab is opened from
             // an external application or bookmark, i.e. somewhere other
             // than the current tab.
             if ((aRelatedToCurrent || aReferrerURI ||
                  Services.prefs.getBoolPref("browser.tabs.insertAllTabsAfterCurrent")) &&
                 Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
               var lastRelatedIndex = this.mLastRelatedIndex ||
                                      this.tabContainer.selectedIndex;
+              if (this.mLastRelatedIndex)
+                  this.tabs[this.mLastRelatedIndex].owner = null;
+              else
+                  t.owner = this.selectedTab;
               this.moveTabTo(t, ++lastRelatedIndex);
               this.mLastRelatedIndex = lastRelatedIndex;
             }
 
             if (aFocusNewTab) {
               var parentTab = this.selectedTab;
               this.selectedTab = t;
               this.mPreviousTab = parentTab;
@@ -2040,16 +2069,23 @@
             oldBrowser.webProgress.removeProgressListener(filter);
             filter.removeProgressListener(this.mTabListeners[index]);
             this.mTabFilters.splice(index, 1);
             this.mTabListeners.splice(index, 1);
 
             // We are no longer the primary content area
             oldBrowser.removeAttribute("primary");
 
+            // Remove this tab as the owner of any other tabs, since it's going away.
+            for (let tab of this.tabs) {
+              if ("owner" in tab && tab.owner == aTab)
+                // |tab| is a child of the tab we're removing, make it an orphan
+                tab.owner = null;
+            }
+
             // Now select the new tab before nuking the old one.
             var currentIndex = this.tabContainer.selectedIndex;
 
             var newIndex = -1;
             if (currentIndex > index)
               newIndex = currentIndex - 1;
             else if (currentIndex < index)
               newIndex = currentIndex;
@@ -2066,17 +2102,21 @@
             this._browsers = null;
 
             // Clean up before/afterselected attributes before removing the tab
             aTab._selected = false;
             aTab.remove();
 
             // When the current tab is removed select a new tab
             // and fire select events on tabpanels and tabs
-            if (this.mPreviousTab && (aTab == this.mCurrentTab))
+            if (aTab.owner && !aTab.owner.hidden && !aTab.owner.closing &&
+                Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
+              this.selectedTab = aTab.owner;
+            }
+            else if (this.mPreviousTab && (aTab == this.mCurrentTab))
               this.selectedTab = this.mPreviousTab;
             else {
               this.tabContainer.selectedIndex = newIndex;
 
               // We need to explicitly clear this, because updateCurrentBrowser
               // doesn't get called for a background tab
               this.mPreviousTab = null;
             }