Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2599)

Unified Diff: ash/wm/workspace/workspace_manager.cc

Issue 9113045: Reworks the workspace code. Here's the new heuristics: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporated feedback and fixed bugs Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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(&copy_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

Powered by Google App Engine
This is Rietveld 408576698