| Index: ash/wm/workspace/workspace_manager.cc
|
| diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc
|
| index a9884b3bf677c118f7639ea47af8e94e1506b52f..9fc41e9d0a2629aa154d5d748f6f39ac09728b2b 100644
|
| --- a/ash/wm/workspace/workspace_manager.cc
|
| +++ b/ash/wm/workspace/workspace_manager.cc
|
| @@ -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,161 +60,156 @@ 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();
|
| }
|
|
|
| -Workspace* WorkspaceManager::GetActiveWorkspace() const {
|
| - return active_workspace_;
|
| -}
|
| +void WorkspaceManager::AddWindow(aura::Window* window) {
|
| + DCHECK(IsManagedWindow(window));
|
|
|
| -Workspace* WorkspaceManager::FindBy(aura::Window* window) const {
|
| - int index = GetWorkspaceIndexContaining(window);
|
| - return index < 0 ? NULL : workspaces_[index];
|
| -}
|
| + if (FindBy(window))
|
| + return; // Already know about this window.
|
|
|
| -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;
|
| + window->AddObserver(this);
|
| +
|
| + if (!window->GetProperty(aura::client::kShowStateKey)) {
|
| + // TODO: set maximized if width < x.
|
| + window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
|
| }
|
| - return NULL;
|
| -}
|
|
|
| -void WorkspaceManager::LayoutWorkspaces() {
|
| - UpdateContentsView();
|
| + // TODO: handle fullscreen.
|
| + if (window_util::IsWindowMaximized(window)) {
|
| + if (!GetRestoreBounds(window))
|
| + SetRestoreBounds(window, window->GetTargetBounds());
|
| + else
|
| + SetWindowBounds(window, GetWorkAreaBounds());
|
| + }
|
|
|
| - 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;
|
| + 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;
|
| }
|
| -}
|
|
|
| -gfx::Rect WorkspaceManager::GetDragAreaBounds() {
|
| - return GetWorkAreaBounds(gfx::Rect(contents_view_->bounds().size()));
|
| + if (!workspace) {
|
| + workspace = new Workspace(this);
|
| + workspace->SetType(type_for_window);
|
| + }
|
| + workspace->AddWindowAfter(window, NULL);
|
| + workspace->Activate();
|
| }
|
|
|
| -void WorkspaceManager::SetOverview(bool overview) {
|
| - if (is_overview_ == overview)
|
| +void WorkspaceManager::RemoveWindow(aura::Window* window) {
|
| + Workspace* workspace = FindBy(window);
|
| + if (!workspace)
|
| 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));
|
| - }
|
| + window->RemoveObserver(this);
|
| + workspace->RemoveWindow(window);
|
| + if (workspace->is_empty())
|
| + delete workspace;
|
| +}
|
|
|
| - transform.SetTranslateX(dx);
|
| - transform.SetTranslateY(workspace_size_.height() * (1.0f - scale) / 2);
|
| - } else if (active_workspace_) {
|
| - transform.SetTranslateX(-active_workspace_->bounds().x());
|
| - }
|
| +void WorkspaceManager::SetActiveWorkspaceByWindow(aura::Window* window) {
|
| + Workspace* workspace = FindBy(window);
|
| + if (workspace)
|
| + workspace->Activate();
|
| +}
|
|
|
| - ui::ScopedLayerAnimationSettings settings(
|
| - contents_view_->layer()->GetAnimator());
|
| - contents_view_->layer()->SetTransform(transform);
|
| +gfx::Rect WorkspaceManager::GetDragAreaBounds() {
|
| + return GetWorkAreaBounds();
|
| }
|
|
|
| -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::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;
|
| - LayoutWorkspaces();
|
| + for (Workspaces::const_iterator i = workspaces_.begin();
|
| + i != workspaces_.end(); ++i) {
|
| + (*i)->WorkspaceSizeChanged();
|
| + }
|
| }
|
|
|
| -void WorkspaceManager::AddObserver(WorkspaceObserver* observer) {
|
| - observers_.AddObserver(observer);
|
| -}
|
| +void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
|
| + const char* name,
|
| + void* old) {
|
| + if (!IsManagedWindow(window))
|
| + return;
|
|
|
| -void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) {
|
| - observers_.RemoveObserver(observer);
|
| + 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) {
|
| - Workspaces::iterator i = std::find(workspaces_.begin(),
|
| - workspaces_.end(),
|
| - workspace);
|
| - DCHECK(i == workspaces_.end());
|
| - workspaces_.push_back(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) {
|
| @@ -205,19 +217,25 @@ void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
|
| workspaces_.end(),
|
| workspace);
|
| DCHECK(i != workspaces_.end());
|
| - Workspace* old = NULL;
|
| -
|
| - if (workspace == active_workspace_) {
|
| - old = active_workspace_;
|
| - active_workspace_ = NULL;
|
| + 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;
|
| }
|
| - workspaces_.erase(i);
|
| - LayoutWorkspaces();
|
| +}
|
|
|
| - if (old) {
|
| - FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
|
| - ActiveWorkspaceChanged(this, old));
|
| - }
|
| +Workspace* WorkspaceManager::GetActiveWorkspace() const {
|
| + return active_workspace_;
|
| +}
|
| +
|
| +Workspace* WorkspaceManager::FindBy(aura::Window* window) const {
|
| + int index = GetWorkspaceIndexContaining(window);
|
| + return index < 0 ? NULL : workspaces_[index];
|
| }
|
|
|
| void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) {
|
| @@ -225,19 +243,17 @@ void WorkspaceManager::SetActiveWorkspace(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);
|
| +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);
|
| +}
|
|
|
| - // 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::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
|
|
|