diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 6d8ddf2caca..7875c3d7866 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -426,11 +426,10 @@ pref("browser.tabs.loadDivertedInBackground", false); pref("browser.tabs.loadBookmarksInBackground", false); pref("browser.tabs.tabClipWidth", 140); pref("browser.tabs.animate", true); -pref("browser.tabs.onTop", true); -#ifdef XP_WIN -pref("browser.tabs.drawInTitlebar", true); -#else +#ifdef UNIX_BUT_NOT_MAC pref("browser.tabs.drawInTitlebar", false); +#else +pref("browser.tabs.drawInTitlebar", true); #endif // Where to show tab close buttons: @@ -1285,3 +1284,6 @@ pref("dom.debug.propagate_gesture_events_through_content", false); // The request URL of the GeoLocation backend. pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%"); + +// CustomizableUI debug logging. +pref("browser.uiCustomization.debug", false); diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js index b638f31f9ea..c63fea50b88 100644 --- a/browser/base/content/browser-addons.js +++ b/browser/base/content/browser-addons.js @@ -415,3 +415,58 @@ var LightWeightThemeWebInstaller = { node.baseURI); } } + +/* + * Listen for Lightweight Theme styling changes and update the browser's theme accordingly. + */ +let LightweightThemeListener = { + _modifiedStyles: [], + + init: function () { + XPCOMUtils.defineLazyGetter(this, "styleSheet", function() { + for (let i = document.styleSheets.length - 1; i >= 0; i--) { + let sheet = document.styleSheets[i]; + if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css") + return sheet; + } + }); + + Services.obs.addObserver(this, "lightweight-theme-styling-update", false); + if (document.documentElement.hasAttribute("lwtheme")) + this.updateStyleSheet(document.documentElement.style.backgroundImage); + }, + + uninit: function () { + Services.obs.removeObserver(this, "lightweight-theme-styling-update"); + }, + + /** + * Append the headerImage to the background-image property of all rulesets in + * browser-lightweightTheme.css. + * + * @param headerImage - a string containing a CSS image for the lightweight theme header. + */ + updateStyleSheet: function(headerImage) { + if (!this.styleSheet) + return; + for (let i = 0; i < this.styleSheet.cssRules.length; i++) { + let rule = this.styleSheet.cssRules[i]; + if (!rule.style.backgroundImage) + continue; + + if (!this._modifiedStyles[i]) + this._modifiedStyles[i] = { backgroundImage: rule.style.backgroundImage }; + + rule.style.backgroundImage = this._modifiedStyles[i].backgroundImage + ", " + headerImage; + } + }, + + // nsIObserver + observe: function (aSubject, aTopic, aData) { + if (aTopic != "lightweight-theme-styling-update" || !this.styleSheet) + return; + + let themeData = JSON.parse(aData); + this.updateStyleSheet("url(" + themeData.headerURL + ")"); + }, +}; diff --git a/browser/base/content/browser-appmenu.inc b/browser/base/content/browser-appmenu.inc deleted file mode 100644 index ecb3b8d5324..00000000000 --- a/browser/base/content/browser-appmenu.inc +++ /dev/null @@ -1,400 +0,0 @@ -# -*- Mode: HTML -*- -# 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/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#define ID_PREFIX appmenu_developer_ -#define OMIT_ACCESSKEYS -#include browser-charsetmenu.inc -#undef ID_PREFIX -#undef OMIT_ACCESSKEYS - - - - -#define ID_PREFIX appmenu_ -#define OMIT_ACCESSKEYS -#include browser-charsetmenu.inc -#undef ID_PREFIX -#undef OMIT_ACCESSKEYS - -#ifdef MOZ_SERVICES_SYNC - - - -#endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#ifdef MOZ_SERVICES_SYNC - -#endif - - - - - - - - - - - - - - - - - - - - - - - - - - -#ifdef MOZ_SERVICES_HEALTHREPORT - -#endif - - - - - - - - - - - diff --git a/browser/base/content/browser-customization.js b/browser/base/content/browser-customization.js new file mode 100644 index 00000000000..3de2174c2e5 --- /dev/null +++ b/browser/base/content/browser-customization.js @@ -0,0 +1,99 @@ +# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# 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/. + +/** + * Customization handler prepares this browser window for entering and exiting + * customization mode by handling customizationstarting and customizationending + * events. + */ +let CustomizationHandler = { + handleEvent: function(aEvent) { + switch(aEvent.type) { + case "customizationstarting": + this._customizationStarting(); + break; + case "customizationending": + this._customizationEnding(aEvent.detail); + break; + } + }, + + _customizationStarting: function() { + // Disable the toolbar context menu items + let menubar = document.getElementById("main-menubar"); + for (let childNode of menubar.childNodes) + childNode.setAttribute("disabled", true); + + let cmd = document.getElementById("cmd_CustomizeToolbars"); + cmd.setAttribute("disabled", "true"); + + let splitter = document.getElementById("urlbar-search-splitter"); + if (splitter) { + splitter.parentNode.removeChild(splitter); + } + + CombinedStopReload.uninit(); + PlacesToolbarHelper.customizeStart(); + BookmarkingUI.customizeStart(); + DownloadsButton.customizeStart(); + }, + + _customizationEnding: function(aDetails) { + // Update global UI elements that may have been added or removed + if (aDetails.changed) { + gURLBar = document.getElementById("urlbar"); + + gProxyFavIcon = document.getElementById("page-proxy-favicon"); + gHomeButton.updateTooltip(); + gIdentityHandler._cacheElements(); + XULBrowserWindow.init(); + +#ifndef XP_MACOSX + updateEditUIVisibility(); +#endif + + // Hacky: update the PopupNotifications' object's reference to the iconBox, + // if it already exists, since it may have changed if the URL bar was + // added/removed. + if (!window.__lookupGetter__("PopupNotifications")) { + PopupNotifications.iconBox = + document.getElementById("notification-popup-box"); + } + + } + + PlacesToolbarHelper.customizeDone(); + BookmarkingUI.customizeDone(); + DownloadsButton.customizeDone(); + + // The url bar splitter state is dependent on whether stop/reload + // and the location bar are combined, so we need this ordering + CombinedStopReload.init(); + UpdateUrlbarSearchSplitterState(); + setUrlAndSearchBarWidthForConditionalForwardButton(); + + // Update the urlbar + if (gURLBar) { + URLBarSetURI(); + XULBrowserWindow.asyncUpdateUI(); + BookmarkingUI.updateStarState(); + SocialMark.updateMarkState(); + } + + // Re-enable parts of the UI we disabled during the dialog + let menubar = document.getElementById("main-menubar"); + for (let childNode of menubar.childNodes) + childNode.setAttribute("disabled", false); + let cmd = document.getElementById("cmd_CustomizeToolbars"); + cmd.removeAttribute("disabled"); + + // make sure to re-enable click-and-hold + if (!getBoolPref("ui.click_hold_context_menus", false)) { + SetClickAndHoldHandlers(); + } + + gBrowser.selectedBrowser.focus(); + } +} diff --git a/browser/base/content/browser-feeds.js b/browser/base/content/browser-feeds.js index 7bba3954082..5b432ede2f9 100644 --- a/browser/base/content/browser-feeds.js +++ b/browser/base/content/browser-feeds.js @@ -8,66 +8,50 @@ * and shows UI when they are discovered. */ var FeedHandler = { - /** - * The click handler for the Feed icon in the toolbar. Opens the - * subscription page if user is not given a choice of feeds. - * (Otherwise the list of available feeds will be presented to the - * user in a popup menu.) - */ - onFeedButtonClick: function(event) { - event.stopPropagation(); - - let feeds = gBrowser.selectedBrowser.feeds || []; - // If there are multiple feeds, the menu will open, so no need to do - // anything. If there are no feeds, nothing to do either. - if (feeds.length != 1) - return; - - if (event.eventPhase == Event.AT_TARGET && - (event.button == 0 || event.button == 1)) { - this.subscribeToFeed(feeds[0].href, event); - } - }, - - /** Called when the user clicks on the Subscribe to This Page... menu item. + /** Called when the user clicks on the Subscribe to This Page... menu item, + * or when the user clicks the feed button when the page contains multiple + * feeds. * Builds a menu of unique feeds associated with the page, and if there * is only one, shows the feed inline in the browser window. - * @param menuPopup - * The feed list menupopup to be populated. - * @returns true if the menu should be shown, false if there was only + * @param container + * The feed list container (menupopup or subview) to be populated. + * @param isSubview + * Whether we're creating a subview (true) or menu (false/undefined) + * @returns true if the menu/subview should be shown, false if there was only * one feed and the feed should be shown inline in the browser - * window (do not show the menupopup). + * window (do not show the menupopup/subview). */ - buildFeedList: function(menuPopup) { + buildFeedList: function(container, isSubview) { var feeds = gBrowser.selectedBrowser.feeds; - if (feeds == null) { + if (!isSubview && feeds == null) { // XXX hack -- menu opening depends on setting of an "open" // attribute, and the menu refuses to open if that attribute is // set (because it thinks it's already open). onpopupshowing gets // called after the attribute is unset, and it doesn't get unset // if we return false. so we unset it here; otherwise, the menu // refuses to work past this point. - menuPopup.parentNode.removeAttribute("open"); + container.parentNode.removeAttribute("open"); return false; } - while (menuPopup.firstChild) - menuPopup.removeChild(menuPopup.firstChild); + while (container.firstChild) + container.removeChild(container.firstChild); - if (feeds.length <= 1) + if (!feeds || feeds.length <= 1) return false; // Build the menu showing the available feed choices for viewing. + var itemNodeType = isSubview ? "toolbarbutton" : "menuitem"; for (let feedInfo of feeds) { - var menuItem = document.createElement("menuitem"); + var item = document.createElement(itemNodeType); var baseTitle = feedInfo.title || feedInfo.href; var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); - menuItem.setAttribute("class", "feed-menuitem"); - menuItem.setAttribute("label", labelStr); - menuItem.setAttribute("feed", feedInfo.href); - menuItem.setAttribute("tooltiptext", feedInfo.href); - menuItem.setAttribute("crop", "center"); - menuPopup.appendChild(menuItem); + item.setAttribute("class", "feed-" + itemNodeType); + item.setAttribute("label", labelStr); + item.setAttribute("feed", feedInfo.href); + item.setAttribute("tooltiptext", feedInfo.href); + item.setAttribute("crop", "center"); + container.appendChild(item); } return true; }, @@ -76,7 +60,7 @@ var FeedHandler = { * Subscribe to a given feed. Called when * 1. Page has a single feed and user clicks feed icon in location bar * 2. Page has a single feed and user selects Subscribe menu item - * 3. Page has multiple feeds and user selects from feed icon popup + * 3. Page has multiple feeds and user selects from feed icon popup (or subview) * 4. Page has multiple feeds and user selects from Subscribe submenu * @param href * The feed to subscribe to. May be null, in which case the diff --git a/browser/base/content/browser-fullScreen.js b/browser/base/content/browser-fullScreen.js index a8ffa754ad0..a89d42b4bbf 100644 --- a/browser/base/content/browser-fullScreen.js +++ b/browser/base/content/browser-fullScreen.js @@ -17,7 +17,7 @@ var FullScreen = { enterFS = !enterFS; // Toggle the View:FullScreen command, which controls elements like the - // fullscreen menuitem, menubars, and the appmenu. + // fullscreen menuitem, and menubars. let fullscreenCommand = document.getElementById("View:FullScreen"); if (enterFS) { fullscreenCommand.setAttribute("checked", enterFS); @@ -517,15 +517,6 @@ var FullScreen = { // XXX don't interfere with previously collapsed toolbars if (el.getAttribute("fullscreentoolbar") == "true") { if (!aShow) { - - var toolbarMode = el.getAttribute("mode"); - if (toolbarMode != "text") { - el.setAttribute("saved-mode", toolbarMode); - el.setAttribute("saved-iconsize", el.getAttribute("iconsize")); - el.setAttribute("mode", "icons"); - el.setAttribute("iconsize", "small"); - } - // Give the main nav bar and the tab bar the fullscreen context menu, // otherwise remove context menu to prevent breakage el.setAttribute("saved-context", el.getAttribute("context")); @@ -539,18 +530,8 @@ var FullScreen = { el.setAttribute("inFullscreen", true); } else { - var restoreAttr = function restoreAttr(attrName) { - var savedAttr = "saved-" + attrName; - if (el.hasAttribute(savedAttr)) { - el.setAttribute(attrName, el.getAttribute(savedAttr)); - el.removeAttribute(savedAttr); - } - } - - restoreAttr("mode"); - restoreAttr("iconsize"); - restoreAttr("context"); - + el.setAttribute("context", el.getAttribute("saved-context")); + el.removeAttribute("saved-context"); el.removeAttribute("inFullscreen"); } } else { @@ -571,11 +552,9 @@ var FullScreen = { document.documentElement.setAttribute("inFullscreen", true); } - // In tabs-on-top mode, move window controls to the tab bar, - // and in tabs-on-bottom mode, move them back to the navigation toolbar. var fullscreenctls = document.getElementById("window-controls"); var navbar = document.getElementById("nav-bar"); - var ctlsOnTabbar = window.toolbar.visible && (navbar.collapsed || TabsOnTop.enabled); + var ctlsOnTabbar = window.toolbar.visible; if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) { fullscreenctls.removeAttribute("flex"); document.getElementById("TabsToolbar").appendChild(fullscreenctls); diff --git a/browser/base/content/browser-fullZoom.js b/browser/base/content/browser-fullZoom.js index 90e9e222200..4fac1744f78 100644 --- a/browser/base/content/browser-fullZoom.js +++ b/browser/base/content/browser-fullZoom.js @@ -390,6 +390,7 @@ var FullZoom = { * prefs store. */ _applyZoomToPref: function FullZoom__applyZoomToPref() { + Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", ""); if (!this.siteSpecific || gInPrintPreviewMode || content.document.mozSyntheticDocument) @@ -407,6 +408,7 @@ var FullZoom = { * Removes from the content prefs store the zoom level of the current browser. */ _removePref: function FullZoom__removePref() { + Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", ""); if (content.document.mozSyntheticDocument) return; let ctxt = this._loadContextFromWindow(gBrowser.contentWindow); @@ -417,6 +419,7 @@ var FullZoom = { }); }, + //**************************************************************************// // Utilities diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 56cf72ceb8d..bf565647ef4 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -185,11 +185,6 @@ accesskey="&viewToolbarsMenu.accesskey;"> - 0) { - this.star.setAttribute("starred", "true"); - this.star.setAttribute("tooltiptext", this._starredTooltip); + this.button.setAttribute("starred", "true"); + this.button.setAttribute("tooltiptext", this._starredTooltip); } else { - this.star.removeAttribute("starred"); - this.star.setAttribute("tooltiptext", this._unstarredTooltip); + this.button.removeAttribute("starred"); + this.button.setAttribute("tooltiptext", this._unstarredTooltip); } }, @@ -1238,6 +1244,10 @@ let BookmarkingUI = { // nsINavBookmarkObserver onItemAdded: function BUI_onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI) { + if (!this.button) { + return; + } + if (aURI && aURI.equals(this._uri)) { // If a new bookmark has been added to the tracked uri, register it. if (this._itemIds.indexOf(aItemId) == -1) { @@ -1248,6 +1258,10 @@ let BookmarkingUI = { }, onItemRemoved: function BUI_onItemRemoved(aItemId) { + if (!this.button) { + return; + } + let index = this._itemIds.indexOf(aItemId); // If one of the tracked bookmarks has been removed, unregister it. if (index != -1) { @@ -1258,6 +1272,10 @@ let BookmarkingUI = { onItemChanged: function BUI_onItemChanged(aItemId, aProperty, aIsAnnotationProperty, aNewValue) { + if (!this.button) { + return; + } + if (aProperty == "uri") { let index = this._itemIds.indexOf(aItemId); // If the changed bookmark was tracked, check if it is now pointing to diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index e17d5252e87..b36f86635d5 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -32,7 +32,6 @@ - diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index 037235209bc..f6f37a6ec46 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -797,9 +797,7 @@ SocialShare = { iframe.setAttribute("src", shareEndpoint); let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon"); + let anchor = document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon"); this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); Social.setErrorListener(iframe, this.setErrorMessage.bind(this)); }, @@ -1238,9 +1236,7 @@ SocialToolbar = { }); let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); + let anchor = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); // Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup // handling from preventing it being opened in some cases. setTimeout(function() { diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js index f6ad77999f2..7fa4cd4a70c 100644 --- a/browser/base/content/browser-tabview.js +++ b/browser/base/content/browser-tabview.js @@ -420,16 +420,13 @@ let TabView = { let toolbar = document.getElementById("TabsToolbar"); let currentSet = toolbar.currentSet.split(","); - let alltabsPos = currentSet.indexOf("alltabs-button"); if (-1 == alltabsPos) return; - currentSet[alltabsPos] += "," + buttonId; - currentSet = currentSet.join(","); - toolbar.currentSet = currentSet; - toolbar.setAttribute("currentset", currentSet); - document.persist(toolbar.id, "currentset"); + let allTabsBtn = document.getElementById("alltabs-button"); + let nextItem = allTabsBtn.nextSibling; + toolbar.insertItem(buttonId, nextItem); }, // ---------- diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index b634dbd9fd2..5ded86c092e 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -13,6 +13,37 @@ browser[remote="true"] { -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser"); } +toolbar[customizable="true"] { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar"); +} + +%ifdef XP_MACOSX +toolbar[customizable="true"]:not([nowindowdrag="true"]) { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); +} +%endif + +#toolbar-menubar[autohide="true"] { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide"); +} + +panelmultiview { + -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview"); +} + +panelview { + -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview"); + -moz-box-orient: vertical; +} + +.panel-mainview { + transition: transform 150ms; +} + +panelview:not([mainview]):not([current]) { + display: none; +} + tabbrowser { -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser"); } @@ -39,11 +70,11 @@ tabbrowser { .tabbrowser-tab:not([pinned]) { -moz-box-flex: 100; - max-width: 250px; + max-width: 180px; min-width: 100px; width: 0; transition: min-width 200ms ease-out, - max-width 250ms ease-out, + max-width 230ms ease-out, opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */; } @@ -52,8 +83,8 @@ tabbrowser { min-width: 0.1px; opacity: 0 !important; transition: min-width 200ms ease-out, - max-width 250ms ease-out, - opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */; + max-width 230ms ease-out, + opacity 50ms ease-out 160ms /* hide the tab for the last 20ms of the max-width transition */; } .tab-throbber:not([fadein]):not([pinned]), @@ -86,20 +117,13 @@ toolbar[printpreview="true"] { -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar"); } -#toolbar-menubar { - -moz-box-ordinal-group: 5; +toolbar[overflowable] > .customization-target { + overflow: hidden; } -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - -moz-box-ordinal-group: 50; -} - -#TabsToolbar { - -moz-box-ordinal-group: 100; -} - -#TabsToolbar[tabsontop="true"] { - -moz-box-ordinal-group: 10; +toolbar[customizing][overflowable] > .overflow-button, +toolbar[overflowable]:not([overflowing]) > .overflow-button { + display: none; } %ifdef CAN_DRAW_IN_TITLEBAR @@ -117,10 +141,26 @@ toolbar[printpreview="true"] { pointer-events: none; } -#main-window[tabsintitlebar] #appmenu-button-container, #main-window[tabsintitlebar] #titlebar-buttonbox { position: relative; } + +#titlebar-buttonbox { + -moz-appearance: -moz-window-button-box; +} + +%ifdef XP_MACOSX +#titlebar-fullscreen-button { + -moz-appearance: -moz-mac-fullscreen-button; +} +%endif + +%ifdef XP_WIN +#main-window[sizemode="maximized"] #titlebar-buttonbox { + -moz-appearance: -moz-window-button-box-maximized; +} +%endif + %endif .bookmarks-toolbar-customize, @@ -132,28 +172,27 @@ toolbar[printpreview="true"] { display: -moz-box; } -#main-window[disablechrome] #navigator-toolbox[tabsontop="true"] > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - visibility: collapse; -} - #wrapper-urlbar-container #urlbar-container > #urlbar > toolbarbutton, #urlbar-container:not([combined]) > #urlbar > toolbarbutton, #urlbar-container[combined] + #reload-button + #stop-button, #urlbar-container[combined] + #reload-button, -toolbar:not([mode="icons"]) > #urlbar-container > #urlbar > toolbarbutton, -toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button:not([displaystop]) + #urlbar-stop-button, -toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button[displaystop], -toolbar[mode="icons"] > #reload-button:not([displaystop]) + #stop-button, -toolbar[mode="icons"] > #reload-button[displaystop] { +#urlbar-reload-button:not([displaystop]) + #urlbar-stop-button, +#urlbar-reload-button[displaystop], +#reload-button:not([displaystop]) + #stop-button, +#reload-button[displaystop] { visibility: collapse; } -#feed-button > .toolbarbutton-menu-dropmarker { - display: none; +#PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) { + direction: rtl; } -#feed-menu > .feed-menuitem:-moz-locale-dir(rtl) { - direction: rtl; +#urlbar-container { + min-width: 50ch; +} + +#search-container { + min-width: 25ch; } #main-window:-moz-lwtheme { @@ -172,27 +211,6 @@ toolbar[mode="icons"] > #reload-button[displaystop] { background-position: bottom left; } -splitmenu { - -moz-binding: url("chrome://browser/content/urlbarBindings.xml#splitmenu"); -} - -.splitmenu-menuitem { - -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem"); - list-style-image: inherit; - -moz-image-region: inherit; -} - -.splitmenu-menuitem[iconic="true"] { - -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic"); -} - -.splitmenu-menu > .menu-text, -:-moz-any(.splitmenu-menu, .splitmenu-menuitem) > .menu-accel-container, -#appmenu-editmenu > .menu-text, -#appmenu-editmenu > .menu-accel-container { - display: none; -} - .menuitem-tooltip { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-tooltip"); } @@ -203,18 +221,6 @@ splitmenu { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-iconic-tooltip"); } -%ifdef MENUBAR_CAN_AUTOHIDE -%ifndef CAN_DRAW_IN_TITLEBAR -#appmenu-toolbar-button > .toolbarbutton-text { - display: -moz-box; -} -%endif - -#appmenu_offlineModeRecovery:not([checked=true]) { - display: none; -} -%endif - /* Hide menu elements intended for keyboard access support */ #main-menubar[openedwithkey=false] .show-only-for-keyboard { display: none; @@ -308,18 +314,20 @@ toolbarbutton.bookmark-item { max-width: 13em; } -%ifdef MENUBAR_CAN_AUTOHIDE -#toolbar-menubar:not([autohide="true"]) ~ toolbar > #bookmarks-menu-button, -#toolbar-menubar:not([autohide="true"]) > #bookmarks-menu-button { - display: none; -} -%endif - #editBMPanel_tagsSelector { /* override default listbox width from xul.css */ width: auto; } +/* The star doesn't make sense as text */ +toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + display: -moz-box !important; +} +toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text, +toolbar[mode="full"] #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-text { + display: none; +} + menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result { display: none; } @@ -438,14 +446,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m min-width: 1px; } -#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon { - display: -moz-box; -} - -#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text { - display: none; -} - /* ::::: Ctrl-Tab Panel ::::: */ .ctrlTab-preview > html|img, diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 977a1be0bbb..e0395044c17 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -91,6 +91,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils", "resource:///modules/AboutHomeUtils.jsm"); +XPCOMUtils.defineLazyGetter(this, "gCustomizeMode", function() { + let scope = {}; + Cu.import("resource:///modules/CustomizeMode.jsm", scope); + return new scope.CustomizeMode(window); +}); + #ifdef MOZ_SERVICES_SYNC XPCOMUtils.defineLazyModuleGetter(this, "Weave", "resource://services-sync/main.js"); @@ -147,6 +153,7 @@ let gInitialPages = [ ]; #include browser-addons.js +#include browser-customization.js #include browser-feeds.js #include browser-fullScreen.js #include browser-fullZoom.js @@ -940,13 +947,12 @@ var gBrowserInit = { goSetCommandEnabled("cmd_newNavigatorTab", false); } -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); +#ifdef CAN_DRAW_IN_TITLEBAR + updateTitlebarDisplay(); #endif // Misc. inits. CombinedStopReload.init(); - TabsOnTop.init(); gPrivateBrowsingUI.init(); TabsInTitlebar.init(); retrieveToolbarIconsizesFromTheme(); @@ -1035,7 +1041,13 @@ var gBrowserInit = { OfflineApps.init(); IndexedDBPromptHelper.init(); gFormSubmitObserver.init(); + // Initialize the full zoom setting. + // We do this before the session restore service gets initialized so we can + // apply full zoom settings to tabs restored by the session restore service. + FullZoom.init(); + PanelUI.init(); SocialUI.init(); + LightweightThemeListener.init(); AddonManager.addAddonListener(AddonsMgrListener); WebrtcIndicator.init(); @@ -1082,11 +1094,6 @@ var gBrowserInit = { if (!getBoolPref("ui.click_hold_context_menus", false)) SetClickAndHoldHandlers(); - // Initialize the full zoom setting. - // We do this before the session restore service gets initialized so we can - // apply full zoom settings to tabs restored by the session restore service. - FullZoom.init(); - // Bug 666804 - NetworkPrioritizer support for e10s if (!gMultiProcessBrowser) { let NP = {}; @@ -1221,15 +1228,6 @@ var gBrowserInit = { cmd.removeAttribute("hidden"); } -#ifdef MENUBAR_CAN_AUTOHIDE - // If the user (or the locale) hasn't enabled the top-level "Character - // Encoding" menu via the "browser.menu.showCharacterEncoding" preference, - // hide it. - if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding", - Ci.nsIPrefLocalizedString).data) - document.getElementById("appmenu_charsetMenu").hidden = true; -#endif - // Enable Responsive UI? let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled"); if (responsiveUIEnabled) { @@ -1241,26 +1239,14 @@ var gBrowserInit = { // Add Devtools menuitems and listeners gDevToolsBrowser.registerBrowserWindow(window); - let appMenuButton = document.getElementById("appmenu-button"); - let appMenuPopup = document.getElementById("appmenu-popup"); - if (appMenuButton && appMenuPopup) { - let appMenuOpening = null; - appMenuButton.addEventListener("mousedown", function(event) { - if (event.button == 0) - appMenuOpening = new Date(); - }, false); - appMenuPopup.addEventListener("popupshown", function(event) { - if (event.target != appMenuPopup || !appMenuOpening) - return; - let duration = new Date() - appMenuOpening; - appMenuOpening = null; - Services.telemetry.getHistogramById("FX_APP_MENU_OPEN_MS").add(duration); - }, false); - } - window.addEventListener("mousemove", MousePosTracker, false); window.addEventListener("dragover", MousePosTracker, false); + gNavToolbox.addEventListener("customizationstarting", CustomizationHandler); + gNavToolbox.addEventListener("customizationending", CustomizationHandler); + + gCustomizeMode.init(); + // End startup crash tracking after a delay to catch crashes while restoring // tabs and to postpone saving the pref to disk. try { @@ -1319,8 +1305,6 @@ var gBrowserInit = { BookmarkingUI.uninit(); - TabsOnTop.uninit(); - TabsInTitlebar.uninit(); var enumerator = Services.wm.getEnumerator(null); @@ -1373,6 +1357,9 @@ var gBrowserInit = { IndexedDBPromptHelper.uninit(); AddonManager.removeAddonListener(AddonsMgrListener); SocialUI.uninit(); + LightweightThemeListener.uninit(); + gCustomizeMode.uninit(); + PanelUI.uninit(); } // Final window teardown, do this last. @@ -2679,8 +2666,8 @@ var PrintPreviewListener = { if (this._chromeState.sidebarOpen) toggleSidebar(this._sidebarCommand); -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); +#ifdef CAN_DRAW_IN_TITLEBAR + updateTitlebarDisplay(); #endif }, _hideChrome: function () { @@ -2800,35 +2787,6 @@ function openHomeDialog(aURL) } } -var bookmarksButtonObserver = { - onDrop: function (aEvent) - { - let name = { }; - let url = browserDragAndDrop.drop(aEvent, name); - try { - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: makeURI(url) - , title: name - , hiddenRows: [ "description" - , "location" - , "loadInSidebar" - , "keyword" ] - }, window); - } catch(ex) { } - }, - - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - aEvent.dropEffect = "link"; - }, - - onDragExit: function (aEvent) - { - } -} - var newTabButtonObserver = { onDragOver: function (aEvent) { @@ -3345,131 +3303,18 @@ function OpenBrowserWindow(options) return win; } -var gCustomizeSheet = false; +//XXXunf Are these still useful to keep around? function BrowserCustomizeToolbar() { - // Disable the toolbar context menu items - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", true); - - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.setAttribute("disabled", "true"); - - var splitter = document.getElementById("urlbar-search-splitter"); - if (splitter) - splitter.parentNode.removeChild(splitter); - - CombinedStopReload.uninit(); - - PlacesToolbarHelper.customizeStart(); - BookmarkingUI.customizeStart(); - DownloadsButton.customizeStart(); - - TabsInTitlebar.allowedBy("customizing-toolbars", false); - - var customizeURL = "chrome://global/content/customizeToolbar.xul"; - gCustomizeSheet = getBoolPref("toolbar.customization.usesheet", false); - - if (gCustomizeSheet) { - let sheetFrame = document.createElement("iframe"); - let panel = document.getElementById("customizeToolbarSheetPopup"); - sheetFrame.id = "customizeToolbarSheetIFrame"; - sheetFrame.toolbox = gNavToolbox; - sheetFrame.panel = panel; - sheetFrame.setAttribute("style", panel.getAttribute("sheetstyle")); - panel.appendChild(sheetFrame); - - // Open the panel, but make it invisible until the iframe has loaded so - // that the user doesn't see a white flash. - panel.style.visibility = "hidden"; - gNavToolbox.addEventListener("beforecustomization", function onBeforeCustomization() { - gNavToolbox.removeEventListener("beforecustomization", onBeforeCustomization, false); - panel.style.removeProperty("visibility"); - }, false); - - sheetFrame.setAttribute("src", customizeURL); - - panel.openPopup(gNavToolbox, "after_start", 0, 0); - } else { - window.openDialog(customizeURL, - "CustomizeToolbar", - "chrome,titlebar,toolbar,location,resizable,dependent", - gNavToolbox); - } + gCustomizeMode.enter(); } function BrowserToolboxCustomizeDone(aToolboxChanged) { - if (gCustomizeSheet) { - document.getElementById("customizeToolbarSheetPopup").hidePopup(); - let iframe = document.getElementById("customizeToolbarSheetIFrame"); - iframe.parentNode.removeChild(iframe); - } - - // Update global UI elements that may have been added or removed - if (aToolboxChanged) { - gURLBar = document.getElementById("urlbar"); - - gProxyFavIcon = document.getElementById("page-proxy-favicon"); - gHomeButton.updateTooltip(); - gIdentityHandler._cacheElements(); - window.XULBrowserWindow.init(); - -#ifndef XP_MACOSX - updateEditUIVisibility(); -#endif - - // Hacky: update the PopupNotifications' object's reference to the iconBox, - // if it already exists, since it may have changed if the URL bar was - // added/removed. - if (!window.__lookupGetter__("PopupNotifications")) - PopupNotifications.iconBox = document.getElementById("notification-popup-box"); - } - - PlacesToolbarHelper.customizeDone(); - BookmarkingUI.customizeDone(); - DownloadsButton.customizeDone(); - - // The url bar splitter state is dependent on whether stop/reload - // and the location bar are combined, so we need this ordering - CombinedStopReload.init(); - UpdateUrlbarSearchSplitterState(); - setUrlAndSearchBarWidthForConditionalForwardButton(); - - // Update the urlbar - if (gURLBar) { - URLBarSetURI(); - XULBrowserWindow.asyncUpdateUI(); - BookmarkingUI.updateStarState(); - SocialMark.updateMarkState(); - SocialShare.update(); - } - - TabsInTitlebar.allowedBy("customizing-toolbars", true); - - // Re-enable parts of the UI we disabled during the dialog - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", false); - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.removeAttribute("disabled"); - - // make sure to re-enable click-and-hold - if (!getBoolPref("ui.click_hold_context_menus", false)) - SetClickAndHoldHandlers(); - - gBrowser.selectedBrowser.focus(); + gCustomizeMode.exit(aToolboxChanged); } function BrowserToolboxCustomizeChange(aType) { - switch (aType) { - case "iconsize": - case "mode": - retrieveToolbarIconsizesFromTheme(); - break; - default: - gHomeButton.updatePersonalToolbarStyle(); - BookmarkingUI.customizeChange(); - } + gHomeButton.updatePersonalToolbarStyle(); + BookmarksMenuButton.customizeChange(); } /** @@ -3521,9 +3366,6 @@ function updateEditUIVisibility() let editMenuPopupState = document.getElementById("menu_EditPopup").state; let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state; let placesContextMenuPopupState = document.getElementById("placesContext").state; -#ifdef MENUBAR_CAN_AUTOHIDE - let appMenuPopupState = document.getElementById("appmenu-popup").state; -#endif // The UI is visible if the Edit menu is opening or open, if the context menu // is open, or if the toolbar has been customized to include the Cut, Copy, @@ -3534,13 +3376,7 @@ function updateEditUIVisibility() contextMenuPopupState == "open" || placesContextMenuPopupState == "showing" || placesContextMenuPopupState == "open" || -#ifdef MENUBAR_CAN_AUTOHIDE - appMenuPopupState == "showing" || - appMenuPopupState == "open" || -#endif - document.getElementById("cut-button") || - document.getElementById("copy-button") || - document.getElementById("paste-button") ? true : false; + document.getElementById("edit-controls") ? true : false; // If UI is visible, update the edit commands' enabled state to reflect // whether or not they are actually enabled for the current focus/selection. @@ -3570,9 +3406,6 @@ function updateEditUIVisibility() function updateCharacterEncodingMenuState() { let charsetMenu = document.getElementById("charsetMenu"); - let appCharsetMenu = document.getElementById("appmenu_charsetMenu"); - let appDevCharsetMenu = - document.getElementById("appmenu_developer_charsetMenu"); // gBrowser is null on Mac when the menubar shows in the context of // non-browser windows. The above elements may be null depending on // what parts of the menubar are present. E.g. no app menu on Mac. @@ -3582,22 +3415,10 @@ function updateCharacterEncodingMenuState() if (charsetMenu) { charsetMenu.removeAttribute("disabled"); } - if (appCharsetMenu) { - appCharsetMenu.removeAttribute("disabled"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.removeAttribute("disabled"); - } } else { if (charsetMenu) { charsetMenu.setAttribute("disabled", "true"); } - if (appCharsetMenu) { - appCharsetMenu.setAttribute("disabled", "true"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.setAttribute("disabled", "true"); - } } } @@ -3629,8 +3450,8 @@ var XULBrowserWindow = { startTime: 0, statusText: "", isBusy: false, - inContentWhitelist: ["about:addons", "about:downloads", "about:permissions", - "about:sync-progress", "about:preferences"], + // Left here for add-on compatibility, see bug 752434 + inContentWhitelist: [], QueryInterface: function (aIID) { if (aIID.equals(Ci.nsIWebProgressListener) || @@ -3660,8 +3481,6 @@ var XULBrowserWindow = { }, init: function () { - this.throbberElement = document.getElementById("navigator-throbber"); - // Bug 666809 - SecurityUI support for e10s if (gMultiProcessBrowser) return; @@ -3675,7 +3494,6 @@ var XULBrowserWindow = { destroy: function () { // XXXjag to avoid leaks :-/, see bug 60729 - delete this.throbberElement; delete this.stopCommand; delete this.reloadCommand; delete this.statusTextField; @@ -3800,10 +3618,6 @@ var XULBrowserWindow = { if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) { this._busyUI = true; - // Turn the throbber on. - if (this.throbberElement) - this.throbberElement.setAttribute("busy", "true"); - // XXX: This needs to be based on window activity... this.stopCommand.removeAttribute("disabled"); CombinedStopReload.switchToStop(); @@ -3848,10 +3662,6 @@ var XULBrowserWindow = { if (this._busyUI) { this._busyUI = false; - // Turn the throbber off. - if (this.throbberElement) - this.throbberElement.removeAttribute("busy"); - this.stopCommand.setAttribute("disabled", "true"); CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest); } @@ -3920,17 +3730,6 @@ var XULBrowserWindow = { SocialShare.update(); } - // Show or hide browser chrome based on the whitelist - if (this.hideChromeForLocation(location)) { - document.documentElement.setAttribute("disablechrome", "true"); - } else { - let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - if (ss.getTabValue(gBrowser.selectedTab, "appOrigin")) - document.documentElement.setAttribute("disablechrome", "true"); - else - document.documentElement.removeAttribute("disablechrome"); - } - // Utility functions for disabling find var shouldDisableFind = function shouldDisableFind(aDocument) { let docElt = aDocument.documentElement; @@ -4007,12 +3806,8 @@ var XULBrowserWindow = { FeedHandler.updateFeeds(); }, - hideChromeForLocation: function(aLocation) { - aLocation = aLocation.toLowerCase(); - return this.inContentWhitelist.some(function(aSpec) { - return aSpec == aLocation; - }); - }, + // Left here for add-on compatibility, see bug 752434 + hideChromeForLocation: function() {}, onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { this.status = aMessage; @@ -4190,8 +3985,7 @@ var CombinedStopReload = { var stop = document.getElementById("stop-button"); if (urlbar) { - if (urlbar.parentNode.getAttribute("mode") != "icons" || - !reload || urlbar.nextSibling != reload || + if (!reload || urlbar.nextSibling != reload || !stop || reload.nextSibling != stop) urlbar.removeAttribute("combined"); else { @@ -4518,8 +4312,6 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) { menuItem.setAttribute("type", "checkbox"); menuItem.setAttribute("label", toolbarName); menuItem.setAttribute("checked", toolbar.getAttribute(hidingAttribute) != "true"); - if (popup.id != "appmenu_customizeMenu") - menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey")); if (popup.id != "toolbar-context-menu") menuItem.setAttribute("key", toolbar.getAttribute("key")); @@ -4548,72 +4340,30 @@ function setToolbarVisibility(toolbar, isVisible) { BookmarkingUI.onToolbarVisibilityChange(); gBrowser.updateWindowResizers(); -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); +#ifdef CAN_DRAW_IN_TITLEBAR + updateTitlebarDisplay(); #endif } -var TabsOnTop = { - init: function TabsOnTop_init() { - Services.prefs.addObserver(this._prefName, this, false); - - // Only show the toggle UI if the user disabled tabs on top. - if (Services.prefs.getBoolPref(this._prefName)) { - for (let item of document.querySelectorAll("menuitem[command=cmd_ToggleTabsOnTop]")) - item.parentNode.removeChild(item); - } - }, - - uninit: function TabsOnTop_uninit() { - Services.prefs.removeObserver(this._prefName, this); - }, - - toggle: function () { - this.enabled = !Services.prefs.getBoolPref(this._prefName); - }, - - syncUI: function () { - let userEnabled = Services.prefs.getBoolPref(this._prefName); - let enabled = userEnabled && gBrowser.tabContainer.visible; - - document.getElementById("cmd_ToggleTabsOnTop") - .setAttribute("checked", userEnabled); - - document.documentElement.setAttribute("tabsontop", enabled); - document.getElementById("navigator-toolbox").setAttribute("tabsontop", enabled); - document.getElementById("TabsToolbar").setAttribute("tabsontop", enabled); - document.getElementById("nav-bar").setAttribute("tabsontop", enabled); - gBrowser.tabContainer.setAttribute("tabsontop", enabled); - TabsInTitlebar.allowedBy("tabs-on-top", enabled); - }, - - get enabled () { - return gNavToolbox.getAttribute("tabsontop") == "true"; - }, - - 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.onTop" -} - var TabsInTitlebar = { init: function () { #ifdef CAN_DRAW_IN_TITLEBAR this._readPref(); Services.prefs.addObserver(this._prefName, this, false); - // Don't trust the initial value of the sizemode attribute; wait for - // the resize event (handled in tabbrowser.xml). - this.allowedBy("sizemode", false); - + // We need to update the appearance of the titlebar when the menu changes + // from the active to the inactive state. We can't, however, rely on + // DOMMenuBarInactive, because the menu fires this event and then removes + // the inactive attribute after an event-loop spin. + // + // Because updating the appearance involves sampling the heights and margins + // of various elements, it's important that the layout be more or less + // settled before updating the titlebar. So instead of listening to + // DOMMenuBarActive and DOMMenuBarInactive, we use a MutationObserver to + // watch the "invalid" attribute directly. + let menu = document.getElementById("toolbar-menubar"); + this._menuObserver = new MutationObserver(this._onMenuMutate); + this._menuObserver.observe(menu, {attributes: true}); this._initialized = true; #endif }, @@ -4623,17 +4373,23 @@ var TabsInTitlebar = { if (allow) { if (condition in this._disallowed) { delete this._disallowed[condition]; - this._update(); + this._update(true); } } else { if (!(condition in this._disallowed)) { this._disallowed[condition] = null; - this._update(); + this._update(true); } } #endif }, + updateAppearance: function updateAppearance(aForce) { +#ifdef CAN_DRAW_IN_TITLEBAR + this._update(aForce); +#endif + }, + get enabled() { return document.documentElement.getAttribute("tabsintitlebar") == "true"; }, @@ -4644,16 +4400,33 @@ var TabsInTitlebar = { this._readPref(); }, + _onMenuMutate: function (aMutations) { + // We don't care about restored windows, since the menu shouldn't be + // pushing the tab-strip down. + if (document.documentElement.getAttribute("sizemode") == "normal") { + return; + } + + for (let mutation of aMutations) { + if (mutation.attributeName == "inactive" || + mutation.attributeName == "autohide") { + TabsInTitlebar._update(true); + return; + } + } + }, + _initialized: false, _disallowed: {}, _prefName: "browser.tabs.drawInTitlebar", + _lastSizeMode: null, _readPref: function () { this.allowedBy("pref", Services.prefs.getBoolPref(this._prefName)); }, - _update: function () { + _update: function (aForce=false) { function $(id) document.getElementById(id); function rect(ele) ele.getBoundingClientRect(); @@ -4661,45 +4434,99 @@ var TabsInTitlebar = { return; let allowed = true; + + if (!aForce) { + // _update is called on resize events, because the window is not ready + // after sizemode events. However, we only care about the event when the + // sizemode is different from the last time we updated the appearance of + // the tabs in the titlebar. + let sizemode = document.documentElement.getAttribute("sizemode"); + if (this._lastSizeMode == sizemode) { + return; + } + this._lastSizeMode = sizemode; + } + for (let something in this._disallowed) { allowed = false; break; } - if (allowed == this.enabled) - return; + function $(id) document.getElementById(id); let titlebar = $("titlebar"); + let titlebarContent = $("titlebar-content"); + let menubar = $("toolbar-menubar"); + + // Reset the margins and padding that _update modifies so that we can take + // accurate measurements. + titlebarContent.style.marginBottom = ""; + titlebar.style.marginBottom = ""; + menubar.style.paddingBottom = ""; if (allowed) { - let tabsToolbar = $("TabsToolbar"); - -#ifdef MENUBAR_CAN_AUTOHIDE - let appmenuButtonBox = $("appmenu-button-container"); - this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width); -#endif - let captionButtonsBox = $("titlebar-buttonbox"); - this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width); - - let tabsToolbarRect = rect(tabsToolbar); - let titlebarTop = rect($("titlebar-content")).top; - titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop, - tabsToolbarRect.height) + "px"; - + // We set the tabsintitlebar attribute first so that our CSS for + // tabsintitlebar manifests before we do our measurements. document.documentElement.setAttribute("tabsintitlebar", "true"); - if (!this._draghandle) { + let captionButtonsBox = $("titlebar-buttonbox"); + this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width); +#ifdef XP_MACOSX + let fullscreenButton = $("titlebar-fullscreen-button"); + this._sizePlaceholder("fullscreen-button", rect(fullscreenButton).width); +#endif + let titlebarContentHeight = rect(titlebarContent).height; + let menuHeight = this._outerHeight(menubar); + + // If the titlebar is taller than the menubar, add more padding to the + // bottom of the menubar so that it matches. + if (menuHeight && titlebarContentHeight > menuHeight) { + let menuTitlebarDelta = titlebarContentHeight - menuHeight; + menubar.style.paddingBottom = menuTitlebarDelta + "px"; + menuHeight += menuTitlebarDelta; + } + + // Next, we calculate how much we need to stretch the titlebar down to + // go all the way to the bottom of the tab strip. + let tabsToolbar = $("TabsToolbar"); + let tabAndMenuHeight = this._outerHeight(tabsToolbar) + menuHeight; + titlebarContent.style.marginBottom = tabAndMenuHeight + "px"; + + // Finally, we have to determine how much to bring up the elements below + // the titlebar. We start with a baseHeight of tabAndMenuHeight, to offset + // the amount we added to the titlebar content. Then, we have two cases: + // + // 1) The titlebar is larger than the tabAndMenuHeight. This can happen in + // large font mode with the menu autohidden. In this case, we want to + // add tabAndMenuHeight, since this should line up the bottom of the + // tabstrip with the bottom of the titlebar. + // + // 2) The titlebar is equal to or smaller than the tabAndMenuHeight. This + // is the more common case, and occurs with normal font sizes. In this + // case, we want to bring the menu and tabstrip right up to the top of + // the titlebar, so we add the titlebarContentHeight to the baseHeight. + let baseHeight = tabAndMenuHeight; + baseHeight += (titlebarContentHeight > tabAndMenuHeight) ? tabAndMenuHeight + : titlebarContentHeight; + titlebar.style.marginBottom = "-" + baseHeight + "px"; + + if (!this._draghandles) { + this._draghandles = {}; let tmp = {}; Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); - this._draghandle = new tmp.WindowDraggingElement(tabsToolbar); - this._draghandle.mouseDownCheck = function () { + + let mouseDownCheck = function () { return !this._dragBindingAlive && TabsInTitlebar.enabled; }; + + this._draghandles.tabsToolbar = new tmp.WindowDraggingElement(tabsToolbar); + this._draghandles.tabsToolbar.mouseDownCheck = mouseDownCheck; + + this._draghandles.navToolbox = new tmp.WindowDraggingElement(gNavToolbox); + this._draghandles.navToolbox.mouseDownCheck = mouseDownCheck; } } else { document.documentElement.removeAttribute("tabsintitlebar"); - - titlebar.style.marginBottom = ""; } }, @@ -4707,36 +4534,45 @@ var TabsInTitlebar = { Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"), function (node) { node.width = width; }); }, + + /** + * Retrieve the height of an element, including its top and bottom + * margins. + * + * @param ele + * The element to measure. + * @return + * The height and margins as an integer. If the height of the element + * is 0, then this returns 0, regardless of what the margins are. + */ + _outerHeight: function (ele) { + let cstyle = document.defaultView.getComputedStyle(ele); + let margins = parseInt(cstyle.marginTop) + parseInt(cstyle.marginBottom); + let height = ele.getBoundingClientRect().height; + return height > 0 ? Math.abs(height + margins) : 0; + }, #endif uninit: function () { #ifdef CAN_DRAW_IN_TITLEBAR this._initialized = false; Services.prefs.removeObserver(this._prefName, this); + this._menuObserver.disconnect(); #endif } }; -#ifdef MENUBAR_CAN_AUTOHIDE -function updateAppButtonDisplay() { - var displayAppButton = - !gInPrintPreviewMode && - window.menubar.visible && - document.getElementById("toolbar-menubar").getAttribute("autohide") == "true"; - #ifdef CAN_DRAW_IN_TITLEBAR - document.getElementById("titlebar").hidden = !displayAppButton; +function updateTitlebarDisplay() { + let drawInTitlebar = !gInPrintPreviewMode && window.toolbar.visible; + document.getElementById("titlebar").hidden = !drawInTitlebar; - if (displayAppButton) + if (drawInTitlebar) document.documentElement.setAttribute("chromemargin", "0,2,2,2"); else document.documentElement.removeAttribute("chromemargin"); - TabsInTitlebar.allowedBy("drawing-in-titlebar", displayAppButton); -#else - document.getElementById("appmenu-toolbar-button").hidden = - !displayAppButton; -#endif + TabsInTitlebar.allowedBy("drawing-in-titlebar", drawInTitlebar); } #endif @@ -6840,12 +6676,6 @@ let gPrivateBrowsingUI = { document.getElementById("Tools:Sanitize").setAttribute("disabled", "true"); if (window.location.href == getBrowserURL()) { -#ifdef XP_MACOSX - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - document.documentElement.setAttribute("drawintitlebar", true); - } -#endif - // Adjust the window's title let docElement = document.documentElement; if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { @@ -6862,7 +6692,6 @@ let gPrivateBrowsingUI = { // Adjust the New Window menu entries [ { normal: "menu_newNavigator", private: "menu_newPrivateWindow" }, - { normal: "appmenu_newNavigator", private: "appmenu_newPrivateWindow" }, ].forEach(function(menu) { let newWindow = document.getElementById(menu.normal); let newPrivateWindow = document.getElementById(menu.private); diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 8ce99ef7047..8bfd595b158 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -9,7 +9,9 @@ + + @@ -22,6 +24,7 @@ # All JS files which are not content (only) dependent that browser.xul @@ -241,10 +246,6 @@ - @@ -305,10 +306,6 @@ - - @@ -331,29 +328,27 @@ #include popup-notifications.inc +#include ../../components/customizableui/content/panelUI.inc.xul #ifdef CAN_DRAW_IN_TITLEBAR -#ifdef MENUBAR_CAN_AUTOHIDE - - - -#endif - + +#ifdef XP_MACOSX + +#endif #endif @@ -381,315 +376,323 @@ #ifdef CAN_DRAW_IN_TITLEBAR - - + + +#ifdef XP_MACOSX + +#endif #endif - + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - + tooltiptext="&newTabButton.tooltip;" + ondrop="newTabButtonObserver.onDrop(event)" + ondragover="newTabButtonObserver.onDragOver(event)" + ondragenter="newTabButtonObserver.onDragOver(event)" + ondragexit="newTabButtonObserver.onDragExit(event)" + removable="true"/> - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + key="key_tabview" + label="&viewTabGroups.label;" + command="Browser:ToggleTabView" + observes="tabviewGroupsNumber"/> + - + - + +#ifdef XP_MACOSX + +#endif +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + tooltiptext="&pageReportIcon.tooltip;" + onclick="gPopupBlockerObserver.onReportButtonClick(event);"/> + + + + + + + - #ifndef XP_WIN - - - + +