diff options
Diffstat (limited to 'application/palemoon')
19 files changed, 703 insertions, 17 deletions
diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js index 15accd146..e53b1693b 100644 --- a/application/palemoon/app/profile/palemoon.js +++ b/application/palemoon/app/profile/palemoon.js @@ -463,6 +463,10 @@ pref("browser.tabs.closeButtons", 1); // false return to the adjacent tab (old default) pref("browser.tabs.selectOwnerOnClose", true); +pref("browser.tabs.showAudioPlayingIcon", true); +// This should match Chromium's audio indicator delay. +pref("browser.tabs.delayHidingAudioPlayingIconMS", 3000); + pref("browser.allTabs.previews", true); pref("browser.ctrlTab.previews", true); pref("browser.ctrlTab.recentlyUsedLimit", 7); diff --git a/application/palemoon/base/content/browser-sets.inc b/application/palemoon/base/content/browser-sets.inc index 25794a65c..78fce2670 100644 --- a/application/palemoon/base/content/browser-sets.inc +++ b/application/palemoon/base/content/browser-sets.inc @@ -32,6 +32,7 @@ <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/> <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/> <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/> + <command id="cmd_toggleMute" oncommand="gBrowser.selectedTab.toggleMuteAudio()"/> <command id="cmd_ToggleTabsOnTop" oncommand="TabsOnTop.toggle()"/> <command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/> <command id="cmd_restartApplication" oncommand="restart(false);"/> @@ -212,6 +213,7 @@ <key id="printKb" key="&printCmd.commandkey;" command="cmd_print" modifiers="accel"/> <key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/> <key id="key_closeWindow" key="&closeCmd.key;" command="cmd_closeWindow" modifiers="accel,shift"/> + <key id="key_toggleMute" key="&toggleMuteCmd.key;" command="cmd_toggleMute" modifiers="control"/> <key id="key_undo" key="&undoCmd.key;" modifiers="accel"/> diff --git a/application/palemoon/base/content/browser-tabPreviews.js b/application/palemoon/base/content/browser-tabPreviews.js index eaae78ba8..e0755b81d 100644 --- a/application/palemoon/base/content/browser-tabPreviews.js +++ b/application/palemoon/base/content/browser-tabPreviews.js @@ -940,6 +940,13 @@ var allTabs = { aPreview.setAttribute("image", aPreview._tab.image); else aPreview.removeAttribute("image"); + + aPreview.removeAttribute("soundplaying"); + aPreview.removeAttribute("muted"); + if (aPreview._tab.hasAttribute("muted")) + aPreview.setAttribute("muted", "true"); + else if (aPreview._tab.hasAttribute("soundplaying")) + aPreview.setAttribute("soundplaying", "true"); var thumbnail = tabPreviews.get(aPreview._tab); if (aPreview.firstChild) { diff --git a/application/palemoon/base/content/browser-tabPreviews.xml b/application/palemoon/base/content/browser-tabPreviews.xml index e957649e7..4f54321ea 100644 --- a/application/palemoon/base/content/browser-tabPreviews.xml +++ b/application/palemoon/base/content/browser-tabPreviews.xml @@ -42,7 +42,10 @@ <xul:hbox class="tabPreview-canvas" xbl:inherits="style=canvasstyle"> <children/> </xul:hbox> - <xul:label flex="1" xbl:inherits="value=label,crop" class="allTabs-preview-label plain"/> + <xul:hbox align="center"> + <xul:image xbl:inherits="soundplaying,muted" class="allTabs-endimage"/> + <xul:label flex="1" xbl:inherits="value=label,crop" class="allTabs-preview-label plain"/> + </xul:hbox> </xul:vbox> <xul:hbox class="allTabs-favicon-container"> <xul:image class="allTabs-favicon" xbl:inherits="src=image"/> diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js index 4167f186c..591d00fbb 100644 --- a/application/palemoon/base/content/browser.js +++ b/application/palemoon/base/content/browser.js @@ -976,6 +976,7 @@ var gBrowserInit = { CombinedStopReload.init(); allTabs.readPref(); TabsOnTop.init(); + AudioIndicator.init(); gPrivateBrowsingUI.init(); TabsInTitlebar.init(); retrieveToolbarIconsizesFromTheme(); @@ -1364,6 +1365,8 @@ var gBrowserInit = { BookmarkingUI.uninit(); TabsOnTop.uninit(); + + AudioIndicator.uninit(); TabsInTitlebar.uninit(); @@ -4597,6 +4600,42 @@ function setToolbarVisibility(toolbar, isVisible) { ToolbarIconColor.inferFromText(); } +var AudioIndicator = { + init: function () { + Services.prefs.addObserver(this._prefName, this, false); + this.syncUI(); + }, + + uninit: function () { + Services.prefs.removeObserver(this._prefName, this); + }, + + toggle: function () { + this.enabled = !Services.prefs.getBoolPref(this._prefName); + }, + + syncUI: function () { + document.getElementById("context_toggleMuteTab").setAttribute("hidden", this.enabled); + document.getElementById("key_toggleMute").setAttribute("disabled", this.enabled); + }, + + get enabled () { + return !Services.prefs.getBoolPref(this._prefName); + }, + + set enabled (val) { + Services.prefs.setBoolPref(this._prefName, !!val); + return val; + }, + + observe: function (subject, topic, data) { + if (topic == "nsPref:changed") + this.syncUI(); + }, + + _prefName: "browser.tabs.showAudioPlayingIcon" +} + var TabsOnTop = { init: function TabsOnTop_init() { Services.prefs.addObserver(this._prefName, this, false); @@ -7021,6 +7060,17 @@ function restoreLastSession() { var TabContextMenu = { contextTab: null, + _updateToggleMuteMenuItem(aTab, aConditionFn) { + ["muted", "soundplaying"].forEach(attr => { + if (!aConditionFn || aConditionFn(attr)) { + if (aTab.hasAttribute(attr)) { + aTab.toggleMuteMenuItem.setAttribute(attr, "true"); + } else { + aTab.toggleMuteMenuItem.removeAttribute(attr); + } + } + }); + }, updateContextMenu: function updateContextMenu(aPopupMenu) { this.contextTab = aPopupMenu.triggerNode.localName == "tab" ? aPopupMenu.triggerNode : gBrowser.selectedTab; @@ -7067,6 +7117,35 @@ var TabContextMenu = { bookmarkAllTabs.hidden = this.contextTab.pinned; if (!bookmarkAllTabs.hidden) PlacesCommandHook.updateBookmarkAllTabsCommand(); + + // Adjust the state of the toggle mute menu item. + let toggleMute = document.getElementById("context_toggleMuteTab"); + if (this.contextTab.hasAttribute("muted")) { + toggleMute.label = gNavigatorBundle.getString("unmuteTab.label"); + toggleMute.accessKey = gNavigatorBundle.getString("unmuteTab.accesskey"); + } else { + toggleMute.label = gNavigatorBundle.getString("muteTab.label"); + toggleMute.accessKey = gNavigatorBundle.getString("muteTab.accesskey"); + } + + this.contextTab.toggleMuteMenuItem = toggleMute; + this._updateToggleMuteMenuItem(this.contextTab); + + this.contextTab.addEventListener("TabAttrModified", this, false); + aPopupMenu.addEventListener("popuphiding", this, false); + }, + handleEvent(aEvent) { + switch (aEvent.type) { + case "popuphiding": + gBrowser.removeEventListener("TabAttrModified", this); + aEvent.target.removeEventListener("popuphiding", this); + break; + case "TabAttrModified": + let tab = aEvent.target; + this._updateToggleMuteMenuItem(tab, + attr => aEvent.detail.changed.indexOf(attr) >= 0); + break; + } } }; diff --git a/application/palemoon/base/content/browser.xul b/application/palemoon/base/content/browser.xul index 07ca54722..ce2a7c5a8 100644 --- a/application/palemoon/base/content/browser.xul +++ b/application/palemoon/base/content/browser.xul @@ -87,6 +87,7 @@ onpopuphidden="if (event.target == this) TabContextMenu.contextTab = null;"> <menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;" oncommand="gBrowser.reloadTab(TabContextMenu.contextTab);"/> + <menuitem id="context_toggleMuteTab" oncommand="TabContextMenu.contextTab.toggleMuteAudio();"/> <menuseparator/> <menuitem id="context_pinTab" label="&pinTab.label;" accesskey="&pinTab.accesskey;" diff --git a/application/palemoon/base/content/tabbrowser.css b/application/palemoon/base/content/tabbrowser.css index 94d6dbb2e..43536b27a 100644 --- a/application/palemoon/base/content/tabbrowser.css +++ b/application/palemoon/base/content/tabbrowser.css @@ -45,10 +45,19 @@ tabpanels { } .tab-throbber:not([busy]), -.tab-throbber[busy] + .tab-icon-image { +.tab-throbber[busy] + .tab-icon-image, +.tab-icon-sound:not([soundplaying]):not([muted]):not([blocked]), +.tab-icon-sound[pinned], +.tab-icon-overlay { display: none; } +.tab-icon-overlay[soundplaying][pinned], +.tab-icon-overlay[muted][pinned], +.tab-icon-overlay[blocked][pinned] { + display: -moz-box; +} + .closing-tabs-spacer { pointer-events: none; } diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml index dc6cb0a9d..929afd057 100644 --- a/application/palemoon/base/content/tabbrowser.xml +++ b/application/palemoon/base/content/tabbrowser.xml @@ -438,6 +438,22 @@ </body> </method> + <method name="getTabFromAudioEvent"> + <parameter name="aEvent"/> + <body> + <![CDATA[ + if (!Services.prefs.getBoolPref("browser.tabs.showAudioPlayingIcon") || + !aEvent.isTrusted) { + return null; + } + + var browser = aEvent.originalTarget; + var tab = this.getTabForBrowser(browser); + return tab; + ]]> + </body> + </method> + <method name="_callProgressListeners"> <parameter name="aBrowser"/> <parameter name="aMethod"/> @@ -616,7 +632,7 @@ if (this.mTab.hasAttribute("busy")) { this.mTab.removeAttribute("busy"); - this.mTabBrowser._tabAttrModified(this.mTab); + this.mTabBrowser._tabAttrModified(this.mTab, ["busy"]); if (!this.mTab.selected) this.mTab.setAttribute("unread", "true"); } @@ -686,6 +702,8 @@ let topLevel = aWebProgress.isTopLevel; if (topLevel) { + let isSameDocument = + !!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT); // We need to clear the typed value // if the document failed to load, to make sure the urlbar reflects the // failed URI (particularly for SSL errors). However, don't clear the value @@ -696,6 +714,19 @@ aLocation.spec != "about:blank")) this.mBrowser.userTypedValue = null; + // If the browser was playing audio, we should remove the playing state. + if (this.mTab.hasAttribute("soundplaying") && !isSameDocument) { + clearTimeout(this.mTab._soundPlayingAttrRemovalTimer); + this.mTab._soundPlayingAttrRemovalTimer = 0; + this.mTab.removeAttribute("soundplaying"); + this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]); + } + + // If the browser was previously muted, we should restore the muted state. + if (this.mTab.hasAttribute("muted")) { + this.mTab.linkedBrowser.mute(); + } + // Don't clear the favicon if this onLocationChange was // triggered by a pushState or a replaceState. See bug 550565. if (!gMultiProcessBrowser) { @@ -804,7 +835,7 @@ aTab.setAttribute("image", sizedIconUrl); else aTab.removeAttribute("image"); - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["image"]); } this._callProgressListeners(browser, "onLinkIconAvailable", [browser.mIconURL]); @@ -1116,8 +1147,8 @@ }); this.mCurrentTab.dispatchEvent(event); - this._tabAttrModified(oldTab); - this._tabAttrModified(this.mCurrentTab); + this._tabAttrModified(oldTab, ["selected"]); + this._tabAttrModified(this.mCurrentTab, ["selected"]); // Adjust focus oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused); @@ -1187,14 +1218,18 @@ <method name="_tabAttrModified"> <parameter name="aTab"/> + <parameter name="aChanged"/> <body><![CDATA[ if (aTab.closing) return; - // This event should be dispatched when any of these attributes change: - // label, crop, busy, image, selected - var event = document.createEvent("Events"); - event.initEvent("TabAttrModified", true, false); + let event = new CustomEvent("TabAttrModified", { + bubbles: true, + cancelable: false, + detail: { + changed: aChanged, + } + }); aTab.dispatchEvent(event); ]]></body> </method> @@ -1205,7 +1240,7 @@ <![CDATA[ aTab.label = this.mStringBundle.getString("tabs.connecting"); aTab.crop = "end"; - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["label", "crop"]); ]]> </body> </method> @@ -1250,7 +1285,7 @@ aTab.label = title; aTab.crop = crop; - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["label", "crop"]); if (aTab.selected) this.updateTitlebar(); @@ -2239,6 +2274,14 @@ var remoteBrowser = aOtherTab.ownerDocument.defaultView.gBrowser; var isPending = aOtherTab.hasAttribute("pending"); + // Expedite the removal of the icon if it was already scheduled. + if (aOtherTab._soundPlayingAttrRemovalTimer) { + clearTimeout(aOtherTab._soundPlayingAttrRemovalTimer); + aOtherTab._soundPlayingAttrRemovalTimer = 0; + aOtherTab.removeAttribute("soundplaying"); + remoteBrowser._tabAttrModified(aOtherTab, ["soundplaying"]); + } + // First, start teardown of the other browser. Make sure to not // fire the beforeunload event in the process. Close the other // window if this was its last tab. @@ -2248,6 +2291,18 @@ let ourBrowser = this.getBrowserForTab(aOurTab); let otherBrowser = aOtherTab.linkedBrowser; + let modifiedAttrs = []; + if (aOtherTab.hasAttribute("muted")) { + aOurTab.setAttribute("muted", "true"); + aOurTab.muteReason = aOtherTab.muteReason; + ourBrowser.mute(); + modifiedAttrs.push("muted"); + } + if (aOtherTab.hasAttribute("soundplaying")) { + aOurTab.setAttribute("soundplaying", "true"); + modifiedAttrs.push("soundplaying"); + } + // If the other tab is pending (i.e. has not been restored, yet) // then do not switch docShells but retrieve the other tab's state // and apply it to our tab. @@ -2266,7 +2321,7 @@ var isBusy = aOtherTab.hasAttribute("busy"); if (isBusy) { aOurTab.setAttribute("busy", "true"); - this._tabAttrModified(aOurTab); + modifiedAttrs.push("busy"); if (aOurTab.selected) this.mIsBusy = true; } @@ -2286,6 +2341,10 @@ // of replaceTabWithWindow), notify onLocationChange, etc. if (aOurTab.selected) this.updateCurrentBrowser(true); + + if (modifiedAttrs.length) { + this._tabAttrModified(aOurTab, modifiedAttrs); + } ]]> </body> </method> @@ -3084,9 +3143,25 @@ event.preventDefault(); return; } - event.target.setAttribute("label", tab.mOverCloseButton ? - tab.getAttribute("closetabtext") : - tab.getAttribute("label")); + + var stringID, label; + if (tab.mOverCloseButton) { + stringID = "tabs.closeTab"; + } else if (tab._overPlayingIcon) { + if (tab.linkedBrowser.audioBlocked) { + stringID = "tabs.unblockAudio.tooltip"; + } else { + stringID = tab.linkedBrowser.audioMuted ? + "tabs.unmuteAudio.tooltip" : + "tabs.muteAudio.tooltip"; + } + } else { + label = tab.getAttribute("label"); + } + if (stringID && !label) { + label = this.mStringBundle.getString(stringID); + } + event.target.setAttribute("label", label); ]]></body> </method> @@ -3300,6 +3375,7 @@ ]]> </getter> </property> + <field name="_soundPlayingAttrRemovalTimer">0</field> </implementation> <handlers> @@ -3347,6 +3423,78 @@ tab.setAttribute("titlechanged", "true"); ]]> </handler> + <handler event="DOMAudioPlaybackStarted"> + <![CDATA[ + var tab = getTabFromAudioEvent(event) + if (!tab) { + return; + } + + clearTimeout(tab._soundPlayingAttrRemovalTimer); + tab._soundPlayingAttrRemovalTimer = 0; + + let modifiedAttrs = []; + if (tab.hasAttribute("soundplaying-scheduledremoval")) { + tab.removeAttribute("soundplaying-scheduledremoval"); + modifiedAttrs.push("soundplaying-scheduledremoval"); + } + + if (!tab.hasAttribute("soundplaying")) { + tab.setAttribute("soundplaying", true); + modifiedAttrs.push("soundplaying"); + } + + this._tabAttrModified(tab, modifiedAttrs); + ]]> + </handler> + <handler event="DOMAudioPlaybackStopped"> + <![CDATA[ + var tab = getTabFromAudioEvent(event) + if (!tab) { + return; + } + + if (tab.hasAttribute("soundplaying")) { + let removalDelay = Services.prefs.getIntPref("browser.tabs.delayHidingAudioPlayingIconMS"); + + tab.style.setProperty("--soundplaying-removal-delay", `${removalDelay - 300}ms`); + tab.setAttribute("soundplaying-scheduledremoval", "true"); + this._tabAttrModified(tab, ["soundplaying-scheduledremoval"]); + + tab._soundPlayingAttrRemovalTimer = setTimeout(() => { + tab.removeAttribute("soundplaying-scheduledremoval"); + tab.removeAttribute("soundplaying"); + this._tabAttrModified(tab, ["soundplaying", "soundplaying-scheduledremoval"]); + }, removalDelay); + } + ]]> + </handler> + <handler event="DOMAudioPlaybackBlockStarted"> + <![CDATA[ + var tab = getTabFromAudioEvent(event) + if (!tab) { + return; + } + + if (!tab.hasAttribute("blocked")) { + tab.setAttribute("blocked", true); + this._tabAttrModified(tab, ["blocked"]); + } + ]]> + </handler> + <handler event="DOMAudioPlaybackBlockStopped"> + <![CDATA[ + var tab = getTabFromAudioEvent(event) + if (!tab) { + return; + } + + if (tab.hasAttribute("blocked")) { + tab.removeAttribute("blocked"); + this._tabAttrModified(tab, ["blocked"]); + } + ]]> + </handler> </handlers> </binding> @@ -4758,10 +4906,18 @@ class="tab-icon-image" role="presentation" anonid="tab-icon"/> + <xul:image xbl:inherits="busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected" + anonid="overlay-icon" + class="tab-icon-overlay" + role="presentation"/> <xul:label flex="1" xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected" class="tab-text tab-label" role="presentation"/> + <xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected" + anonid="soundplaying-icon" + class="tab-icon-sound" + role="presentation"/> <xul:toolbarbutton anonid="close-button" xbl:inherits="fadein,pinned,selected" class="tab-close-button close-icon"/> @@ -4782,9 +4938,59 @@ </property> <field name="mOverCloseButton">false</field> + <property name="_overPlayingIcon" readonly="true"> + <getter><![CDATA[ + let iconVisible = this.hasAttribute("soundplaying") || + this.hasAttribute("muted") || + this.hasAttribute("blocked"); + let soundPlayingIcon = + document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon"); + let overlayIcon = + document.getAnonymousElementByAttribute(this, "anonid", "overlay-icon"); + + return soundPlayingIcon && soundPlayingIcon.matches(":hover") || + (overlayIcon && overlayIcon.matches(":hover") && iconVisible); + ]]></getter> + </property> <field name="mCorrespondingMenuitem">null</field> <field name="closing">false</field> <field name="lastAccessed">0</field> + + <method name="toggleMuteAudio"> + <parameter name="aMuteReason"/> + <body> + <![CDATA[ + let tabContainer = this.parentNode; + let browser = this.linkedBrowser; + let modifiedAttrs = []; + if (browser.audioBlocked) { + this.removeAttribute("blocked"); + modifiedAttrs.push("blocked"); + + // We don't want sound icon flickering between "blocked", "none" and + // "sound-playing", here adding the "soundplaying" is to keep the + // transition smoothly. + if (!this.hasAttribute("soundplaying")) { + this.setAttribute("soundplaying", true); + modifiedAttrs.push("soundplaying"); + } + + browser.resumeMedia(); + } else { + if (browser.audioMuted) { + browser.unmute(); + this.removeAttribute("muted"); + } else { + browser.mute(); + this.setAttribute("muted", "true"); + } + this.muteReason = aMuteReason || null; + modifiedAttrs.push("muted"); + } + tabContainer.tabbrowser._tabAttrModified(this, modifiedAttrs); + ]]> + </body> + </method> </implementation> <handlers> @@ -4843,7 +5049,8 @@ if (this.selected) { this.style.MozUserFocus = 'ignore'; this.clientTop; // just using this to flush style updates - } else if (this.mOverCloseButton) { + } else if (this.mOverCloseButton || + this._overPlayingIcon) { // Prevent tabbox.xml from selecting the tab. event.stopPropagation(); } @@ -4852,6 +5059,17 @@ <handler event="mouseup"> this.style.MozUserFocus = ''; </handler> + <handler event="click"> + <![CDATA[ + if (event.button != 0) { + return; + } + + if (this._overPlayingIcon) { + this.toggleMuteAudio(); + } + ]]> + </handler> </handlers> </binding> @@ -4957,6 +5175,24 @@ aMenuitem.setAttribute("selected", "true"); else aMenuitem.removeAttribute("selected"); + + function addEndImage() { + let endImage = document.createElement("image"); + endImage.setAttribute("class", "allTabs-endimage"); + let endImageContainer = document.createElement("hbox"); + endImageContainer.setAttribute("align", "center"); + endImageContainer.setAttribute("pack", "center"); + endImageContainer.appendChild(endImage); + aMenuitem.appendChild(endImageContainer); + return endImage; + } + + if (aMenuitem.firstChild) + aMenuitem.firstChild.remove(); + if (aTab.hasAttribute("muted")) + addEndImage().setAttribute("muted", "true"); + else if (aTab.hasAttribute("soundplaying")) + addEndImage().setAttribute("soundplaying", "true"); ]]></body> </method> </implementation> diff --git a/application/palemoon/locales/en-US/chrome/browser/browser.dtd b/application/palemoon/locales/en-US/chrome/browser/browser.dtd index 2d80c8078..8632b44b4 100644 --- a/application/palemoon/locales/en-US/chrome/browser/browser.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/browser.dtd @@ -507,6 +507,8 @@ you can use these alternative items. Otherwise, their values should be empty. - <!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"> diff --git a/application/palemoon/locales/en-US/chrome/browser/browser.properties b/application/palemoon/locales/en-US/chrome/browser/browser.properties index 9969bd753..dbe6dbaa1 100644 --- a/application/palemoon/locales/en-US/chrome/browser/browser.properties +++ b/application/palemoon/locales/en-US/chrome/browser/browser.properties @@ -397,3 +397,8 @@ slowStartup.helpButton.label = Learn How to Speed It Up slowStartup.helpButton.accesskey = L slowStartup.disableNotificationButton.label = Don't Tell Me Again slowStartup.disableNotificationButton.accesskey = A + +muteTab.label = Mute Tab +muteTab.accesskey = M +unmuteTab.label = Unmute Tab +unmuteTab.accesskey = M
\ No newline at end of file diff --git a/application/palemoon/locales/en-US/chrome/browser/tabbrowser.properties b/application/palemoon/locales/en-US/chrome/browser/tabbrowser.properties index 0d21d4d14..a4a0be0a0 100644 --- a/application/palemoon/locales/en-US/chrome/browser/tabbrowser.properties +++ b/application/palemoon/locales/en-US/chrome/browser/tabbrowser.properties @@ -24,3 +24,7 @@ tabs.closeWarningTitle=Confirm close tabs.closeWarningMultipleTabs=You are about to close %S tabs. Are you sure you want to continue? tabs.closeButtonMultiple=Close tabs tabs.closeWarningPromptMe=Warn me when I attempt to close multiple tabs + +tabs.muteAudio.tooltip=Mute tab +tabs.unmuteAudio.tooltip=Unmute tab +tabs.unblockAudio.tooltip=Play tab diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css index c6587babc..516677fe6 100644 --- a/application/palemoon/themes/linux/browser.css +++ b/application/palemoon/themes/linux/browser.css @@ -1758,6 +1758,90 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- -moz-margin-end: -1px; } +/* Tab sound indicator */ +.tab-icon-sound { + -moz-margin-start: 4px; + width: 16px; + height: 16px; + padding: 0; +} + +.allTabs-endimage[soundplaying], +.tab-icon-sound[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio"); +} + +.allTabs-endimage[muted], +.tab-icon-sound[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted"); +} + +.allTabs-endimage[blocked], +.tab-icon-sound[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], +#TabsToolbar[brighttext] .tab-icon-sound[blocked], +#TabsToolbar[brighttext] .tab-icon-sound[muted] { + filter: invert(1); +} + +.tab-icon-sound[soundplaying-scheduledremoval]:not([muted]):not(:hover), +.tab-icon-overlay[soundplaying-scheduledremoval]:not([muted]):not(:hover) { + transition: opacity .3s linear var(--soundplaying-removal-delay); + opacity: 0; +} + +/* Tab icon overlay */ +.tab-icon-overlay { + width: 16px; + height: 16px; + margin-top: -8px; + margin-inline-start: -15px; + margin-inline-end: -1px; + position: relative; +} + +.tab-icon-overlay[soundplaying], +.tab-icon-overlay[muted]:not([crashed]), +.tab-icon-overlay[blocked]:not([crashed]) { + border-radius: 10px; +} + +.tab-icon-overlay[soundplaying]:hover, +.tab-icon-overlay[muted]:not([crashed]):hover, +.tab-icon-overlay[blocked]:not([crashed]):hover { + background-color: white; +} + +.tab-icon-overlay[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio"); +} + +.tab-icon-overlay[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted"); +} + +.tab-icon-overlay[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +.tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); +} + /* Tabstrip new tab button */ .tabs-newtab-button, #TabsToolbar > #new-tab-button , diff --git a/application/palemoon/themes/linux/jar.mn b/application/palemoon/themes/linux/jar.mn index 8b2e9dc77..8cb6878e8 100644 --- a/application/palemoon/themes/linux/jar.mn +++ b/application/palemoon/themes/linux/jar.mn @@ -123,6 +123,8 @@ browser.jar: skin/classic/browser/tabbrowser/tab.png (tabbrowser/tab.png) skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-audio.svg (../shared/tabbrowser/tab-audio.svg) + skin/classic/browser/tabbrowser/tab-audio-small.svg (../shared/tabbrowser/tab-audio-small.svg) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-16-throbber.png skin/classic/browser/sync-16.png diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css index a915af3a3..a7bd683bd 100644 --- a/application/palemoon/themes/osx/browser.css +++ b/application/palemoon/themes/osx/browser.css @@ -1821,6 +1821,90 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url- } } +/* Tab sound indicator */ +.tab-icon-sound { + -moz-margin-start: 4px; + width: 16px; + height: 16px; + padding: 0; +} + +.allTabs-endimage[soundplaying], +.tab-icon-sound[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio"); +} + +.allTabs-endimage[muted], +.tab-icon-sound[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted"); +} + +.allTabs-endimage[blocked], +.tab-icon-sound[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], +#TabsToolbar[brighttext] .tab-icon-sound[blocked], +#TabsToolbar[brighttext] .tab-icon-sound[muted] { + filter: invert(1); +} + +.tab-icon-sound[soundplaying-scheduledremoval]:not([muted]):not(:hover), +.tab-icon-overlay[soundplaying-scheduledremoval]:not([muted]):not(:hover) { + transition: opacity .3s linear var(--soundplaying-removal-delay); + opacity: 0; +} + +/* Tab icon overlay */ +.tab-icon-overlay { + width: 16px; + height: 16px; + margin-top: -8px; + margin-inline-start: -15px; + margin-inline-end: -1px; + position: relative; +} + +.tab-icon-overlay[soundplaying], +.tab-icon-overlay[muted]:not([crashed]), +.tab-icon-overlay[blocked]:not([crashed]) { + border-radius: 10px; +} + +.tab-icon-overlay[soundplaying]:hover, +.tab-icon-overlay[muted]:not([crashed]):hover, +.tab-icon-overlay[blocked]:not([crashed]):hover { + background-color: white; +} + +.tab-icon-overlay[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio"); +} + +.tab-icon-overlay[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted"); +} + +.tab-icon-overlay[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +.tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); +} + /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */ .tabbrowser-arrowscrollbox > .scrollbutton-up, diff --git a/application/palemoon/themes/osx/jar.mn b/application/palemoon/themes/osx/jar.mn index a66563989..1a11d0a30 100644 --- a/application/palemoon/themes/osx/jar.mn +++ b/application/palemoon/themes/osx/jar.mn @@ -166,6 +166,8 @@ browser.jar: skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png) skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-audio.svg (../shared/tabbrowser/tab-audio.svg) + skin/classic/browser/tabbrowser/tab-audio-small.svg (../shared/tabbrowser/tab-audio-small.svg) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-throbber.png skin/classic/browser/sync-16.png diff --git a/application/palemoon/themes/shared/tabbrowser/tab-audio-small.svg b/application/palemoon/themes/shared/tabbrowser/tab-audio-small.svg new file mode 100644 index 000000000..abfe71268 --- /dev/null +++ b/application/palemoon/themes/shared/tabbrowser/tab-audio-small.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16"> + <style> + .icon:not(:target) { + display: none; + } + + .icon { + fill: #262626; + } + .icon > .outline { + fill: #fff; + } + + .icon.white { + fill: #fff; + } + .icon.white > .outline { + fill: #000; + fill-opacity: .5; + } + </style> + + <g id="tab-audio" class="icon"> + <path class="outline" d="M12.4,3.6l-1-0.6l-0.9,2.5H10V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5H4C2.9,5,2,5.9,2,7v2c0,1.1,0.9,2,2,2h1.6l3.6,3.6 c0.3,0.3,0.9,0.1,0.9-0.4v-3.7h0.5l0.9,2.5l1-0.6C14,11.5,15,9.8,15,8S14,4.5,12.4,3.6z M9,13l-3-3H4c-0.6,0-1-0.4-1-1V7 c0-0.6,0.4-1,1-1h2l3-3V13z M10,9.5v-3c0.8,0,1.5,0.7,1.5,1.5S10.8,9.5,10,9.5z M11.9,11.5l-0.4-0.9C12.4,10,13,9.1,13,8 s-0.6-2-1.4-2.5l0.3-1C13.2,5.2,14,6.5,14,8S13.2,10.8,11.9,11.5z"/> + <path d="M4,6C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h2l3,3V3L6,6H4z M10,6.5v3c0.8,0,1.5-0.7,1.5-1.5S10.8,6.5,10,6.5z M11.9,4.5 l-0.4,0.9C12.4,6,13,6.9,13,8s-0.6,2-1.4,2.5l0.4,0.9c1.2-0.7,2.1-2,2.1-3.5S13.2,5.2,11.9,4.5z"/> + </g> + <g id="tab-audio-muted" class="icon"> + <path class="outline" d="M5.6,5H4C2.9,5,2,5.9,2,7v2c0,0.7,0.3,1.3,0.9,1.7l-1.8,1.8l2.5,2.5l3-3l2.6,2.6c0.3,0.3,0.9,0.1,0.9-0.4V8.5l3.9-3.9 l-2.5-2.5L10,3.5V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5z"/> + <path d="M11.5,3.5L9,5.9V3L6,6H4C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h0.9l-2.5,2.5l1.1,1.1l9-9L11.5,3.5z M9,13V9.7l-1.7,1.7L9,13z"/> + </g> + + <g id="tab-audio-white" class="icon white"> + <path class="outline" d="M12.4,3.6l-1-0.6l-0.9,2.5H10V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5H4C2.9,5,2,5.9,2,7v2c0,1.1,0.9,2,2,2h1.6l3.6,3.6 c0.3,0.3,0.9,0.1,0.9-0.4v-3.7h0.5l0.9,2.5l1-0.6C14,11.5,15,9.8,15,8S14,4.5,12.4,3.6z M9,13l-3-3H4c-0.6,0-1-0.4-1-1V7 c0-0.6,0.4-1,1-1h2l3-3V13z M10,9.5v-3c0.8,0,1.5,0.7,1.5,1.5S10.8,9.5,10,9.5z M11.9,11.5l-0.4-0.9C12.4,10,13,9.1,13,8 s-0.6-2-1.4-2.5l0.3-1C13.2,5.2,14,6.5,14,8S13.2,10.8,11.9,11.5z"/> + <path d="M4,6C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h2l3,3V3L6,6H4z M10,6.5v3c0.8,0,1.5-0.7,1.5-1.5S10.8,6.5,10,6.5z M11.9,4.5 l-0.4,0.9C12.4,6,13,6.9,13,8s-0.6,2-1.4,2.5l0.4,0.9c1.2-0.7,2.1-2,2.1-3.5S13.2,5.2,11.9,4.5z"/> + </g> + <g id="tab-audio-white-muted" class="icon white"> + <path class="outline" d="M5.6,5H4C2.9,5,2,5.9,2,7v2c0,0.7,0.3,1.3,0.9,1.7l-1.8,1.8l2.5,2.5l3-3l2.6,2.6c0.3,0.3,0.9,0.1,0.9-0.4V8.5l3.9-3.9 l-2.5-2.5L10,3.5V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5z"/> + <path d="M11.5,3.5L9,5.9V3L6,6H4C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h0.9l-2.5,2.5l1.1,1.1l9-9L11.5,3.5z M9,13V9.7l-1.7,1.7L9,13z"/> + </g> + + <g id="tab-audio-blocked" class="icon"> + <path class="outline" d="M8,1.2C4.3,1.2,1.2,4.3,1.2,8s3.1,6.8,6.8,6.8s6.8-3.1,6.8-6.8S11.7,1.2,8,1.2z M8,11.9 + c-2.1,0-3.9-1.7-3.9-3.9c0-2.1,1.7-3.9,3.9-3.9s3.9,1.7,3.9,3.9C11.9,10.1,10.1,11.9,8,11.9z M11.1,7.3L6.6,4.6L5.4,3.9v1.4v5.3V12 + l1.2-0.7L11,8.6L12.2,8L11.1,7.3z"/> + <path d="M8,2C4.7,2,2,4.7,2,8s2.7,6,6,6s6-2.7,6-6S11.3,2,8,2z M8,12.7c-2.6,0-4.7-2.1-4.7-4.7 + S5.4,3.3,8,3.3s4.7,2.1,4.7,4.7S10.6,12.7,8,12.7z M10.7,8L6.2,5.3v5.4L10.7,8z"/> + </g> + <g id="tab-audio-white-blocked" class="icon"> + <path class="outline" d="M8,0c3.3,0,6.4,2.2,7.5,5.3c1.1,3.1,0.1,6.7-2.5,8.9c-2.6,2.1-6.3,2.4-9.2,0.7 + C1,13.1-0.5,9.8,0.1,6.5C0.9,2.8,4.2,0,8,0z"/> + <path d="M8,2C4.7,2,2,4.7,2,8s2.7,6,6,6s6-2.7,6-6S11.3,2,8,2z M8,12.7c-2.6,0-4.7-2.1-4.7-4.7 + S5.4,3.3,8,3.3s4.7,2.1,4.7,4.7S10.6,12.7,8,12.7z M10.7,8L6.2,5.3v5.4L10.7,8z"/> + </g> +</svg> diff --git a/application/palemoon/themes/shared/tabbrowser/tab-audio.svg b/application/palemoon/themes/shared/tabbrowser/tab-audio.svg new file mode 100644 index 000000000..274e10c29 --- /dev/null +++ b/application/palemoon/themes/shared/tabbrowser/tab-audio.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <style> + path:not(:target) { + display: none; + } + </style> + + <path id="tab-audio" d="M4,5C2.9,5,2,5.9,2,7v2c0,1.1,0.9,2,2,2h1.2L9,14V2L5.2,5H4z M11,8c0-0.6-0.4-1-1-1v2C10.6,9,11,8.6,11,8z M13,8 c0-1.4-1-2.6-2.3-2.9L10.4,6C11.3,6.2,12,7,12,8s-0.7,1.8-1.6,2l0.4,0.9C12,10.6,13,9.4,13,8z M11.4,3.2l-0.4,0.9 C12.8,4.6,14,6.2,14,8s-1.2,3.4-2.9,3.8l0.4,0.9C13.5,12.2,15,10.3,15,8S13.5,3.8,11.4,3.2z"/> + + <path id="tab-audio-muted" d="M12.5,3.4L9,6.3V2L5.2,5H4C2.9,5,2,5.9,2,7v2c0,0.9,0.6,1.6,1.4,1.9l-1.9,1.5l1,1.2l11-9L12.5,3.4z M9,14v-4l-2.5,2L9,14z"/> + + <path id="tab-audio-blocked" d="M8,0C3.6,0,0,3.6,0,8s3.6,8,8,8s8-3.6,8-8S12.4,0,8,0z M5.6,11.6l6-3.6l-6-3.6V11.6z M8,14.2 + c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/> +</svg> diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css index e4f5f679f..f921554df 100644 --- a/application/palemoon/themes/windows/browser.css +++ b/application/palemoon/themes/windows/browser.css @@ -2018,6 +2018,90 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://global/skin/icons/close-inverted.svg"); } +/* Tab sound indicator */ +.tab-icon-sound { + -moz-margin-start: 4px; + width: 16px; + height: 16px; + padding: 0; +} + +.allTabs-endimage[soundplaying], +.tab-icon-sound[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio"); +} + +.allTabs-endimage[muted], +.tab-icon-sound[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted"); +} + +.allTabs-endimage[blocked], +.tab-icon-sound[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], +#TabsToolbar[brighttext] .tab-icon-sound[blocked], +#TabsToolbar[brighttext] .tab-icon-sound[muted] { + filter: invert(1); +} + +.tab-icon-sound[soundplaying-scheduledremoval]:not([muted]):not(:hover), +.tab-icon-overlay[soundplaying-scheduledremoval]:not([muted]):not(:hover) { + transition: opacity .3s linear var(--soundplaying-removal-delay); + opacity: 0; +} + +/* Tab icon overlay */ +.tab-icon-overlay { + width: 16px; + height: 16px; + margin-top: -8px; + margin-inline-start: -15px; + margin-inline-end: -1px; + position: relative; +} + +.tab-icon-overlay[soundplaying], +.tab-icon-overlay[muted]:not([crashed]), +.tab-icon-overlay[blocked]:not([crashed]) { + border-radius: 10px; +} + +.tab-icon-overlay[soundplaying]:hover, +.tab-icon-overlay[muted]:not([crashed]):hover, +.tab-icon-overlay[blocked]:not([crashed]):hover { + background-color: white; +} + +.tab-icon-overlay[soundplaying] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio"); +} + +.tab-icon-overlay[muted] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted"); +} + +.tab-icon-overlay[blocked] { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +.tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); +} + +#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +.tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); +} + /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */ .tabbrowser-arrowscrollbox > .scrollbutton-up, diff --git a/application/palemoon/themes/windows/jar.mn b/application/palemoon/themes/windows/jar.mn index eb5edb3c1..724bac689 100644 --- a/application/palemoon/themes/windows/jar.mn +++ b/application/palemoon/themes/windows/jar.mn @@ -150,6 +150,8 @@ browser.jar: skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png) skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-audio.svg (../shared/tabbrowser/tab-audio.svg) + skin/classic/browser/tabbrowser/tab-audio-small.svg (../shared/tabbrowser/tab-audio-small.svg) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-throbber.png skin/classic/browser/sync-16.png |