summaryrefslogtreecommitdiff
path: root/chromium/ash/wm/dock/docked_window_layout_manager.cc
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-11-21 14:09:57 +0100
committerAndras Becsi <andras.becsi@digia.com>2013-11-29 15:14:36 +0100
commiteb32ba6f51d0c21d58cd7d89785285ff8fa64624 (patch)
tree2c7c940e1dbee81b89d935626110816b494aa32c /chromium/ash/wm/dock/docked_window_layout_manager.cc
parent9427c1a0222ebd67efef1a2c7990a0fa5c9aac84 (diff)
downloadqtwebengine-chromium-eb32ba6f51d0c21d58cd7d89785285ff8fa64624.tar.gz
Update chromium to branch 1599.
Change-Id: I04e775a946a208bb4500d3b722bcb05c82b9d7cb Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ash/wm/dock/docked_window_layout_manager.cc')
-rw-r--r--chromium/ash/wm/dock/docked_window_layout_manager.cc350
1 files changed, 160 insertions, 190 deletions
diff --git a/chromium/ash/wm/dock/docked_window_layout_manager.cc b/chromium/ash/wm/dock/docked_window_layout_manager.cc
index 1dacf5e9fbd..d73a0ccac7d 100644
--- a/chromium/ash/wm/dock/docked_window_layout_manager.cc
+++ b/chromium/ash/wm/dock/docked_window_layout_manager.cc
@@ -84,58 +84,10 @@ bool IsUsedByLayout(aura::Window* window) {
window->type() != aura::client::WINDOW_TYPE_POPUP);
}
-// A functor used to sort the windows in order of their center Y position.
-// |delta| is a pre-calculated distance from the bottom of one window to the top
-// of the next. Its value can be positive (gap) or negative (overlap).
-// Half of |delta| is used as a transition point at which windows could ideally
-// swap positions.
-struct CompareWindowPos {
- CompareWindowPos(aura::Window* dragged_window, float delta)
- : dragged_window_(dragged_window),
- delta_(delta / 2) {}
-
- bool operator()(const aura::Window* win1, const aura::Window* win2) {
- const gfx::Rect win1_bounds = win1->GetBoundsInScreen();
- const gfx::Rect win2_bounds = win2->GetBoundsInScreen();
- // If one of the windows is the |dragged_window_| attempt to make an
- // earlier swap between the windows than just based on their centers.
- // This is possible if the dragged window is at least as tall as the other
- // window.
- if (win1 == dragged_window_)
- return compare_two_windows(win1_bounds, win2_bounds);
- if (win2 == dragged_window_)
- return !compare_two_windows(win2_bounds, win1_bounds);
- // Otherwise just compare the centers.
- return win1_bounds.CenterPoint().y() < win2_bounds.CenterPoint().y();
- }
-
- // Based on center point tries to deduce where the drag is coming from.
- // When dragging from below up the transition point is lower.
- // When dragging from above down the transition point is higher.
- bool compare_bounds(const gfx::Rect dragged, const gfx::Rect other) {
- if (dragged.CenterPoint().y() < other.CenterPoint().y())
- return dragged.CenterPoint().y() < other.y() - delta_;
- return dragged.CenterPoint().y() < other.bottom() + delta_;
- }
-
- // Performs comparison both ways and selects stable result.
- bool compare_two_windows(const gfx::Rect bounds1, const gfx::Rect bounds2) {
- // Try comparing windows in both possible orders and see if the comparison
- // is stable.
- bool result1 = compare_bounds(bounds1, bounds2);
- bool result2 = compare_bounds(bounds2, bounds1);
- if (result1 != result2)
- return result1;
-
- // Otherwise it is not possible to be sure that the windows will not bounce.
- // In this case just compare the centers.
- return bounds1.CenterPoint().y() < bounds2.CenterPoint().y();
- }
-
- private:
- aura::Window* dragged_window_;
- float delta_;
-};
+bool CompareWindowPos(const aura::Window* win1, const aura::Window* win2) {
+ return win1->GetTargetBounds().CenterPoint().y() <
+ win2->GetTargetBounds().CenterPoint().y();
+}
} // namespace
@@ -146,8 +98,6 @@ DockedWindowLayoutManager::DockedWindowLayoutManager(
: dock_container_(dock_container),
in_layout_(false),
dragged_window_(NULL),
- is_dragged_window_docked_(false),
- is_dragged_from_dock_(false),
launcher_(NULL),
shelf_layout_manager_(NULL),
shelf_hidden_(false),
@@ -189,79 +139,106 @@ void DockedWindowLayoutManager::RemoveObserver(
}
void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
+ if (window->parent() != dock_container_)
+ return;
DCHECK(!dragged_window_);
dragged_window_ = window;
- // Start observing a window unless it is docked container's child in which
- // case it is already observed.
- if (dragged_window_->parent() != dock_container_)
- dragged_window_->AddObserver(this);
- is_dragged_from_dock_ = window->parent() == dock_container_;
- DCHECK(!is_dragged_window_docked_);
-}
-
-void DockedWindowLayoutManager::DockDraggedWindow(aura::Window* window) {
- OnWindowDocked(window);
Relayout();
}
-void DockedWindowLayoutManager::UndockDraggedWindow() {
- OnWindowUndocked();
- Relayout();
- is_dragged_from_dock_ = false;
-}
-
void DockedWindowLayoutManager::FinishDragging() {
- DCHECK(dragged_window_);
- if (is_dragged_window_docked_)
- OnWindowUndocked();
- DCHECK (!is_dragged_window_docked_);
- // Stop observing a window unless it is docked container's child in which
- // case it needs to keep being observed after the drag completes.
- if (dragged_window_->parent() != dock_container_)
- dragged_window_->RemoveObserver(this);
- dragged_window_ = NULL;
+ if (!dragged_window_)
+ return;
+
+ // If this is the first window getting docked - update alignment.
+ if (alignment_ == DOCKED_ALIGNMENT_NONE) {
+ alignment_ = AlignmentOfWindow(dragged_window_);
+ } else {
+ // There were some docked windows before. Check if the |dragged_window_|
+ // was the only one remaining and if so possibly switch alignment to
+ // opposite side. Ignore popups.
+ bool found_docked_window = false;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window(dock_container_->children()[i]);
+ if (window != dragged_window_ &&
+ window->type() != aura::client::WINDOW_TYPE_POPUP) {
+ found_docked_window = true;
+ break;
+ }
+ }
+ if (!found_docked_window)
+ alignment_ = AlignmentOfWindow(dragged_window_);
+ }
+
+ // We no longer need to observe |dragged_window_| unless it is added back;
+ if (dragged_window_) {
+ if (dragged_window_->parent() != dock_container_)
+ dragged_window_->RemoveObserver(this);
+ dragged_window_ = NULL;
+ }
+
Relayout();
UpdateDockBounds();
}
-void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) {
- DCHECK(!launcher_);
- DCHECK(!shelf_layout_manager_);
- launcher_ = launcher;
- if (launcher_->shelf_widget()) {
- shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
- launcher_->shelf_widget()->GetNativeWindow());
- WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
- shelf_layout_manager_->AddObserver(this);
+// static
+bool DockedWindowLayoutManager::ShouldWindowDock(aura::Window* window,
+ const gfx::Point& location) {
+ DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
+ location);
+ const DockedAlignment alignment = layout_manager->CalculateAlignment();
+ const gfx::Rect& bounds(window->GetBoundsInScreen());
+ const gfx::Rect docked_bounds = (alignment == DOCKED_ALIGNMENT_NONE) ?
+ layout_manager->dock_container_->GetBoundsInScreen() :
+ layout_manager->docked_bounds_;
+ DockedAlignment dock_edge = DOCKED_ALIGNMENT_NONE;
+ if (alignment == DOCKED_ALIGNMENT_NONE) {
+ // Check if the window is touching the edge - it may need to get docked.
+ dock_edge = layout_manager->AlignmentOfWindow(window);
+ } else if ((docked_bounds.Intersects(bounds) &&
+ docked_bounds.Contains(location)) ||
+ alignment == layout_manager->AlignmentOfWindow(window)) {
+ // A window is being added to other docked windows (on the same side).
+ // Both bounds and pointer location are checked because some drags involve
+ // sticky edges and so the |location| may be outside of the |bounds|.
+ // It is also possible that all the docked windows are minimized or hidden
+ // in which case the dragged window needs to be exactly touching the same
+ // edge that those docked windows were aligned before they got minimized.
+ dock_edge = alignment;
}
-}
-DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow(
- const aura::Window* window) const {
- const gfx::Rect& bounds(window->GetBoundsInScreen());
- const gfx::Rect docked_bounds = dock_container_->GetBoundsInScreen();
+ // Do not allow docking on the same side as launcher shelf.
+ if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
+ ShelfAlignment shelf_alignment =
+ layout_manager->launcher_->shelf_widget()->GetAlignment();
+ if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
+ dock_edge == DOCKED_ALIGNMENT_LEFT) ||
+ (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
+ dock_edge == DOCKED_ALIGNMENT_RIGHT)) {
+ dock_edge = DOCKED_ALIGNMENT_NONE;
+ }
+ }
// Do not allow docking if a window is vertically maximized (as is the case
// when it is snapped).
const gfx::Rect work_area =
- Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
+ Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
if (bounds.y() == work_area.y() && bounds.height() == work_area.height())
- return DOCKED_ALIGNMENT_NONE;
+ dock_edge = DOCKED_ALIGNMENT_NONE;
- // Do not allow docking on the same side as launcher shelf.
- ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM;
- if (launcher_)
- shelf_alignment = launcher_->alignment();
+ return dock_edge != DOCKED_ALIGNMENT_NONE;
+}
- if (bounds.x() == docked_bounds.x() &&
- shelf_alignment != SHELF_ALIGNMENT_LEFT) {
- return DOCKED_ALIGNMENT_LEFT;
- }
- if (bounds.right() == docked_bounds.right() &&
- shelf_alignment != SHELF_ALIGNMENT_RIGHT) {
- return DOCKED_ALIGNMENT_RIGHT;
+void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) {
+ DCHECK(!launcher_);
+ DCHECK(!shelf_layout_manager_);
+ launcher_ = launcher;
+ if (launcher_->shelf_widget()) {
+ shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
+ launcher_->shelf_widget()->GetNativeWindow());
+ WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
+ shelf_layout_manager_->AddObserver(this);
}
- return DOCKED_ALIGNMENT_NONE;
}
DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const {
@@ -285,24 +262,22 @@ DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const {
// DockLayoutManager, aura::LayoutManager implementation:
void DockedWindowLayoutManager::OnWindowResized() {
Relayout();
- // When screen resizes update the insets even when dock width or alignment
- // does not change.
+ // When screen resizes we need to update the insets even when dock width or
+ // alignment does not change.
UpdateDockBounds();
}
void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
if (child->type() == aura::client::WINDOW_TYPE_POPUP)
return;
- // Dragged windows are already observed by StartDragging and do not change
- // docked alignment during the drag.
- if (child == dragged_window_)
- return;
+
// If this is the first window getting docked - update alignment.
- if (alignment_ == DOCKED_ALIGNMENT_NONE) {
- alignment_ = GetAlignmentOfWindow(child);
- DCHECK(alignment_ != DOCKED_ALIGNMENT_NONE);
- }
- child->AddObserver(this);
+ if (alignment_ == DOCKED_ALIGNMENT_NONE)
+ alignment_ = AlignmentOfWindow(child);
+ // We need to observe a child unless it is a |dragged_window_| that just got
+ // added back in which case we are already observing it.
+ if (child != dragged_window_)
+ child->AddObserver(this);
Relayout();
UpdateDockBounds();
}
@@ -310,20 +285,36 @@ void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
if (child->type() == aura::client::WINDOW_TYPE_POPUP)
return;
- // Dragged windows are stopped being observed by FinishDragging and do not
- // change alignment during the drag. They also cannot be set to be the
- // |last_active_window_|.
- if (child == dragged_window_)
- return;
- // If this is the last window, set alignment and maximize the workspace.
- if (!IsAnyWindowDocked()) {
- alignment_ = DOCKED_ALIGNMENT_NONE;
- docked_width_ = 0;
+
+ // Try to find a child that is not a popup and is not being dragged.
+ bool found_docked_window = false;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window(dock_container_->children()[i]);
+ if (window != dragged_window_ &&
+ window->type() != aura::client::WINDOW_TYPE_POPUP) {
+ found_docked_window = true;
+ break;
+ }
}
+ if (!found_docked_window)
+ alignment_ = DOCKED_ALIGNMENT_NONE;
+
+ // Keep track of former children if they are dragged as they can be reparented
+ // temporarily just for the drag.
+ if (child != dragged_window_)
+ child->RemoveObserver(this);
+
if (last_active_window_ == child)
last_active_window_ = NULL;
- child->RemoveObserver(this);
+
+ // Close the dock and expand workspace work area.
Relayout();
+
+ // When a panel is removed from this layout manager it may still be dragged.
+ // Delay updating dock and workspace bounds until the drag is completed. This
+ // preserves the docked area width until the panel drag is finished.
+ if (child->type() != aura::client::WINDOW_TYPE_PANEL)
+ UpdateDockBounds();
}
void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
@@ -340,8 +331,11 @@ void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
void DockedWindowLayoutManager::SetChildBounds(
aura::Window* child,
const gfx::Rect& requested_bounds) {
- // Whenever one of our windows is moved or resized enforce layout.
+ // Whenever one of our windows is moved or resized we need to enforce layout.
SetChildBoundsDirect(child, requested_bounds);
+ if (child->type() == aura::client::WINDOW_TYPE_POPUP)
+ return;
+ Relayout();
}
////////////////////////////////////////////////////////////////////////////////
@@ -394,18 +388,13 @@ void DockedWindowLayoutManager::OnWindowBoundsChanged(
aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- // Only relayout if the dragged window would get docked.
- if (window == dragged_window_ && is_dragged_window_docked_)
+ if (window == dragged_window_)
Relayout();
}
void DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) {
if (dragged_window_ == window)
- FinishDragging();
- DCHECK(!dragged_window_);
- DCHECK (!is_dragged_window_docked_);
- if (window == last_active_window_)
- last_active_window_ = NULL;
+ dragged_window_ = NULL;
}
@@ -437,7 +426,7 @@ void DockedWindowLayoutManager::WillChangeVisibilityState(
// to allow the full-screen application to use the full screen.
// TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
- // SHELF_AUTO_HIDE when in immersive mode. Distinguish this from
+ // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
// when shelf enters auto-hide state based on mouse hover when auto-hide
// setting is enabled and hide all windows (immersive mode should hide docked
// windows).
@@ -473,43 +462,30 @@ void DockedWindowLayoutManager::RestoreWindow(aura::Window* window) {
window->Show();
}
-void DockedWindowLayoutManager::OnWindowDocked(aura::Window* window) {
- DCHECK(!is_dragged_window_docked_);
- is_dragged_window_docked_ = true;
-
- // If there are no other docked windows update alignment.
- if (!IsAnyWindowDocked())
- alignment_ = DOCKED_ALIGNMENT_NONE;
-}
-
-void DockedWindowLayoutManager::OnWindowUndocked() {
- // If this is the first window getting docked - update alignment.
- if (!IsAnyWindowDocked())
- alignment_ = GetAlignmentOfWindow(dragged_window_);
-
- DCHECK (is_dragged_window_docked_);
- is_dragged_window_docked_ = false;
-}
-
-bool DockedWindowLayoutManager::IsAnyWindowDocked() {
- return CalculateAlignment() != DOCKED_ALIGNMENT_NONE;
+DockedAlignment DockedWindowLayoutManager::AlignmentOfWindow(
+ const aura::Window* window) const {
+ const gfx::Rect& bounds(window->GetBoundsInScreen());
+ const gfx::Rect docked_bounds = dock_container_->GetBoundsInScreen();
+ if (bounds.x() == docked_bounds.x())
+ return DOCKED_ALIGNMENT_LEFT;
+ if (bounds.right() == docked_bounds.right())
+ return DOCKED_ALIGNMENT_RIGHT;
+ return DOCKED_ALIGNMENT_NONE;
}
void DockedWindowLayoutManager::Relayout() {
- if (in_layout_)
- return;
- if (alignment_ == DOCKED_ALIGNMENT_NONE && !is_dragged_window_docked_)
+ if (in_layout_ || alignment_ == DOCKED_ALIGNMENT_NONE)
return;
base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
- gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen();
+ gfx::Rect dock_bounds = dock_container_->bounds();
aura::Window* active_window = NULL;
aura::Window::Windows visible_windows;
docked_width_ = 0;
for (size_t i = 0; i < dock_container_->children().size(); ++i) {
aura::Window* window(dock_container_->children()[i]);
- if (!IsUsedByLayout(window) || window == dragged_window_)
+ if (!IsUsedByLayout(window))
continue;
// If the shelf is currently hidden (full-screen mode), hide window until
@@ -529,14 +505,14 @@ void DockedWindowLayoutManager::Relayout() {
visible_windows.push_back(window);
}
- // Consider docked dragged_window_ when fanning out other child windows.
- if (is_dragged_window_docked_) {
+ // Consider windows that were formerly children of the |dock_container_|
+ // when fanning out other child windows.
+ if (dragged_window_ && dragged_window_->parent() != dock_container_)
visible_windows.push_back(dragged_window_);
- DCHECK(!active_window);
- active_window = dragged_window_;
- }
- // Calculate free space or overlap.
+ // Sort windows by their center positions and fan out overlapping
+ // windows.
+ std::sort(visible_windows.begin(), visible_windows.end(), CompareWindowPos);
gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
dock_container_);
const gfx::Rect work_area = display.work_area();
@@ -549,19 +525,15 @@ void DockedWindowLayoutManager::Relayout() {
const float delta = (float)available_room /
((available_room > 0 || num_windows <= 1) ?
num_windows + 1 : num_windows - 1);
- float y_pos = work_area.y() + ((available_room > 0) ? delta : 0);
+ float y_pos = (available_room > 0) ? delta : 0;
- // Sort windows by their center positions and fan out overlapping
- // windows.
- std::sort(visible_windows.begin(),
- visible_windows.end(),
- CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL,
- delta));
- is_dragged_from_dock_ = true;
for (aura::Window::Windows::const_iterator iter = visible_windows.begin();
iter != visible_windows.end(); ++iter) {
aura::Window* window = *iter;
- gfx::Rect bounds = window->GetBoundsInScreen();
+ gfx::Rect bounds = window->GetTargetBounds();
+ // Do not force position of a single window.
+ if (num_windows == 1)
+ y_pos = bounds.y();
// Fan out windows evenly distributing the overlap or remaining free space.
bounds.set_y(std::max(work_area.y(),
@@ -571,27 +543,24 @@ void DockedWindowLayoutManager::Relayout() {
// All docked windows other than the one currently dragged remain stuck
// to the screen edge.
+ if (window == dragged_window_)
+ continue;
switch (alignment_) {
case DOCKED_ALIGNMENT_LEFT:
- bounds.set_x(dock_bounds.x());
+ bounds.set_x(0);
break;
case DOCKED_ALIGNMENT_RIGHT:
bounds.set_x(dock_bounds.right() - bounds.width());
break;
case DOCKED_ALIGNMENT_NONE:
+ NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
break;
}
- if (window == dragged_window_) {
- dragged_bounds_ = bounds;
- continue;
- }
- DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE);
// Keep the dock at least kMinDockWidth when all windows in it overhang.
docked_width_ = std::min(kMaxDockWidth,
std::max(docked_width_,
bounds.width() > kMaxDockWidth ?
kMinDockWidth : bounds.width()));
- bounds = ScreenAsh::ConvertRectFromScreen(dock_container_, bounds);
SetChildBoundsDirect(window, bounds);
}
UpdateStacking(active_window);
@@ -600,7 +569,7 @@ void DockedWindowLayoutManager::Relayout() {
void DockedWindowLayoutManager::UpdateDockBounds() {
int dock_inset = docked_width_ + (docked_width_ > 0 ? kMinDockGap : 0);
gfx::Rect bounds = gfx::Rect(
- alignment_ == DOCKED_ALIGNMENT_RIGHT && dock_inset > 0 ?
+ alignment_ == DOCKED_ALIGNMENT_RIGHT ?
dock_container_->bounds().right() - dock_inset:
dock_container_->bounds().x(),
dock_container_->bounds().y(),
@@ -632,7 +601,7 @@ void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
active_window = last_active_window_;
}
- // Windows are stacked like a deck of cards:
+ // We want to to stack the windows like a deck of cards:
// ,------.
// |,------.|
// |,------.|
@@ -641,7 +610,7 @@ void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
// |`------'|
// |`------'|
// `------'
- // Use the middle of each window to figure out how to stack the window.
+ // We use the middle of each window to figure out how to stack the window.
// This allows us to update the stacking when a window is being dragged around
// by the titlebar.
std::map<int, aura::Window*> window_ordering;
@@ -656,7 +625,7 @@ void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
}
int active_center_y = active_window->bounds().CenterPoint().y();
- aura::Window* previous_window = NULL;
+ aura::Window* previous_window = background_widget_->GetNativeWindow();
for (std::map<int, aura::Window*>::const_iterator it =
window_ordering.begin();
it != window_ordering.end() && it->first < active_center_y; ++it) {
@@ -676,8 +645,9 @@ void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
if (active_window->parent() == dock_container_)
dock_container_->StackChildAtTop(active_window);
- if (active_window != dragged_window_)
- last_active_window_ = active_window;
+ if (dragged_window_ && dragged_window_->parent() == dock_container_)
+ dock_container_->StackChildAtTop(dragged_window_);
+ last_active_window_ = active_window;
}
////////////////////////////////////////////////////////////////////////////////