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 |