| Index: ash/wm/workspace/workspace_window_resizer.cc
|
| diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
|
| index a68c9fdff151663d71dd6edc4dc4af65717ef1da..e7ace29b303b83f26c87e6a42ef8a2ca62ac0b76 100644
|
| --- a/ash/wm/workspace/workspace_window_resizer.cc
|
| +++ b/ash/wm/workspace/workspace_window_resizer.cc
|
| @@ -27,6 +27,10 @@ const aura::WindowProperty<int> kHeightBeforeObscuredProp = {0};
|
| const aura::WindowProperty<int>* const kHeightBeforeObscuredKey =
|
| &kHeightBeforeObscuredProp;
|
|
|
| +const aura::WindowProperty<int> kWidthBeforeObscuredProp = {0};
|
| +const aura::WindowProperty<int>* const kWidthBeforeObscuredKey =
|
| + &kWidthBeforeObscuredProp;
|
| +
|
| void SetHeightBeforeObscured(aura::Window* window, int height) {
|
| window->SetProperty(kHeightBeforeObscuredKey, height);
|
| }
|
| @@ -39,8 +43,23 @@ void ClearHeightBeforeObscured(aura::Window* window) {
|
| window->SetProperty(kHeightBeforeObscuredKey, 0);
|
| }
|
|
|
| +void SetWidthBeforeObscured(aura::Window* window, int width) {
|
| + window->SetProperty(kWidthBeforeObscuredKey, width);
|
| +}
|
| +
|
| +int GetWidthBeforeObscured(aura::Window* window) {
|
| + return window->GetProperty(kWidthBeforeObscuredKey);
|
| +}
|
| +
|
| +void ClearWidthBeforeObscured(aura::Window* window) {
|
| + window->SetProperty(kWidthBeforeObscuredKey, 0);
|
| +}
|
| +
|
| } // namespace
|
|
|
| +// static
|
| +const int WorkspaceWindowResizer::kMinOnscreenSize = 20;
|
| +
|
| WorkspaceWindowResizer::~WorkspaceWindowResizer() {
|
| if (root_filter_)
|
| root_filter_->UnlockCursor();
|
| @@ -51,10 +70,11 @@ WorkspaceWindowResizer* WorkspaceWindowResizer::Create(
|
| aura::Window* window,
|
| const gfx::Point& location,
|
| int window_component,
|
| - int grid_size) {
|
| + int grid_size,
|
| + const std::vector<aura::Window*>& attached_windows) {
|
| Details details(window, location, window_component, grid_size);
|
| return details.is_resizable ?
|
| - new WorkspaceWindowResizer(details) : NULL;
|
| + new WorkspaceWindowResizer(details, attached_windows) : NULL;
|
| }
|
|
|
| void WorkspaceWindowResizer::Drag(const gfx::Point& location) {
|
| @@ -65,9 +85,17 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location) {
|
| did_move_or_resize_ = true;
|
| details_.window->SetBounds(bounds);
|
| }
|
| + if (!attached_windows_.empty()) {
|
| + if (details_.window_component == HTRIGHT)
|
| + LayoutAttachedWindowsHorizontally(bounds);
|
| + else
|
| + LayoutAttachedWindowsVertically(bounds);
|
| + }
|
| }
|
|
|
| void WorkspaceWindowResizer::CompleteDrag() {
|
| + // This code only matters when dragging the caption and there's a grid, so
|
| + // it doesn't need to worry about attached windows.
|
| if (details_.grid_size <= 1 || !did_move_or_resize_ ||
|
| details_.window_component != HTCAPTION)
|
| return;
|
| @@ -112,30 +140,185 @@ void WorkspaceWindowResizer::RevertDrag() {
|
| return;
|
|
|
| details_.window->SetBounds(details_.initial_bounds);
|
| + if (details_.window_component == HTRIGHT) {
|
| + int last_x = details_.initial_bounds.right();
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect bounds(attached_windows_[i]->bounds());
|
| + bounds.set_x(last_x);
|
| + bounds.set_width(initial_size_[i]);
|
| + attached_windows_[i]->SetBounds(bounds);
|
| + last_x = attached_windows_[i]->bounds().right();
|
| + }
|
| + } else {
|
| + int last_y = details_.initial_bounds.bottom();
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect bounds(attached_windows_[i]->bounds());
|
| + bounds.set_y(last_y);
|
| + bounds.set_height(initial_size_[i]);
|
| + attached_windows_[i]->SetBounds(bounds);
|
| + last_y = attached_windows_[i]->bounds().bottom();
|
| + }
|
| + }
|
| }
|
|
|
| WorkspaceWindowResizer::WorkspaceWindowResizer(
|
| - const Details& details)
|
| + const Details& details,
|
| + const std::vector<aura::Window*>& attached_windows)
|
| : details_(details),
|
| constrain_size_(wm::IsWindowNormal(details.window)),
|
| + attached_windows_(attached_windows),
|
| did_move_or_resize_(false),
|
| - root_filter_(NULL) {
|
| + root_filter_(NULL),
|
| + total_min_(0),
|
| + total_initial_size_(0) {
|
| DCHECK(details_.is_resizable);
|
| root_filter_ = Shell::GetInstance()->root_filter();
|
| if (root_filter_)
|
| root_filter_->LockCursor();
|
|
|
| + // We should never be in a situation where we have an attached window and not
|
| + // constrain the size. The only case we don't constrain size is for dragging
|
| + // tabs, which should never have an attached window.
|
| + DCHECK(attached_windows_.empty() || constrain_size_);
|
| + // Only support attaching to the right/bottom.
|
| + DCHECK(attached_windows_.empty() ||
|
| + (details.window_component == HTRIGHT ||
|
| + details.window_component == HTBOTTOM));
|
| +
|
| + // TODO: figure out how to deal with window going off the edge.
|
| +
|
| + // Calculate sizes so that we can maintain the ratios if we need to resize.
|
| + int total_available = 0;
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Size min(attached_windows_[i]->delegate()->GetMinimumSize());
|
| + int initial_size = PrimaryAxisSize(attached_windows_[i]->bounds().size());
|
| + int cached_size = PrimaryAxisCoordinate(
|
| + GetWidthBeforeObscured(attached_windows_[i]),
|
| + GetHeightBeforeObscured(attached_windows_[i]));
|
| + if (initial_size > cached_size) {
|
| + if (details.window_component == HTRIGHT)
|
| + ClearWidthBeforeObscured(attached_windows_[i]);
|
| + else
|
| + ClearHeightBeforeObscured(attached_windows_[i]);
|
| + } else if (cached_size) {
|
| + initial_size = cached_size;
|
| + }
|
| + initial_size_.push_back(initial_size);
|
| + // If current size is smaller than the min, use the current size as the min.
|
| + // This way we don't snap on resize.
|
| + int min_size = std::min(initial_size,
|
| + std::max(PrimaryAxisSize(min), kMinOnscreenSize));
|
| + // Make sure the min size falls on the grid.
|
| + if (details_.grid_size > 1 && min_size % details_.grid_size != 0)
|
| + min_size = (min_size / details_.grid_size + 1) * details_.grid_size;
|
| + min_size_.push_back(min_size);
|
| + total_min_ += min_size;
|
| + total_initial_size_ += initial_size;
|
| + total_available += std::max(min_size, initial_size) - min_size;
|
| + }
|
| +
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + if (total_initial_size_ != total_min_) {
|
| + compress_fraction_.push_back(
|
| + static_cast<float>(initial_size_[i] - min_size_[i]) /
|
| + static_cast<float>(total_available));
|
| + } else {
|
| + compress_fraction_.push_back(0.0f);
|
| + }
|
| + }
|
| +
|
| if (is_resizable() && constrain_size_ &&
|
| (!TouchesBottomOfScreen() ||
|
| details_.bounds_change != kBoundsChange_Repositions)) {
|
| ClearCachedHeights();
|
| }
|
| +
|
| + if (is_resizable() && constrain_size_ &&
|
| + (!TouchesRightSideOfScreen() ||
|
| + details_.bounds_change != kBoundsChange_Repositions)) {
|
| + ClearCachedWidths();
|
| + }
|
| +}
|
| +
|
| +void WorkspaceWindowResizer::LayoutAttachedWindowsHorizontally(
|
| + const gfx::Rect& bounds) {
|
| + gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window()));
|
| + int last_x = bounds.right();
|
| + if (bounds.right() <= work_area.right() - total_initial_size_) {
|
| + ClearCachedWidths();
|
| + // All the windows fit at their initial size; tile them horizontally.
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect attached_bounds(attached_windows_[i]->bounds());
|
| + attached_bounds.set_x(last_x);
|
| + attached_bounds.set_width(initial_size_[i]);
|
| + attached_windows_[i]->SetBounds(attached_bounds);
|
| + last_x = attached_bounds.right();
|
| + }
|
| + } else {
|
| + DCHECK_NE(total_initial_size_, total_min_);
|
| + int delta = total_initial_size_ - (work_area.right() - bounds.right());
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect attached_bounds(attached_windows_[i]->bounds());
|
| + int size = initial_size_[i] -
|
| + static_cast<int>(compress_fraction_[i] * delta);
|
| + size = AlignToGrid(size, details_.grid_size);
|
| + if (!GetWidthBeforeObscured(attached_windows_[i]))
|
| + SetWidthBeforeObscured(attached_windows_[i], attached_bounds.width());
|
| + attached_bounds.set_x(last_x);
|
| + if (i == attached_windows_.size())
|
| + size = work_area.right() - last_x;
|
| + attached_bounds.set_width(size);
|
| + attached_windows_[i]->SetBounds(attached_bounds);
|
| + last_x = attached_bounds.right();
|
| + }
|
| + }
|
| +}
|
| +
|
| +void WorkspaceWindowResizer::LayoutAttachedWindowsVertically(
|
| + const gfx::Rect& bounds) {
|
| + gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window()));
|
| + int last_y = bounds.bottom();
|
| + if (bounds.bottom() <= work_area.bottom() - total_initial_size_) {
|
| + ClearCachedHeights();
|
| + // All the windows fit at their initial size; tile them vertically.
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect attached_bounds(attached_windows_[i]->bounds());
|
| + attached_bounds.set_y(last_y);
|
| + attached_bounds.set_height(initial_size_[i]);
|
| + attached_windows_[i]->SetBounds(attached_bounds);
|
| + last_y = attached_bounds.bottom();
|
| + }
|
| + } else {
|
| + DCHECK_NE(total_initial_size_, total_min_);
|
| + int delta = total_initial_size_ - (work_area.bottom() - bounds.bottom());
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i) {
|
| + gfx::Rect attached_bounds(attached_windows_[i]->bounds());
|
| + int size = initial_size_[i] -
|
| + static_cast<int>(compress_fraction_[i] * delta);
|
| + size = AlignToGrid(size, details_.grid_size);
|
| + if (i == attached_windows_.size())
|
| + size = work_area.bottom() - last_y;
|
| + if (!GetHeightBeforeObscured(attached_windows_[i]))
|
| + SetHeightBeforeObscured(attached_windows_[i], attached_bounds.height());
|
| + attached_bounds.set_height(size);
|
| + attached_bounds.set_y(last_y);
|
| + attached_windows_[i]->SetBounds(attached_bounds);
|
| + last_y = attached_bounds.bottom();
|
| + }
|
| + }
|
| }
|
|
|
| void WorkspaceWindowResizer::AdjustBoundsForMainWindow(
|
| gfx::Rect* bounds) const {
|
| gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window()));
|
| + if (!attached_windows_.empty() && details_.window_component == HTBOTTOM)
|
| + work_area.set_height(work_area.height() - total_min_);
|
| AdjustBoundsForWindow(work_area, window(), bounds);
|
| +
|
| + if (!attached_windows_.empty() && details_.window_component == HTRIGHT) {
|
| + bounds->set_width(std::min(bounds->width(),
|
| + work_area.right() - total_min_ - bounds->x()));
|
| + }
|
| }
|
|
|
| void WorkspaceWindowResizer::AdjustBoundsForWindow(
|
| @@ -168,12 +351,48 @@ void WorkspaceWindowResizer::AdjustBoundsForWindow(
|
|
|
| void WorkspaceWindowResizer::ClearCachedHeights() {
|
| ClearHeightBeforeObscured(details_.window);
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i)
|
| + ClearHeightBeforeObscured(attached_windows_[i]);
|
| +}
|
| +
|
| +void WorkspaceWindowResizer::ClearCachedWidths() {
|
| + ClearWidthBeforeObscured(details_.window);
|
| + for (size_t i = 0; i < attached_windows_.size(); ++i)
|
| + ClearWidthBeforeObscured(attached_windows_[i]);
|
| }
|
|
|
| bool WorkspaceWindowResizer::TouchesBottomOfScreen() const {
|
| gfx::Rect work_area(
|
| gfx::Screen::GetMonitorWorkAreaNearestWindow(details_.window));
|
| - return details_.window->bounds().bottom() == work_area.bottom();
|
| + return (attached_windows_.empty() &&
|
| + details_.window->bounds().bottom() == work_area.bottom()) ||
|
| + (!attached_windows_.empty() &&
|
| + attached_windows_.back()->bounds().bottom() == work_area.bottom());
|
| +}
|
| +
|
| +bool WorkspaceWindowResizer::TouchesRightSideOfScreen() const {
|
| + gfx::Rect work_area(
|
| + gfx::Screen::GetMonitorWorkAreaNearestWindow(details_.window));
|
| + return (attached_windows_.empty() &&
|
| + details_.window->bounds().right() == work_area.right()) ||
|
| + (!attached_windows_.empty() &&
|
| + attached_windows_.back()->bounds().right() == work_area.right());
|
| +}
|
| +
|
| +int WorkspaceWindowResizer::PrimaryAxisSize(const gfx::Size& size) const {
|
| + return PrimaryAxisCoordinate(size.width(), size.height());
|
| +}
|
| +
|
| +int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const {
|
| + switch (details_.window_component) {
|
| + case HTRIGHT:
|
| + return x;
|
| + case HTBOTTOM:
|
| + return y;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + return 0;
|
| }
|
|
|
| } // namespace internal
|
|
|