Commit de99a643 authored by oshima@google.com's avatar oshima@google.com

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
parent 1efc51c6
......@@ -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)
......
......@@ -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);
}
////////////////////////////////////////////////////////////////////////////////
......
......@@ -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);
......
......@@ -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
......@@ -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_;
......
......@@ -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 +
......
......@@ -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();
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment