diff --git a/browser/devtools/debugger/debugger-view.js b/browser/devtools/debugger/debugger-view.js index c117697f20fb..b81ee3ede01a 100644 --- a/browser/devtools/debugger/debugger-view.js +++ b/browser/devtools/debugger/debugger-view.js @@ -14,6 +14,7 @@ const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars const BREAKPOINT_CONDITIONAL_POPUP_POSITION = "before_start"; const BREAKPOINT_CONDITIONAL_POPUP_OFFSET_X = 7; // px const BREAKPOINT_CONDITIONAL_POPUP_OFFSET_Y = -3; // px +const BREAKPOINT_SMALL_WINDOW_WIDTH = 850; // px const RESULTS_PANEL_POPUP_POSITION = "before_end"; const RESULTS_PANEL_MAX_RESULTS = 10; const FILE_SEARCH_ACTION_MAX_DELAY = 300; // ms @@ -30,6 +31,7 @@ const SEARCH_AUTOFILL = [SEARCH_GLOBAL_FLAG, SEARCH_FUNCTION_FLAG, SEARCH_TOKEN_ const EDITOR_VARIABLE_HOVER_DELAY = 750; // ms const EDITOR_VARIABLE_POPUP_POSITION = "topcenter bottomleft"; const TOOLBAR_ORDER_POPUP_POSITION = "topcenter bottomleft"; +const RESIZE_REFRESH_RATE = 50; // ms const PROMISE_DEBUGGER_URL = "chrome://browser/content/devtools/promisedebugger/promise-debugger.xhtml"; @@ -93,6 +95,8 @@ let DebuggerView = { return this._shutdown; } + window.removeEventListener("resize", this._onResize, false); + let deferred = promise.defer(); this._shutdown = deferred.promise; @@ -141,10 +145,10 @@ let DebuggerView = { this._instrumentsPane.setAttribute("width", Prefs.instrumentsWidth); this.toggleInstrumentsPane({ visible: Prefs.panesVisibleOnStartup }); - // Side hosts requires a different arrangement of the debugger widgets. - if (gHostType == "side") { - this.handleHostChanged(gHostType); - } + this.updateLayoutMode(); + + this._onResize = this._onResize.bind(this); + window.addEventListener("resize", this._onResize, false); }, /** @@ -619,24 +623,64 @@ let DebuggerView = { * @param string aType * The host type, either "bottom", "side" or "window". */ - handleHostChanged: function(aType) { - let newLayout = ""; - - if (aType == "side") { - newLayout = "vertical"; - this._enterVerticalLayout(); - } else { - newLayout = "horizontal"; - this._enterHorizontalLayout(); - } - - this._hostType = aType; - this._body.setAttribute("layout", newLayout); - window.emit(EVENTS.LAYOUT_CHANGED, newLayout); + handleHostChanged: function(hostType) { + this._hostType = hostType; + this.updateLayoutMode(); }, /** - * Switches the debugger widgets to a horizontal layout. + * Resize handler for this container's window. + */ + _onResize: function (evt) { + // Allow requests to settle down first. + setNamedTimeout( + "resize-events", RESIZE_REFRESH_RATE, () => this.updateLayoutMode()); + }, + + /** + * Set the layout to "vertical" or "horizontal" depending on the host type. + */ + updateLayoutMode: function() { + if (this._isSmallWindowHost() || this._hostType == "side") { + this._setLayoutMode("vertical"); + } else { + this._setLayoutMode("horizontal"); + } + }, + + /** + * Check if the current host is in window mode and is + * too small for horizontal layout + */ + _isSmallWindowHost: function() { + if (this._hostType != "window") { + return false; + } + + return window.outerWidth <= BREAKPOINT_SMALL_WINDOW_WIDTH; + }, + + /** + * Enter the provided layoutMode. Do nothing if the layout is the same as the current one. + * @param {String} layoutMode new layout ("vertical" or "horizontal") + */ + _setLayoutMode: function(layoutMode) { + if (this._body.getAttribute("layout") == layoutMode) { + return; + } + + if (layoutMode == "vertical") { + this._enterVerticalLayout(); + } else { + this._enterHorizontalLayout(); + } + + this._body.setAttribute("layout", layoutMode); + window.emit(EVENTS.LAYOUT_CHANGED, layoutMode); + }, + + /** + * Switches the debugger widgets to a vertical layout. */ _enterVerticalLayout: function() { let vertContainer = document.getElementById("vertical-layout-panes-container"); @@ -653,7 +697,7 @@ let DebuggerView = { }, /** - * Switches the debugger widgets to a vertical layout. + * Switches the debugger widgets to a horizontal layout. */ _enterHorizontalLayout: function() { let normContainer = document.getElementById("debugger-widgets"); diff --git a/browser/devtools/debugger/panel.js b/browser/devtools/debugger/panel.js index 879e1c10a7b0..369f91454c97 100644 --- a/browser/devtools/debugger/panel.js +++ b/browser/devtools/debugger/panel.js @@ -26,7 +26,7 @@ function DebuggerPanel(iframeWindow, toolbox) { this.unhighlightWhenResumed = this.unhighlightWhenResumed.bind(this); EventEmitter.decorate(this); -}; +} exports.DebuggerPanel = DebuggerPanel; diff --git a/browser/devtools/debugger/test/mochitest/browser_dbg_host-layout.js b/browser/devtools/debugger/test/mochitest/browser_dbg_host-layout.js index 2f3ecd5952d2..e83143140e8a 100644 --- a/browser/devtools/debugger/test/mochitest/browser_dbg_host-layout.js +++ b/browser/devtools/debugger/test/mochitest/browser_dbg_host-layout.js @@ -6,15 +6,22 @@ * host changes. */ +"use strict"; + let gDefaultHostType = Services.prefs.getCharPref("devtools.toolbox.host"); function test() { + // test is too slow on some platforms due to the number of test cases + requestLongerTimeout(2); + Task.spawn(function*() { - yield testHosts(["bottom", "side", "window"], ["horizontal", "vertical", "horizontal"]); + yield testHosts(["bottom", "side", "window:big"], ["horizontal", "vertical", "horizontal"]); yield testHosts(["side", "bottom", "side"], ["vertical", "horizontal", "vertical"]); yield testHosts(["bottom", "side", "bottom"], ["horizontal", "vertical", "horizontal"]); - yield testHosts(["side", "window", "side"], ["vertical", "horizontal", "vertical"]); - yield testHosts(["window", "side", "window"], ["horizontal", "vertical", "horizontal"]); + yield testHosts(["side", "window:big", "side"], ["vertical", "horizontal", "vertical"]); + yield testHosts(["window:big", "side", "window:big"], ["horizontal", "vertical", "horizontal"]); + yield testHosts(["window:small", "bottom", "side"], ["vertical", "horizontal", "vertical"]); + yield testHosts(["window:small", "window:big", "window:small"], ["vertical", "horizontal", "vertical"]); finish(); }); } @@ -23,11 +30,15 @@ function testHosts(aHostTypes, aLayoutTypes) { let [firstHost, secondHost, thirdHost] = aHostTypes; let [firstLayout, secondLayout, thirdLayout] = aLayoutTypes; - Services.prefs.setCharPref("devtools.toolbox.host", firstHost); + Services.prefs.setCharPref("devtools.toolbox.host", getHost(firstHost)); return Task.spawn(function*() { let [tab, debuggee, panel] = yield initDebugger("about:blank"); - yield testHost(tab, panel, firstHost, firstLayout); + if (getHost(firstHost) === "window") { + yield resizeToolboxWindow(panel, firstHost); + } + + yield testHost(panel, getHost(firstHost), firstLayout); yield switchAndTestHost(tab, panel, secondHost, secondLayout); yield switchAndTestHost(tab, panel, thirdHost, thirdLayout); yield teardown(panel); @@ -39,26 +50,63 @@ function switchAndTestHost(aTab, aPanel, aHostType, aLayoutType) { let gDebugger = aPanel.panelWin; return Task.spawn(function*() { - let layoutChanged = once(gDebugger, gDebugger.EVENTS.LAYOUT_CHANGED); - let hostChanged = gToolbox.switchHost(aHostType); + let layoutChanged = waitEventOnce(gDebugger, gDebugger.EVENTS.LAYOUT_CHANGED); + let hostChanged = gToolbox.switchHost(getHost(aHostType)); yield hostChanged; - ok(true, "The toolbox's host has changed."); + info("The toolbox's host has changed."); + + if (getHost(aHostType) === "window") { + yield resizeToolboxWindow(aPanel, aHostType); + } yield layoutChanged; - ok(true, "The debugger's layout has changed."); + info("The debugger's layout has changed."); - yield testHost(aTab, aPanel, aHostType, aLayoutType); + yield testHost(aPanel, getHost(aHostType), aLayoutType); }); +} - function once(aTarget, aEvent) { - let deferred = promise.defer(); - aTarget.once(aEvent, deferred.resolve); - return deferred.promise; +function waitEventOnce(aTarget, aEvent) { + let deferred = promise.defer(); + aTarget.once(aEvent, deferred.resolve); + return deferred.promise; +} + +function getHost(host) { + if (host.indexOf("window") == 0) { + return "window"; + } + return host; +} + +function resizeToolboxWindow(panel, host) { + let sizeOption = host.split(":")[1]; + let win = panel._toolbox._host._window; + + // should be the same value as BREAKPOINT_SMALL_WINDOW_WIDTH in debugger-view.js + let breakpoint = 850; + + if (sizeOption == "big" && win.outerWidth <= breakpoint) { + yield resizeAndWaitForLayoutChange(panel, breakpoint + 300); + } else if (sizeOption == "small" && win.outerWidth >= breakpoint) { + yield resizeAndWaitForLayoutChange(panel, breakpoint - 300); + } else { + info("Window resize unnecessary for host " + host); } } -function testHost(aTab, aPanel, aHostType, aLayoutType) { +function resizeAndWaitForLayoutChange(panel, width) { + info("Updating toolbox window width to " + width); + + let win = panel._toolbox._host._window; + let gDebugger = panel.panelWin; + + win.resizeTo(width, window.screen.availHeight); + yield waitEventOnce(gDebugger, gDebugger.EVENTS.LAYOUT_CHANGED); +} + +function testHost(aPanel, aHostType, aLayoutType) { let gDebugger = aPanel.panelWin; let gView = gDebugger.DebuggerView;