OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "ui/aura_shell/activation_controller.h" |
| 6 |
| 7 #include "base/auto_reset.h" |
| 8 #include "ui/aura/client/activation_delegate.h" |
| 9 #include "ui/aura/client/aura_constants.h" |
| 10 #include "ui/aura/root_window.h" |
| 11 #include "ui/aura/window.h" |
| 12 #include "ui/aura/window_delegate.h" |
| 13 #include "ui/aura_shell/shell.h" |
| 14 #include "ui/aura_shell/shell_window_ids.h" |
| 15 #include "ui/aura_shell/window_util.h" |
| 16 |
| 17 namespace aura_shell { |
| 18 namespace internal { |
| 19 namespace { |
| 20 |
| 21 aura::Window* GetContainer(int id) { |
| 22 return Shell::GetInstance()->GetContainer(id); |
| 23 } |
| 24 |
| 25 // Returns true if children of |window| can be activated. |
| 26 bool SupportsChildActivation(aura::Window* window) { |
| 27 return window->id() == kShellWindowId_DefaultContainer || |
| 28 window->id() == kShellWindowId_AlwaysOnTopContainer || |
| 29 window->id() == kShellWindowId_ModalContainer || |
| 30 window->id() == kShellWindowId_LockModalContainer; |
| 31 } |
| 32 |
| 33 // Returns true if |window| can be activated or deactivated. |
| 34 // A window manager typically defines some notion of "top level window" that |
| 35 // supports activation/deactivation. |
| 36 bool CanActivateWindow(aura::Window* window) { |
| 37 return window && |
| 38 window->IsVisible() && |
| 39 (!aura::ActivationDelegate::GetActivationDelegate(window) || |
| 40 aura::ActivationDelegate::GetActivationDelegate(window)-> |
| 41 ShouldActivate(NULL)) && |
| 42 SupportsChildActivation(window->parent()); |
| 43 } |
| 44 |
| 45 } // namespace |
| 46 |
| 47 //////////////////////////////////////////////////////////////////////////////// |
| 48 // ActivationController, public: |
| 49 |
| 50 ActivationController::ActivationController() |
| 51 : updating_activation_(false), |
| 52 default_container_for_test_(NULL) { |
| 53 aura::ActivationClient::SetActivationClient(this); |
| 54 aura::RootWindow::GetInstance()->AddRootWindowObserver(this); |
| 55 } |
| 56 |
| 57 ActivationController::~ActivationController() { |
| 58 aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this); |
| 59 } |
| 60 |
| 61 // static |
| 62 aura::Window* ActivationController::GetActivatableWindow(aura::Window* window) { |
| 63 aura::Window* parent = window->parent(); |
| 64 aura::Window* child = window; |
| 65 while (parent) { |
| 66 if (SupportsChildActivation(parent)) |
| 67 return child; |
| 68 // If |child| isn't activatable, but has transient parent, trace |
| 69 // that path instead. |
| 70 if (child->transient_parent()) |
| 71 return GetActivatableWindow(child->transient_parent()); |
| 72 parent = parent->parent(); |
| 73 child = child->parent(); |
| 74 } |
| 75 return NULL; |
| 76 } |
| 77 |
| 78 //////////////////////////////////////////////////////////////////////////////// |
| 79 // StackingController, aura::ActivationClient implementation: |
| 80 |
| 81 void ActivationController::ActivateWindow(aura::Window* window) { |
| 82 // Prevent recursion when called from focus. |
| 83 if (updating_activation_) |
| 84 return; |
| 85 |
| 86 AutoReset<bool> in_activate_window(&updating_activation_, true); |
| 87 if (!window) |
| 88 return; |
| 89 // Nothing may actually have changed. |
| 90 aura::Window* old_active = GetActiveWindow(); |
| 91 if (old_active == window) |
| 92 return; |
| 93 // The stacking client may impose rules on what window configurations can be |
| 94 // activated or deactivated. |
| 95 if (!CanActivateWindow(window)) |
| 96 return; |
| 97 |
| 98 if (!window->Contains(window->GetFocusManager()->GetFocusedWindow())) |
| 99 window->GetFocusManager()->SetFocusedWindow(window); |
| 100 aura::RootWindow::GetInstance()->SetProperty(aura::kRootWindowActiveWindow, |
| 101 window); |
| 102 // Invoke OnLostActive after we've changed the active window. That way if the |
| 103 // delegate queries for active state it doesn't think the window is still |
| 104 // active. |
| 105 if (old_active && aura::ActivationDelegate::GetActivationDelegate(old_active)) |
| 106 aura::ActivationDelegate::GetActivationDelegate(old_active)->OnLostActive(); |
| 107 if (window) { |
| 108 window->parent()->StackChildAtTop(window); |
| 109 if (aura::ActivationDelegate::GetActivationDelegate(window)) |
| 110 aura::ActivationDelegate::GetActivationDelegate(window)->OnActivated(); |
| 111 } |
| 112 } |
| 113 |
| 114 void ActivationController::DeactivateWindow(aura::Window* window) { |
| 115 if (window) |
| 116 ActivateNextWindow(window); |
| 117 } |
| 118 |
| 119 aura::Window* ActivationController::GetActiveWindow() { |
| 120 return reinterpret_cast<aura::Window*>( |
| 121 aura::RootWindow::GetInstance()->GetProperty( |
| 122 aura::kRootWindowActiveWindow)); |
| 123 } |
| 124 |
| 125 bool ActivationController::CanFocusWindow(aura::Window* window) const { |
| 126 return CanActivateWindow(GetActivatableWindow(window)); |
| 127 } |
| 128 |
| 129 //////////////////////////////////////////////////////////////////////////////// |
| 130 // ActivationController, aura::WindowObserver implementation: |
| 131 |
| 132 void ActivationController::OnWindowVisibilityChanged(aura::Window* window, |
| 133 bool visible) { |
| 134 if (!visible) |
| 135 ActivateNextWindow(window); |
| 136 } |
| 137 |
| 138 void ActivationController::OnWindowDestroyed(aura::Window* window) { |
| 139 if (IsActiveWindow(window)) { |
| 140 // Clear the property before activating something else, since |
| 141 // ActivateWindow() will attempt to notify the window stored in this value |
| 142 // otherwise. |
| 143 aura::RootWindow::GetInstance()->SetProperty(aura::kRootWindowActiveWindow, |
| 144 NULL); |
| 145 ActivateWindow(GetTopmostWindowToActivate(window)); |
| 146 } |
| 147 window->RemoveObserver(this); |
| 148 } |
| 149 |
| 150 //////////////////////////////////////////////////////////////////////////////// |
| 151 // ActivationController, aura::RootWindowObserver implementation: |
| 152 |
| 153 void ActivationController::OnWindowInitialized(aura::Window* window) { |
| 154 window->AddObserver(this); |
| 155 } |
| 156 |
| 157 void ActivationController::OnWindowFocused(aura::Window* window) { |
| 158 ActivateWindow(GetActivatableWindow(window)); |
| 159 } |
| 160 |
| 161 //////////////////////////////////////////////////////////////////////////////// |
| 162 // ActivationController, private: |
| 163 |
| 164 void ActivationController::ActivateNextWindow(aura::Window* window) { |
| 165 if (IsActiveWindow(window)) |
| 166 ActivateWindow(GetTopmostWindowToActivate(window)); |
| 167 } |
| 168 |
| 169 aura::Window* ActivationController::GetTopmostWindowToActivate( |
| 170 aura::Window* ignore) const { |
| 171 const aura::Window* container = |
| 172 default_container_for_test_ ? default_container_for_test_ : |
| 173 GetContainer(kShellWindowId_DefaultContainer); |
| 174 for (aura::Window::Windows::const_reverse_iterator i = |
| 175 container->children().rbegin(); |
| 176 i != container->children().rend(); |
| 177 ++i) { |
| 178 if (*i != ignore && CanActivateWindow(*i)) |
| 179 return *i; |
| 180 } |
| 181 return NULL; |
| 182 } |
| 183 |
| 184 } // namespace internal |
| 185 } // namespace aura_shell |
OLD | NEW |