| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ash/wm/workspace/workspace_manager.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "ash/screen_ash.h" | |
| 10 #include "ash/shell.h" | |
| 11 #include "ash/wm/property_util.h" | |
| 12 #include "ash/wm/shelf_layout_manager.h" | |
| 13 #include "ash/wm/window_animations.h" | |
| 14 #include "ash/wm/window_util.h" | |
| 15 #include "ash/wm/workspace/managed_workspace.h" | |
| 16 #include "ash/wm/workspace/maximized_workspace.h" | |
| 17 #include "base/auto_reset.h" | |
| 18 #include "base/logging.h" | |
| 19 #include "base/stl_util.h" | |
| 20 #include "ui/aura/client/aura_constants.h" | |
| 21 #include "ui/aura/env.h" | |
| 22 #include "ui/aura/root_window.h" | |
| 23 #include "ui/aura/window.h" | |
| 24 #include "ui/base/ui_base_types.h" | |
| 25 #include "ui/compositor/layer.h" | |
| 26 #include "ui/compositor/layer_animator.h" | |
| 27 #include "ui/compositor/scoped_layer_animation_settings.h" | |
| 28 #include "ui/gfx/screen.h" | |
| 29 #include "ui/gfx/transform.h" | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 // Returns a list of all the windows with layers in |result|. Optionally | |
| 34 // ignores the window |ignore_window|. | |
| 35 void BuildWindowList(const std::vector<aura::Window*>& windows, | |
| 36 aura::Window* ignore_window, | |
| 37 std::vector<aura::Window*>* result) { | |
| 38 for (size_t i = 0; i < windows.size(); ++i) { | |
| 39 if (windows[i] == ignore_window) | |
| 40 continue; | |
| 41 if (windows[i]->layer()) | |
| 42 result->push_back(windows[i]); | |
| 43 BuildWindowList(windows[i]->transient_children(), ignore_window, result); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 } | |
| 48 | |
| 49 namespace ash { | |
| 50 namespace internal { | |
| 51 | |
| 52 //////////////////////////////////////////////////////////////////////////////// | |
| 53 // WindowManager, public: | |
| 54 | |
| 55 WorkspaceManager::WorkspaceManager(aura::Window* contents_view) | |
| 56 : contents_view_(contents_view), | |
| 57 active_workspace_(NULL), | |
| 58 maximize_restore_window_(NULL), | |
| 59 grid_size_(0), | |
| 60 shelf_(NULL) { | |
| 61 DCHECK(contents_view); | |
| 62 } | |
| 63 | |
| 64 WorkspaceManager::~WorkspaceManager() { | |
| 65 std::vector<Workspace*> copy_to_delete(workspaces_); | |
| 66 STLDeleteElements(©_to_delete); | |
| 67 } | |
| 68 | |
| 69 // static | |
| 70 bool WorkspaceManager::ShouldManageWindow(aura::Window* window) { | |
| 71 return window->type() == aura::client::WINDOW_TYPE_NORMAL && | |
| 72 !window->transient_parent() && | |
| 73 ash::GetTrackedByWorkspace(window) && | |
| 74 (!ash::GetPersistsAcrossAllWorkspaces(window) || | |
| 75 wm::IsWindowMaximized(window)); | |
| 76 } | |
| 77 | |
| 78 bool WorkspaceManager::Contains(aura::Window* window) const { | |
| 79 return FindBy(window) != NULL; | |
| 80 } | |
| 81 | |
| 82 void WorkspaceManager::AddWindow(aura::Window* window) { | |
| 83 DCHECK(ShouldManageWindow(window)); | |
| 84 | |
| 85 Workspace* current_workspace = FindBy(window); | |
| 86 if (current_workspace) { | |
| 87 // Already know about this window. Make sure the workspace is active. | |
| 88 if (active_workspace_ != current_workspace) { | |
| 89 if (active_workspace_) | |
| 90 window->layer()->GetAnimator()->StopAnimating(); | |
| 91 current_workspace->Activate(); | |
| 92 } | |
| 93 window->Show(); | |
| 94 UpdateShelfVisibility(); | |
| 95 return; | |
| 96 } | |
| 97 | |
| 98 Workspace* workspace = NULL; | |
| 99 Workspace::Type type_for_window = Workspace::TypeForWindow(window); | |
| 100 switch (type_for_window) { | |
| 101 case Workspace::TYPE_MANAGED: | |
| 102 // All normal windows go in the same workspace. | |
| 103 workspace = GetManagedWorkspace(); | |
| 104 break; | |
| 105 | |
| 106 case Workspace::TYPE_MAXIMIZED: | |
| 107 // All maximized windows go in their own workspace. | |
| 108 break; | |
| 109 } | |
| 110 | |
| 111 if (!workspace) | |
| 112 workspace = CreateWorkspace(type_for_window); | |
| 113 workspace->AddWindowAfter(window, NULL); | |
| 114 workspace->Activate(); | |
| 115 UpdateShelfVisibility(); | |
| 116 } | |
| 117 | |
| 118 void WorkspaceManager::RemoveWindow(aura::Window* window) { | |
| 119 Workspace* workspace = FindBy(window); | |
| 120 if (!workspace) | |
| 121 return; | |
| 122 workspace->RemoveWindow(window); | |
| 123 CleanupWorkspace(workspace); | |
| 124 } | |
| 125 | |
| 126 void WorkspaceManager::UpdateShelfVisibility() { | |
| 127 if (shelf_) | |
| 128 shelf_->UpdateVisibilityState(); | |
| 129 } | |
| 130 | |
| 131 void WorkspaceManager::ShowStateChanged(aura::Window* window) { | |
| 132 Workspace* workspace = FindBy(window); | |
| 133 if (!workspace) | |
| 134 return; | |
| 135 if (!ShouldManageWindow(window)) { | |
| 136 RemoveWindow(window); | |
| 137 } else { | |
| 138 Workspace::Type old_type = workspace->type(); | |
| 139 Workspace::Type new_type = Workspace::TypeForWindow(window); | |
| 140 if (new_type != old_type) | |
| 141 OnTypeOfWorkspacedNeededChanged(window); | |
| 142 } | |
| 143 UpdateShelfVisibility(); | |
| 144 } | |
| 145 | |
| 146 bool WorkspaceManager::IsInMaximizedMode() const { | |
| 147 return active_workspace_ && | |
| 148 active_workspace_->type() == Workspace::TYPE_MAXIMIZED; | |
| 149 } | |
| 150 | |
| 151 WorkspaceWindowState WorkspaceManager::GetWindowState() const { | |
| 152 if (!shelf_ || !active_workspace_) | |
| 153 return WORKSPACE_WINDOW_STATE_DEFAULT; | |
| 154 | |
| 155 // TODO: this code needs to be made multi-display aware. | |
| 156 gfx::Rect shelf_bounds(shelf_->GetIdealBounds()); | |
| 157 const aura::Window::Windows& windows(contents_view_->children()); | |
| 158 bool window_overlaps_launcher = false; | |
| 159 bool has_maximized_window = false; | |
| 160 for (aura::Window::Windows::const_iterator i = windows.begin(); | |
| 161 i != windows.end(); ++i) { | |
| 162 gfx::Rect b = (*i)->bounds(); | |
| 163 if (GetIgnoredByShelf(*i)) | |
| 164 continue; | |
| 165 ui::Layer* layer = (*i)->layer(); | |
| 166 if (!layer->GetTargetVisibility() || layer->GetTargetOpacity() == 0.0f) | |
| 167 continue; | |
| 168 if (wm::IsWindowMaximized(*i)) { | |
| 169 // An untracked window may still be fullscreen so we keep iterating when | |
| 170 // we hit a maximized window. | |
| 171 has_maximized_window = true; | |
| 172 } else if (wm::IsWindowFullscreen(*i)) { | |
| 173 return WORKSPACE_WINDOW_STATE_FULL_SCREEN; | |
| 174 } | |
| 175 if (!window_overlaps_launcher && (*i)->bounds().Intersects(shelf_bounds)) | |
| 176 window_overlaps_launcher = true; | |
| 177 } | |
| 178 if (has_maximized_window) | |
| 179 return WORKSPACE_WINDOW_STATE_MAXIMIZED; | |
| 180 | |
| 181 return window_overlaps_launcher ? | |
| 182 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF : | |
| 183 WORKSPACE_WINDOW_STATE_DEFAULT; | |
| 184 } | |
| 185 | |
| 186 void WorkspaceManager::SetShelf(ShelfLayoutManager* shelf) { | |
| 187 shelf_ = shelf; | |
| 188 } | |
| 189 | |
| 190 void WorkspaceManager::SetActiveWorkspaceByWindow(aura::Window* window) { | |
| 191 Workspace* workspace = FindBy(window); | |
| 192 if (workspace) | |
| 193 workspace->Activate(); | |
| 194 } | |
| 195 | |
| 196 aura::Window* WorkspaceManager::GetParentForNewWindow(aura::Window* window) { | |
| 197 return contents_view_; | |
| 198 } | |
| 199 | |
| 200 //////////////////////////////////////////////////////////////////////////////// | |
| 201 // WorkspaceManager, private: | |
| 202 | |
| 203 void WorkspaceManager::AddWorkspace(Workspace* workspace) { | |
| 204 DCHECK(std::find(workspaces_.begin(), workspaces_.end(), | |
| 205 workspace) == workspaces_.end()); | |
| 206 if (active_workspace_) { | |
| 207 // New workspaces go right after current workspace. | |
| 208 Workspaces::iterator i = std::find(workspaces_.begin(), workspaces_.end(), | |
| 209 active_workspace_); | |
| 210 workspaces_.insert(++i, workspace); | |
| 211 } else { | |
| 212 workspaces_.push_back(workspace); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 void WorkspaceManager::RemoveWorkspace(Workspace* workspace) { | |
| 217 Workspaces::iterator i = std::find(workspaces_.begin(), | |
| 218 workspaces_.end(), | |
| 219 workspace); | |
| 220 DCHECK(i != workspaces_.end()); | |
| 221 i = workspaces_.erase(i); | |
| 222 if (active_workspace_ == workspace) { | |
| 223 // TODO: need mru order. | |
| 224 if (i != workspaces_.end()) | |
| 225 SetActiveWorkspace(*i); | |
| 226 else if (!workspaces_.empty()) | |
| 227 SetActiveWorkspace(workspaces_.back()); | |
| 228 else | |
| 229 active_workspace_ = NULL; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 void WorkspaceManager::SetVisibilityOfWorkspaceWindows( | |
| 234 ash::internal::Workspace* workspace, | |
| 235 AnimateChangeType change_type, | |
| 236 bool value) { | |
| 237 std::vector<aura::Window*> children; | |
| 238 BuildWindowList(workspace->windows(), maximize_restore_window_, &children); | |
| 239 SetWindowLayerVisibility(children, change_type, value); | |
| 240 } | |
| 241 | |
| 242 void WorkspaceManager::SetWindowLayerVisibility( | |
| 243 const std::vector<aura::Window*>& windows, | |
| 244 AnimateChangeType change_type, | |
| 245 bool value) { | |
| 246 for (size_t i = 0; i < windows.size(); ++i) { | |
| 247 ui::Layer* layer = windows[i]->layer(); | |
| 248 // Only show the layer for windows that want to be visible. | |
| 249 if (layer && (!value || windows[i]->TargetVisibility())) { | |
| 250 bool animation_disabled = | |
| 251 windows[i]->GetProperty(aura::client::kAnimationsDisabledKey); | |
| 252 WindowVisibilityAnimationType animation_type = | |
| 253 GetWindowVisibilityAnimationType(windows[i]); | |
| 254 windows[i]->SetProperty(aura::client::kAnimationsDisabledKey, | |
| 255 change_type == DONT_ANIMATE); | |
| 256 bool update_layer = true; | |
| 257 if (change_type == ANIMATE) { | |
| 258 ash::SetWindowVisibilityAnimationType( | |
| 259 windows[i], | |
| 260 value ? ash::WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_SHOW : | |
| 261 ash::WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_HIDE); | |
| 262 if (ash::internal::AnimateOnChildWindowVisibilityChanged( | |
| 263 windows[i], value)) | |
| 264 update_layer = false; | |
| 265 } | |
| 266 if (update_layer) | |
| 267 layer->SetVisible(value); | |
| 268 // Reset the animation type so it isn't used in a future hide/show. | |
| 269 ash::SetWindowVisibilityAnimationType( | |
| 270 windows[i], animation_type); | |
| 271 windows[i]->SetProperty(aura::client::kAnimationsDisabledKey, | |
| 272 animation_disabled); | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 Workspace* WorkspaceManager::GetActiveWorkspace() const { | |
| 278 return active_workspace_; | |
| 279 } | |
| 280 | |
| 281 Workspace* WorkspaceManager::FindBy(aura::Window* window) const { | |
| 282 int index = GetWorkspaceIndexContaining(window); | |
| 283 return index < 0 ? NULL : workspaces_[index]; | |
| 284 } | |
| 285 | |
| 286 void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) { | |
| 287 if (active_workspace_ == workspace) | |
| 288 return; | |
| 289 DCHECK(std::find(workspaces_.begin(), workspaces_.end(), | |
| 290 workspace) != workspaces_.end()); | |
| 291 if (active_workspace_) | |
| 292 SetVisibilityOfWorkspaceWindows(active_workspace_, ANIMATE, false); | |
| 293 Workspace* last_active = active_workspace_; | |
| 294 active_workspace_ = workspace; | |
| 295 if (active_workspace_) { | |
| 296 SetVisibilityOfWorkspaceWindows(active_workspace_, | |
| 297 last_active ? ANIMATE : DONT_ANIMATE, true); | |
| 298 UpdateShelfVisibility(); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 // Returns the index of the workspace that contains the |window|. | |
| 303 int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const { | |
| 304 for (Workspaces::const_iterator i = workspaces_.begin(); | |
| 305 i != workspaces_.end(); | |
| 306 ++i) { | |
| 307 if ((*i)->Contains(window)) | |
| 308 return i - workspaces_.begin(); | |
| 309 } | |
| 310 return -1; | |
| 311 } | |
| 312 | |
| 313 void WorkspaceManager::SetWindowBounds(aura::Window* window, | |
| 314 const gfx::Rect& bounds) { | |
| 315 window->SetBounds(bounds); | |
| 316 } | |
| 317 | |
| 318 void WorkspaceManager::OnTypeOfWorkspacedNeededChanged(aura::Window* window) { | |
| 319 DCHECK(ShouldManageWindow(window)); | |
| 320 Workspace* current_workspace = FindBy(window); | |
| 321 DCHECK(current_workspace); | |
| 322 Workspace* new_workspace = NULL; | |
| 323 if (Workspace::TypeForWindow(window) == Workspace::TYPE_MAXIMIZED) { | |
| 324 // Unmaximized -> maximized; create a new workspace. | |
| 325 current_workspace->RemoveWindow(window); | |
| 326 new_workspace = CreateWorkspace(Workspace::TYPE_MAXIMIZED); | |
| 327 new_workspace->AddWindowAfter(window, NULL); | |
| 328 } else { | |
| 329 // Maximized -> unmaximized; move window to unmaximized workspace. | |
| 330 new_workspace = GetManagedWorkspace(); | |
| 331 current_workspace->RemoveWindow(window); | |
| 332 if (!new_workspace) | |
| 333 new_workspace = CreateWorkspace(Workspace::TYPE_MANAGED); | |
| 334 new_workspace->AddWindowAfter(window, NULL); | |
| 335 } | |
| 336 maximize_restore_window_ = window; | |
| 337 SetActiveWorkspace(new_workspace); | |
| 338 maximize_restore_window_ = NULL; | |
| 339 // Delete at the end so that we don't attempt to switch to another | |
| 340 // workspace in RemoveWorkspace(). | |
| 341 CleanupWorkspace(current_workspace); | |
| 342 } | |
| 343 | |
| 344 Workspace* WorkspaceManager::GetManagedWorkspace() { | |
| 345 for (size_t i = 0; i < workspaces_.size(); ++i) { | |
| 346 if (workspaces_[i]->type() == Workspace::TYPE_MANAGED) | |
| 347 return workspaces_[i]; | |
| 348 } | |
| 349 return NULL; | |
| 350 } | |
| 351 | |
| 352 Workspace* WorkspaceManager::CreateWorkspace(Workspace::Type type) { | |
| 353 Workspace* workspace = NULL; | |
| 354 if (type == Workspace::TYPE_MAXIMIZED) | |
| 355 workspace = new MaximizedWorkspace(this); | |
| 356 else | |
| 357 workspace = new ManagedWorkspace(this); | |
| 358 AddWorkspace(workspace); | |
| 359 return workspace; | |
| 360 } | |
| 361 | |
| 362 void WorkspaceManager::CleanupWorkspace(Workspace* workspace) { | |
| 363 if (workspace->type() != Workspace::TYPE_MANAGED && workspace->is_empty()) | |
| 364 delete workspace; | |
| 365 } | |
| 366 | |
| 367 } // namespace internal | |
| 368 } // namespace ash | |
| OLD | NEW |