diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-25 22:30:50 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-25 22:30:50 +0000 |
commit | 5ae18725d3bba85f251f6d0f76453c2d891290ff (patch) | |
tree | dddb996f5538c201b840b2cc6965dbc61714ef5f /ash | |
parent | 0239e8694892e4ad603f77f758bbff30b3aff216 (diff) | |
download | chromium_src-5ae18725d3bba85f251f6d0f76453c2d891290ff.zip chromium_src-5ae18725d3bba85f251f6d0f76453c2d891290ff.tar.gz chromium_src-5ae18725d3bba85f251f6d0f76453c2d891290ff.tar.bz2 |
Attempt 4:
Makes managed mode constrain the height of windows so they don't
overlap the launcher.
BUG=115581
TEST=see bug, covered by unit tests too
R=ben@chromium.org
TBR=ben@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9466032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123674 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 3 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter.cc | 14 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter.h | 6 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter_unittest.cc | 1 | ||||
-rw-r--r-- | ash/wm/window_resizer.cc | 18 | ||||
-rw-r--r-- | ash/wm/window_resizer.h | 14 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_event_filter.cc | 55 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_event_filter.h | 22 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager.cc | 40 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager.h | 15 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 113 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.h | 52 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer_unittest.cc | 274 |
13 files changed, 504 insertions, 123 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index ce530c7..fa3b733 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -202,6 +202,8 @@ 'wm/workspace/workspace_layout_manager.h', 'wm/workspace/workspace_manager.cc', 'wm/workspace/workspace_manager.h', + 'wm/workspace/workspace_window_resizer.cc', + 'wm/workspace/workspace_window_resizer.h', ], 'conditions': [ ['OS=="mac"', { @@ -282,6 +284,7 @@ 'wm/window_cycle_controller_unittest.cc', 'wm/window_modality_controller_unittest.cc', 'wm/workspace/workspace_manager_unittest.cc', + 'wm/workspace/workspace_window_resizer_unittest.cc', 'wm/workspace_controller_unittest.cc', '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc', diff --git a/ash/wm/toplevel_window_event_filter.cc b/ash/wm/toplevel_window_event_filter.cc index 20ae5e5..78645fef 100644 --- a/ash/wm/toplevel_window_event_filter.cc +++ b/ash/wm/toplevel_window_event_filter.cc @@ -48,8 +48,7 @@ bool ToplevelWindowEventFilter::PreHandleMouseEvent(aura::Window* target, target->delegate()->GetNonClientComponent(event->location()); if (WindowResizer::GetBoundsChangeForWindowComponent(component)) { window_resizer_.reset( - new WindowResizer(target, event->location(), component, - grid_size_)); + CreateWindowResizer(target, event->location(), component)); if (!window_resizer_->is_resizable()) window_resizer_.reset(); } else { @@ -93,7 +92,7 @@ ui::GestureStatus ToplevelWindowEventFilter::PreHandleGestureEvent( } in_gesture_resize_ = true; window_resizer_.reset( - new WindowResizer(target, event->location(), component, grid_size_)); + CreateWindowResizer(target, event->location(), component)); if (!window_resizer_->is_resizable()) window_resizer_.reset(); break; @@ -125,7 +124,7 @@ void ToplevelWindowEventFilter::RunMoveLoop(aura::Window* source) { aura::Window::ConvertPointToWindow( Shell::GetRootWindow(), source, &source_mouse_location); window_resizer_.reset( - new WindowResizer(source, source_mouse_location, HTCAPTION, grid_size_)); + CreateWindowResizer(source, source_mouse_location, HTCAPTION)); #if !defined(OS_MACOSX) MessageLoopForUI::current()->RunWithDispatcher( aura::Env::GetInstance()->GetDispatcher()); @@ -143,6 +142,13 @@ void ToplevelWindowEventFilter::EndMoveLoop() { Shell::GetRootWindow()->PostNativeEvent(ui::CreateNoopEvent()); } +WindowResizer* ToplevelWindowEventFilter::CreateWindowResizer( + aura::Window* window, + const gfx::Point& point, + int window_component) { + return new WindowResizer(window, point, window_component, grid_size_); +} + void ToplevelWindowEventFilter::CompleteDrag(aura::Window* window) { scoped_ptr<WindowResizer> resizer(window_resizer_.release()); if (resizer.get()) diff --git a/ash/wm/toplevel_window_event_filter.h b/ash/wm/toplevel_window_event_filter.h index f6899de..01bced7 100644 --- a/ash/wm/toplevel_window_event_filter.h +++ b/ash/wm/toplevel_window_event_filter.h @@ -54,6 +54,12 @@ class ASH_EXPORT ToplevelWindowEventFilter : virtual void RunMoveLoop(aura::Window* source) OVERRIDE; virtual void EndMoveLoop() OVERRIDE; + protected: + // Creates a new WindowResizer. + virtual WindowResizer* CreateWindowResizer(aura::Window* window, + const gfx::Point& point, + int window_component); + private: // Invoked when the mouse is released to cleanup after a drag. void CompleteDrag(aura::Window* window); diff --git a/ash/wm/toplevel_window_event_filter_unittest.cc b/ash/wm/toplevel_window_event_filter_unittest.cc index 611ba5e..2f436a7 100644 --- a/ash/wm/toplevel_window_event_filter_unittest.cc +++ b/ash/wm/toplevel_window_event_filter_unittest.cc @@ -25,7 +25,6 @@ #endif #endif - namespace ash { namespace test { diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc index 9cc1c2a..fbb523c 100644 --- a/ash/wm/window_resizer.cc +++ b/ash/wm/window_resizer.cc @@ -205,13 +205,16 @@ void WindowResizer::Drag(const gfx::Point& location) { void WindowResizer::CompleteDrag() { if (grid_size_ <= 1 || !did_move_or_resize_) return; - const gfx::Rect& bounds(window_->bounds()); - int x = AlignToGrid(bounds.x(), grid_size_); - int y = AlignToGrid(bounds.y(), grid_size_); - gfx::Rect new_bounds(x, y, bounds.width(), bounds.height()); + gfx::Rect new_bounds(GetFinalBounds()); if (new_bounds == window_->bounds()) return; + if (new_bounds.size() != window_->bounds().size()) { + // Don't attempt to animate a size change. + window_->SetBounds(new_bounds); + return; + } + ui::ScopedLayerAnimationSettings scoped_setter( window_->layer()->GetAnimator()); // Use a small duration since the grid is small. @@ -256,6 +259,13 @@ gfx::Rect WindowResizer::GetBoundsForDrag(const gfx::Point& location) { return new_bounds; } +gfx::Rect WindowResizer::GetFinalBounds() { + const gfx::Rect& bounds(window_->bounds()); + int x = AlignToGrid(bounds.x(), grid_size_); + int y = AlignToGrid(bounds.y(), grid_size_); + return gfx::Rect(x, y, bounds.width(), bounds.height()); +} + gfx::Point WindowResizer::GetOriginForDrag( int delta_x, int delta_y) const { diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h index f44081b..777eff3 100644 --- a/ash/wm/window_resizer.h +++ b/ash/wm/window_resizer.h @@ -38,7 +38,7 @@ class ASH_EXPORT WindowResizer { const gfx::Point& location, int window_component, int grid_size); - ~WindowResizer(); + virtual ~WindowResizer(); // Returns a bitmask of the kBoundsChange_ values. static int GetBoundsChangeForWindowComponent(int component); @@ -64,12 +64,20 @@ class ASH_EXPORT WindowResizer { } int window_component() const { return window_component_; } aura::Window* window() const { return window_; } + int grid_size() const { return grid_size_; } + bool did_move_or_resize() const { return did_move_or_resize_; } + int bounds_change() const { return bounds_change_; } - private: + protected: // Returns the bounds to give to the window once the mouse has moved to // |location|. - gfx::Rect GetBoundsForDrag(const gfx::Point& location); + virtual gfx::Rect GetBoundsForDrag(const gfx::Point& location); + + // Returns the final bounds. This differs from current bounds if a grid_size + // was specified. + virtual gfx::Rect GetFinalBounds(); + private: // Returns the new origin of the window. The arguments are the difference // between the current location and the initial location. gfx::Point GetOriginForDrag(int delta_x, int delta_y) const; diff --git a/ash/wm/workspace/workspace_event_filter.cc b/ash/wm/workspace/workspace_event_filter.cc index e64bc90..0fe8bb2 100644 --- a/ash/wm/workspace/workspace_event_filter.cc +++ b/ash/wm/workspace/workspace_event_filter.cc @@ -7,6 +7,7 @@ #include "ash/wm/window_frame.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/workspace_layout_manager.h" +#include "ash/wm/workspace/workspace_window_resizer.h" #include "ui/aura/event.h" #include "ui/aura/window.h" #include "ui/base/hit_test.h" @@ -31,8 +32,6 @@ namespace internal { WorkspaceEventFilter::WorkspaceEventFilter(aura::Window* owner) : ToplevelWindowEventFilter(owner), - owner_(owner), - drag_state_(DRAG_NONE), hovered_window_(NULL) { } @@ -43,57 +42,18 @@ WorkspaceEventFilter::~WorkspaceEventFilter() { bool WorkspaceEventFilter::PreHandleMouseEvent(aura::Window* target, aura::MouseEvent* event) { - WorkspaceLayoutManager* layout_manager = - static_cast<WorkspaceLayoutManager*>(owner_->layout_manager()); - DCHECK(layout_manager); - - // TODO(oshima|derat): Incorporate the logic below and introduce DragObserver - // (or something similar) to decouple DCLM. - - // Notify layout manager that drag event may move/resize the target wnidow. - if (event->type() == ui::ET_MOUSE_DRAGGED && drag_state_ == DRAG_NONE) - layout_manager->PrepareForMoveOrResize(target, event); - - bool handled = ToplevelWindowEventFilter::PreHandleMouseEvent(target, event); - switch (event->type()) { - case ui::ET_MOUSE_DRAGGED: - // Cancel move/resize if the event wasn't handled, or - // drag_state_ didn't move to MOVE or RESIZE. - if (handled) { - switch (drag_state_) { - case DRAG_NONE: - if (!UpdateDragState()) - layout_manager->CancelMoveOrResize(target, event); - break; - case DRAG_MOVE: - layout_manager->ProcessMove(target, event); - break; - case DRAG_RESIZE: - break; - } - } else { - layout_manager->CancelMoveOrResize(target, event); - } - break; case ui::ET_MOUSE_ENTERED: UpdateHoveredWindow(GetActivatableWindow(target)); break; + case ui::ET_MOUSE_CAPTURE_CHANGED: case ui::ET_MOUSE_EXITED: UpdateHoveredWindow(NULL); break; - case ui::ET_MOUSE_RELEASED: - if (drag_state_ == DRAG_MOVE) - layout_manager->EndMove(target, event); - else if (drag_state_ == DRAG_RESIZE) - layout_manager->EndResize(target, event); - - drag_state_ = DRAG_NONE; - break; default: break; } - return handled; + return ToplevelWindowEventFilter::PreHandleMouseEvent(target, event); } void WorkspaceEventFilter::OnWindowDestroyed(aura::Window* window) { @@ -102,9 +62,12 @@ void WorkspaceEventFilter::OnWindowDestroyed(aura::Window* window) { hovered_window_ = NULL; } -bool WorkspaceEventFilter::UpdateDragState() { - // TODO(sky): nuke this method. - return false; +WindowResizer* WorkspaceEventFilter::CreateWindowResizer( + aura::Window* window, + const gfx::Point& point, + int window_component) { + return + new WorkspaceWindowResizer(window, point, window_component, grid_size()); } void WorkspaceEventFilter::UpdateHoveredWindow( diff --git a/ash/wm/workspace/workspace_event_filter.h b/ash/wm/workspace/workspace_event_filter.h index 2c15c37..5598185 100644 --- a/ash/wm/workspace/workspace_event_filter.h +++ b/ash/wm/workspace/workspace_event_filter.h @@ -30,27 +30,17 @@ class WorkspaceEventFilter : public ToplevelWindowEventFilter, // Overriden from WindowObserver: virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE; - private: - enum DragState { - DRAG_NONE, - DRAG_MOVE, - DRAG_RESIZE - }; - - // If the mouse is currently over a portion of the window that should - // trigger a drag or resize, drag_state_ is set appropriately and true - // is returned. If the mouse is not over a portion of the window that should - // trigger a more or resize, drag_state_ is not updated and false is returned. - bool UpdateDragState(); + protected: + // Overriden from ToplevelWindowEventFilter: + virtual WindowResizer* CreateWindowResizer(aura::Window* window, + const gfx::Point& point, + int window_component) OVERRIDE; + private: // Updates the top-level window under the mouse so that we can change // the look of the caption area based on mouse-hover. void UpdateHoveredWindow(aura::Window* toplevel); - aura::Window* owner_; - - DragState drag_state_; - // Top-level window under the mouse cursor. aura::Window* hovered_window_; diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc index a705059..bbe26f57 100644 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ b/ash/wm/workspace/workspace_layout_manager.cc @@ -31,38 +31,6 @@ WorkspaceLayoutManager::WorkspaceLayoutManager( WorkspaceLayoutManager::~WorkspaceLayoutManager() {} -void WorkspaceLayoutManager::PrepareForMoveOrResize( - aura::Window* drag, - aura::MouseEvent* event) { -} - -void WorkspaceLayoutManager::CancelMoveOrResize( - aura::Window* drag, - aura::MouseEvent* event) { -} - -void WorkspaceLayoutManager::ProcessMove( - aura::Window* drag, - aura::MouseEvent* event) { - // TODO: needs implementation for TYPE_SPLIT. For TYPE_SPLIT I want to - // disallow eventfilter from moving and instead deal with it here. -} - -void WorkspaceLayoutManager::EndMove( - aura::Window* drag, - aura::MouseEvent* evnet) { - // TODO: see comment in ProcessMove. -} - -void WorkspaceLayoutManager::EndResize( - aura::Window* drag, - aura::MouseEvent* evnet) { - // TODO: see comment in ProcessMove. -} - -//////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, aura::LayoutManager implementation: - void WorkspaceLayoutManager::OnWindowResized() { // Workspace is updated via RootWindowObserver::OnRootWindowResized. } @@ -112,10 +80,14 @@ void WorkspaceLayoutManager::SetChildBounds( aura::Window* child, const gfx::Rect& requested_bounds) { gfx::Rect child_bounds(requested_bounds); - if (window_util::IsWindowMaximized(child)) + if (window_util::IsWindowMaximized(child)) { child_bounds = gfx::Screen::GetMonitorWorkAreaNearestWindow(child); - else if (window_util::IsWindowFullscreen(child)) + } else if (window_util::IsWindowFullscreen(child)) { child_bounds = gfx::Screen::GetMonitorAreaNearestWindow(child); + } else { + child_bounds = gfx::Screen::GetMonitorWorkAreaNearestWindow(child). + AdjustToFit(requested_bounds); + } SetChildBoundsDirect(child, child_bounds); } diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h index 7be5143..e350ad2 100644 --- a/ash/wm/workspace/workspace_layout_manager.h +++ b/ash/wm/workspace/workspace_layout_manager.h @@ -36,21 +36,6 @@ class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager { return workspace_manager_; } - // Invoked when a window receives drag event. - void PrepareForMoveOrResize(aura::Window* drag, aura::MouseEvent* event); - - // Invoked when a drag event didn't start any drag operation. - void CancelMoveOrResize(aura::Window* drag, aura::MouseEvent* event); - - // Invoked when a drag event moved the |window|. - void ProcessMove(aura::Window* window, aura::MouseEvent* event); - - // Invoked when a user finished moving window. - void EndMove(aura::Window* drag, aura::MouseEvent* event); - - // Invoked when a user finished resizing window. - void EndResize(aura::Window* drag, aura::MouseEvent* event); - // Overridden from aura::LayoutManager: virtual void OnWindowResized() OVERRIDE; virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc new file mode 100644 index 0000000..a16178c --- /dev/null +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2012 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. + +#include "ash/wm/workspace/workspace_window_resizer.h" + +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/aura/window_property.h" +#include "ui/gfx/screen.h" + +DECLARE_WINDOW_PROPERTY_TYPE(int) + +namespace ash { +namespace internal { + +namespace { + +const aura::WindowProperty<int> kHeightBeforeObscuredProp = {0}; +const aura::WindowProperty<int>* const kHeightBeforeObscuredKey = + &kHeightBeforeObscuredProp; + +} // namespace + +WorkspaceWindowResizer::WorkspaceWindowResizer(aura::Window* window, + const gfx::Point& location, + int window_component, + int grid_size) + : WindowResizer(window, location, window_component, grid_size) { + if (is_resizable() && GetHeightBeforeObscured(window) && + (!WindowTouchesBottomOfScreen() || + bounds_change() != kBoundsChange_Repositions)) { + ClearHeightBeforeObscured(window); + } +} + +WorkspaceWindowResizer::~WorkspaceWindowResizer() { +} + +gfx::Rect WorkspaceWindowResizer::GetBoundsForDrag(const gfx::Point& location) { + if (!is_resizable()) + return WindowResizer::GetBoundsForDrag(location); + + gfx::Rect bounds(WindowResizer::GetBoundsForDrag(location)); + AdjustBounds(&bounds); + return bounds; +} + +gfx::Rect WorkspaceWindowResizer::GetFinalBounds() { + if (grid_size() <= 1 || !GetHeightBeforeObscured(window())) + return WindowResizer::GetFinalBounds(); + + gfx::Rect initial_bounds(window()->bounds()); + bool at_bottom = WindowTouchesBottomOfScreen(); + gfx::Rect bounds(WindowResizer::GetFinalBounds()); + if (at_bottom && bounds.y() != initial_bounds.y()) { + if (bounds.y() < initial_bounds.y()) { + bounds.set_height(bounds.height() + grid_size() - + (initial_bounds.y() - bounds.y())); + } + AdjustBounds(&bounds); + } + return bounds; +} + +// static +void WorkspaceWindowResizer::SetHeightBeforeObscured(aura::Window* window, + int height) { + window->SetProperty(kHeightBeforeObscuredKey, height); +} + +// static +void WorkspaceWindowResizer::ClearHeightBeforeObscured(aura::Window* window) { + window->SetProperty(kHeightBeforeObscuredKey, 0); +} + +// static +int WorkspaceWindowResizer::GetHeightBeforeObscured(aura::Window* window) { + return window->GetProperty(kHeightBeforeObscuredKey); +} + +void WorkspaceWindowResizer::AdjustBounds(gfx::Rect* bounds) const { + gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window())); + if (bounds->bottom() < work_area.bottom()) { + int height = GetHeightBeforeObscured(window()); + if (!height) + return; + height = std::max(bounds->height(), height); + bounds->set_height(std::min(work_area.bottom() - bounds->y(), height)); + return; + } + + if (bounds->bottom() == work_area.bottom()) + return; + + if (!GetHeightBeforeObscured(window())) + SetHeightBeforeObscured(window(), window()->bounds().height()); + + gfx::Size min_size = window()->delegate()->GetMinimumSize(); + bounds->set_height(std::max(0, work_area.bottom() - bounds->y())); + if (bounds->height() < min_size.height()) { + bounds->set_height(min_size.height()); + bounds->set_y(work_area.bottom() - min_size.height()); + } +} + +bool WorkspaceWindowResizer::WindowTouchesBottomOfScreen() const { + gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window())); + return window()->bounds().bottom() == work_area.bottom(); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h new file mode 100644 index 0000000..d32b0be --- /dev/null +++ b/ash/wm/workspace/workspace_window_resizer.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 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. + +#ifndef ASH_WM_WORKSPACE_WINDOW_RESIZER_H_ +#define ASH_WM_WORKSPACE_WINDOW_RESIZER_H_ +#pragma once + +#include "ash/wm/window_resizer.h" +#include "base/compiler_specific.h" + +namespace ash { +namespace internal { + +// WindowResizer implementation for workspaces. This enforces that windows are +// not allowed to vertically move or resize outside of the work area. As windows +// are moved outside the work area they are shrunk. We remember the height of +// the window before it was moved so that if the window is again moved up we +// attempt to restore the old height. +class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { + public: + WorkspaceWindowResizer(aura::Window* window, + const gfx::Point& location, + int window_component, + int grid_size); + virtual ~WorkspaceWindowResizer(); + + protected: + // WindowResizer overrides: + virtual gfx::Rect GetBoundsForDrag(const gfx::Point& location) OVERRIDE; + virtual gfx::Rect GetFinalBounds() OVERRIDE; + + private: + // Used to maintain the height of the window before we started collapsing it. + static void SetHeightBeforeObscured(aura::Window* window, int height); + static void ClearHeightBeforeObscured(aura::Window* window); + static int GetHeightBeforeObscured(aura::Window* window); + + // Adjusts the bounds to enforce that windows are vertically contained in the + // work area. + void AdjustBounds(gfx::Rect* bounds) const; + + // Returns true if the window touches the bottom of the work area. + bool WindowTouchesBottomOfScreen() const; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizer); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_WM_WORKSPACE_WINDOW_RESIZER_H_ diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc new file mode 100644 index 0000000..7787ddc --- /dev/null +++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc @@ -0,0 +1,274 @@ +// Copyright (c) 2012 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. + +#include "ash/wm/workspace/workspace_window_resizer.h" + +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ui/aura/root_window.h" +#include "ui/aura/screen_aura.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/base/hit_test.h" + +namespace ash { +namespace internal { +namespace { + +const int kRootHeight = 600; + +// A simple window delegate that returns the specified min size. +class TestWindowDelegate : public aura::test::TestWindowDelegate { + public: + TestWindowDelegate() { + } + virtual ~TestWindowDelegate() {} + + void set_min_size(const gfx::Size& size) { + min_size_ = size; + } + + private: + // Overridden from aura::Test::TestWindowDelegate: + virtual gfx::Size GetMinimumSize() const OVERRIDE { + return min_size_; + } + + gfx::Size min_size_; + + DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate); +}; + +class WorkspaceWindowResizerTest : public test::AshTestBase { + public: + WorkspaceWindowResizerTest() : window_(NULL) {} + virtual ~WorkspaceWindowResizerTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + aura::RootWindow* root = Shell::GetInstance()->GetRootWindow(); + root->SetBounds(gfx::Rect(0, 0, 800, kRootHeight)); + gfx::Rect root_bounds(root->bounds()); + EXPECT_EQ(kRootHeight, root_bounds.height()); + root->screen()->set_work_area_insets(gfx::Insets()); + window_.reset(new aura::Window(&delegate_)); + window_->Init(ui::Layer::LAYER_NOT_DRAWN); + window_->SetParent(Shell::GetInstance()->GetRootWindow()); + } + + virtual void TearDown() OVERRIDE { + window_.reset(); + AshTestBase::TearDown(); + } + + protected: + gfx::Point CalculateDragPoint(const WindowResizer& resizer, + int delta_y) const { + gfx::Point location = resizer.initial_location_in_parent(); + location.set_y(location.y() + delta_y); + aura::Window::ConvertPointToWindow(window_->parent(), window_.get(), + &location); + return location; + } + + TestWindowDelegate delegate_; + scoped_ptr<aura::Window> window_; + + private: + DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest); +}; + +// Assertions around making sure dragging shrinks when appropriate. +TEST_F(WorkspaceWindowResizerTest, ShrinkOnDrag) { + int initial_y = 300; + window_->SetBounds(gfx::Rect(0, initial_y, 400, 296)); + + // Drag down past the bottom of the screen, height should stop when it hits + // the bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTBOTTOM, 0); + EXPECT_TRUE(resizer.is_resizable()); + resizer.Drag(CalculateDragPoint(resizer, 600)); + EXPECT_EQ(kRootHeight - initial_y, window_->bounds().height()); + + // Drag up 10 and make sure height is the same. + resizer.Drag(CalculateDragPoint(resizer, 590)); + EXPECT_EQ(kRootHeight - initial_y, window_->bounds().height()); + } + + { + // Move the window down 10 pixels, the height should change. + int initial_height = window_->bounds().height(); + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, 10)); + EXPECT_EQ(initial_height - 10, window_->bounds().height()); + + // Move up 10, height should grow. + resizer.Drag(CalculateDragPoint(resizer, 0)); + EXPECT_EQ(initial_height, window_->bounds().height()); + + // Move up another 10, height shouldn't change. + resizer.Drag(CalculateDragPoint(resizer, -10)); + EXPECT_EQ(initial_height, window_->bounds().height()); + } +} + +// More assertions around making sure dragging shrinks when appropriate. +TEST_F(WorkspaceWindowResizerTest, ShrinkOnDrag2) { + window_->SetBounds(gfx::Rect(0, 300, 400, 300)); + + // Drag down past the bottom of the screen, height should stop when it hits + // the bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + EXPECT_TRUE(resizer.is_resizable()); + resizer.Drag(CalculateDragPoint(resizer, 200)); + EXPECT_EQ(500, window_->bounds().y()); + EXPECT_EQ(100, window_->bounds().height()); + // End and start a new drag session. + } + + { + // Drag up 400. + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, -400)); + EXPECT_EQ(100, window_->bounds().y()); + EXPECT_EQ(300, window_->bounds().height()); + } +} + +// Moves enough to shrink, then moves up twice to expose more than was initially +// exposed. +TEST_F(WorkspaceWindowResizerTest, ShrinkMoveThanMoveUp) { + window_->SetBounds(gfx::Rect(0, 300, 400, 300)); + + // Drag down past the bottom of the screen, height should stop when it hits + // the bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + EXPECT_TRUE(resizer.is_resizable()); + resizer.Drag(CalculateDragPoint(resizer, 200)); + EXPECT_EQ(500, window_->bounds().y()); + EXPECT_EQ(100, window_->bounds().height()); + // End and start a new drag session. + } + + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, -400)); + resizer.Drag(CalculateDragPoint(resizer, -450)); + EXPECT_EQ(50, window_->bounds().y()); + EXPECT_EQ(300, window_->bounds().height()); + } +} + +// Makes sure shrinking honors the grid appropriately. +TEST_F(WorkspaceWindowResizerTest, ShrinkWithGrid) { + window_->SetBounds(gfx::Rect(0, 300, 400, 296)); + + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 5); + EXPECT_TRUE(resizer.is_resizable()); + // Drag down 8 pixels. + resizer.Drag(CalculateDragPoint(resizer, 8)); + resizer.CompleteDrag(); + EXPECT_EQ(310, window_->bounds().y()); + EXPECT_EQ(kRootHeight - 310, window_->bounds().height()); +} + +// Makes sure once a window has been shrunk it can grow bigger than obscured +// height +TEST_F(WorkspaceWindowResizerTest, ShrinkThanGrow) { + int initial_y = 400; + int initial_height = 150; + window_->SetBounds(gfx::Rect(0, initial_y, 400, initial_height)); + + // Most past the bottom of the screen, height should stop when it hits the + // bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, 150)); + EXPECT_EQ(550, window_->bounds().y()); + EXPECT_EQ(50, window_->bounds().height()); + } + + // Resize the window 500 pixels up. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTTOP, 0); + resizer.Drag(CalculateDragPoint(resizer, -500)); + EXPECT_EQ(50, window_->bounds().y()); + EXPECT_EQ(550, window_->bounds().height()); + } +} + +// Makes sure once a window has been shrunk it can grow bigger than obscured +// height +TEST_F(WorkspaceWindowResizerTest, DontRememberAfterMove) { + window_->SetBounds(gfx::Rect(0, 300, 400, 300)); + + // Most past the bottom of the screen, height should stop when it hits the + // bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, 150)); + EXPECT_EQ(450, window_->bounds().y()); + EXPECT_EQ(150, window_->bounds().height()); + resizer.Drag(CalculateDragPoint(resizer, -150)); + EXPECT_EQ(150, window_->bounds().y()); + EXPECT_EQ(300, window_->bounds().height()); + } + + // Resize it slightly. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTBOTTOM, 0); + resizer.Drag(CalculateDragPoint(resizer, -100)); + EXPECT_EQ(150, window_->bounds().y()); + EXPECT_EQ(200, window_->bounds().height()); + } + + { + // Move it down then back up. + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, 400)); + EXPECT_EQ(550, window_->bounds().y()); + EXPECT_EQ(50, window_->bounds().height()); + + resizer.Drag(CalculateDragPoint(resizer, 0)); + EXPECT_EQ(150, window_->bounds().y()); + EXPECT_EQ(200, window_->bounds().height()); + } +} + +// Makes sure we honor the min size. +TEST_F(WorkspaceWindowResizerTest, HonorMin) { + delegate_.set_min_size(gfx::Size(50, 100)); + window_->SetBounds(gfx::Rect(0, 300, 400, 300)); + + // Most past the bottom of the screen, height should stop when it hits the + // bottom. + { + WorkspaceWindowResizer resizer(window_.get(), gfx::Point(), HTCAPTION, 0); + resizer.Drag(CalculateDragPoint(resizer, 350)); + EXPECT_EQ(500, window_->bounds().y()); + EXPECT_EQ(100, window_->bounds().height()); + + resizer.Drag(CalculateDragPoint(resizer, 300)); + EXPECT_EQ(500, window_->bounds().y()); + EXPECT_EQ(100, window_->bounds().height()); + + resizer.Drag(CalculateDragPoint(resizer, 250)); + EXPECT_EQ(500, window_->bounds().y()); + EXPECT_EQ(100, window_->bounds().height()); + + resizer.Drag(CalculateDragPoint(resizer, 100)); + EXPECT_EQ(400, window_->bounds().y()); + EXPECT_EQ(200, window_->bounds().height()); + + resizer.Drag(CalculateDragPoint(resizer, -100)); + EXPECT_EQ(200, window_->bounds().y()); + EXPECT_EQ(300, window_->bounds().height()); + } +} + +} // namespace +} // namespace test +} // namespace aura |