summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/resources/options/browser_options.js9
-rw-r--r--chrome/browser/resources/options/chromeos/display_layout.js139
-rw-r--r--chrome/browser/resources/options/chromeos/display_layout_manager.js4
-rw-r--r--chrome/browser/resources/options/chromeos/display_layout_manager_multi.js366
-rw-r--r--chrome/browser/resources/options/chromeos/display_options.css16
-rw-r--r--chrome/browser/resources/options/chromeos/display_options.js26
-rw-r--r--chrome/browser/resources/options/options_bundle.js1
-rw-r--r--chrome/browser/ui/webui/options/chromeos/display_options_handler.cc7
-rw-r--r--chromeos/chromeos_switches.cc3
-rw-r--r--chromeos/chromeos_switches.h1
10 files changed, 544 insertions, 28 deletions
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index d6e92d6..c5347ef 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -1735,12 +1735,17 @@ cr.define('options', function() {
/**
* Enables or disables the Chrome OS display settings button and overlay.
+ * @param {boolean} enabled
+ * @param {boolean} showUnifiedDesktop
+ * @param {boolean} multiDisplayLayout
* @private
*/
- enableDisplaySettings_: function(enabled, showUnifiedDesktop) {
+ enableDisplaySettings_: function(
+ enabled, showUnifiedDesktop, multiDisplayLayout) {
if (cr.isChromeOS) {
$('display-options').disabled = !enabled;
- DisplayOptions.getInstance().setEnabled(enabled, showUnifiedDesktop);
+ DisplayOptions.getInstance().setEnabled(
+ enabled, showUnifiedDesktop, multiDisplayLayout);
}
},
diff --git a/chrome/browser/resources/options/chromeos/display_layout.js b/chrome/browser/resources/options/chromeos/display_layout.js
index ea6bf76..f7506d66 100644
--- a/chrome/browser/resources/options/chromeos/display_layout.js
+++ b/chrome/browser/resources/options/chromeos/display_layout.js
@@ -44,21 +44,28 @@ cr.define('options', function() {
* @param {number} width The width of the region.
* @param {number} basePoint The starting point of the base region.
* @param {number} baseWidth The width of the base region.
+ * @param {number=} opt_snapDistance Provide to override the snap distance.
+ * 0 means snap at any distance.
* @return {number} The moved point. Returns the point itself if it doesn't
* need to snap to the edge.
* @private
*/
- function snapToEdge(point, width, basePoint, baseWidth) {
+ function snapToEdge_(point, width, basePoint, baseWidth, opt_snapDistance) {
// If the edge of the region is smaller than this, it will snap to the
// base's edge.
/** @const */ var SNAP_DISTANCE_PX = 16;
+ var snapDist;
+ if (opt_snapDistance !== undefined)
+ snapDist = opt_snapDistance;
+ else
+ snapDist = SNAP_DISTANCE_PX;
var startDiff = Math.abs(point - basePoint);
var endDiff = Math.abs(point + width - (basePoint + baseWidth));
// Prefer the closer one if both edges are close enough.
- if (startDiff < SNAP_DISTANCE_PX && startDiff < endDiff)
+ if ((!snapDist || startDiff < snapDist) && startDiff < endDiff)
return basePoint;
- else if (endDiff < SNAP_DISTANCE_PX)
+ else if (!snapDist || endDiff < snapDist)
return basePoint + baseWidth - width;
return point;
@@ -150,9 +157,9 @@ cr.define('options', function() {
},
/**
- * Calculates the offset for displayLayout relative to its parent.
+ * Calculates the offset relative to |parent|.
* @param {number} scale
- * @param {options.DisplayLayout} parent
+ * @param {?options.DisplayLayout} parent
*/
calculateOffset: function(scale, parent) {
// Offset is calculated from top or left edge.
@@ -172,12 +179,67 @@ cr.define('options', function() {
},
/**
+ * Calculates the bounds relative to |parentBounds|.
+ * @param {!options.DisplayBounds} parentBounds
+ * @return {!options.DisplayBounds}
+ */
+ calculateBounds: function(parentBounds) {
+ var left = 0, top = 0;
+ switch (this.layoutType) {
+ case options.DisplayLayoutType.TOP:
+ left = parentBounds.left + this.offset;
+ top = parentBounds.top - this.bounds.height;
+ break;
+ case options.DisplayLayoutType.RIGHT:
+ left = parentBounds.left + parentBounds.width;
+ top = parentBounds.top + this.offset;
+ break;
+ case options.DisplayLayoutType.BOTTOM:
+ left = parentBounds.left + this.offset;
+ top = parentBounds.top + parentBounds.height;
+ break;
+ case options.DisplayLayoutType.LEFT:
+ left = parentBounds.left - this.bounds.width;
+ top = parentBounds.top + this.offset;
+ break;
+ }
+ return {
+ left: left,
+ top: top,
+ width: this.bounds.width,
+ height: this.bounds.height
+ };
+ },
+
+ /**
+ * Snap |newPosition| to the edge specified by |layoutType| and call
+ * setDivPosition.
+ * @param {options.DisplayPosition} newPosition
+ * @param {?HTMLElement} parentDiv
+ * @param {!options.DisplayLayoutType} layoutType
+ */
+ snapAndSetDivPosition(newPosition, parentDiv, layoutType) {
+ var snapX = (layoutType == options.DisplayLayoutType.LEFT ||
+ layoutType == options.DisplayLayoutType.RIGHT) ?
+ 0 /* infinite */ :
+ undefined /* default */;
+ var snapY = (layoutType == options.DisplayLayoutType.TOP ||
+ layoutType == options.DisplayLayoutType.BOTTOM) ?
+ 0 /* infinite */ :
+ undefined /* default */;
+
+ newPosition.x = this.snapToX(newPosition.x, parentDiv, snapX);
+ newPosition.y = this.snapToY(newPosition.y, parentDiv, snapY);
+
+ this.setDivPosition(newPosition, parentDiv, layoutType);
+ },
+
+ /**
* Update the div location to the position closest to |newPosition| along
* the edge of |parentDiv| specified by |layoutType|.
* @param {options.DisplayPosition} newPosition
* @param {?HTMLElement} parentDiv
* @param {!options.DisplayLayoutType} layoutType
- * @private
*/
setDivPosition(newPosition, parentDiv, layoutType) {
var div = this.div;
@@ -205,7 +267,6 @@ cr.define('options', function() {
* Ensures that there is a minimum overlap when displays meet at a corner.
* @param {?HTMLElement} parentDiv
* @param {options.DisplayLayoutType} layoutType
- * @private
*/
adjustCorners: function(parentDiv, layoutType) {
// The number of pixels to share the edges between displays.
@@ -233,29 +294,73 @@ cr.define('options', function() {
},
/**
+ * Calculates the layoutType for |position| relative to |parentDiv|.
+ * @param {?HTMLElement} parentDiv
+ * @param {!options.DisplayPosition} position
+ * @return {options.DisplayLayoutType}
+ */
+ getLayoutTypeForPosition: function(parentDiv, position) {
+ var div = this.div;
+
+ // Translate position from top-left to center.
+ var x = position.x + div.offsetWidth / 2;
+ var y = position.y + div.offsetHeight / 2;
+
+ // Determine the distance from the new position to both of the near edges.
+ var div = parentDiv;
+ var left = div.offsetLeft;
+ var top = div.offsetTop;
+ var width = div.offsetWidth;
+ var height = div.offsetHeight;
+
+ // Signed deltas to the center of the div.
+ var dx = x - (left + width / 2);
+ var dy = y - (top + height / 2);
+
+ // Unsigned distance to each edge.
+ var distx = Math.abs(dx) - width / 2;
+ var disty = Math.abs(dy) - height / 2;
+
+ if (distx > disty) {
+ if (dx < 0)
+ return options.DisplayLayoutType.LEFT;
+ else
+ return options.DisplayLayoutType.RIGHT;
+ } else {
+ if (dy < 0)
+ return options.DisplayLayoutType.TOP;
+ else
+ return options.DisplayLayoutType.BOTTOM;
+ }
+ },
+
+ /**
* Snaps a horizontal value, see SnapToEdge.
* @param {number} x
* @param {?HTMLElement} parentDiv
+ * @param {number=} opt_snapDistance Provide to override the snap distance.
+ * 0 means snap from any distance.
* @return {number}
- * @private
*/
- snapToX: function(x, parentDiv) {
- return snapToEdge(
- x, this.div.offsetWidth, parentDiv.offsetLeft, parentDiv.offsetWidth);
+ snapToX: function(x, parentDiv, opt_snapDistance) {
+ return snapToEdge_(
+ x, this.div.offsetWidth, parentDiv.offsetLeft, parentDiv.offsetWidth,
+ opt_snapDistance);
},
/**
* Snaps a vertical value, see SnapToEdge.
* @param {number} y
* @param {?HTMLElement} parentDiv
+ * @param {number=} opt_snapDistance Provide to override the snap distance.
+ * 0 means snap from any distance.
* @return {number}
- * @private
*/
- snapToY: function(y, parentDiv) {
- return snapToEdge(
- y, this.div.offsetHeight, parentDiv.offsetTop,
- parentDiv.offsetHeight);
- },
+ snapToY: function(y, parentDiv, opt_snapDistance) {
+ return snapToEdge_(
+ y, this.div.offsetHeight, parentDiv.offsetTop, parentDiv.offsetHeight,
+ opt_snapDistance);
+ }
};
// Export
diff --git a/chrome/browser/resources/options/chromeos/display_layout_manager.js b/chrome/browser/resources/options/chromeos/display_layout_manager.js
index 54ba6a1..c51cbdc 100644
--- a/chrome/browser/resources/options/chromeos/display_layout_manager.js
+++ b/chrome/browser/resources/options/chromeos/display_layout_manager.js
@@ -151,8 +151,10 @@ cr.define('options', function() {
* Sets the display layout div corresponding to |id| to focused and
* sets all other display layouts to unfocused.
* @param {string} focusedId
+ * @param {boolean=} opt_userAction If true, focus was triggered by a
+ * user action. (Used in DisplayLayoutManagerMulti override).
*/
- setFocusedId: function(focusedId) {
+ setFocusedId: function(focusedId, opt_userAction) {
for (var id in this.displayLayoutMap_) {
var layout = this.displayLayoutMap_[id];
layout.div.classList.toggle('displays-focused', layout.id == focusedId);
diff --git a/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js b/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js
new file mode 100644
index 0000000..b5cc4ab
--- /dev/null
+++ b/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js
@@ -0,0 +1,366 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.exportPath('options');
+
+cr.define('options', function() {
+ 'use strict';
+
+ var DisplayLayoutManager = options.DisplayLayoutManager;
+
+ /** @const */ var FAKE_ID_PREFIX = 'fakeId';
+ var fakeDisplayNum = 3;
+ var fakeDisplays = [];
+
+ /**
+ * @constructor
+ * @extends {options.DisplayLayoutManager}
+ */
+ function DisplayLayoutManagerMulti() { DisplayLayoutManager.call(this); }
+
+ // Helper class for display layout management. Implements logic for laying
+ // out 3+ displays.
+ DisplayLayoutManagerMulti.prototype = {
+ __proto__: DisplayLayoutManager.prototype,
+
+ /** @type {string} */
+ dragId_: '',
+
+ /** @type {string} */
+ dragParentId_: '',
+
+ /** @type {options.DisplayLayoutType} */
+ dragLayoutType_: options.DisplayLayoutType.RIGHT,
+
+ /** @override */
+ createDisplayArea: function(displayAreaDiv, minVisualScale) {
+ // Add fake displays just before creating divs.
+ this.createFakeDisplays_(fakeDisplayNum);
+ for (var i = 0; i < fakeDisplayNum; ++i) {
+ var fake = fakeDisplays[i];
+ this.displayLayoutMap_[fake.id] = fake;
+ }
+ return DisplayLayoutManager.prototype.createDisplayArea.call(
+ this, displayAreaDiv, minVisualScale);
+ },
+
+ /** @override */
+ setFocusedId: function(focusedId, opt_userAction) {
+ DisplayLayoutManager.prototype.setFocusedId.call(this, focusedId);
+ if (!opt_userAction || this.dragId_ != '')
+ return;
+ var layout = this.displayLayoutMap_[focusedId];
+ this.highlightEdge_(layout.parentId, layout.layoutType);
+ },
+
+ /** @override */
+ updatePosition: function(id, newPosition) {
+ this.dragId_ = id;
+ // Find the closest parent.
+ var layout = this.displayLayoutMap_[id];
+ this.dragParentId_ = this.findClosest_(layout, newPosition);
+ var parent = this.displayLayoutMap_[this.dragParentId_];
+
+ // Find the closest edge.
+ this.dragLayoutType_ =
+ layout.getLayoutTypeForPosition(parent.div, newPosition);
+
+ // Update the div (but not the actual layout type or offset yet),
+ layout.snapAndSetDivPosition(
+ newPosition, parent.div, this.dragLayoutType_);
+
+ this.highlightEdge_(this.dragParentId_, this.dragLayoutType_);
+ },
+
+ /** @override */
+ finalizePosition: function(id) {
+ if (id != this.dragId_) {
+ this.dragId_ = '';
+ return false;
+ }
+
+ var layout = this.displayLayoutMap_[id];
+
+ // All immediate children of |layout| will need to be re-parented.
+ var orphanIds = this.findChildren_(id, false /* do not recurse */);
+
+ if (layout.parentId == '') {
+ // We can not re-parent the primary display, so instead re-parent the
+ // "drag parent" to the primary display and make all other displays
+ // orphans.
+ orphanIds = this.findChildren_(id, true /* recurse */);
+
+ // Remove the "drag parent" from the orphans list and reparent it first.
+ var index = orphanIds.indexOf(this.dragParentId_);
+ assert(index != -1);
+ orphanIds.splice(index, 1);
+ this.reparentOrphan_(this.dragParentId_, orphanIds);
+ } else {
+ var dragParent = this.displayLayoutMap_[this.dragParentId_];
+
+ // Special case: re-parenting to a descendant. Parent the immediate
+ // child (the 'top parent') to the dragged display's current parent.
+ var topParent = dragParent;
+ while (topParent) {
+ if (topParent.parentId == '')
+ break;
+ if (topParent.parentId == id) {
+ topParent.parentId = layout.parentId;
+ break;
+ }
+ topParent = this.displayLayoutMap_[topParent.parentId];
+ }
+
+ // Re-parent the dragged display.
+ layout.parentId = this.dragParentId_;
+ layout.layoutType = this.dragLayoutType_;
+
+ // Snap to corners and calculate the offset from the new parent.
+ // This does not depend on any unresolved child layout.
+ layout.adjustCorners(dragParent.div, this.dragLayoutType_);
+ layout.calculateOffset(this.visualScale_, dragParent);
+ }
+
+ // Update any orphaned children. This may cause the dragged display to
+ // be re-attached if it was attached to a child.
+ this.updateOrphans_(orphanIds);
+
+ // Update the fake displays.
+ for (var i = 0; i < fakeDisplayNum; ++i) {
+ var fakeId = fakeDisplays[i].id;
+ var current = this.displayLayoutMap_[fakeId];
+ var bounds = /** @type {!options.DisplayBounds} */ (
+ this.calcLayoutBounds_(current));
+ fakeDisplays[i] = new options.DisplayLayout(
+ current.id, current.name, bounds, current.layoutType,
+ current.parentId);
+ }
+
+ this.highlightEdge_('', undefined); // Remove any highlights.
+ this.dragId_ = '';
+
+ return layout.originalDivOffsets.x != layout.div.offsetLeft ||
+ layout.originalDivOffsets.y != layout.div.offsetTop;
+ },
+
+ /**
+ * Re-parent all entries in |orphanIds| and any children.
+ * @param {Array<string>} orphanIds The list of ids affected by the move.
+ * @private
+ */
+ updateOrphans_: function(orphanIds) {
+ var orphans = orphanIds.slice();
+ for (var orphan of orphanIds) {
+ var newOrphans = this.findChildren_(orphan, true /* recurse */);
+ // If the dragged display was re-parented to one of its children,
+ // there may be duplicates so merge the lists.
+ for (var o of newOrphans) {
+ if (orphans.indexOf(o) == -1)
+ orphans.push(o);
+ }
+ }
+
+ // Remove each orphan from the list as it is re-parented so that
+ // subsequent orphans can be parented to it.
+ while (orphans.length) {
+ var orphanId = orphans.shift();
+ this.reparentOrphan_(orphanId, orphans);
+ }
+ },
+
+ /**
+ * Re-parent the orphan to a layout that is not a member of
+ * |otherOrphanIds|.
+ * @param {string} orphanId The id of the orphan to re-parent.
+ * @param {Array<string>} otherOrphanIds The list of ids of other orphans
+ * to ignore when re-parenting.
+ * @private
+ */
+ reparentOrphan_: function(orphanId, otherOrphanIds) {
+ var orphan = this.displayLayoutMap_[orphanId];
+
+ if (orphanId == this.dragId_ && orphan.parentId != '') {
+ // Preserve the layout and offset of the dragged div.
+ var parent = this.displayLayoutMap_[orphan.parentId];
+ orphan.bounds = this.calcLayoutBounds_(orphan);
+ orphan.layoutDivFromBounds(
+ this.displayAreaOffset_, this.visualScale_, parent);
+ return;
+ }
+
+ // Find the closest parent.
+ var pos = {x: orphan.div.offsetLeft, y: orphan.div.offsetTop};
+ var newParentId = this.findClosest_(orphan, pos, otherOrphanIds);
+ orphan.parentId = newParentId;
+ assert(newParentId != '');
+ var parent = this.displayLayoutMap_[newParentId];
+
+ // Find the closest edge.
+ orphan.layoutType = orphan.getLayoutTypeForPosition(parent.div, pos);
+
+ // Update the div and adjust the corners.
+ orphan.snapAndSetDivPosition(pos, parent.div, orphan.layoutType);
+ orphan.adjustCorners(parent.div, orphan.layoutType);
+
+ // Calculate the bounds from the new div position.
+ orphan.calculateOffset(this.visualScale_, parent);
+
+ // TODO(stevenjb): Set bounds and send orphan update.
+ },
+
+ /**
+ * @param {string} parentId
+ * @param {boolean} recurse Include descendants of children.
+ * @return {!Array<string>}
+ * @private
+ */
+ findChildren_: function(parentId, recurse) {
+ var children = [];
+ for (var childId in this.displayLayoutMap_) {
+ if (childId == parentId)
+ continue;
+ if (this.displayLayoutMap_[childId].parentId == parentId) {
+ // Insert immediate children at the front of the array.
+ children.unshift(childId);
+ if (recurse) {
+ // Descendants get added to the end of the list.
+ children = children.concat(this.findChildren_(childId, true));
+ }
+ }
+ }
+ return children;
+ },
+
+ /**
+ * Finds the display closest to |position| ignoring |child|.
+ * @param {!options.DisplayLayout} child
+ * @param {!options.DisplayPosition} position
+ * @param {Array<string>=} opt_ignoreIds Ids to ignore.
+ * @return {string}
+ * @private
+ */
+ findClosest_: function(child, position, opt_ignoreIds) {
+ var x = position.x + child.div.offsetWidth / 2;
+ var y = position.y + child.div.offsetHeight / 2;
+ var closestId = '';
+ var closestDelta2 = 0;
+ for (var id in this.displayLayoutMap_) {
+ if (id == child.id)
+ continue;
+ if (opt_ignoreIds && opt_ignoreIds.indexOf(id) != -1)
+ continue;
+ var div = this.displayLayoutMap_[id].div;
+ var left = div.offsetLeft;
+ var top = div.offsetTop;
+ var width = div.offsetWidth;
+ var height = div.offsetHeight;
+ if (x >= left && x < left + width && y >= top && y < top + height)
+ return id; // point is inside rect
+ var dx, dy;
+ if (x < left)
+ dx = left - x;
+ else if (x > left + width)
+ dx = x - (left + width);
+ else
+ dx = 0;
+ if (y < top)
+ dy = top - y;
+ else if (y > top + height)
+ dy = y - (top + height);
+ else
+ dy = 0;
+ var delta2 = dx * dx + dy * dy;
+ if (closestId == '' || delta2 < closestDelta2) {
+ closestId = id;
+ closestDelta2 = delta2;
+ }
+ }
+ return closestId;
+ },
+
+ /**
+ * Highlights the edge of the div associated with |parentId| based on
+ * |layoutType| and removes any other highlights. If |layoutType| is
+ * undefined, removes all highlights.
+ * @param {string} id
+ * @param {options.DisplayLayoutType|undefined} layoutType
+ * @private
+ */
+ highlightEdge_: function(id, layoutType) {
+ for (var tid in this.displayLayoutMap_) {
+ var tlayout = this.displayLayoutMap_[tid];
+ var highlight = '';
+ if (tlayout.id == id) {
+ switch (layoutType) {
+ case options.DisplayLayoutType.RIGHT:
+ highlight = 'displays-parent-right';
+ break;
+ case options.DisplayLayoutType.LEFT:
+ highlight = 'displays-parent-left';
+ break;
+ case options.DisplayLayoutType.TOP:
+ highlight = 'displays-parent-top';
+ break;
+ case options.DisplayLayoutType.BOTTOM:
+ highlight = 'displays-parent-bottom';
+ break;
+ }
+ }
+ tlayout.div.classList.toggle(
+ 'displays-parent-right', highlight == 'displays-parent-right');
+ tlayout.div.classList.toggle(
+ 'displays-parent-left', highlight == 'displays-parent-left');
+ tlayout.div.classList.toggle(
+ 'displays-parent-top', highlight == 'displays-parent-top');
+ tlayout.div.classList.toggle(
+ 'displays-parent-bottom', highlight == 'displays-parent-bottom');
+ }
+ },
+
+ /**
+ * Calculates but do not set the div bound.
+ * @param {!options.DisplayLayout} layout
+ * @return {!options.DisplayBounds}
+ */
+ calcLayoutBounds_: function(layout) {
+ if (layout.parentId == '')
+ return /** @type {!options.DisplayBounds} */ (layout.bounds);
+ var parent = this.displayLayoutMap_[layout.parentId];
+ // Parent layout bounds may not be calculated yet, so calculate (but
+ // do not set) them.
+ var parentBounds = this.calcLayoutBounds_(parent);
+ return layout.calculateBounds(parentBounds);
+ },
+
+ /**
+ * @param {number} num
+ */
+ createFakeDisplays_: function(num) {
+ if (num != fakeDisplayNum)
+ fakeDisplays = [];
+ var primary;
+ for (var id in this.displayLayoutMap_) {
+ var layout = this.displayLayoutMap_[id];
+ if (layout.parentId == '')
+ primary = layout;
+ }
+ for (var i = 0; i < num; ++i) {
+ if (i < fakeDisplays.length) {
+ fakeDisplays[i].div = null;
+ } else {
+ var fakeId = FAKE_ID_PREFIX + i;
+ var layoutType = /** @type {options.DisplayLayoutType} */ (i % 4);
+ var bounds = /** @type {!options.DisplayBounds} */ (primary.bounds);
+ var fakeDisplayLayout = new options.DisplayLayout(
+ fakeId, 'Fake Display ' + i, bounds, layoutType, primary.id);
+ fakeDisplayLayout.bounds = this.calcLayoutBounds_(fakeDisplayLayout);
+ fakeDisplays.push(fakeDisplayLayout);
+ }
+ }
+ }
+ };
+
+ // Export
+ return {DisplayLayoutManagerMulti: DisplayLayoutManagerMulti};
+});
diff --git a/chrome/browser/resources/options/chromeos/display_options.css b/chrome/browser/resources/options/chromeos/display_options.css
index de3995f..36b6332 100644
--- a/chrome/browser/resources/options/chromeos/display_options.css
+++ b/chrome/browser/resources/options/chromeos/display_options.css
@@ -93,6 +93,22 @@
color: rgb(0, 138, 255);
}
+.displays-parent-left {
+ border-left: solid 1px rgb(255, 138, 0);
+}
+
+.displays-parent-right {
+ border-right: solid 1px rgb(255, 138, 0);
+}
+
+.displays-parent-top {
+ border-top: solid 1px rgb(255, 138, 0);
+}
+
+.displays-parent-bottom {
+ border-bottom: solid 1px rgb(255, 138, 0);
+}
+
#display-options-select-mirroring {
margin-right: 5px;
}
diff --git a/chrome/browser/resources/options/chromeos/display_options.js b/chrome/browser/resources/options/chromeos/display_options.js
index 778b21c..b90e346 100644
--- a/chrome/browser/resources/options/chromeos/display_options.js
+++ b/chrome/browser/resources/options/chromeos/display_options.js
@@ -106,6 +106,13 @@ cr.define('options', function() {
displays_: [],
/**
+ * Whether to use DisplayLayoutManagerMulti.
+ * @type {boolean}
+ * @private
+ */
+ multiDisplayLayout_: false,
+
+ /**
* Manages the display layout.
* @type {?options.DisplayLayoutManager}
* @private
@@ -234,14 +241,15 @@ cr.define('options', function() {
* @param {boolean} enabled Whether the page should be enabled.
* @param {boolean} showUnifiedDesktop Whether the unified desktop option
* should be present.
+ * @param {boolean} multiDisplayLayout Whether to use
+ * DisplayLayoutManagerMulti.
*/
- setEnabled: function(enabled, showUnifiedDesktop) {
- if (this.enabled_ == enabled &&
- this.showUnifiedDesktopOption_ == showUnifiedDesktop) {
+ setEnabled: function(enabled, showUnifiedDesktop, multiDisplayLayout) {
+ this.showUnifiedDesktopOption_ = showUnifiedDesktop;
+ this.multiDisplayLayout_ = multiDisplayLayout;
+ if (this.enabled_ == enabled)
return;
- }
this.enabled_ = enabled;
- this.showUnifiedDesktopOption_ = showUnifiedDesktop;
if (!enabled && this.visible)
PageManager.closeOverlay();
},
@@ -389,7 +397,8 @@ cr.define('options', function() {
var updateDisplayDescription = focused.id != this.focusedId_;
this.focusedId_ = focused.id;
- this.displayLayoutManager_.setFocusedId(focused.id);
+ this.displayLayoutManager_.setFocusedId(
+ focused.id, true /* user action */);
if (this.displayLayoutManager_.getDisplayLayoutCount() > 1) {
this.dragInfo_ = {
@@ -639,7 +648,10 @@ cr.define('options', function() {
*/
layoutDisplays_: function(layoutType) {
// Create the layout manager.
- this.displayLayoutManager_ = new options.DisplayLayoutManager();
+ if (this.multiDisplayLayout_)
+ this.displayLayoutManager_ = new options.DisplayLayoutManagerMulti();
+ else
+ this.displayLayoutManager_ = new options.DisplayLayoutManager();
// Create the display layouts. Child displays are parented to the primary.
// TODO(stevenjb): DisplayInfo should provide the parent id for displays.
diff --git a/chrome/browser/resources/options/options_bundle.js b/chrome/browser/resources/options/options_bundle.js
index 7e14154..811c5f0 100644
--- a/chrome/browser/resources/options/options_bundle.js
+++ b/chrome/browser/resources/options/options_bundle.js
@@ -34,6 +34,7 @@
<include src="chromeos/consumer_management_overlay.js">
<include src="chromeos/display_layout.js">
<include src="chromeos/display_layout_manager.js">
+<include src="chromeos/display_layout_manager_multi.js">
<include src="chromeos/display_options.js">
<include src="chromeos/display_overscan.js">
<include src="chromeos/keyboard_overlay.js">
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
index 5813b42..1396536 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -17,12 +17,14 @@
#include "ash/screen_util.h"
#include "ash/shell.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/chromeos/display/display_preferences.h"
#include "chrome/grit/generated_resources.h"
+#include "chromeos/chromeos_switches.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_ui.h"
#include "grit/ash_strings.h"
@@ -346,11 +348,14 @@ void DisplayOptionsHandler::SendDisplayInfo(
void DisplayOptionsHandler::UpdateDisplaySettingsEnabled() {
bool enabled = GetDisplayManager()->num_connected_displays() <= 2;
bool show_unified_desktop = GetDisplayManager()->unified_desktop_enabled();
+ bool multi_display_layout = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kEnableMultiDisplayLayout);
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.enableDisplaySettings",
base::FundamentalValue(enabled),
- base::FundamentalValue(show_unified_desktop));
+ base::FundamentalValue(show_unified_desktop),
+ base::FundamentalValue(multi_display_layout));
}
void DisplayOptionsHandler::HandleDisplayInfo(
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index b148ac7..afb9b83f 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -158,6 +158,9 @@ const char kEnableScreenshotTestingWithMode[] =
// than the kiosk app mode.
const char kEnableKioskMode[] = "enable-kiosk-mode";
+// Enable the multiple display layout UI.
+const char kEnableMultiDisplayLayout[] = "enable-multi-display-layout";
+
// Enables request of tablet site (via user agent override).
const char kEnableRequestTabletSite[] = "enable-request-tablet-site";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 87e7a4c..ee53d4e 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -63,6 +63,7 @@ CHROMEOS_EXPORT extern const char kEnableExtensionAssetsSharing[];
CHROMEOS_EXPORT extern const char kEnableFirstRunUITransitions[];
CHROMEOS_EXPORT extern const char kEnableImeMenu[];
CHROMEOS_EXPORT extern const char kEnableKioskMode[];
+CHROMEOS_EXPORT extern const char kEnableMultiDisplayLayout[];
CHROMEOS_EXPORT extern const char kEnableNetworkPortalNotification[];
CHROMEOS_EXPORT extern const char kDisableNewKoreanIme[];
CHROMEOS_EXPORT extern const char kEnablePhysicalKeyboardAutocorrect[];