diff options
author | oshima@google.com <oshima@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-27 22:49:02 +0000 |
---|---|---|
committer | oshima@google.com <oshima@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-27 22:49:02 +0000 |
commit | de99a643650df35457d0a0ca33f0c51c981890a6 (patch) | |
tree | 332607c361ea5907a7f4f882f7560344073889a5 /ui | |
parent | 1efc51c6eb81806e372e8edcdb136d2915c2b287 (diff) | |
download | chromium_src-de99a643650df35457d0a0ca33f0c51c981890a6.zip chromium_src-de99a643650df35457d0a0ca33f0c51c981890a6.tar.gz chromium_src-de99a643650df35457d0a0ca33f0c51c981890a6.tar.bz2 |
Drag and rotate windows between/within workspaces
BUG=none
TEST=new tests in workspace_manager_unittests
Review URL: http://codereview.chromium.org/8391035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107643 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura_shell/default_container_event_filter.cc | 19 | ||||
-rw-r--r-- | ui/aura_shell/default_container_layout_manager.cc | 30 | ||||
-rw-r--r-- | ui/aura_shell/default_container_layout_manager.h | 3 | ||||
-rw-r--r-- | ui/aura_shell/workspace/workspace.cc | 147 | ||||
-rw-r--r-- | ui/aura_shell/workspace/workspace.h | 51 | ||||
-rw-r--r-- | ui/aura_shell/workspace/workspace_manager.cc | 52 | ||||
-rw-r--r-- | ui/aura_shell/workspace/workspace_manager.h | 10 | ||||
-rw-r--r-- | ui/aura_shell/workspace/workspace_manager_unittest.cc | 360 |
8 files changed, 599 insertions, 73 deletions
diff --git a/ui/aura_shell/default_container_event_filter.cc b/ui/aura_shell/default_container_event_filter.cc index 9547148..e06aa0b 100644 --- a/ui/aura_shell/default_container_event_filter.cc +++ b/ui/aura_shell/default_container_event_filter.cc @@ -26,6 +26,10 @@ bool DefaultContainerEventFilter::PreHandleMouseEvent(aura::Window* target, static_cast<DefaultContainerLayoutManager*>(owner()->layout_manager()); DCHECK(layout_manager); + // TODO(oshima|derat): Move ToplevelWindowEventFilter to the shell, + // incorporate the logic below and intorduce 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); @@ -36,8 +40,21 @@ bool DefaultContainerEventFilter::PreHandleMouseEvent(aura::Window* target, 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 || (drag_state_ == DRAG_NONE && !UpdateDragState())) + 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_RELEASED: if (drag_state_ == DRAG_MOVE) diff --git a/ui/aura_shell/default_container_layout_manager.cc b/ui/aura_shell/default_container_layout_manager.cc index 85560df..caa5331 100644 --- a/ui/aura_shell/default_container_layout_manager.cc +++ b/ui/aura_shell/default_container_layout_manager.cc @@ -6,6 +6,7 @@ #include "base/auto_reset.h" #include "ui/aura/desktop.h" +#include "ui/aura/event.h" #include "ui/aura/window.h" #include "ui/aura/screen_aura.h" #include "ui/aura/window_types.h" @@ -44,6 +45,29 @@ void DefaultContainerLayoutManager::CancelMoveOrResize( drag_window_ = NULL; } +void DefaultContainerLayoutManager::ProcessMove( + aura::Window* drag, + aura::MouseEvent* event) { + AutoReset<bool> reset(&ignore_calculate_bounds_, true); + + // TODO(oshima): Just zooming out may (and will) move/swap window without + // a users's intent. We probably should scroll viewport, but that may not + // be enough. See crbug.com/101826 for more discussion. + workspace_manager_->SetOverview(true); + + gfx::Point point_in_owner = event->location(); + aura::Window::ConvertPointToWindow( + drag, + owner_, + &point_in_owner); + // TODO(oshima): We should support simply moving to another + // workspace when the destination workspace has enough room to accomodate. + aura::Window* rotate_target = + workspace_manager_->FindRotateWindowForLocation(point_in_owner); + if (rotate_target) + workspace_manager_->RotateWindows(drag, rotate_target); +} + void DefaultContainerLayoutManager::EndMove( aura::Window* drag, aura::MouseEvent* evnet) { @@ -52,7 +76,8 @@ void DefaultContainerLayoutManager::EndMove( drag_window_ = NULL; Workspace* workspace = workspace_manager_->GetActiveWorkspace(); if (workspace) - workspace->Layout(NULL); + workspace->Layout(NULL, NULL); + workspace_manager_->SetOverview(false); } void DefaultContainerLayoutManager::EndResize( @@ -62,7 +87,8 @@ void DefaultContainerLayoutManager::EndResize( drag_window_ = NULL; Workspace* workspace = workspace_manager_->GetActiveWorkspace(); if (workspace) - workspace->Layout(NULL); + workspace->Layout(NULL, NULL); + workspace_manager_->SetOverview(false); } //////////////////////////////////////////////////////////////////////////////// diff --git a/ui/aura_shell/default_container_layout_manager.h b/ui/aura_shell/default_container_layout_manager.h index 4d5924c..53cd0d1 100644 --- a/ui/aura_shell/default_container_layout_manager.h +++ b/ui/aura_shell/default_container_layout_manager.h @@ -39,6 +39,9 @@ class AURA_SHELL_EXPORT DefaultContainerLayoutManager // 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* evnet); diff --git a/ui/aura_shell/workspace/workspace.cc b/ui/aura_shell/workspace/workspace.cc index 8e9f2cd..a9574da 100644 --- a/ui/aura_shell/workspace/workspace.cc +++ b/ui/aura_shell/workspace/workspace.cc @@ -5,6 +5,7 @@ #include "ui/aura_shell/workspace/workspace.h" #include "base/logging.h" +#include "ui/aura/desktop.h" #include "ui/aura/window.h" #include "ui/aura_shell/workspace/workspace_manager.h" #include "ui/gfx/compositor/layer.h" @@ -12,6 +13,9 @@ namespace { // Horizontal margin between windows. const int kWindowHorizontalMargin = 10; + +// Maximum number of windows a workspace can have. +size_t g_max_windows_per_workspace = 2; } namespace aura_shell { @@ -29,7 +33,7 @@ void Workspace::SetBounds(const gfx::Rect& bounds) { bool bounds_changed = bounds_ != bounds; bounds_ = bounds; if (bounds_changed) - Layout(NULL); + Layout(NULL, NULL); } gfx::Rect Workspace::GetWorkAreaBounds() const { @@ -49,7 +53,7 @@ bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) { std::find(windows_.begin(), windows_.end(), after); windows_.insert(++i, window); } - Layout(window); + Layout(NULL, window); return true; } @@ -57,45 +61,124 @@ bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) { void Workspace::RemoveWindow(aura::Window* window) { DCHECK(Contains(window)); windows_.erase(std::find(windows_.begin(), windows_.end(), window)); - Layout(NULL); + Layout(NULL, NULL); } bool Workspace::Contains(aura::Window* window) const { return std::find(windows_.begin(), windows_.end(), window) != windows_.end(); } +aura::Window* Workspace::FindRotateWindowForLocation( + const gfx::Point& position) { + aura::Window* active = aura::Desktop::GetInstance()->active_window(); + if (GetTotalWindowsWidth() < bounds_.width()) { + // If all windows fit to the width of the workspace, it returns the + // window which contains |position|'s x coordinate. + for (aura::Window::Windows::const_iterator i = windows_.begin(); + i != windows_.end(); + ++i) { + if (active == *i) + continue; + gfx::Rect bounds = (*i)->GetTargetBounds(); + if (bounds.x() < position.x() && position.x() < bounds.right()) + return *i; + } + } else if (bounds_.x() < position.x() && position.x() < bounds_.right()) { + // If windows are overlapping, it divides the workspace into + // regions with the same width, and returns the Nth window that + // corresponds to the region that contains the |position|. + int width = bounds_.width() / windows_.size(); + size_t index = (position.x() - bounds_.x()) / width; + DCHECK(index < windows_.size()); + aura::Window* window = windows_[index]; + if (window != active) + return window; + } + return NULL; +} + +void Workspace::RotateWindows(aura::Window* source, aura::Window* target) { + DCHECK(Contains(source)); + DCHECK(Contains(target)); + aura::Window::Windows::iterator source_iter = + std::find(windows_.begin(), windows_.end(), source); + aura::Window::Windows::iterator target_iter = + std::find(windows_.begin(), windows_.end(), target); + DCHECK(source_iter != target_iter); + if (source_iter < target_iter) + std::rotate(source_iter, source_iter + 1, target_iter + 1); + else + std::rotate(target_iter, source_iter, source_iter + 1); + Layout(source, NULL); +} + +aura::Window* Workspace::ShiftWindows(aura::Window* insert, + aura::Window* until, + aura::Window* target, + ShiftDirection direction) { + DCHECK(until); + DCHECK(!Contains(insert)); + + bool shift_reached_until = GetIndexOf(until) >= 0; + if (shift_reached_until) + RemoveWindow(until); + aura::Window* pushed = NULL; + if (direction == SHIFT_TO_RIGHT) { + aura::Window::Windows::iterator iter = + std::find(windows_.begin(), windows_.end(), target); + // Insert at |target| position, or at the begining. + if (iter == windows_.end()) + iter = windows_.begin(); + windows_.insert(iter, insert); + if (!shift_reached_until) { + pushed = windows_.back(); + windows_.erase(--windows_.end()); + } + } else { + aura::Window::Windows::iterator iter = + std::find(windows_.begin(), windows_.end(), target); + // Insert after |target|, or at the end. + if (iter != windows_.end()) + ++iter; + windows_.insert(iter, insert); + if (!shift_reached_until) { + pushed = windows_.front(); + windows_.erase(windows_.begin()); + } + } + Layout(shift_reached_until ? until : NULL, NULL); + return pushed; +} + void Workspace::Activate() { workspace_manager_->SetActiveWorkspace(this); } -void Workspace::Layout(aura::Window* no_animation) { +void Workspace::Layout(aura::Window* ignore, aura::Window* no_animation) { gfx::Rect work_area = workspace_manager_->GetWorkAreaBounds(bounds_); - int total_width = 0; - for (aura::Window::Windows::const_iterator i = windows_.begin(); - i != windows_.end(); - ++i) { - if (total_width) - total_width += kWindowHorizontalMargin; - // TODO(oshima): use restored bounds. - total_width += (*i)->bounds().width(); - } - + int total_width = GetTotalWindowsWidth(); if (total_width < work_area.width()) { int dx = (work_area.width() - total_width) / 2; for (aura::Window::Windows::iterator i = windows_.begin(); i != windows_.end(); ++i) { - MoveWindowTo(*i, - gfx::Point(work_area.x() + dx, work_area.y()), - no_animation != *i); + if (*i != ignore) { + MoveWindowTo(*i, + gfx::Point(work_area.x() + dx, work_area.y()), + no_animation != *i); + } dx += (*i)->bounds().width() + kWindowHorizontalMargin; } } else { DCHECK_LT(windows_.size(), 3U); - // TODO(oshima): Figure out general algorithm to layout more than - // 2 windows. - MoveWindowTo(windows_[0], work_area.origin(), no_animation != windows_[0]); - if (windows_.size() == 2) { + // TODO(oshima): This is messy. Figure out general algorithm to + // layout more than 2 windows. + if (windows_[0] != ignore) { + MoveWindowTo(windows_[0], + work_area.origin(), + no_animation != windows_[0]); + } + if (windows_.size() == 2 && windows_[1] != ignore) { MoveWindowTo(windows_[1], gfx::Point(work_area.right() - windows_[1]->bounds().width(), work_area.y()), @@ -114,7 +197,7 @@ bool Workspace::CanAdd(aura::Window* window) const { // TODO(oshima): This should be based on available space and the // size of the |window|. NOTIMPLEMENTED(); - return windows_.size() < 2; + return windows_.size() < g_max_windows_per_workspace; } void Workspace::MoveWindowTo( @@ -134,4 +217,24 @@ void Workspace::MoveWindowTo( } } +int Workspace::GetTotalWindowsWidth() const { + int total_width = 0; + for (aura::Window::Windows::const_iterator i = windows_.begin(); + i != windows_.end(); + ++i) { + if (total_width) + total_width += kWindowHorizontalMargin; + // TODO(oshima): use restored bounds. + total_width += (*i)->bounds().width(); + } + return total_width; +} + +// static +size_t Workspace::SetMaxWindowsCount(size_t max) { + int old = g_max_windows_per_workspace; + g_max_windows_per_workspace = max; + return old; +} + } // namespace aura_shell diff --git a/ui/aura_shell/workspace/workspace.h b/ui/aura_shell/workspace/workspace.h index 136c88b..d04060e 100644 --- a/ui/aura_shell/workspace/workspace.h +++ b/ui/aura_shell/workspace/workspace.h @@ -32,6 +32,12 @@ class AURA_SHELL_EXPORT Workspace { explicit Workspace(WorkspaceManager* manager); virtual ~Workspace(); + // Specifies the direction to shift windows in |ShiftWindows()|. + enum ShiftDirection { + SHIFT_TO_RIGHT, + SHIFT_TO_LEFT + }; + // Returns true if this workspace has no windows. bool is_empty() const { return windows_.empty(); } @@ -49,23 +55,48 @@ class AURA_SHELL_EXPORT Workspace { // failed. bool AddWindowAfter(aura::Window* window, aura::Window* after); - // Removes the |window| from this workspace. + // Removes |window| from this workspace. void RemoveWindow(aura::Window* window); - // Return true if this workspace has the |window|. + // Return true if this workspace has |window|. bool Contains(aura::Window* window) const; + // Returns a window to rotate to based on |position|. + aura::Window* FindRotateWindowForLocation(const gfx::Point& position); + + // Rotates the windows by removing |source| and inserting it to the + // position that |target| was in. It re-layouts windows except for |source|. + void RotateWindows(aura::Window* source, aura::Window* target); + + // Shift the windows in the workspace by inserting |window| until it + // reaches |until|. If |direction| is |SHIFT_TO_RIGHT|, |insert| is + // inserted at the position of |target| or at the beginning if + // |target| is NULL. If |direction| is |SHIFT_TO_LEFT|, |insert| is + // inserted after the position of |target|, or at the end if + // |target| is NULL. It returns the window that is overflowed by + // shifting, or NULL if shifting stopped at |until|. + aura::Window* ShiftWindows(aura::Window* insert, + aura::Window* until, + aura::Window* target, + ShiftDirection direction); + // Activates this workspace. void Activate(); - // Layout windows. Moving animation is applied to all windows except - // for the window specified by |no_animation|. - void Layout(aura::Window* no_animation); + // Layout windows. The workspace doesn't set bounds on |ignore| if it's + // given. It still uses |ignore| window's bounds to calculate + // bounds for other windows. Moving animation is applied to all + // windows except for the window specified by |no_animation| and |ignore|. + void Layout(aura::Window* ignore, aura::Window* no_animation); private: FRIEND_TEST_ALL_PREFIXES(WorkspaceTest, WorkspaceBasic); + FRIEND_TEST_ALL_PREFIXES(WorkspaceTest, RotateWindows); + FRIEND_TEST_ALL_PREFIXES(WorkspaceTest, ShiftWindowsSingle); + FRIEND_TEST_ALL_PREFIXES(WorkspaceTest, ShiftWindowsMultiple); + FRIEND_TEST_ALL_PREFIXES(WorkspaceManagerTest, RotateWindows); - // Returns the index in layout order of the |window| in this workspace. + // Returns the index in layout order of |window| in this workspace. int GetIndexOf(aura::Window* window) const; // Returns true if the given |window| can be added to this workspace. @@ -77,6 +108,14 @@ class AURA_SHELL_EXPORT Workspace { const gfx::Point& origin, bool animate); + // Returns the sum of all window's width. + int GetTotalWindowsWidth() const; + + // Test only: Changes how may windows workspace can have. + // Returns the current value so that it can be reverted back to + // original value. + static size_t SetMaxWindowsCount(size_t max); + WorkspaceManager* workspace_manager_; gfx::Rect bounds_; diff --git a/ui/aura_shell/workspace/workspace_manager.cc b/ui/aura_shell/workspace/workspace_manager.cc index 14fda79..4a6ecaa 100644 --- a/ui/aura_shell/workspace/workspace_manager.cc +++ b/ui/aura_shell/workspace/workspace_manager.cc @@ -60,11 +60,18 @@ Workspace* WorkspaceManager::GetActiveWorkspace() const { } Workspace* WorkspaceManager::FindBy(aura::Window* window) const { + int index = GetWorkspaceIndexContaining(window); + return index < 0 ? NULL : workspaces_[index]; +} + +aura::Window* WorkspaceManager::FindRotateWindowForLocation( + const gfx::Point& point) { for (Workspaces::const_iterator i = workspaces_.begin(); i != workspaces_.end(); ++i) { - if ((*i)->Contains(window)) - return *i; + aura::Window* window = (*i)->FindRotateWindowForLocation(point); + if (window) + return window; } return NULL; } @@ -128,6 +135,36 @@ void WorkspaceManager::SetOverview(bool overview) { viewport_->layer()->SetTransform(transform); } +void WorkspaceManager::RotateWindows(aura::Window* source, + aura::Window* target) { + DCHECK(source); + DCHECK(target); + int source_ws_index = GetWorkspaceIndexContaining(source); + int target_ws_index = GetWorkspaceIndexContaining(target); + DCHECK(source_ws_index >= 0); + DCHECK(target_ws_index >= 0); + if (source_ws_index == target_ws_index) { + workspaces_[source_ws_index]->RotateWindows(source, target); + } else { + aura::Window* insert = source; + if (source_ws_index < target_ws_index) { + for (int i = target_ws_index; i >= source_ws_index; --i) { + insert = workspaces_[i]->ShiftWindows( + insert, source, target, Workspace::SHIFT_TO_LEFT); + // |target| can only be in the 1st workspace. + target = NULL; + } + } else { + for (int i = target_ws_index; i <= source_ws_index; ++i) { + insert = workspaces_[i]->ShiftWindows( + insert, source, target, Workspace::SHIFT_TO_RIGHT); + // |target| can only be in the 1st workspace. + target = NULL; + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// // WorkspaceManager, Overridden from aura::DesktopObserver: @@ -186,6 +223,17 @@ gfx::Rect WorkspaceManager::GetWorkAreaBounds( return bounds; } +// Returns the index of the workspace that contains the |window|. +int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const { + for (Workspaces::const_iterator i = workspaces_.begin(); + i != workspaces_.end(); + ++i) { + if ((*i)->Contains(window)) + return i - workspaces_.begin(); + } + return -1; +} + void WorkspaceManager::UpdateViewport() { int num_workspaces = std::max(1, static_cast<int>(workspaces_.size())); int total_width = workspace_size_.width() * num_workspaces + diff --git a/ui/aura_shell/workspace/workspace_manager.h b/ui/aura_shell/workspace/workspace_manager.h index 925fea2..a9a7123 100644 --- a/ui/aura_shell/workspace/workspace_manager.h +++ b/ui/aura_shell/workspace/workspace_manager.h @@ -44,6 +44,9 @@ class AURA_SHELL_EXPORT WorkspaceManager : public aura::DesktopObserver { // Returns the workspace that contanis the |window|. Workspace* FindBy(aura::Window* window) const; + // Returns the window for rotate operation based on the |location|. + aura::Window* FindRotateWindowForLocation(const gfx::Point& location); + // Sets the bounds of all workspaces. void LayoutWorkspaces(); @@ -54,6 +57,9 @@ class AURA_SHELL_EXPORT WorkspaceManager : public aura::DesktopObserver { void SetOverview(bool overview); bool is_overview() const { return is_overview_; } + // Rotate windows by moving |source| window to the position of |target|. + void RotateWindows(aura::Window* source, aura::Window* target); + // Overridden from aura::DesktopObserver: virtual void OnDesktopResized(const gfx::Size& new_size) OVERRIDE; virtual void OnActiveWindowChanged(aura::Window* active) OVERRIDE; @@ -62,6 +68,7 @@ class AURA_SHELL_EXPORT WorkspaceManager : public aura::DesktopObserver { friend class Workspace; FRIEND_TEST_ALL_PREFIXES(WorkspaceManagerTest, Overview); FRIEND_TEST_ALL_PREFIXES(WorkspaceManagerTest, LayoutWorkspaces); + FRIEND_TEST_ALL_PREFIXES(WorkspaceManagerTest, FindRotateWindow); void AddWorkspace(Workspace* workspace); void RemoveWorkspace(Workspace* workspace); @@ -72,6 +79,9 @@ class AURA_SHELL_EXPORT WorkspaceManager : public aura::DesktopObserver { // Returns the bounds of the work are given |workspace_bounds|. gfx::Rect GetWorkAreaBounds(const gfx::Rect& workspace_bounds); + // Returns the index of the workspace that contains the |window|. + int GetWorkspaceIndexContaining(aura::Window* window) const; + // Update viewport size and move to the active workspace. void UpdateViewport(); diff --git a/ui/aura_shell/workspace/workspace_manager_unittest.cc b/ui/aura_shell/workspace/workspace_manager_unittest.cc index 2f2214a..30d169b 100644 --- a/ui/aura_shell/workspace/workspace_manager_unittest.cc +++ b/ui/aura_shell/workspace/workspace_manager_unittest.cc @@ -15,6 +15,19 @@ namespace { class WorkspaceManagerTestBase : public aura::test::AuraTestBase { public: + WorkspaceManagerTestBase() {} + virtual ~WorkspaceManagerTestBase() {} + + virtual void SetUp() OVERRIDE { + aura::test::AuraTestBase::SetUp(); + manager_.reset(new aura_shell::WorkspaceManager(viewport())); + } + + virtual void TearDown() OVERRIDE { + manager_.reset(); + aura::test::AuraTestBase::TearDown(); + } + aura::Window* CreateTestWindow() { aura::Window* window = new aura::Window(NULL); window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE); @@ -24,6 +37,10 @@ class WorkspaceManagerTestBase : public aura::test::AuraTestBase { aura::Window* viewport() { return GetTestDesktopDelegate()->default_container(); } + scoped_ptr<aura_shell::WorkspaceManager> manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTestBase); }; } // namespace @@ -38,46 +55,47 @@ class WorkspaceManagerTest : public WorkspaceManagerTestBase { }; TEST_F(WorkspaceManagerTest, WorkspaceManagerCreateAddFind) { - WorkspaceManager manager(viewport()); scoped_ptr<Window> w1(CreateTestWindow()); scoped_ptr<Window> w2(CreateTestWindow()); - Workspace* ws1 = manager.CreateWorkspace(); + Workspace* ws1 = manager_->CreateWorkspace(); ws1->AddWindowAfter(w1.get(), NULL); // w2 is not a part of any workspace yet. - EXPECT_EQ(NULL, manager.FindBy(w2.get())); + EXPECT_EQ(NULL, manager_->FindBy(w2.get())); // w2 is in ws2 workspace. - Workspace* ws2 = manager.CreateWorkspace(); + Workspace* ws2 = manager_->CreateWorkspace(); ws2->AddWindowAfter(w2.get(), NULL); - EXPECT_EQ(ws2, manager.FindBy(w2.get())); + EXPECT_EQ(ws2, manager_->FindBy(w2.get())); // Make sure |FindBy(w1.get())| still returns // correct workspace. - EXPECT_EQ(ws1, manager.FindBy(w1.get())); + EXPECT_EQ(ws1, manager_->FindBy(w1.get())); // once workspace is gone, w2 shouldn't match // any workspace. delete ws2; - EXPECT_EQ(NULL, manager.FindBy(w2.get())); + EXPECT_EQ(NULL, manager_->FindBy(w2.get())); + + // Reset now before windows are destroyed. + manager_.reset(); } TEST_F(WorkspaceManagerTest, LayoutWorkspaces) { - WorkspaceManager manager(viewport()); - manager.workspace_size_ = gfx::Size(100, 100); - manager.LayoutWorkspaces(); + manager_->workspace_size_ = gfx::Size(100, 100); + manager_->LayoutWorkspaces(); EXPECT_EQ("0,0 100x100", viewport()->bounds().ToString()); - Workspace* ws1 = manager.CreateWorkspace(); - manager.LayoutWorkspaces(); + Workspace* ws1 = manager_->CreateWorkspace(); + manager_->LayoutWorkspaces(); // ws1 is laied out in left most position. EXPECT_EQ(100, viewport()->bounds().width()); EXPECT_EQ("0,0 100x100", ws1->bounds().ToString()); // ws2 is laied out next to ws1, with 50 margin. - Workspace* ws2 = manager.CreateWorkspace(); - manager.LayoutWorkspaces(); + Workspace* ws2 = manager_->CreateWorkspace(); + manager_->LayoutWorkspaces(); EXPECT_EQ(250, viewport()->bounds().width()); EXPECT_EQ("0,0 100x100", ws1->bounds().ToString()); @@ -87,87 +105,188 @@ TEST_F(WorkspaceManagerTest, LayoutWorkspaces) { TEST_F(WorkspaceManagerTest, WorkspaceManagerDragArea) { aura::Desktop::GetInstance()->screen()->set_work_area_insets( gfx::Insets(10, 10, 10, 10)); - - WorkspaceManager manager(viewport()); viewport()->SetBounds(gfx::Rect(0, 0, 200, 200)); - EXPECT_EQ("10,10 180x180", manager.GetDragAreaBounds().ToString()); + EXPECT_EQ("10,10 180x180", manager_->GetDragAreaBounds().ToString()); } TEST_F(WorkspaceManagerTest, Overview) { - WorkspaceManager manager(viewport()); - manager.workspace_size_ = gfx::Size(500, 300); + manager_->workspace_size_ = gfx::Size(500, 300); // Creating two workspaces, ws1 which contains window w1, // and ws2 which contains window w2. - Workspace* ws1 = manager.CreateWorkspace(); + Workspace* ws1 = manager_->CreateWorkspace(); scoped_ptr<Window> w1(CreateTestWindow()); viewport()->AddChild(w1.get()); EXPECT_TRUE(ws1->AddWindowAfter(w1.get(), NULL)); - Workspace* ws2 = manager.CreateWorkspace(); + Workspace* ws2 = manager_->CreateWorkspace(); scoped_ptr<Window> w2(CreateTestWindow()); viewport()->AddChild(w2.get()); EXPECT_TRUE(ws2->AddWindowAfter(w2.get(), NULL)); // Activating a window switches the active workspace. w2->Activate(); - EXPECT_EQ(ws2, manager.GetActiveWorkspace()); + EXPECT_EQ(ws2, manager_->GetActiveWorkspace()); // The size of viewport() is now ws1(500) + ws2(500) + margin(50). EXPECT_EQ("0,0 1050x300", viewport()->bounds().ToString()); - EXPECT_FALSE(manager.is_overview()); - manager.SetOverview(true); - EXPECT_TRUE(manager.is_overview()); + EXPECT_FALSE(manager_->is_overview()); + manager_->SetOverview(true); + EXPECT_TRUE(manager_->is_overview()); // Switching overview mode doesn't change the active workspace. - EXPECT_EQ(ws2, manager.GetActiveWorkspace()); + EXPECT_EQ(ws2, manager_->GetActiveWorkspace()); // Activaing window w1 switches the active window and // the mode back to normal mode. w1->Activate(); - EXPECT_EQ(ws1, manager.GetActiveWorkspace()); - EXPECT_FALSE(manager.is_overview()); + EXPECT_EQ(ws1, manager_->GetActiveWorkspace()); + EXPECT_FALSE(manager_->is_overview()); // Deleting w1 without DesktopDelegate resets the active workspace ws1->RemoveWindow(w1.get()); delete ws1; w1.reset(); - EXPECT_EQ(NULL, manager.GetActiveWorkspace()); - + EXPECT_EQ(NULL, manager_->GetActiveWorkspace()); EXPECT_EQ("0,0 500x300", viewport()->bounds().ToString()); ws2->RemoveWindow(w2.get()); delete ws2; // The size of viewport() for no workspace case must be // same as one viewport() case. EXPECT_EQ("0,0 500x300", viewport()->bounds().ToString()); + + // Reset now before windows are destroyed. + manager_.reset(); } TEST_F(WorkspaceManagerTest, WorkspaceManagerActivate) { - WorkspaceManager manager(viewport()); - Workspace* ws1 = manager.CreateWorkspace(); - Workspace* ws2 = manager.CreateWorkspace(); - EXPECT_EQ(NULL, manager.GetActiveWorkspace()); + Workspace* ws1 = manager_->CreateWorkspace(); + Workspace* ws2 = manager_->CreateWorkspace(); + EXPECT_EQ(NULL, manager_->GetActiveWorkspace()); // Activate ws1. ws1->Activate(); - EXPECT_EQ(ws1, manager.GetActiveWorkspace()); + EXPECT_EQ(ws1, manager_->GetActiveWorkspace()); // Activate ws2. ws2->Activate(); - EXPECT_EQ(ws2, manager.GetActiveWorkspace()); + EXPECT_EQ(ws2, manager_->GetActiveWorkspace()); // Deleting active workspace sets active workspace to NULL. delete ws2; - EXPECT_EQ(NULL, manager.GetActiveWorkspace()); + EXPECT_EQ(NULL, manager_->GetActiveWorkspace()); + manager_.reset(); +} + +TEST_F(WorkspaceManagerTest, FindRotateWindow) { + manager_->workspace_size_ = gfx::Size(500, 300); + + Workspace* ws1 = manager_->CreateWorkspace(); + scoped_ptr<Window> w11(CreateTestWindow()); + w11->SetBounds(gfx::Rect(0, 0, 100, 100)); + ws1->AddWindowAfter(w11.get(), NULL); + + scoped_ptr<Window> w12(CreateTestWindow()); + w12->SetBounds(gfx::Rect(0, 0, 100, 100)); + ws1->AddWindowAfter(w12.get(), NULL); + manager_->LayoutWorkspaces(); + + // Workspaces are 0-empt-145-w11-245-margin-265-365-500. + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(0, 0))); + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(100, 0))); + EXPECT_EQ(w11.get(), + manager_->FindRotateWindowForLocation(gfx::Point(150, 0))); + EXPECT_EQ(w12.get(), + manager_->FindRotateWindowForLocation(gfx::Point(300, 0))); + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(400, 0))); + + w11->SetBounds(gfx::Rect(0, 0, 400, 100)); + w12->SetBounds(gfx::Rect(0, 0, 200, 100)); + manager_->LayoutWorkspaces(); + EXPECT_EQ(w11.get(), + manager_->FindRotateWindowForLocation(gfx::Point(10, 0))); + EXPECT_EQ(w11.get(), + manager_->FindRotateWindowForLocation(gfx::Point(240, 0))); + EXPECT_EQ(w12.get(), + manager_->FindRotateWindowForLocation(gfx::Point(260, 0))); + EXPECT_EQ(w12.get(), + manager_->FindRotateWindowForLocation(gfx::Point(490, 0))); + + Workspace* ws2 = manager_->CreateWorkspace(); + scoped_ptr<Window> w21(CreateTestWindow()); + w21->SetBounds(gfx::Rect(0, 0, 100, 100)); + ws2->AddWindowAfter(w21.get(), NULL); + manager_->LayoutWorkspaces(); + + // 2nd workspace starts from 500+50 and the window is centered 750-850. + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(600, 0))); + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(740, 0))); + EXPECT_EQ(w21.get(), + manager_->FindRotateWindowForLocation(gfx::Point(760, 0))); + EXPECT_EQ(w21.get(), + manager_->FindRotateWindowForLocation(gfx::Point(840, 0))); + EXPECT_EQ(NULL, manager_->FindRotateWindowForLocation(gfx::Point(860, 0))); + + // Reset now before windows are destroyed. + manager_.reset(); +} + +TEST_F(WorkspaceManagerTest, RotateWindows) { + Workspace* ws1 = manager_->CreateWorkspace(); + Workspace* ws2 = manager_->CreateWorkspace(); + + scoped_ptr<Window> w11(CreateTestWindow()); + ws1->AddWindowAfter(w11.get(), NULL); + + scoped_ptr<Window> w21(CreateTestWindow()); + scoped_ptr<Window> w22(CreateTestWindow()); + ws2->AddWindowAfter(w21.get(), NULL); + ws2->AddWindowAfter(w22.get(), NULL); + + EXPECT_EQ(0, ws1->GetIndexOf(w11.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w21.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w22.get())); + + // Rotate right most to left most. + manager_->RotateWindows(w22.get(), w11.get()); + + EXPECT_EQ(0, ws1->GetIndexOf(w22.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w11.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w21.get())); + + // Rotate left most to right most. + manager_->RotateWindows(w22.get(), w21.get()); + EXPECT_EQ(0, ws1->GetIndexOf(w11.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w21.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w22.get())); + + // Rotate left most to 1st element in 2nd workspace. + manager_->RotateWindows(w11.get(), w21.get()); + EXPECT_EQ(0, ws1->GetIndexOf(w21.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w11.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w22.get())); + + // Rotate middle to right most. + manager_->RotateWindows(w11.get(), w22.get()); + EXPECT_EQ(0, ws1->GetIndexOf(w21.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w22.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w11.get())); + + // Rotate middle to left most. + manager_->RotateWindows(w22.get(), w21.get()); + EXPECT_EQ(0, ws1->GetIndexOf(w22.get())); + EXPECT_EQ(0, ws2->GetIndexOf(w21.get())); + EXPECT_EQ(1, ws2->GetIndexOf(w11.get())); + + // Reset now before windows are destroyed. + manager_.reset(); } class WorkspaceTest : public WorkspaceManagerTestBase { }; TEST_F(WorkspaceTest, WorkspaceBasic) { - WorkspaceManager manager(viewport()); - - Workspace* ws = manager.CreateWorkspace(); + Workspace* ws = manager_->CreateWorkspace(); // Sanity check EXPECT_TRUE(ws->is_empty()); @@ -207,6 +326,167 @@ TEST_F(WorkspaceTest, WorkspaceBasic) { EXPECT_TRUE(ws->AddWindowAfter(w1.get(), w2.get())); EXPECT_EQ(0, ws->GetIndexOf(w2.get())); EXPECT_EQ(1, ws->GetIndexOf(w1.get())); + + // Reset now before windows are destroyed. + manager_.reset(); +} + +TEST_F(WorkspaceTest, RotateWindows) { + size_t orig_max = Workspace::SetMaxWindowsCount(3); + Workspace* ws = manager_->CreateWorkspace(); + scoped_ptr<Window> w1(CreateTestWindow()); + scoped_ptr<Window> w2(CreateTestWindow()); + scoped_ptr<Window> w3(CreateTestWindow()); + ws->AddWindowAfter(w1.get(), NULL); + ws->AddWindowAfter(w2.get(), NULL); + ws->AddWindowAfter(w3.get(), NULL); + + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(2, ws->GetIndexOf(w3.get())); + + // Rotate to left. + ws->RotateWindows(w1.get(), w3.get()); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + EXPECT_EQ(1, ws->GetIndexOf(w3.get())); + EXPECT_EQ(2, ws->GetIndexOf(w1.get())); + + // Rotate to right. + ws->RotateWindows(w1.get(), w2.get()); + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(2, ws->GetIndexOf(w3.get())); + + // Rotating to the middle from left. + ws->RotateWindows(w1.get(), w2.get()); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + EXPECT_EQ(1, ws->GetIndexOf(w1.get())); + EXPECT_EQ(2, ws->GetIndexOf(w3.get())); + + // Rotating to the middle from right. + ws->RotateWindows(w3.get(), w1.get()); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + EXPECT_EQ(1, ws->GetIndexOf(w3.get())); + EXPECT_EQ(2, ws->GetIndexOf(w1.get())); + + // Reset now before windows are destroyed. + manager_.reset(); + Workspace::SetMaxWindowsCount(orig_max); +} + +TEST_F(WorkspaceTest, ShiftWindowsSingle) { + Workspace* ws = manager_->CreateWorkspace(); + // Single window in a workspace case. + scoped_ptr<Window> w1(CreateTestWindow()); + ws->AddWindowAfter(w1.get(), NULL); + + scoped_ptr<Window> w2(CreateTestWindow()); + + // Sanity check. + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + + // Insert |w2| at the beginning and shift. + aura::Window* overflow = + ws->ShiftWindows( + w2.get(), w2.get(), NULL, Workspace::SHIFT_TO_RIGHT); + EXPECT_EQ(w1.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w1.get())); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + + // Insert |w1| at the end and shift. + overflow = ws->ShiftWindows( + w1.get(), w1.get(), NULL, Workspace::SHIFT_TO_LEFT); + EXPECT_EQ(w2.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + + // Insert |w2| at the begining and shift up to the w1. + overflow = ws->ShiftWindows( + w2.get(), w1.get(), NULL, Workspace::SHIFT_TO_RIGHT); + EXPECT_EQ(NULL, overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w1.get())); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + + // Insert |w1| at the end and shift up to the w2. + overflow = ws->ShiftWindows( + w1.get(), w2.get(), NULL, Workspace::SHIFT_TO_LEFT); + EXPECT_EQ(NULL, overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + + // Reset now before windows are destroyed. + manager_.reset(); +} + +TEST_F(WorkspaceTest, ShiftWindowsMultiple) { + Workspace* ws = manager_->CreateWorkspace(); + // Single window in a workspace case. + scoped_ptr<Window> w1(CreateTestWindow()); + scoped_ptr<Window> w2(CreateTestWindow()); + ws->AddWindowAfter(w1.get(), NULL); + ws->AddWindowAfter(w2.get(), NULL); + + scoped_ptr<Window> w3(CreateTestWindow()); + + // Sanity check. + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(-1, ws->GetIndexOf(w3.get())); + + // Insert |w3| at the beginning and shift. + aura::Window* overflow = + ws->ShiftWindows(w3.get(), w3.get(), NULL, + Workspace::SHIFT_TO_RIGHT); + EXPECT_EQ(w2.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(0, ws->GetIndexOf(w3.get())); + EXPECT_EQ(1, ws->GetIndexOf(w1.get())); + + // Insert |w3| at the end and shift. + overflow = ws->ShiftWindows(w2.get(), w2.get(), NULL, + Workspace::SHIFT_TO_LEFT); + EXPECT_EQ(w3.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w3.get())); + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(1, ws->GetIndexOf(w2.get())); + + // Insert |w3| at the begining and shift up to the w1. + overflow = ws->ShiftWindows(w3.get(), w1.get(), NULL, + Workspace::SHIFT_TO_RIGHT); + EXPECT_EQ(NULL, overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w1.get())); + EXPECT_EQ(0, ws->GetIndexOf(w3.get())); + EXPECT_EQ(1, ws->GetIndexOf(w2.get())); + + // Insert |w1| at the end and shift up to the w2. + overflow = ws->ShiftWindows(w1.get(), w2.get(), NULL, + Workspace::SHIFT_TO_LEFT); + EXPECT_EQ(NULL, overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(0, ws->GetIndexOf(w3.get())); + EXPECT_EQ(1, ws->GetIndexOf(w1.get())); + + scoped_ptr<Window> unused(CreateTestWindow()); + + // Insert |w2| at the |w3| and shift to right. + overflow = ws->ShiftWindows(w2.get(), unused.get(), w3.get(), + Workspace::SHIFT_TO_RIGHT); + EXPECT_EQ(w1.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w1.get())); + EXPECT_EQ(0, ws->GetIndexOf(w2.get())); + EXPECT_EQ(1, ws->GetIndexOf(w3.get())); + + // Insert |w1| at the |w2| and shift to left. + overflow = ws->ShiftWindows(w1.get(), unused.get(), w2.get(), + Workspace::SHIFT_TO_LEFT); + EXPECT_EQ(w2.get(), overflow); + EXPECT_EQ(-1, ws->GetIndexOf(w2.get())); + EXPECT_EQ(0, ws->GetIndexOf(w1.get())); + EXPECT_EQ(1, ws->GetIndexOf(w3.get())); + + // Reset now before windows are destroyed. + manager_.reset(); } } // namespace aura_shell |