Reworks the workspace code. Here's the new heuristics:
. All normal windows end up in a single workspace. . Each maximized window ends up in its own workspace. . There is an additional workspace for split windows, but the heuristics of this aren't implemented yet. I've left some bits of the old code, in particular overview but there isn't really a way to get into it yet and it'll need some reworking if we decide to keep it. BUG=111285 TEST=none R=ben@chromium.org,oshima@chromium.org Review URL: https://chromiumcodereview.appspot.com/9113045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119282 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
ash
ash.gyp
shell
wm
show_state_controller.ccshow_state_controller.hwindow_util.ccwindow_util.h
workspace
workspace.ccworkspace.hworkspace_event_filter.ccworkspace_event_filter.hworkspace_layout_manager.ccworkspace_layout_manager.hworkspace_layout_manager_unittest.ccworkspace_manager.ccworkspace_manager.hworkspace_manager_unittest.ccworkspace_observer.h
workspace_controller.ccworkspace_controller.hworkspace_controller_unittest.ccchrome/browser/ui/views/aura
@ -138,8 +138,6 @@
|
||||
'wm/shadow_types.h',
|
||||
'wm/shelf_layout_manager.cc',
|
||||
'wm/shelf_layout_manager.h',
|
||||
'wm/show_state_controller.h',
|
||||
'wm/show_state_controller.cc',
|
||||
'wm/stacking_controller.cc',
|
||||
'wm/stacking_controller.h',
|
||||
'wm/status_area_layout_manager.cc',
|
||||
@ -176,7 +174,6 @@
|
||||
'wm/workspace/workspace_layout_manager.h',
|
||||
'wm/workspace/workspace_manager.cc',
|
||||
'wm/workspace/workspace_manager.h',
|
||||
'wm/workspace/workspace_observer.h',
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -238,7 +235,6 @@
|
||||
'wm/window_cycle_controller_unittest.cc',
|
||||
'wm/window_modality_controller_unittest.cc',
|
||||
'wm/workspace_controller_unittest.cc',
|
||||
'wm/workspace/workspace_layout_manager_unittest.cc',
|
||||
'wm/workspace/workspace_manager_unittest.cc',
|
||||
|
||||
'<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc',
|
||||
|
@ -157,7 +157,9 @@ class ShellDelegateImpl : public ash::ShellDelegate {
|
||||
|
||||
virtual void LauncherItemClicked(
|
||||
const ash::LauncherItem& item) OVERRIDE {
|
||||
ash::ActivateWindow(watcher_->GetWindowByID(item.id));
|
||||
aura::Window* window = watcher_->GetWindowByID(item.id);
|
||||
window->Show();
|
||||
ash::ActivateWindow(window);
|
||||
}
|
||||
|
||||
virtual int GetBrowserShortcutResourceId() OVERRIDE {
|
||||
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2011 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/show_state_controller.h"
|
||||
|
||||
#include "ash/wm/property_util.h"
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_manager.h"
|
||||
#include "ui/aura/client/aura_constants.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
ShowStateController::ShowStateController(
|
||||
WorkspaceManager* workspace_manager)
|
||||
: workspace_manager_(workspace_manager) {
|
||||
}
|
||||
|
||||
ShowStateController::~ShowStateController() {
|
||||
}
|
||||
|
||||
void ShowStateController::OnWindowPropertyChanged(aura::Window* window,
|
||||
const char* name,
|
||||
void* old) {
|
||||
if (name != aura::client::kShowStateKey)
|
||||
return;
|
||||
if (window->GetIntProperty(name) == ui::SHOW_STATE_NORMAL) {
|
||||
// Restore the size of window first, then let Workspace layout the window.
|
||||
const gfx::Rect* restore = GetRestoreBounds(window);
|
||||
window->SetProperty(aura::client::kRestoreBoundsKey, NULL);
|
||||
if (restore)
|
||||
window->SetBounds(*restore);
|
||||
delete restore;
|
||||
} else if (old == reinterpret_cast<void*>(ui::SHOW_STATE_NORMAL)) {
|
||||
// Store the restore bounds only if previous state is normal.
|
||||
DCHECK(window->GetProperty(aura::client::kRestoreBoundsKey) == NULL);
|
||||
SetRestoreBounds(window, window->GetTargetBounds());
|
||||
}
|
||||
|
||||
workspace_manager_->FindBy(window)->Layout(window);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ash
|
@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2011 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_SHOW_STATE_CONTROLLER_H_
|
||||
#define ASH_WM_SHOW_STATE_CONTROLLER_H_
|
||||
#pragma once
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "ui/aura/window_observer.h"
|
||||
|
||||
namespace aura {
|
||||
class Window;
|
||||
}
|
||||
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
class WorkspaceManager;
|
||||
|
||||
// ShowStateController controls the window's bounds when
|
||||
// the window's show state property has changed.
|
||||
class ShowStateController : public aura::WindowObserver {
|
||||
public:
|
||||
explicit ShowStateController(WorkspaceManager* layout_manager);
|
||||
virtual ~ShowStateController();
|
||||
|
||||
// aura::WindowObserver overrides:
|
||||
virtual void OnWindowPropertyChanged(aura::Window* window,
|
||||
const char* name,
|
||||
void* old) OVERRIDE;
|
||||
|
||||
private:
|
||||
// |workspace_maanger_| is owned by |WorkspaceController|.
|
||||
WorkspaceManager* workspace_manager_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ShowStateController);
|
||||
};
|
||||
|
||||
} // namepsace internal
|
||||
} // namepsace ash
|
||||
|
||||
#endif // ASH_WM_SHOW_STATE_CONTROLLER_H_
|
@ -14,6 +14,12 @@
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kOpenWindowSplitKey[] = "OpenWindowSplit";
|
||||
|
||||
} // namespace
|
||||
|
||||
void ActivateWindow(aura::Window* window) {
|
||||
aura::client::GetActivationClient()->ActivateWindow(window);
|
||||
}
|
||||
@ -64,5 +70,13 @@ bool HasFullscreenWindow(const WindowSet& windows) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetOpenWindowSplit(aura::Window* window, bool value) {
|
||||
window->SetIntProperty(kOpenWindowSplitKey, value ? 1 : 0);
|
||||
}
|
||||
|
||||
bool GetOpenWindowSplit(aura::Window* window) {
|
||||
return window->GetIntProperty(kOpenWindowSplitKey) == 1;
|
||||
}
|
||||
|
||||
} // namespace window_util
|
||||
} // namespace ash
|
||||
|
@ -49,6 +49,11 @@ ASH_EXPORT void RestoreWindow(aura::Window* window);
|
||||
typedef std::set<aura::Window*> WindowSet;
|
||||
ASH_EXPORT bool HasFullscreenWindow(const WindowSet& windows);
|
||||
|
||||
// Sets whether the window should be open in a split mode. Only applicable when
|
||||
// workspaces are used.
|
||||
ASH_EXPORT void SetOpenWindowSplit(aura::Window* window, bool value);
|
||||
ASH_EXPORT bool GetOpenWindowSplit(aura::Window* window);
|
||||
|
||||
} // namespace window_util
|
||||
} // namespace ash
|
||||
|
||||
|
@ -14,41 +14,13 @@
|
||||
#include "ui/aura/root_window.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "ui/gfx/compositor/layer.h"
|
||||
#include "ui/gfx/compositor/layer_animator.h"
|
||||
#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
|
||||
|
||||
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;
|
||||
|
||||
// Returns the bounds of the window that should be used to calculate
|
||||
// the layout. It uses the restore bounds if exits, or
|
||||
// the target bounds of the window. The target bounds is the
|
||||
// final destination of |window| if the window's layer is animating,
|
||||
// or the current bounds of the window of no animation is currently
|
||||
// in progress.
|
||||
gfx::Rect GetLayoutBounds(aura::Window* window) {
|
||||
const gfx::Rect* restore_bounds = ash::GetRestoreBounds(window);
|
||||
return restore_bounds ? *restore_bounds : window->GetTargetBounds();
|
||||
}
|
||||
|
||||
// Returns the width of the window that should be used to calculate
|
||||
// the layout. See |GetLayoutBounds| for more details.
|
||||
int GetLayoutWidth(aura::Window* window) {
|
||||
return GetLayoutBounds(window).width();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
Workspace::Workspace(WorkspaceManager* manager)
|
||||
: workspace_manager_(manager) {
|
||||
: type_(TYPE_NORMAL),
|
||||
workspace_manager_(manager) {
|
||||
workspace_manager_->AddWorkspace(this);
|
||||
}
|
||||
|
||||
@ -56,15 +28,34 @@ Workspace::~Workspace() {
|
||||
workspace_manager_->RemoveWorkspace(this);
|
||||
}
|
||||
|
||||
void Workspace::SetBounds(const gfx::Rect& bounds) {
|
||||
bool bounds_changed = bounds_ != bounds;
|
||||
bounds_ = bounds;
|
||||
if (bounds_changed)
|
||||
Layout(NULL);
|
||||
// static
|
||||
Workspace::Type Workspace::TypeForWindow(aura::Window* window) {
|
||||
if (window_util::GetOpenWindowSplit(window))
|
||||
return TYPE_SPLIT;
|
||||
if (window_util::IsWindowMaximized(window) ||
|
||||
window_util::IsWindowFullscreen(window)) {
|
||||
return TYPE_MAXIMIZED;
|
||||
}
|
||||
return TYPE_NORMAL;
|
||||
}
|
||||
|
||||
void Workspace::SetType(Type type) {
|
||||
// Can only change the type when there are no windows, or the type of window
|
||||
// matches the type changing to. We need only check the first window as CanAdd
|
||||
// only allows new windows if the type matches.
|
||||
DCHECK(windows_.empty() || TypeForWindow(windows_[0]) == type);
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void Workspace::WorkspaceSizeChanged() {
|
||||
if (!windows_.empty()) {
|
||||
// TODO: need to handle size changing.
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect Workspace::GetWorkAreaBounds() const {
|
||||
return workspace_manager_->GetWorkAreaBounds(bounds_);
|
||||
return workspace_manager_->GetWorkAreaBounds();
|
||||
}
|
||||
|
||||
bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
|
||||
@ -72,15 +63,19 @@ bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
|
||||
return false;
|
||||
DCHECK(!Contains(window));
|
||||
|
||||
if (!after) { // insert at the end.
|
||||
aura::Window::Windows::iterator i =
|
||||
std::find(windows_.begin(), windows_.end(), after);
|
||||
if (!after || i == windows_.end())
|
||||
windows_.push_back(window);
|
||||
} else {
|
||||
DCHECK(Contains(after));
|
||||
aura::Window::Windows::iterator i =
|
||||
std::find(windows_.begin(), windows_.end(), after);
|
||||
else
|
||||
windows_.insert(++i, window);
|
||||
|
||||
if (type_ == TYPE_MAXIMIZED) {
|
||||
workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
|
||||
} else if (type_ == TYPE_SPLIT) {
|
||||
// TODO: this needs to adjust bounds appropriately.
|
||||
workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
|
||||
}
|
||||
Layout(window);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -88,138 +83,17 @@ 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);
|
||||
// TODO: this needs to adjust things.
|
||||
}
|
||||
|
||||
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 = ash::GetActiveWindow();
|
||||
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(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) {
|
||||
// Calling RemoveWindow here causes the animation set in Layout below
|
||||
// to be ignored. See crbug.com/102413.
|
||||
windows_.erase(std::find(windows_.begin(), windows_.end(), 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(NULL);
|
||||
return pushed;
|
||||
}
|
||||
|
||||
void Workspace::Activate() {
|
||||
workspace_manager_->SetActiveWorkspace(this);
|
||||
}
|
||||
|
||||
void Workspace::Layout(aura::Window* no_animation) {
|
||||
aura::Window* ignore = workspace_manager_->ignored_window();
|
||||
workspace_manager_->set_layout_in_progress(true);
|
||||
gfx::Rect work_area = workspace_manager_->GetWorkAreaBounds(bounds_);
|
||||
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) {
|
||||
if (*i != ignore) {
|
||||
MoveWindowTo(*i,
|
||||
gfx::Point(work_area.x() + dx, work_area.y()),
|
||||
no_animation != *i);
|
||||
}
|
||||
dx += GetLayoutWidth(*i) + kWindowHorizontalMargin;
|
||||
}
|
||||
} else {
|
||||
DCHECK_LT(windows_.size(), 3U);
|
||||
// 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() - GetLayoutWidth(windows_[1]),
|
||||
work_area.y()),
|
||||
no_animation != windows_[1]);
|
||||
}
|
||||
}
|
||||
workspace_manager_->set_layout_in_progress(false);
|
||||
}
|
||||
|
||||
bool Workspace::ContainsFullscreenWindow() const {
|
||||
for (aura::Window::Windows::const_iterator i = windows_.begin();
|
||||
i != windows_.end();
|
||||
@ -240,47 +114,7 @@ int Workspace::GetIndexOf(aura::Window* window) const {
|
||||
}
|
||||
|
||||
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() < g_max_windows_per_workspace;
|
||||
}
|
||||
|
||||
void Workspace::MoveWindowTo(
|
||||
aura::Window* window,
|
||||
const gfx::Point& origin,
|
||||
bool animate) {
|
||||
gfx::Rect bounds = GetLayoutBounds(window);
|
||||
gfx::Rect work_area = GetWorkAreaBounds();
|
||||
// Make sure the window isn't bigger than the workspace size.
|
||||
bounds.SetRect(origin.x(), origin.y(),
|
||||
std::min(work_area.width(), bounds.width()),
|
||||
std::min(work_area.height(), bounds.height()));
|
||||
if (animate) {
|
||||
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
|
||||
window->SetBounds(bounds);
|
||||
} else {
|
||||
window->SetBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
total_width += GetLayoutWidth(*i);
|
||||
}
|
||||
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;
|
||||
return TypeForWindow(window) == type_;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -22,17 +22,24 @@ namespace internal {
|
||||
class WorkspaceManager;
|
||||
class WorkspaceTest;
|
||||
|
||||
// A workspace is a partial area of the entire desktop (viewport) that
|
||||
// is visible to the user at a given time. The size of the workspace is
|
||||
// generally the same as the size of the monitor, and the desktop can
|
||||
// have multiple workspaces.
|
||||
// A workspace contains a limited number of windows and the workspace
|
||||
// manager may create a new workspace if there is not enough room for
|
||||
// a new window.
|
||||
// A workspace contains a number of windows. The number of windows a Workspace
|
||||
// may contain is dictated by the type. Typically only one workspace is visible
|
||||
// at a time. The exception to that is when overview mode is active.
|
||||
class ASH_EXPORT Workspace {
|
||||
public:
|
||||
explicit Workspace(WorkspaceManager* manager);
|
||||
virtual ~Workspace();
|
||||
// Type of workspace. The type of workspace dictates the types of windows the
|
||||
// workspace can contain.
|
||||
enum Type {
|
||||
// The workspace holds a single maximized or full screen window.
|
||||
TYPE_MAXIMIZED,
|
||||
|
||||
// Workspace contains multiple windows that are split (also known as
|
||||
// co-maximized).
|
||||
TYPE_SPLIT,
|
||||
|
||||
// Workspace contains non-maximized windows that can be moved in anyway.
|
||||
TYPE_NORMAL,
|
||||
};
|
||||
|
||||
// Specifies the direction to shift windows in |ShiftWindows()|.
|
||||
enum ShiftDirection {
|
||||
@ -40,15 +47,25 @@ class ASH_EXPORT Workspace {
|
||||
SHIFT_TO_LEFT
|
||||
};
|
||||
|
||||
// Returns true if this workspace has no windows.
|
||||
explicit Workspace(WorkspaceManager* manager);
|
||||
virtual ~Workspace();
|
||||
|
||||
// Returns the type of workspace that can contain |window|.
|
||||
static Type TypeForWindow(aura::Window* window);
|
||||
|
||||
// The type of this Workspace.
|
||||
void SetType(Type type);
|
||||
Type type() const { return type_; }
|
||||
|
||||
// Returns true if this workspace has no windows.
|
||||
bool is_empty() const { return windows_.empty(); }
|
||||
size_t num_windows() const { return windows_.size(); }
|
||||
const std::vector<aura::Window*>& windows() const { return windows_; }
|
||||
|
||||
// Sets/gets bounds of this workspace.
|
||||
const gfx::Rect& bounds() { return bounds_; }
|
||||
void SetBounds(const gfx::Rect& bounds);
|
||||
// Invoked when the size of the workspace changes.
|
||||
void WorkspaceSizeChanged();
|
||||
|
||||
// Returns the work area bounds of this workspace in viewport
|
||||
// coordinates.
|
||||
// Returns the work area bounds of this workspace in viewport coordinates.
|
||||
gfx::Rect GetWorkAreaBounds() const;
|
||||
|
||||
// Adds the |window| at the position after the window |after|. It
|
||||
@ -63,35 +80,9 @@ class ASH_EXPORT Workspace {
|
||||
// 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. The workspace doesn't set bounds on
|
||||
// |WorkspaceManager::ignored_window| if it's set. It still uses the 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* no_animation);
|
||||
|
||||
// Returns true if the workspace contains a fullscreen window.
|
||||
bool ContainsFullscreenWindow() const;
|
||||
|
||||
@ -108,24 +99,10 @@ class ASH_EXPORT Workspace {
|
||||
// Returns true if the given |window| can be added to this workspace.
|
||||
bool CanAdd(aura::Window* window) const;
|
||||
|
||||
// Moves |window| to the given point. It performs animation when
|
||||
// |animate| is true.
|
||||
void MoveWindowTo(aura::Window* window,
|
||||
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);
|
||||
Type type_;
|
||||
|
||||
WorkspaceManager* workspace_manager_;
|
||||
|
||||
gfx::Rect bounds_;
|
||||
|
||||
// Windows in the workspace in layout order.
|
||||
std::vector<aura::Window*> windows_;
|
||||
|
||||
|
@ -38,6 +38,8 @@ WorkspaceEventFilter::WorkspaceEventFilter(aura::Window* owner)
|
||||
}
|
||||
|
||||
WorkspaceEventFilter::~WorkspaceEventFilter() {
|
||||
if (hovered_window_)
|
||||
hovered_window_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
bool WorkspaceEventFilter::PreHandleMouseEvent(aura::Window* target,
|
||||
@ -95,6 +97,12 @@ bool WorkspaceEventFilter::PreHandleMouseEvent(aura::Window* target,
|
||||
return handled;
|
||||
}
|
||||
|
||||
void WorkspaceEventFilter::OnWindowDestroyed(aura::Window* window) {
|
||||
DCHECK_EQ(hovered_window_, window);
|
||||
hovered_window_->RemoveObserver(this);
|
||||
hovered_window_ = NULL;
|
||||
}
|
||||
|
||||
bool WorkspaceEventFilter::UpdateDragState() {
|
||||
DCHECK_EQ(DRAG_NONE, drag_state_);
|
||||
switch (window_component()) {
|
||||
@ -122,9 +130,13 @@ void WorkspaceEventFilter::UpdateHoveredWindow(
|
||||
aura::Window* toplevel_window) {
|
||||
if (toplevel_window == hovered_window_)
|
||||
return;
|
||||
if (hovered_window_)
|
||||
hovered_window_->RemoveObserver(this);
|
||||
WindowHoverChanged(hovered_window_, false);
|
||||
hovered_window_ = toplevel_window;
|
||||
WindowHoverChanged(hovered_window_, true);
|
||||
if (hovered_window_)
|
||||
hovered_window_->AddObserver(this);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ash/wm/toplevel_window_event_filter.h"
|
||||
#include "ui/aura/window_observer.h"
|
||||
|
||||
namespace aura {
|
||||
class MouseEvent;
|
||||
@ -16,7 +17,8 @@ class Window;
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
class WorkspaceEventFilter : public ToplevelWindowEventFilter {
|
||||
class WorkspaceEventFilter : public ToplevelWindowEventFilter,
|
||||
public aura::WindowObserver {
|
||||
public:
|
||||
explicit WorkspaceEventFilter(aura::Window* owner);
|
||||
virtual ~WorkspaceEventFilter();
|
||||
@ -25,6 +27,9 @@ class WorkspaceEventFilter : public ToplevelWindowEventFilter {
|
||||
virtual bool PreHandleMouseEvent(aura::Window* target,
|
||||
aura::MouseEvent* event) OVERRIDE;
|
||||
|
||||
// Overriden from WindowObserver:
|
||||
virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
|
||||
|
||||
private:
|
||||
enum DragState {
|
||||
DRAG_NONE,
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "ash/wm/workspace/workspace_layout_manager.h"
|
||||
|
||||
#include "ash/wm/property_util.h"
|
||||
#include "ash/wm/show_state_controller.h"
|
||||
#include "ash/wm/window_util.h"
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_manager.h"
|
||||
@ -27,8 +26,7 @@ namespace internal {
|
||||
|
||||
WorkspaceLayoutManager::WorkspaceLayoutManager(
|
||||
WorkspaceManager* workspace_manager)
|
||||
: workspace_manager_(workspace_manager),
|
||||
show_state_controller_(new ShowStateController(workspace_manager)) {
|
||||
: workspace_manager_(workspace_manager) {
|
||||
}
|
||||
|
||||
WorkspaceLayoutManager::~WorkspaceLayoutManager() {}
|
||||
@ -48,43 +46,22 @@ void WorkspaceLayoutManager::CancelMoveOrResize(
|
||||
void WorkspaceLayoutManager::ProcessMove(
|
||||
aura::Window* drag,
|
||||
aura::MouseEvent* event) {
|
||||
// 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,
|
||||
workspace_manager_->contents_view(),
|
||||
&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);
|
||||
// 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(oshima): finish moving window between workspaces.
|
||||
// TODO: see comment in ProcessMove.
|
||||
workspace_manager_->set_ignored_window(NULL);
|
||||
Workspace* workspace = workspace_manager_->FindBy(drag);
|
||||
workspace->Layout(NULL);
|
||||
workspace->Activate();
|
||||
workspace_manager_->SetOverview(false);
|
||||
}
|
||||
|
||||
void WorkspaceLayoutManager::EndResize(
|
||||
aura::Window* drag,
|
||||
aura::MouseEvent* evnet) {
|
||||
// TODO: see comment in ProcessMove.
|
||||
workspace_manager_->set_ignored_window(NULL);
|
||||
Workspace* workspace = workspace_manager_->GetActiveWorkspace();
|
||||
if (workspace)
|
||||
workspace->Layout(NULL);
|
||||
workspace_manager_->SetOverview(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -95,95 +72,41 @@ void WorkspaceLayoutManager::OnWindowResized() {
|
||||
}
|
||||
|
||||
void WorkspaceLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
|
||||
if (child->type() != aura::client::WINDOW_TYPE_NORMAL ||
|
||||
child->transient_parent()) {
|
||||
if (!workspace_manager_->IsManagedWindow(child))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!child->GetProperty(aura::client::kShowStateKey))
|
||||
child->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
|
||||
child->AddObserver(show_state_controller_.get());
|
||||
|
||||
Workspace* workspace = workspace_manager_->GetActiveWorkspace();
|
||||
if (workspace) {
|
||||
aura::Window* active = ash::GetActiveWindow();
|
||||
// Active window may not be in the default container layer.
|
||||
if (!workspace->Contains(active))
|
||||
active = NULL;
|
||||
if (workspace->AddWindowAfter(child, active))
|
||||
return;
|
||||
}
|
||||
// Create new workspace if new |child| doesn't fit to current workspace.
|
||||
Workspace* new_workspace = workspace_manager_->CreateWorkspace();
|
||||
new_workspace->AddWindowAfter(child, NULL);
|
||||
new_workspace->Activate();
|
||||
if (child->IsVisible())
|
||||
workspace_manager_->AddWindow(child);
|
||||
}
|
||||
|
||||
void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(
|
||||
aura::Window* child) {
|
||||
child->RemoveObserver(show_state_controller_.get());
|
||||
ClearRestoreBounds(child);
|
||||
|
||||
Workspace* workspace = workspace_manager_->FindBy(child);
|
||||
if (!workspace)
|
||||
return;
|
||||
workspace->RemoveWindow(child);
|
||||
if (workspace->is_empty())
|
||||
delete workspace;
|
||||
workspace_manager_->RemoveWindow(child);
|
||||
}
|
||||
|
||||
void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(
|
||||
aura::Window* child,
|
||||
bool visible) {
|
||||
NOTIMPLEMENTED();
|
||||
if (!workspace_manager_->IsManagedWindow(child))
|
||||
return;
|
||||
if (visible)
|
||||
workspace_manager_->AddWindow(child);
|
||||
else
|
||||
workspace_manager_->RemoveWindow(child);
|
||||
}
|
||||
|
||||
void WorkspaceLayoutManager::SetChildBounds(
|
||||
aura::Window* child,
|
||||
const gfx::Rect& requested_bounds) {
|
||||
gfx::Rect adjusted_bounds = requested_bounds;
|
||||
|
||||
// First, calculate the adjusted bounds.
|
||||
if (child->type() != aura::client::WINDOW_TYPE_NORMAL ||
|
||||
workspace_manager_->layout_in_progress() ||
|
||||
child->transient_parent()) {
|
||||
// Use the requested bounds as is.
|
||||
} else if (child == workspace_manager_->ignored_window()) {
|
||||
// If a drag window is requesting bounds, make sure its attached to
|
||||
// the workarea's top and fits within the total drag area.
|
||||
gfx::Rect drag_area = workspace_manager_->GetDragAreaBounds();
|
||||
adjusted_bounds.set_y(drag_area.y());
|
||||
adjusted_bounds = adjusted_bounds.AdjustToFit(drag_area);
|
||||
} else {
|
||||
Workspace* workspace = workspace_manager_->FindBy(child);
|
||||
gfx::Rect work_area = workspace->GetWorkAreaBounds();
|
||||
adjusted_bounds.set_origin(
|
||||
gfx::Point(child->GetTargetBounds().x(), work_area.y()));
|
||||
adjusted_bounds = adjusted_bounds.AdjustToFit(work_area);
|
||||
// Allow setting the bounds for any window we don't care about, isn't visible,
|
||||
// or we're setting the bounds of. All other request are dropped on the floor.
|
||||
if (child == workspace_manager_->ignored_window() ||
|
||||
!workspace_manager_->IsManagedWindow(child) || !child->IsVisible() ||
|
||||
(!window_util::IsWindowMaximized(child) &&
|
||||
!window_util::IsWindowFullscreen(child))) {
|
||||
SetChildBoundsDirect(child, requested_bounds);
|
||||
}
|
||||
|
||||
ui::WindowShowState show_state = static_cast<ui::WindowShowState>(
|
||||
child->GetIntProperty(aura::client::kShowStateKey));
|
||||
|
||||
// Second, check if the window is either maximized or in fullscreen mode.
|
||||
if (show_state == ui::SHOW_STATE_MAXIMIZED ||
|
||||
show_state == ui::SHOW_STATE_FULLSCREEN) {
|
||||
// If the request is not from workspace manager,
|
||||
// remember the requested bounds.
|
||||
if (!workspace_manager_->layout_in_progress())
|
||||
SetRestoreBounds(child, adjusted_bounds);
|
||||
|
||||
Workspace* workspace = workspace_manager_->FindBy(child);
|
||||
if (show_state == ui::SHOW_STATE_MAXIMIZED)
|
||||
adjusted_bounds = workspace->GetWorkAreaBounds();
|
||||
else
|
||||
adjusted_bounds = workspace->bounds();
|
||||
// Don't
|
||||
if (child->GetTargetBounds() == adjusted_bounds)
|
||||
return;
|
||||
}
|
||||
SetChildBoundsDirect(child, adjusted_bounds);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -6,11 +6,10 @@
|
||||
#define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_
|
||||
#pragma once
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/aura/layout_manager.h"
|
||||
#include "ash/ash_export.h"
|
||||
|
||||
namespace aura {
|
||||
class MouseEvent;
|
||||
@ -24,10 +23,9 @@ class Rect;
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
class ShowStateController;
|
||||
class WorkspaceManager;
|
||||
|
||||
// LayoutManager for the default window container.
|
||||
// LayoutManager for top level windows when WorkspaceManager is enabled.
|
||||
class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager {
|
||||
public:
|
||||
explicit WorkspaceLayoutManager(WorkspaceManager* workspace_manager);
|
||||
@ -61,12 +59,11 @@ class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager {
|
||||
bool visibile) OVERRIDE;
|
||||
virtual void SetChildBounds(aura::Window* child,
|
||||
const gfx::Rect& requested_bounds) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Owned by WorkspaceController.
|
||||
WorkspaceManager* workspace_manager_;
|
||||
|
||||
scoped_ptr<ShowStateController> show_state_controller_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager);
|
||||
};
|
||||
|
||||
|
@ -1,341 +0,0 @@
|
||||
// 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_layout_manager.h"
|
||||
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_manager.h"
|
||||
#include "ash/wm/workspace_controller.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_vector.h"
|
||||
#include "ui/aura/client/aura_constants.h"
|
||||
#include "ui/aura/root_window.h"
|
||||
#include "ui/aura/screen_aura.h"
|
||||
#include "ui/aura/test/aura_test_base.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "ui/views/widget/native_widget_aura.h"
|
||||
|
||||
namespace ash {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
using views::Widget;
|
||||
using ash::internal::WorkspaceLayoutManager;
|
||||
|
||||
class WorkspaceLayoutManagerTest : public aura::test::AuraTestBase {
|
||||
public:
|
||||
WorkspaceLayoutManagerTest() : layout_manager_(NULL) {}
|
||||
virtual ~WorkspaceLayoutManagerTest() {}
|
||||
|
||||
virtual void SetUp() OVERRIDE {
|
||||
aura::test::AuraTestBase::SetUp();
|
||||
aura::RootWindow* root_window = aura::RootWindow::GetInstance();
|
||||
container_.reset(
|
||||
CreateTestWindow(gfx::Rect(0, 0, 500, 400), root_window));
|
||||
workspace_controller_.reset(
|
||||
new ash::internal::WorkspaceController(container_.get()));
|
||||
layout_manager_ = new WorkspaceLayoutManager(
|
||||
workspace_controller_->workspace_manager());
|
||||
container_->SetLayoutManager(layout_manager_);
|
||||
|
||||
root_window->SetHostSize(gfx::Size(500, 400));
|
||||
}
|
||||
|
||||
aura::Window* CreateTestWindowWithType(const gfx::Rect& bounds,
|
||||
aura::Window* parent,
|
||||
aura::client::WindowType type) {
|
||||
aura::Window* window = new aura::Window(NULL);
|
||||
window->SetType(type);
|
||||
window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
|
||||
window->SetBounds(bounds);
|
||||
window->Show();
|
||||
window->SetParent(parent);
|
||||
return window;
|
||||
}
|
||||
|
||||
aura::Window* CreateTestWindow(const gfx::Rect& bounds,
|
||||
aura::Window* parent) {
|
||||
return CreateTestWindowWithType(bounds,
|
||||
parent,
|
||||
aura::client::WINDOW_TYPE_NORMAL);
|
||||
}
|
||||
|
||||
aura::Window* container() { return container_.get(); }
|
||||
|
||||
WorkspaceLayoutManager* default_container_layout_manager() {
|
||||
return layout_manager_;
|
||||
}
|
||||
|
||||
protected:
|
||||
ash::internal::WorkspaceManager* workspace_manager() {
|
||||
return workspace_controller_->workspace_manager();
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_ptr<aura::Window> container_;
|
||||
scoped_ptr<ash::internal::WorkspaceController> workspace_controller_;
|
||||
// LayoutManager is owned by |container|.
|
||||
ash::internal::WorkspaceLayoutManager* layout_manager_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerTest);
|
||||
};
|
||||
|
||||
// Utility functions to set and get show state on |window|.
|
||||
void Maximize(aura::Window* window) {
|
||||
window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
}
|
||||
|
||||
void Fullscreen(aura::Window* window) {
|
||||
window->SetIntProperty(aura::client::kShowStateKey,
|
||||
ui::SHOW_STATE_FULLSCREEN);
|
||||
}
|
||||
|
||||
void Restore(aura::Window* window) {
|
||||
window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
}
|
||||
|
||||
ui::WindowShowState GetShowState(aura::Window* window) {
|
||||
return static_cast<ui::WindowShowState>(
|
||||
window->GetIntProperty(aura::client::kShowStateKey));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(WorkspaceLayoutManagerTest, SetBounds) {
|
||||
// Layout Manager moves the window to (0,0) to fit to draggable area.
|
||||
scoped_ptr<aura::Window> child(
|
||||
CreateTestWindow(gfx::Rect(0, -1000, 100, 100), container()));
|
||||
// Window is centered in workspace.
|
||||
EXPECT_EQ("200,0 100x100", child->bounds().ToString());
|
||||
|
||||
// DCLM enforces the window height can't be taller than its owner's height.
|
||||
child->SetBounds(gfx::Rect(0, 0, 100, 500));
|
||||
EXPECT_EQ("200,0 100x400", child->bounds().ToString());
|
||||
|
||||
// DCLM enforces the window width can't be wider than its owner's width.
|
||||
child->SetBounds(gfx::Rect(0, 0, 900, 500));
|
||||
EXPECT_EQ("0,0 500x400", child->bounds().ToString());
|
||||
|
||||
// Y origin must always be the top of drag area.
|
||||
child->SetBounds(gfx::Rect(0, 500, 900, 500));
|
||||
EXPECT_EQ("0,0 500x400", child->bounds().ToString());
|
||||
child->SetBounds(gfx::Rect(0, -500, 900, 500));
|
||||
EXPECT_EQ("0,0 500x400", child->bounds().ToString());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceLayoutManagerTest, DragWindow) {
|
||||
scoped_ptr<aura::Window> child(
|
||||
CreateTestWindow(gfx::Rect(0, -1000, 50, 50), container()));
|
||||
gfx::Rect original_bounds = child->bounds();
|
||||
|
||||
default_container_layout_manager()->PrepareForMoveOrResize(
|
||||
child.get(), NULL);
|
||||
// X origin must fit within viewport.
|
||||
child->SetBounds(gfx::Rect(-100, 500, 50, 50));
|
||||
EXPECT_EQ("0,0 50x50", child->GetTargetBounds().ToString());
|
||||
child->SetBounds(gfx::Rect(1000, 500, 50, 50));
|
||||
EXPECT_EQ("450,0 50x50", child->GetTargetBounds().ToString());
|
||||
default_container_layout_manager()->EndMove(child.get(), NULL);
|
||||
EXPECT_EQ(original_bounds.ToString(), child->GetTargetBounds().ToString());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceLayoutManagerTest, Popup) {
|
||||
scoped_ptr<aura::Window> popup(
|
||||
CreateTestWindowWithType(gfx::Rect(0, -1000, 100, 100),
|
||||
container(),
|
||||
aura::client::WINDOW_TYPE_POPUP));
|
||||
// A popup window can be placed outside of draggable area.
|
||||
EXPECT_EQ("0,-1000 100x100", popup->bounds().ToString());
|
||||
|
||||
// A popup window can be moved to outside of draggable area.
|
||||
popup->SetBounds(gfx::Rect(-100, 0, 100, 100));
|
||||
EXPECT_EQ("-100,0 100x100", popup->bounds().ToString());
|
||||
|
||||
// A popup window can be resized to the size bigger than draggable area.
|
||||
popup->SetBounds(gfx::Rect(0, 0, 1000, 1000));
|
||||
EXPECT_EQ("0,0 1000x1000", popup->bounds().ToString());
|
||||
}
|
||||
|
||||
// Make sure a window with a transient parent isn't resized by the layout
|
||||
// manager.
|
||||
TEST_F(WorkspaceLayoutManagerTest, IgnoreTransient) {
|
||||
scoped_ptr<aura::Window> window(new aura::Window(NULL));
|
||||
window->SetType(aura::client::WINDOW_TYPE_NORMAL);
|
||||
window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
|
||||
aura::RootWindow::GetInstance()->AddTransientChild(window.get());
|
||||
window->SetBounds(gfx::Rect(0, 0, 200, 200));
|
||||
window->Show();
|
||||
window->SetParent(container());
|
||||
|
||||
EXPECT_EQ("0,0 200x200", window->bounds().ToString());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceLayoutManagerTest, Fullscreen) {
|
||||
scoped_ptr<aura::Window> w(
|
||||
CreateTestWindow(gfx::Rect(0, 0, 100, 100), container()));
|
||||
gfx::Rect fullscreen_bounds =
|
||||
workspace_manager()->FindBy(w.get())->bounds();
|
||||
gfx::Rect original_bounds = w->GetTargetBounds();
|
||||
|
||||
// Restoreing the restored window.
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
// Fullscreen
|
||||
Fullscreen(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
|
||||
EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
|
||||
w->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
Fullscreen(w.get());
|
||||
// Setting |ui::SHOW_STATE_FULLSCREEN| should have no additional effect.
|
||||
Fullscreen(w.get());
|
||||
EXPECT_EQ(fullscreen_bounds, w->bounds());
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
// Calling SetBounds() in fullscreen mode should only update the
|
||||
// restore bounds not change the bounds of the window.
|
||||
gfx::Rect new_bounds(50, 50, 50, 50);
|
||||
Fullscreen(w.get());
|
||||
w->SetBounds(new_bounds);
|
||||
EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
|
||||
EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(50, w->bounds().height());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceLayoutManagerTest, Maximized) {
|
||||
scoped_ptr<aura::Window> w(
|
||||
CreateTestWindow(gfx::Rect(0, 0, 100, 100), container()));
|
||||
gfx::Rect original_bounds = w->GetTargetBounds();
|
||||
gfx::Rect fullscreen_bounds =
|
||||
workspace_manager()->FindBy(w.get())->bounds();
|
||||
gfx::Rect work_area_bounds =
|
||||
workspace_manager()->FindBy(w.get())->GetWorkAreaBounds();
|
||||
|
||||
// Maximized
|
||||
Maximize(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
// Maximize twice
|
||||
Maximize(w.get());
|
||||
Maximize(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
// Maximized -> Fullscreen -> Maximized -> Normal
|
||||
Maximize(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
|
||||
Fullscreen(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetShowState(w.get()));
|
||||
EXPECT_EQ(fullscreen_bounds.ToString(), w->bounds().ToString());
|
||||
Maximize(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetShowState(w.get()));
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(original_bounds.ToString(), w->bounds().ToString());
|
||||
|
||||
// Calling SetBounds() in maximized mode mode should only update the
|
||||
// restore bounds not change the bounds of the window.
|
||||
gfx::Rect new_bounds(50, 50, 50, 50);
|
||||
Maximize(w.get());
|
||||
w->SetBounds(new_bounds);
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w->bounds().ToString());
|
||||
Restore(w.get());
|
||||
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetShowState(w.get()));
|
||||
EXPECT_EQ(50, w->bounds().height());
|
||||
}
|
||||
|
||||
// Tests that fullscreen windows get resized after root window is resized.
|
||||
TEST_F(WorkspaceLayoutManagerTest, FullscreenAfterRootWindowResize) {
|
||||
scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(300, 400),
|
||||
container()));
|
||||
gfx::Rect window_bounds = w1->GetTargetBounds();
|
||||
gfx::Rect fullscreen_bounds =
|
||||
workspace_manager()->FindBy(w1.get())->bounds();
|
||||
|
||||
w1->Show();
|
||||
EXPECT_EQ(window_bounds.ToString(), w1->bounds().ToString());
|
||||
|
||||
Fullscreen(w1.get());
|
||||
EXPECT_EQ(fullscreen_bounds.ToString(), w1->bounds().ToString());
|
||||
|
||||
// Resize the root window.
|
||||
aura::RootWindow* root_window = aura::RootWindow::GetInstance();
|
||||
gfx::Size new_root_window_size = root_window->GetHostSize();
|
||||
new_root_window_size.Enlarge(100, 200);
|
||||
root_window->OnHostResized(new_root_window_size);
|
||||
|
||||
gfx::Rect new_fullscreen_bounds =
|
||||
workspace_manager()->FindBy(w1.get())->bounds();
|
||||
EXPECT_NE(fullscreen_bounds.size().ToString(),
|
||||
new_fullscreen_bounds.size().ToString());
|
||||
|
||||
EXPECT_EQ(new_fullscreen_bounds.ToString(),
|
||||
w1->GetTargetBounds().ToString());
|
||||
|
||||
Restore(w1.get());
|
||||
|
||||
// The following test does not pass due to crbug.com/102413.
|
||||
// TODO(oshima): Re-enable this once the bug is fixed.
|
||||
// EXPECT_EQ(window_bounds.size().ToString(),
|
||||
// w1->GetTargetBounds().size().ToString());
|
||||
}
|
||||
|
||||
// Tests that maximized windows get resized after root_window is resized.
|
||||
TEST_F(WorkspaceLayoutManagerTest, MaximizeAfterRootWindowResize) {
|
||||
scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(300, 400),
|
||||
container()));
|
||||
gfx::Rect window_bounds = w1->GetTargetBounds();
|
||||
gfx::Rect work_area_bounds =
|
||||
workspace_manager()->FindBy(w1.get())->GetWorkAreaBounds();
|
||||
|
||||
w1->Show();
|
||||
EXPECT_EQ(window_bounds.ToString(), w1->bounds().ToString());
|
||||
|
||||
Maximize(w1.get());
|
||||
EXPECT_EQ(work_area_bounds.ToString(), w1->bounds().ToString());
|
||||
|
||||
// Resize the root window.
|
||||
aura::RootWindow* root_window = aura::RootWindow::GetInstance();
|
||||
gfx::Size new_root_window_size = root_window->GetHostSize();
|
||||
new_root_window_size.Enlarge(100, 200);
|
||||
root_window->OnHostResized(new_root_window_size);
|
||||
|
||||
gfx::Rect new_work_area_bounds =
|
||||
workspace_manager()->FindBy(w1.get())->bounds();
|
||||
EXPECT_NE(work_area_bounds.size().ToString(),
|
||||
new_work_area_bounds.size().ToString());
|
||||
|
||||
EXPECT_EQ(new_work_area_bounds.ToString(),
|
||||
w1->GetTargetBounds().ToString());
|
||||
|
||||
Restore(w1.get());
|
||||
// The following test does not pass due to crbug.com/102413.
|
||||
// TODO(oshima): Re-enable this once the bug is fixed.
|
||||
// EXPECT_EQ(window_bounds.size().ToString(),
|
||||
// w1->GetTargetBounds().size().ToString());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace ash
|
@ -6,14 +6,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ash/wm/property_util.h"
|
||||
#include "ash/wm/window_util.h"
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_observer.h"
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "ui/aura/client/aura_constants.h"
|
||||
#include "ui/aura/root_window.h"
|
||||
#include "ui/aura/screen_aura.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "ui/gfx/compositor/layer.h"
|
||||
#include "ui/gfx/compositor/layer_animator.h"
|
||||
#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
|
||||
@ -29,6 +32,20 @@ const int kWorkspaceHorizontalMargin = 50;
|
||||
const float kMaxOverviewScale = 0.9f;
|
||||
const float kMinOverviewScale = 0.3f;
|
||||
|
||||
// Sets the visibility of the layer of each window in |windows| to |value|. We
|
||||
// set the visibility of the layer rather than the Window so that views doesn't
|
||||
// see the visibility change.
|
||||
// TODO: revisit this. Ideally the Window would think it's still visibile after
|
||||
// this. May be possible after Ben lands his changes.
|
||||
void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows,
|
||||
bool value) {
|
||||
for (size_t i = 0; i < windows.size(); ++i){
|
||||
if (windows[i]->layer())
|
||||
windows[i]->layer()->SetVisible(value);
|
||||
SetWindowLayerVisibility(windows[i]->transient_children(), value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ash {
|
||||
@ -43,20 +60,173 @@ WorkspaceManager::WorkspaceManager(aura::Window* contents_view)
|
||||
workspace_size_(
|
||||
gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()),
|
||||
is_overview_(false),
|
||||
layout_in_progress_(false),
|
||||
ignored_window_(NULL) {
|
||||
DCHECK(contents_view);
|
||||
}
|
||||
|
||||
WorkspaceManager::~WorkspaceManager() {
|
||||
for (size_t i = 0; i < workspaces_.size(); ++i) {
|
||||
Workspace* workspace = workspaces_[i];
|
||||
for (size_t j = 0; j < workspace->windows().size(); ++j)
|
||||
workspace->windows()[j]->RemoveObserver(this);
|
||||
}
|
||||
std::vector<Workspace*> copy_to_delete(workspaces_);
|
||||
STLDeleteElements(©_to_delete);
|
||||
}
|
||||
|
||||
Workspace* WorkspaceManager::CreateWorkspace() {
|
||||
Workspace* workspace = new Workspace(this);
|
||||
LayoutWorkspaces();
|
||||
return workspace;
|
||||
bool WorkspaceManager::IsManagedWindow(aura::Window* window) const {
|
||||
return window->type() == aura::client::WINDOW_TYPE_NORMAL &&
|
||||
!window->transient_parent();
|
||||
}
|
||||
|
||||
void WorkspaceManager::AddWindow(aura::Window* window) {
|
||||
DCHECK(IsManagedWindow(window));
|
||||
|
||||
if (FindBy(window))
|
||||
return; // Already know about this window.
|
||||
|
||||
window->AddObserver(this);
|
||||
|
||||
if (!window->GetProperty(aura::client::kShowStateKey)) {
|
||||
// TODO: set maximized if width < x.
|
||||
window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
}
|
||||
|
||||
// TODO: handle fullscreen.
|
||||
if (window_util::IsWindowMaximized(window)) {
|
||||
if (!GetRestoreBounds(window))
|
||||
SetRestoreBounds(window, window->GetTargetBounds());
|
||||
else
|
||||
SetWindowBounds(window, GetWorkAreaBounds());
|
||||
}
|
||||
|
||||
Workspace* workspace = NULL;
|
||||
Workspace::Type type_for_window = Workspace::TypeForWindow(window);
|
||||
switch (type_for_window) {
|
||||
case Workspace::TYPE_SPLIT:
|
||||
// Splits either go in current workspace (if maximized or split). If the
|
||||
// current workspace isn't split/maximized, then create a maximized
|
||||
// workspace.
|
||||
workspace = GetActiveWorkspace();
|
||||
if (workspace &&
|
||||
(workspace->type() == Workspace::TYPE_SPLIT ||
|
||||
workspace->type() == Workspace::TYPE_MAXIMIZED)) {
|
||||
// TODO: this needs to reset bounds of any existing windows in
|
||||
// workspace.
|
||||
workspace->SetType(Workspace::TYPE_SPLIT);
|
||||
} else {
|
||||
type_for_window = Workspace::TYPE_MAXIMIZED;
|
||||
workspace = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case Workspace::TYPE_NORMAL:
|
||||
// All normal windows go in the same workspace.
|
||||
workspace = GetNormalWorkspace();
|
||||
break;
|
||||
|
||||
case Workspace::TYPE_MAXIMIZED:
|
||||
// All maximized windows go in their own workspace.
|
||||
break;
|
||||
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!workspace) {
|
||||
workspace = new Workspace(this);
|
||||
workspace->SetType(type_for_window);
|
||||
}
|
||||
workspace->AddWindowAfter(window, NULL);
|
||||
workspace->Activate();
|
||||
}
|
||||
|
||||
void WorkspaceManager::RemoveWindow(aura::Window* window) {
|
||||
Workspace* workspace = FindBy(window);
|
||||
if (!workspace)
|
||||
return;
|
||||
window->RemoveObserver(this);
|
||||
workspace->RemoveWindow(window);
|
||||
if (workspace->is_empty())
|
||||
delete workspace;
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetActiveWorkspaceByWindow(aura::Window* window) {
|
||||
Workspace* workspace = FindBy(window);
|
||||
if (workspace)
|
||||
workspace->Activate();
|
||||
}
|
||||
|
||||
gfx::Rect WorkspaceManager::GetDragAreaBounds() {
|
||||
return GetWorkAreaBounds();
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetOverview(bool overview) {
|
||||
if (is_overview_ == overview)
|
||||
return;
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
|
||||
if (workspace_size == workspace_size_)
|
||||
return;
|
||||
workspace_size_ = workspace_size;
|
||||
for (Workspaces::const_iterator i = workspaces_.begin();
|
||||
i != workspaces_.end(); ++i) {
|
||||
(*i)->WorkspaceSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
|
||||
const char* name,
|
||||
void* old) {
|
||||
if (!IsManagedWindow(window))
|
||||
return;
|
||||
|
||||
if (name != aura::client::kShowStateKey)
|
||||
return;
|
||||
// TODO: handle fullscreen.
|
||||
bool is_maximized = window->GetIntProperty(name) == ui::SHOW_STATE_MAXIMIZED;
|
||||
bool was_maximized =
|
||||
(old == reinterpret_cast<void*>(ui::SHOW_STATE_MAXIMIZED));
|
||||
if (is_maximized == was_maximized)
|
||||
return;
|
||||
|
||||
MaximizedStateChanged(window);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WorkspaceManager, private:
|
||||
|
||||
void WorkspaceManager::AddWorkspace(Workspace* workspace) {
|
||||
DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
|
||||
workspace) == workspaces_.end());
|
||||
if (active_workspace_) {
|
||||
// New workspaces go right after current workspace.
|
||||
Workspaces::iterator i = std::find(workspaces_.begin(), workspaces_.end(),
|
||||
active_workspace_);
|
||||
workspaces_.insert(++i, workspace);
|
||||
} else {
|
||||
workspaces_.push_back(workspace);
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
|
||||
Workspaces::iterator i = std::find(workspaces_.begin(),
|
||||
workspaces_.end(),
|
||||
workspace);
|
||||
DCHECK(i != workspaces_.end());
|
||||
i = workspaces_.erase(i);
|
||||
if (active_workspace_ == workspace) {
|
||||
// TODO: need mru order.
|
||||
if (i != workspaces_.end())
|
||||
SetActiveWorkspace(*i);
|
||||
else if (!workspaces_.empty())
|
||||
SetActiveWorkspace(workspaces_.back());
|
||||
else
|
||||
active_workspace_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Workspace* WorkspaceManager::GetActiveWorkspace() const {
|
||||
@ -68,176 +238,22 @@ Workspace* WorkspaceManager::FindBy(aura::Window* window) const {
|
||||
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) {
|
||||
aura::Window* window = (*i)->FindRotateWindowForLocation(point);
|
||||
if (window)
|
||||
return window;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WorkspaceManager::LayoutWorkspaces() {
|
||||
UpdateContentsView();
|
||||
|
||||
gfx::Rect bounds(workspace_size_);
|
||||
int x = 0;
|
||||
for (Workspaces::const_iterator i = workspaces_.begin();
|
||||
i != workspaces_.end();
|
||||
++i) {
|
||||
Workspace* workspace = *i;
|
||||
bounds.set_x(x);
|
||||
workspace->SetBounds(bounds);
|
||||
x += bounds.width() + kWorkspaceHorizontalMargin;
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect WorkspaceManager::GetDragAreaBounds() {
|
||||
return GetWorkAreaBounds(gfx::Rect(contents_view_->bounds().size()));
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetOverview(bool overview) {
|
||||
if (is_overview_ == overview)
|
||||
return;
|
||||
is_overview_ = overview;
|
||||
|
||||
ui::Transform transform;
|
||||
if (is_overview_) {
|
||||
// TODO(oshima|sky): We limit the how small windows can be shrinked
|
||||
// in overview mode, thus part of the contents_view may not be visible.
|
||||
// We need to add capability to scroll/move contents_view in overview mode.
|
||||
float scale = std::min(
|
||||
kMaxOverviewScale,
|
||||
workspace_size_.width() /
|
||||
static_cast<float>(contents_view_->bounds().width()));
|
||||
scale = std::max(kMinOverviewScale, scale);
|
||||
|
||||
transform.SetScale(scale, scale);
|
||||
|
||||
int overview_width = contents_view_->bounds().width() * scale;
|
||||
int dx = 0;
|
||||
if (overview_width < workspace_size_.width()) {
|
||||
dx = (workspace_size_.width() - overview_width) / 2;
|
||||
} else if (active_workspace_) {
|
||||
// Center the active workspace.
|
||||
int active_workspace_mid_x = (active_workspace_->bounds().x() +
|
||||
active_workspace_->bounds().width() / 2) * scale;
|
||||
dx = workspace_size_.width() / 2 - active_workspace_mid_x;
|
||||
dx = std::min(0, std::max(dx, workspace_size_.width() - overview_width));
|
||||
}
|
||||
|
||||
transform.SetTranslateX(dx);
|
||||
transform.SetTranslateY(workspace_size_.height() * (1.0f - scale) / 2);
|
||||
} else if (active_workspace_) {
|
||||
transform.SetTranslateX(-active_workspace_->bounds().x());
|
||||
}
|
||||
|
||||
ui::ScopedLayerAnimationSettings settings(
|
||||
contents_view_->layer()->GetAnimator());
|
||||
contents_view_->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;
|
||||
aura::Window* target_to_insert = target;
|
||||
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_to_insert, Workspace::SHIFT_TO_LEFT);
|
||||
// |target| can only be in the 1st workspace.
|
||||
target_to_insert = NULL;
|
||||
}
|
||||
} else {
|
||||
for (int i = target_ws_index; i <= source_ws_index; ++i) {
|
||||
insert = workspaces_[i]->ShiftWindows(
|
||||
insert, source, target_to_insert, Workspace::SHIFT_TO_RIGHT);
|
||||
// |target| can only be in the 1st workspace.
|
||||
target_to_insert = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
|
||||
WindowMoved(this, source, target));
|
||||
workspaces_[target_ws_index]->Activate();
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
|
||||
if (workspace_size == workspace_size_)
|
||||
return;
|
||||
workspace_size_ = workspace_size;
|
||||
LayoutWorkspaces();
|
||||
}
|
||||
|
||||
void WorkspaceManager::AddObserver(WorkspaceObserver* observer) {
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) {
|
||||
observers_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WorkspaceManager, private:
|
||||
|
||||
void WorkspaceManager::AddWorkspace(Workspace* workspace) {
|
||||
Workspaces::iterator i = std::find(workspaces_.begin(),
|
||||
workspaces_.end(),
|
||||
workspace);
|
||||
DCHECK(i == workspaces_.end());
|
||||
workspaces_.push_back(workspace);
|
||||
}
|
||||
|
||||
void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
|
||||
Workspaces::iterator i = std::find(workspaces_.begin(),
|
||||
workspaces_.end(),
|
||||
workspace);
|
||||
DCHECK(i != workspaces_.end());
|
||||
Workspace* old = NULL;
|
||||
|
||||
if (workspace == active_workspace_) {
|
||||
old = active_workspace_;
|
||||
active_workspace_ = NULL;
|
||||
}
|
||||
workspaces_.erase(i);
|
||||
LayoutWorkspaces();
|
||||
|
||||
if (old) {
|
||||
FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
|
||||
ActiveWorkspaceChanged(this, old));
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) {
|
||||
if (active_workspace_ == workspace)
|
||||
return;
|
||||
DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
|
||||
workspace) != workspaces_.end());
|
||||
Workspace* old = active_workspace_;
|
||||
if (active_workspace_)
|
||||
SetWindowLayerVisibility(active_workspace_->windows(), false);
|
||||
active_workspace_ = workspace;
|
||||
if (active_workspace_)
|
||||
SetWindowLayerVisibility(active_workspace_->windows(), true);
|
||||
|
||||
is_overview_ = false;
|
||||
UpdateContentsView();
|
||||
|
||||
FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
|
||||
ActiveWorkspaceChanged(this, old));
|
||||
}
|
||||
|
||||
gfx::Rect WorkspaceManager::GetWorkAreaBounds(
|
||||
const gfx::Rect& workspace_bounds) {
|
||||
gfx::Rect bounds = workspace_bounds;
|
||||
gfx::Rect WorkspaceManager::GetWorkAreaBounds() {
|
||||
gfx::Rect bounds(workspace_size_);
|
||||
bounds.Inset(
|
||||
aura::RootWindow::GetInstance()->screen()->work_area_insets());
|
||||
return bounds;
|
||||
@ -254,23 +270,75 @@ int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WorkspaceManager::UpdateContentsView() {
|
||||
int num_workspaces = std::max(1, static_cast<int>(workspaces_.size()));
|
||||
int total_width = workspace_size_.width() * num_workspaces +
|
||||
kWorkspaceHorizontalMargin * (num_workspaces - 1);
|
||||
gfx::Rect bounds(0, 0, total_width, workspace_size_.height());
|
||||
void WorkspaceManager::SetWindowBounds(aura::Window* window,
|
||||
const gfx::Rect& bounds) {
|
||||
// TODO: I suspect it's possible for this to be invoked when ignored_window_
|
||||
// is non-NULL.
|
||||
ignored_window_ = window;
|
||||
window->SetBounds(bounds);
|
||||
ignored_window_ = NULL;
|
||||
}
|
||||
|
||||
if (contents_view_->GetTargetBounds() != bounds)
|
||||
contents_view_->SetBounds(bounds);
|
||||
|
||||
// Move to active workspace.
|
||||
if (active_workspace_) {
|
||||
ui::Transform transform;
|
||||
transform.SetTranslateX(-active_workspace_->bounds().x());
|
||||
ui::ScopedLayerAnimationSettings settings(
|
||||
contents_view_->layer()->GetAnimator());
|
||||
contents_view_->SetTransform(transform);
|
||||
void WorkspaceManager::SetWindowBoundsFromRestoreBounds(aura::Window* window) {
|
||||
Workspace* workspace = FindBy(window);
|
||||
DCHECK(workspace);
|
||||
const gfx::Rect* restore = GetRestoreBounds(window);
|
||||
if (restore) {
|
||||
SetWindowBounds(window,
|
||||
restore->AdjustToFit(workspace->GetWorkAreaBounds()));
|
||||
} else {
|
||||
SetWindowBounds(window, window->bounds().AdjustToFit(
|
||||
workspace->GetWorkAreaBounds()));
|
||||
}
|
||||
ash::ClearRestoreBounds(window);
|
||||
}
|
||||
|
||||
void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
|
||||
DCHECK(IsManagedWindow(window));
|
||||
bool is_maximized = window_util::IsWindowMaximized(window);
|
||||
Workspace* current_workspace = FindBy(window);
|
||||
DCHECK(current_workspace);
|
||||
if (is_maximized) {
|
||||
// Unmaximized -> maximized; create a new workspace (unless current only has
|
||||
// one window).
|
||||
SetRestoreBounds(window, window->GetTargetBounds());
|
||||
if (current_workspace->num_windows() != 1) {
|
||||
current_workspace->RemoveWindow(window);
|
||||
Workspace* workspace = new Workspace(this);
|
||||
workspace->SetType(Workspace::TYPE_MAXIMIZED);
|
||||
workspace->AddWindowAfter(window, NULL);
|
||||
current_workspace = workspace;
|
||||
} else {
|
||||
current_workspace->SetType(Workspace::TYPE_MAXIMIZED);
|
||||
}
|
||||
SetWindowBounds(window, GetWorkAreaBounds());
|
||||
} else {
|
||||
// Maximized -> unmaximized; move window to unmaximized workspace (or reuse
|
||||
// current if there isn't one).
|
||||
window_util::SetOpenWindowSplit(window, false);
|
||||
Workspace* workspace = GetNormalWorkspace();
|
||||
if (workspace) {
|
||||
current_workspace->RemoveWindow(window);
|
||||
DCHECK(current_workspace->is_empty());
|
||||
workspace->AddWindowAfter(window, NULL);
|
||||
delete current_workspace;
|
||||
current_workspace = workspace;
|
||||
} else {
|
||||
current_workspace->SetType(Workspace::TYPE_NORMAL);
|
||||
}
|
||||
|
||||
SetWindowBoundsFromRestoreBounds(window);
|
||||
}
|
||||
|
||||
SetActiveWorkspace(current_workspace);
|
||||
}
|
||||
|
||||
Workspace* WorkspaceManager::GetNormalWorkspace() {
|
||||
for (size_t i = 0; i < workspaces_.size(); ++i) {
|
||||
if (workspaces_[i]->type() == Workspace::TYPE_NORMAL)
|
||||
return workspaces_[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "ash/ash_export.h"
|
||||
#include "ui/aura/window_observer.h"
|
||||
#include "ui/gfx/insets.h"
|
||||
#include "ui/gfx/size.h"
|
||||
|
||||
@ -26,34 +26,32 @@ class Rect;
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
class Workspace;
|
||||
class WorkspaceObserver;
|
||||
class WorkspaceManagerTest;
|
||||
|
||||
// WorkspaceManager manages multiple workspaces in the desktop.
|
||||
class ASH_EXPORT WorkspaceManager {
|
||||
class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
|
||||
public:
|
||||
explicit WorkspaceManager(aura::Window* viewport);
|
||||
virtual ~WorkspaceManager();
|
||||
|
||||
// Returns true if |window| should be managed by the WorkspaceManager.
|
||||
bool IsManagedWindow(aura::Window* window) const;
|
||||
|
||||
// Adds/removes a window creating/destroying workspace as necessary.
|
||||
void AddWindow(aura::Window* window);
|
||||
void RemoveWindow(aura::Window* window);
|
||||
|
||||
// Activates the workspace containing |window|. Does nothing if |window| is
|
||||
// NULL or not contained in a workspace.
|
||||
void SetActiveWorkspaceByWindow(aura::Window* window);
|
||||
|
||||
// Returns the Window this WorkspaceManager controls.
|
||||
aura::Window* contents_view() { return contents_view_; }
|
||||
|
||||
// Create new workspace. Workspace objects are managed by
|
||||
// this WorkspaceManager. Deleting workspace will automatically
|
||||
// remove the workspace from the workspace_manager.
|
||||
Workspace* CreateWorkspace();
|
||||
|
||||
// Returns the active workspace.
|
||||
Workspace* GetActiveWorkspace() const;
|
||||
|
||||
// Returns the workspace that contanis the |window|.
|
||||
Workspace* FindBy(aura::Window* window) const;
|
||||
|
||||
// Returns the window for rotate operation based on the |location|.
|
||||
// TODO: this isn't currently used; remove if we do away with overview.
|
||||
aura::Window* FindRotateWindowForLocation(const gfx::Point& location);
|
||||
|
||||
// Sets the bounds of all workspaces.
|
||||
void LayoutWorkspaces();
|
||||
|
||||
// Returns the bounds in which a window can be moved/resized.
|
||||
gfx::Rect GetDragAreaBounds();
|
||||
|
||||
@ -61,25 +59,9 @@ class ASH_EXPORT WorkspaceManager {
|
||||
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);
|
||||
|
||||
// Sets the size of a single workspace (all workspaces have the same size).
|
||||
void SetWorkspaceSize(const gfx::Size& workspace_size);
|
||||
|
||||
// Adds/Removes workspace observer.
|
||||
void AddObserver(WorkspaceObserver* observer);
|
||||
void RemoveObserver(WorkspaceObserver* observer);
|
||||
|
||||
// Returns true if this workspace manager is laying out windows.
|
||||
// When true, LayoutManager must give windows their requested bounds.
|
||||
bool layout_in_progress() const { return layout_in_progress_; }
|
||||
|
||||
// Sets the |layout_in_progress_| flag.
|
||||
void set_layout_in_progress(bool layout_in_progress) {
|
||||
layout_in_progress_ = layout_in_progress;
|
||||
}
|
||||
|
||||
// Sets/Returns the ignored window that the workspace manager does not
|
||||
// set bounds on.
|
||||
void set_ignored_window(aura::Window* ignored_window) {
|
||||
@ -87,23 +69,47 @@ class ASH_EXPORT WorkspaceManager {
|
||||
}
|
||||
aura::Window* ignored_window() { return ignored_window_; }
|
||||
|
||||
// Overriden from aura::WindowObserver:
|
||||
virtual void OnWindowPropertyChanged(aura::Window* window,
|
||||
const char* name,
|
||||
void* old) OVERRIDE;
|
||||
|
||||
private:
|
||||
friend class Workspace;
|
||||
friend class WorkspaceManagerTest;
|
||||
|
||||
void AddWorkspace(Workspace* workspace);
|
||||
void RemoveWorkspace(Workspace* workspace);
|
||||
|
||||
// Returns the active workspace.
|
||||
Workspace* GetActiveWorkspace() const;
|
||||
|
||||
// Returns the workspace that contanis the |window|.
|
||||
Workspace* FindBy(aura::Window* window) const;
|
||||
|
||||
// Sets the active workspace.
|
||||
void SetActiveWorkspace(Workspace* workspace);
|
||||
|
||||
// Returns the bounds of the work are given |workspace_bounds|.
|
||||
gfx::Rect GetWorkAreaBounds(const gfx::Rect& workspace_bounds);
|
||||
// Returns the bounds of the work area.
|
||||
gfx::Rect GetWorkAreaBounds();
|
||||
|
||||
// Returns the index of the workspace that contains the |window|.
|
||||
int GetWorkspaceIndexContaining(aura::Window* window) const;
|
||||
|
||||
// Update contents_view size and move the viewport to the active workspace.
|
||||
void UpdateContentsView();
|
||||
// Sets the bounds of |window|. This sets |ignored_window_| to |window| so
|
||||
// that the bounds change is allowed through.
|
||||
void SetWindowBounds(aura::Window* window, const gfx::Rect& bounds);
|
||||
|
||||
// Resets the bounds of |window| to its restored bounds (if set), ensuring
|
||||
// it fits in the the windows current workspace.
|
||||
void SetWindowBoundsFromRestoreBounds(aura::Window* window);
|
||||
|
||||
// Invoked when the maximized state of |window| changes.
|
||||
void MaximizedStateChanged(aura::Window* window);
|
||||
|
||||
// Returns the Workspace whose type is TYPE_NORMAL, or NULL if there isn't
|
||||
// one.
|
||||
Workspace* GetNormalWorkspace();
|
||||
|
||||
aura::Window* contents_view_;
|
||||
|
||||
@ -118,14 +124,9 @@ class ASH_EXPORT WorkspaceManager {
|
||||
// True if the workspace manager is in overview mode.
|
||||
bool is_overview_;
|
||||
|
||||
// True if this layout manager is laying out windows.
|
||||
bool layout_in_progress_;
|
||||
|
||||
// The window that WorkspaceManager does not set the bounds on.
|
||||
aura::Window* ignored_window_;
|
||||
|
||||
ObserverList<WorkspaceObserver> observers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceManager);
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include "ash/shell_window_ids.h"
|
||||
#include "ash/wm/activation_controller.h"
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_observer.h"
|
||||
#include "ash/wm/workspace/workspace_layout_manager.h"
|
||||
#include "ui/aura/client/aura_constants.h"
|
||||
#include "ui/aura/root_window.h"
|
||||
#include "ui/aura/screen_aura.h"
|
||||
@ -15,81 +15,27 @@
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
|
||||
namespace {
|
||||
using ash::internal::Workspace;
|
||||
using ash::internal::WorkspaceManager;
|
||||
using aura::Window;
|
||||
|
||||
class TestWorkspaceObserver : public ash::internal::WorkspaceObserver {
|
||||
public:
|
||||
explicit TestWorkspaceObserver(WorkspaceManager* manager)
|
||||
: manager_(manager),
|
||||
move_source_(NULL),
|
||||
move_target_(NULL),
|
||||
active_workspace_(NULL),
|
||||
old_active_workspace_(NULL) {
|
||||
manager_->AddObserver(this);
|
||||
}
|
||||
|
||||
virtual ~TestWorkspaceObserver() {
|
||||
manager_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
Window* move_source() { return move_source_; }
|
||||
Window* move_target() { return move_target_; }
|
||||
Workspace* active_workspace() { return active_workspace_; }
|
||||
Workspace* old_active_workspace() { return old_active_workspace_; }
|
||||
|
||||
// Resets the observer states.
|
||||
void reset() {
|
||||
active_workspace_ = NULL;
|
||||
old_active_workspace_ = NULL;
|
||||
move_source_ = NULL;
|
||||
move_target_ = NULL;
|
||||
}
|
||||
|
||||
// Overridden from WorkspaceObserver:
|
||||
virtual void WindowMoved(WorkspaceManager* manager,
|
||||
Window* source,
|
||||
Window* target) {
|
||||
move_source_ = source;
|
||||
move_target_ = target;
|
||||
}
|
||||
virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
|
||||
Workspace* old) {
|
||||
old_active_workspace_ = old;
|
||||
active_workspace_ = manager->GetActiveWorkspace();
|
||||
}
|
||||
|
||||
private:
|
||||
WorkspaceManager* manager_;
|
||||
Window* move_source_;
|
||||
Window* move_target_;
|
||||
Workspace* active_workspace_;
|
||||
Workspace* old_active_workspace_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestWorkspaceObserver);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
|
||||
class WorkspaceManagerTestBase : public aura::test::AuraTestBase {
|
||||
class WorkspaceManagerTest : public aura::test::AuraTestBase {
|
||||
public:
|
||||
WorkspaceManagerTestBase() {
|
||||
WorkspaceManagerTest() : layout_manager_(NULL) {
|
||||
aura::RootWindow::GetInstance()->set_id(
|
||||
internal::kShellWindowId_DefaultContainer);
|
||||
activation_controller_.reset(new internal::ActivationController);
|
||||
activation_controller_->set_default_container_for_test(
|
||||
aura::RootWindow::GetInstance());
|
||||
}
|
||||
virtual ~WorkspaceManagerTestBase() {}
|
||||
virtual ~WorkspaceManagerTest() {}
|
||||
|
||||
virtual void SetUp() OVERRIDE {
|
||||
aura::test::AuraTestBase::SetUp();
|
||||
manager_.reset(new WorkspaceManager(viewport()));
|
||||
layout_manager_ = new WorkspaceLayoutManager(manager_.get());
|
||||
viewport()->SetLayoutManager(layout_manager_);
|
||||
}
|
||||
|
||||
virtual void TearDown() OVERRIDE {
|
||||
@ -99,468 +45,243 @@ class WorkspaceManagerTestBase : public aura::test::AuraTestBase {
|
||||
|
||||
aura::Window* CreateTestWindow() {
|
||||
aura::Window* window = new aura::Window(NULL);
|
||||
window->Init(ui::Layer::LAYER_HAS_NO_TEXTURE);
|
||||
window->SetType(aura::client::WINDOW_TYPE_NORMAL);
|
||||
window->Init(ui::Layer::LAYER_HAS_TEXTURE);
|
||||
window->SetParent(viewport());
|
||||
return window;
|
||||
}
|
||||
|
||||
aura::Window* viewport() {
|
||||
return aura::RootWindow::GetInstance();
|
||||
}
|
||||
|
||||
const std::vector<Workspace*>& workspaces() const {
|
||||
return manager_->workspaces_;
|
||||
}
|
||||
|
||||
gfx::Rect GetWorkAreaBounds() {
|
||||
return manager_->GetWorkAreaBounds();
|
||||
}
|
||||
|
||||
Workspace* active_workspace() {
|
||||
return manager_->active_workspace_;
|
||||
}
|
||||
|
||||
Workspace* FindBy(aura::Window* window) const {
|
||||
return manager_->FindBy(window);
|
||||
}
|
||||
|
||||
scoped_ptr<WorkspaceManager> manager_;
|
||||
|
||||
// Owned by viewport().
|
||||
WorkspaceLayoutManager* layout_manager_;
|
||||
|
||||
private:
|
||||
scoped_ptr<internal::ActivationController> activation_controller_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTestBase);
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTest);
|
||||
};
|
||||
|
||||
class WorkspaceManagerTest : public WorkspaceManagerTestBase {
|
||||
};
|
||||
|
||||
TEST_F(WorkspaceManagerTest, WorkspaceManagerCreateAddFind) {
|
||||
// Assertions around adding a normal window.
|
||||
TEST_F(WorkspaceManagerTest, AddNormalWindowWhenEmpty) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
|
||||
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()));
|
||||
ASSERT_TRUE(manager_->IsManagedWindow(w1.get()));
|
||||
EXPECT_FALSE(FindBy(w1.get()));
|
||||
|
||||
// w2 is in ws2 workspace.
|
||||
Workspace* ws2 = manager_->CreateWorkspace();
|
||||
ws2->AddWindowAfter(w2.get(), NULL);
|
||||
EXPECT_EQ(ws2, manager_->FindBy(w2.get()));
|
||||
|
||||
// Make sure |FindBy(w1.get())| still returns
|
||||
// correct workspace.
|
||||
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()));
|
||||
|
||||
// Reset now before windows are destroyed.
|
||||
manager_.reset();
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceManagerTest, LayoutWorkspaces) {
|
||||
manager_->SetWorkspaceSize(gfx::Size(100, 100));
|
||||
EXPECT_EQ("0,0 100x100", viewport()->bounds().ToString());
|
||||
|
||||
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();
|
||||
|
||||
EXPECT_EQ(250, viewport()->bounds().width());
|
||||
EXPECT_EQ("0,0 100x100", ws1->bounds().ToString());
|
||||
EXPECT_EQ("150,0 100x100", ws2->bounds().ToString());
|
||||
}
|
||||
|
||||
// Makes sure the bounds of window are resized if the workspace size shrinks.
|
||||
TEST_F(WorkspaceManagerTest, ResizeDuringLayout) {
|
||||
manager_->SetWorkspaceSize(gfx::Size(100, 100));
|
||||
EXPECT_EQ("0,0 100x100", viewport()->bounds().ToString());
|
||||
|
||||
Workspace* ws1 = manager_->CreateWorkspace();
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 100, 100));
|
||||
viewport()->AddChild(w1.get());
|
||||
EXPECT_TRUE(ws1->AddWindowAfter(w1.get(), NULL));
|
||||
manager_->SetWorkspaceSize(gfx::Size(50, 50));
|
||||
|
||||
// ws1 is laied out in left most position.
|
||||
EXPECT_EQ("0,0 50x50", ws1->bounds().ToString());
|
||||
EXPECT_EQ("0,0 50x50", w1->layer()->GetTargetBounds().ToString());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceManagerTest, WorkspaceManagerDragArea) {
|
||||
aura::RootWindow::GetInstance()->screen()->set_work_area_insets(
|
||||
gfx::Insets(10, 10, 10, 10));
|
||||
viewport()->SetBounds(gfx::Rect(0, 0, 200, 200));
|
||||
EXPECT_EQ("10,10 180x180", manager_->GetDragAreaBounds().ToString());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceManagerTest, WorkspaceManagerActivate) {
|
||||
TestWorkspaceObserver observer(manager_.get());
|
||||
Workspace* ws1 = manager_->CreateWorkspace();
|
||||
Workspace* ws2 = manager_->CreateWorkspace();
|
||||
EXPECT_EQ(NULL, manager_->GetActiveWorkspace());
|
||||
|
||||
// Activate ws1.
|
||||
ws1->Activate();
|
||||
EXPECT_EQ(ws1, manager_->GetActiveWorkspace());
|
||||
EXPECT_EQ(NULL, observer.old_active_workspace());
|
||||
EXPECT_EQ(ws1, observer.active_workspace());
|
||||
observer.reset();
|
||||
|
||||
// Activate ws2.
|
||||
ws2->Activate();
|
||||
EXPECT_EQ(ws2, manager_->GetActiveWorkspace());
|
||||
EXPECT_EQ(ws1, observer.old_active_workspace());
|
||||
EXPECT_EQ(ws2, observer.active_workspace());
|
||||
observer.reset();
|
||||
|
||||
// Deleting active workspace sets active workspace to NULL.
|
||||
delete ws2;
|
||||
EXPECT_EQ(NULL, manager_->GetActiveWorkspace());
|
||||
EXPECT_EQ(ws2, observer.old_active_workspace());
|
||||
EXPECT_EQ(NULL, observer.active_workspace());
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceManagerTest, FindRotateWindow) {
|
||||
manager_->SetWorkspaceSize(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-<lmgn>-145-<w11>-245-<wmng>-255-<w12>-355-<rmgn>-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_->FindBy(w11.get())->Layout(NULL);
|
||||
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) {
|
||||
scoped_ptr<TestWorkspaceObserver> observer(
|
||||
new TestWorkspaceObserver(manager_.get()));
|
||||
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(w22.get(), observer->move_source());
|
||||
EXPECT_EQ(w11.get(), observer->move_target());
|
||||
|
||||
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()));
|
||||
EXPECT_EQ(w22.get(), observer->move_source());
|
||||
EXPECT_EQ(w21.get(), observer->move_target());
|
||||
|
||||
// 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()));
|
||||
EXPECT_EQ(w11.get(), observer->move_source());
|
||||
EXPECT_EQ(w21.get(), observer->move_target());
|
||||
|
||||
// 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()));
|
||||
EXPECT_EQ(w11.get(), observer->move_source());
|
||||
EXPECT_EQ(w22.get(), observer->move_target());
|
||||
|
||||
// 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()));
|
||||
EXPECT_EQ(w22.get(), observer->move_source());
|
||||
EXPECT_EQ(w21.get(), observer->move_target());
|
||||
|
||||
// Reset now before windows are destroyed.
|
||||
observer.reset();
|
||||
manager_.reset();
|
||||
}
|
||||
|
||||
class WorkspaceTest : public WorkspaceManagerTestBase {
|
||||
};
|
||||
|
||||
TEST_F(WorkspaceTest, WorkspaceBasic) {
|
||||
Workspace* ws = manager_->CreateWorkspace();
|
||||
// Sanity check
|
||||
EXPECT_TRUE(ws->is_empty());
|
||||
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
scoped_ptr<Window> w3(CreateTestWindow());
|
||||
// ws is empty and can accomodate new window.
|
||||
EXPECT_TRUE(ws->CanAdd(w1.get()));
|
||||
|
||||
// Add w1.
|
||||
EXPECT_TRUE(ws->AddWindowAfter(w1.get(), NULL));
|
||||
EXPECT_TRUE(ws->Contains(w1.get()));
|
||||
EXPECT_FALSE(ws->is_empty());
|
||||
|
||||
// The workspac still has room for next window.
|
||||
EXPECT_TRUE(ws->CanAdd(w2.get()));
|
||||
EXPECT_TRUE(ws->AddWindowAfter(w2.get(), NULL));
|
||||
EXPECT_TRUE(ws->Contains(w2.get()));
|
||||
|
||||
// The workspace no longer accepts new window.
|
||||
EXPECT_FALSE(ws->CanAdd(w3.get()));
|
||||
EXPECT_FALSE(ws->AddWindowAfter(w3.get(), NULL));
|
||||
EXPECT_FALSE(ws->Contains(w3.get()));
|
||||
|
||||
// Check if the window has correct layout index.
|
||||
EXPECT_EQ(0, ws->GetIndexOf(w1.get()));
|
||||
EXPECT_EQ(1, ws->GetIndexOf(w2.get()));
|
||||
EXPECT_EQ(-1, ws->GetIndexOf(w3.get()));
|
||||
|
||||
// w1 is gone, so no index for w2.
|
||||
ws->RemoveWindow(w1.get());
|
||||
EXPECT_EQ(-1, ws->GetIndexOf(w1.get()));
|
||||
EXPECT_EQ(0, ws->GetIndexOf(w2.get()));
|
||||
EXPECT_FALSE(ws->Contains(w1.get()));
|
||||
|
||||
// Add w1 back. w1 now has index = 1.
|
||||
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();
|
||||
}
|
||||
|
||||
TEST_F(WorkspaceTest, ContainsFullscreenWindow) {
|
||||
Workspace* ws = manager_->CreateWorkspace();
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
ws->AddWindowAfter(w1.get(), NULL);
|
||||
ws->AddWindowAfter(w2.get(), NULL);
|
||||
w1->Show();
|
||||
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
|
||||
EXPECT_EQ(250, w1->bounds().width());
|
||||
EXPECT_EQ(251, w1->bounds().height());
|
||||
|
||||
// Should be 1 workspace, TYPE_NORNMAL with w1.
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
}
|
||||
|
||||
// Assertions around maximizing/unmaximizing.
|
||||
TEST_F(WorkspaceManagerTest, SingleMaximizeWindow) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
|
||||
ASSERT_TRUE(manager_->IsManagedWindow(w1.get()));
|
||||
|
||||
w1->Show();
|
||||
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
|
||||
EXPECT_EQ(250, w1->bounds().width());
|
||||
EXPECT_EQ(251, w1->bounds().height());
|
||||
|
||||
// Maximize the window.
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
|
||||
// Should be 1 workspace, TYPE_MAXIMIZED with w1.
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(GetWorkAreaBounds().width(), w1->bounds().width());
|
||||
EXPECT_EQ(GetWorkAreaBounds().height(), w1->bounds().height());
|
||||
|
||||
// Restore the window.
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
|
||||
// Should be 1 workspace, TYPE_NORMAL with w1.
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(250, w1->bounds().width());
|
||||
EXPECT_EQ(251, w1->bounds().height());
|
||||
}
|
||||
|
||||
// Assertions around closing the last window in a workspace.
|
||||
TEST_F(WorkspaceManagerTest, CloseLastWindowInWorkspace) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
w1->Show();
|
||||
w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
w2->Show();
|
||||
|
||||
EXPECT_FALSE(ws->ContainsFullscreenWindow());
|
||||
// Should be 2 workspaces, TYPE_NORMAL with w1, and TYPE_MAXIMIZED with w2.
|
||||
ASSERT_EQ(2u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
|
||||
ASSERT_EQ(1u, workspaces()[1]->windows().size());
|
||||
EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
|
||||
EXPECT_FALSE(w1->layer()->visible());
|
||||
EXPECT_TRUE(w2->layer()->visible());
|
||||
// TYPE_MAXIMIZED workspace should be active.
|
||||
EXPECT_EQ(workspaces()[1], active_workspace());
|
||||
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
|
||||
EXPECT_TRUE(ws->ContainsFullscreenWindow());
|
||||
// Close w2.
|
||||
w2.reset();
|
||||
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
EXPECT_FALSE(ws->ContainsFullscreenWindow());
|
||||
// Should have one workspace, TYPE_NORMAL with w1.
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
EXPECT_EQ(workspaces()[0], active_workspace());
|
||||
}
|
||||
|
||||
w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
|
||||
EXPECT_TRUE(ws->ContainsFullscreenWindow());
|
||||
// Assertions around adding a maximized window when empty.
|
||||
TEST_F(WorkspaceManagerTest, AddMaximizedWindowWhenEmpty) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
w1->Show();
|
||||
|
||||
w2->Hide();
|
||||
EXPECT_FALSE(ws->ContainsFullscreenWindow());
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
gfx::Rect work_area(
|
||||
gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()));
|
||||
EXPECT_EQ(work_area.width(), w1->bounds().width());
|
||||
EXPECT_EQ(work_area.height(), w1->bounds().height());
|
||||
|
||||
// Should be 1 workspace, TYPE_NORNMAL with w1.
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
}
|
||||
|
||||
// Assertions around two windows and toggling one to be maximized.
|
||||
TEST_F(WorkspaceManagerTest, MaximizeWithNormalWindow) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
w1->Show();
|
||||
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
|
||||
w2->SetBounds(gfx::Rect(0, 0, 50, 51));
|
||||
w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
w2->Show();
|
||||
|
||||
// Should now be two workspaces.
|
||||
ASSERT_EQ(2u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
|
||||
ASSERT_EQ(1u, workspaces()[1]->windows().size());
|
||||
EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_FALSE(w1->layer()->visible());
|
||||
ASSERT_TRUE(w2->layer() != NULL);
|
||||
EXPECT_TRUE(w2->layer()->visible());
|
||||
|
||||
gfx::Rect work_area(
|
||||
gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()));
|
||||
EXPECT_EQ(work_area.width(), w2->bounds().width());
|
||||
EXPECT_EQ(work_area.height(), w2->bounds().height());
|
||||
|
||||
// Restore w2, which should then go back to one workspace.
|
||||
w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
||||
ASSERT_EQ(1u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
|
||||
ASSERT_EQ(2u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(w2.get(), workspaces()[0]->windows()[1]);
|
||||
EXPECT_EQ(50, w2->bounds().width());
|
||||
EXPECT_EQ(51, w2->bounds().height());
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_TRUE(w1->layer()->visible());
|
||||
ASSERT_TRUE(w2->layer() != NULL);
|
||||
EXPECT_TRUE(w2->layer()->visible());
|
||||
}
|
||||
|
||||
// Assertions around two maximized windows.
|
||||
TEST_F(WorkspaceManagerTest, TwoMaximized) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
w1->SetBounds(gfx::Rect(0, 0, 250, 251));
|
||||
w1->Show();
|
||||
w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
|
||||
w2->SetBounds(gfx::Rect(0, 0, 50, 51));
|
||||
w2->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
|
||||
w2->Show();
|
||||
|
||||
// Should now be two workspaces.
|
||||
ASSERT_EQ(2u, workspaces().size());
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
|
||||
ASSERT_EQ(1u, workspaces()[0]->windows().size());
|
||||
EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
|
||||
EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[1]->type());
|
||||
ASSERT_EQ(1u, workspaces()[1]->windows().size());
|
||||
EXPECT_EQ(w2.get(), workspaces()[1]->windows()[0]);
|
||||
ASSERT_TRUE(w1->layer() != NULL);
|
||||
EXPECT_FALSE(w1->layer()->visible());
|
||||
ASSERT_TRUE(w2->layer() != NULL);
|
||||
EXPECT_TRUE(w2->layer()->visible());
|
||||
}
|
||||
|
||||
// Makes sure requests to change the bounds of a normal window go through.
|
||||
TEST_F(WorkspaceManagerTest, ChangeBoundsOfNormalWindow) {
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
w1->Show();
|
||||
|
||||
EXPECT_TRUE(manager_->IsManagedWindow(w1.get()));
|
||||
// Setting the bounds should go through since the window is in the normal
|
||||
// workspace.
|
||||
w1->SetBounds(gfx::Rect(0, 0, 200, 500));
|
||||
EXPECT_EQ(200, w1->bounds().width());
|
||||
EXPECT_EQ(500, w1->bounds().height());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2011 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_WORKSPACE_OBSERVER_H_
|
||||
#define ASH_WM_WORKSPACE_WORKSPACE_OBSERVER_H_
|
||||
#pragma once
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
|
||||
namespace aura {
|
||||
class Window;
|
||||
}
|
||||
|
||||
namespace ash {
|
||||
namespace internal {
|
||||
class Workspace;
|
||||
class WorkspaceManager;
|
||||
|
||||
// A class to observe changes in workspace state.
|
||||
class ASH_EXPORT WorkspaceObserver {
|
||||
public:
|
||||
// Invoked when |start| window is moved and inserted
|
||||
// at the |target| window's position by |WorkspaceManager::RotateWindow|.
|
||||
virtual void WindowMoved(WorkspaceManager* manager,
|
||||
aura::Window* source,
|
||||
aura::Window* target) = 0;
|
||||
|
||||
// Invoked when the active workspace changes. |old| is
|
||||
// the old active workspace and can be NULL.
|
||||
virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
|
||||
Workspace* old) = 0;
|
||||
protected:
|
||||
virtual ~WorkspaceObserver() {}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_WM_WORKSPACE_WORKSPACE_OBSERVER_H_
|
@ -8,7 +8,6 @@
|
||||
#include "ash/launcher/launcher_model.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/wm/window_util.h"
|
||||
#include "ash/wm/workspace/workspace.h"
|
||||
#include "ash/wm/workspace/workspace_layout_manager.h"
|
||||
#include "ash/wm/workspace/workspace_manager.h"
|
||||
#include "ui/aura/client/activation_client.h"
|
||||
@ -23,13 +22,11 @@ WorkspaceController::WorkspaceController(aura::Window* viewport)
|
||||
: workspace_manager_(new WorkspaceManager(viewport)),
|
||||
launcher_model_(NULL),
|
||||
ignore_move_event_(false) {
|
||||
workspace_manager_->AddObserver(this);
|
||||
aura::RootWindow::GetInstance()->AddRootWindowObserver(this);
|
||||
aura::RootWindow::GetInstance()->AddObserver(this);
|
||||
}
|
||||
|
||||
WorkspaceController::~WorkspaceController() {
|
||||
workspace_manager_->RemoveObserver(this);
|
||||
if (launcher_model_)
|
||||
launcher_model_->RemoveObserver(this);
|
||||
aura::RootWindow::GetInstance()->RemoveObserver(this);
|
||||
@ -59,32 +56,8 @@ void WorkspaceController::OnRootWindowResized(const gfx::Size& new_size) {
|
||||
void WorkspaceController::OnWindowPropertyChanged(aura::Window* window,
|
||||
const char* key,
|
||||
void* old) {
|
||||
if (key == aura::client::kRootWindowActiveWindow) {
|
||||
// FindBy handles NULL.
|
||||
Workspace* workspace = workspace_manager_->FindBy(GetActiveWindow());
|
||||
if (workspace)
|
||||
workspace->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WorkspaceController, ash::internal::WorkspaceObserver overrides:
|
||||
|
||||
void WorkspaceController::WindowMoved(WorkspaceManager* manager,
|
||||
aura::Window* source,
|
||||
aura::Window* target) {
|
||||
if (ignore_move_event_ || !launcher_model_)
|
||||
return;
|
||||
// TODO: there is no longer a 1-1 mapping between the launcher and windows;
|
||||
// decide how we want to handle it.
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void WorkspaceController::ActiveWorkspaceChanged(WorkspaceManager* manager,
|
||||
Workspace* old) {
|
||||
// TODO(oshima): Update Launcher and Status area state when the active
|
||||
// workspace's fullscreen state changes.
|
||||
//NOTIMPLEMENTED();
|
||||
if (key == aura::client::kRootWindowActiveWindow)
|
||||
workspace_manager_->SetActiveWorkspaceByWindow(GetActiveWindow());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -7,7 +7,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ash/launcher/launcher_model_observer.h"
|
||||
#include "ash/wm/workspace/workspace_observer.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/aura/root_window_observer.h"
|
||||
@ -35,7 +34,6 @@ class WorkspaceManager;
|
||||
class ASH_EXPORT WorkspaceController :
|
||||
public aura::RootWindowObserver,
|
||||
public aura::WindowObserver,
|
||||
public ash::internal::WorkspaceObserver,
|
||||
public ash::LauncherModelObserver {
|
||||
public:
|
||||
explicit WorkspaceController(aura::Window* workspace_viewport);
|
||||
@ -58,13 +56,6 @@ class ASH_EXPORT WorkspaceController :
|
||||
const char* key,
|
||||
void* old) OVERRIDE;
|
||||
|
||||
// WorkspaceObserver overrides:
|
||||
virtual void WindowMoved(WorkspaceManager* manager,
|
||||
aura::Window* source,
|
||||
aura::Window* target) OVERRIDE;
|
||||
virtual void ActiveWorkspaceChanged(WorkspaceManager* manager,
|
||||
Workspace* old) OVERRIDE;
|
||||
|
||||
// Invoked after an item has been added to the model.
|
||||
virtual void LauncherItemAdded(int index) OVERRIDE;
|
||||
virtual void LauncherItemRemoved(int index) OVERRIDE;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -67,53 +67,5 @@ class WorkspaceControllerTest : public aura::test::AuraTestBase {
|
||||
DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest);
|
||||
};
|
||||
|
||||
TEST_F(WorkspaceControllerTest, Overview) {
|
||||
workspace_manager()->SetWorkspaceSize(gfx::Size(500, 300));
|
||||
|
||||
// Creating two workspaces, ws1 which contains window w1,
|
||||
// and ws2 which contains window w2.
|
||||
Workspace* ws1 = workspace_manager()->CreateWorkspace();
|
||||
scoped_ptr<Window> w1(CreateTestWindow());
|
||||
EXPECT_TRUE(ws1->AddWindowAfter(w1.get(), NULL));
|
||||
|
||||
Workspace* ws2 = workspace_manager()->CreateWorkspace();
|
||||
scoped_ptr<Window> w2(CreateTestWindow());
|
||||
EXPECT_TRUE(ws2->AddWindowAfter(w2.get(), NULL));
|
||||
|
||||
// Activating a window switches the active workspace.
|
||||
ash::ActivateWindow(w2.get());
|
||||
EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
|
||||
|
||||
// The size of contents_view() is now ws1(500) + ws2(500) + margin(50).
|
||||
EXPECT_EQ("0,0 1050x300", contents_view()->bounds().ToString());
|
||||
EXPECT_FALSE(workspace_manager()->is_overview());
|
||||
workspace_manager()->SetOverview(true);
|
||||
EXPECT_TRUE(workspace_manager()->is_overview());
|
||||
|
||||
// Switching overview mode doesn't change the active workspace.
|
||||
EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
|
||||
|
||||
// Activating window w1 switches the active window and
|
||||
// the mode back to normal mode.
|
||||
ash::ActivateWindow(w1.get());
|
||||
EXPECT_EQ(ws1, workspace_manager()->GetActiveWorkspace());
|
||||
EXPECT_FALSE(workspace_manager()->is_overview());
|
||||
|
||||
// Deleting w1 without StackingClient resets the active workspace
|
||||
ws1->RemoveWindow(w1.get());
|
||||
delete ws1;
|
||||
w1.reset();
|
||||
EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace());
|
||||
EXPECT_EQ("0,0 500x300", contents_view()->bounds().ToString());
|
||||
ws2->RemoveWindow(w2.get());
|
||||
delete ws2;
|
||||
// The size of contents_view() for no workspace case must be
|
||||
// same as one contents_view() case.
|
||||
EXPECT_EQ("0,0 500x300", contents_view()->bounds().ToString());
|
||||
|
||||
// Reset now before windows are destroyed.
|
||||
controller_.reset();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ash
|
||||
|
@ -112,6 +112,7 @@ void LauncherIconUpdater::ActivateByID(ash::LauncherID id) {
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
updater->window_->Show();
|
||||
ash::ActivateWindow(updater->window_);
|
||||
if (tab) {
|
||||
updater->tab_model_->ActivateTabAt(
|
||||
|
Reference in New Issue
Block a user