Chromium Code Reviews| 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..918882cf5b0fdd3a324c1eced9c7b5eea53c49d7 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,15 @@ 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|. |
|
oshima
2012/01/26 16:37:25
I guess we set visibility on layer so that we trea
|
| +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); |
| + } |
|
oshima
2012/01/26 16:37:25
Don't we have to change the visibility of transien
|
| +} |
| + |
| } |
| namespace ash { |
| @@ -43,161 +55,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)) { |
|
oshima
2012/01/26 16:37:25
window->HasProperty
|
| + // 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 = CreateWorkspace(); |
| + 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; |
| + |
| + 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; |
| -void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) { |
| - observers_.RemoveObserver(observer); |
| + 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 +212,30 @@ 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::CreateWorkspace() { |
| + Workspace* workspace = new Workspace(this); |
| + return workspace; |
|
oshima
2012/01/26 16:37:25
return new Workspace(this);
sky
2012/01/26 16:51:23
Probably not worth a method now. I removed it enti
|
| +} |
| + |
| +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. |
|
oshima
2012/01/26 16:37:25
It's possible, but it shouldn't happen, should it?
sky
2012/01/26 16:51:23
It's possible with the current WorkspaceLayoutMana
|
| + 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 = CreateWorkspace(); |
| + 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(FindBy(window)); |
|
oshima
2012/01/26 16:37:25
Can this be
SetActiveWorksace(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 |