| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "athena/screen/screen_manager_impl.h" | |
| 6 | |
| 7 #include "athena/input/public/accelerator_manager.h" | |
| 8 #include "athena/screen/modal_window_controller.h" | |
| 9 #include "athena/screen/screen_accelerator_handler.h" | |
| 10 #include "athena/util/container_priorities.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "ui/aura/client/aura_constants.h" | |
| 14 #include "ui/aura/client/screen_position_client.h" | |
| 15 #include "ui/aura/test/test_screen.h" | |
| 16 #include "ui/aura/window.h" | |
| 17 #include "ui/aura/window_property.h" | |
| 18 #include "ui/aura/window_targeter.h" | |
| 19 #include "ui/aura/window_tree_host.h" | |
| 20 #include "ui/gfx/display.h" | |
| 21 #include "ui/gfx/screen.h" | |
| 22 #include "ui/wm/core/base_focus_rules.h" | |
| 23 #include "ui/wm/core/capture_controller.h" | |
| 24 #include "ui/wm/core/default_screen_position_client.h" | |
| 25 #include "ui/wm/core/focus_controller.h" | |
| 26 #include "ui/wm/core/window_util.h" | |
| 27 | |
| 28 DECLARE_WINDOW_PROPERTY_TYPE(athena::ScreenManager::ContainerParams*); | |
| 29 | |
| 30 namespace athena { | |
| 31 namespace { | |
| 32 | |
| 33 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, | |
| 34 kContainerParamsKey, | |
| 35 nullptr); | |
| 36 | |
| 37 ScreenManagerImpl* instance = nullptr; | |
| 38 | |
| 39 // A functor to find a container that has the higher priority. | |
| 40 struct HigherPriorityFinder { | |
| 41 HigherPriorityFinder(int p) : priority(p) {} | |
| 42 bool operator()(aura::Window* window) { | |
| 43 return window->GetProperty(kContainerParamsKey)->z_order_priority > | |
| 44 priority; | |
| 45 } | |
| 46 int priority; | |
| 47 }; | |
| 48 | |
| 49 bool BlockEvents(aura::Window* container) { | |
| 50 ScreenManager::ContainerParams* params = | |
| 51 container->GetProperty(kContainerParamsKey); | |
| 52 return params && params->block_events && container->IsVisible(); | |
| 53 } | |
| 54 | |
| 55 bool DefaultContainer(aura::Window* container) { | |
| 56 ScreenManager::ContainerParams* params = | |
| 57 container->GetProperty(kContainerParamsKey); | |
| 58 return params && params->default_parent; | |
| 59 } | |
| 60 | |
| 61 bool HasModalContainerPriority(aura::Window* container) { | |
| 62 ScreenManager::ContainerParams* params = | |
| 63 container->GetProperty(kContainerParamsKey); | |
| 64 return params && params->modal_container_priority != -1; | |
| 65 } | |
| 66 | |
| 67 bool IsSystemModal(aura::Window* window) { | |
| 68 return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM; | |
| 69 } | |
| 70 | |
| 71 // Returns the container which contains |window|. | |
| 72 aura::Window* GetContainer(aura::Window* window) { | |
| 73 aura::Window* container = window; | |
| 74 while (container && !container->GetProperty(kContainerParamsKey)) | |
| 75 container = container->parent(); | |
| 76 return container; | |
| 77 } | |
| 78 | |
| 79 class AthenaFocusRules : public wm::BaseFocusRules { | |
| 80 public: | |
| 81 AthenaFocusRules() {} | |
| 82 ~AthenaFocusRules() override {} | |
| 83 | |
| 84 // wm::BaseFocusRules: | |
| 85 virtual bool SupportsChildActivation(aura::Window* window) const override { | |
| 86 ScreenManager::ContainerParams* params = | |
| 87 window->GetProperty(kContainerParamsKey); | |
| 88 return params && params->can_activate_children; | |
| 89 } | |
| 90 virtual bool CanActivateWindow(aura::Window* window) const override { | |
| 91 if (!window) | |
| 92 return true; | |
| 93 | |
| 94 // Check if containers of higher z-order than |window| have 'block_events' | |
| 95 // fields. | |
| 96 if (window->GetRootWindow()) { | |
| 97 const aura::Window::Windows& containers = | |
| 98 window->GetRootWindow()->children(); | |
| 99 aura::Window::Windows::const_iterator iter = | |
| 100 std::find(containers.begin(), containers.end(), GetContainer(window)); | |
| 101 DCHECK(iter != containers.end()); | |
| 102 for (++iter; iter != containers.end(); ++iter) { | |
| 103 if (BlockEvents(*iter)) | |
| 104 return false; | |
| 105 } | |
| 106 } | |
| 107 return BaseFocusRules::CanActivateWindow(window); | |
| 108 } | |
| 109 | |
| 110 aura::Window* GetTopmostWindowToActivateInContainer( | |
| 111 aura::Window* container, | |
| 112 aura::Window* ignore) const { | |
| 113 for (aura::Window::Windows::const_reverse_iterator i = | |
| 114 container->children().rbegin(); | |
| 115 i != container->children().rend(); | |
| 116 ++i) { | |
| 117 if (*i != ignore && CanActivateWindow(*i)) | |
| 118 return *i; | |
| 119 } | |
| 120 return NULL; | |
| 121 } | |
| 122 | |
| 123 virtual aura::Window* GetNextActivatableWindow( | |
| 124 aura::Window* ignore) const override { | |
| 125 const aura::Window::Windows& containers = | |
| 126 ignore->GetRootWindow()->children(); | |
| 127 auto starting_container_iter = containers.begin(); | |
| 128 for (auto container_iter = containers.begin(); | |
| 129 container_iter != containers.end(); | |
| 130 container_iter++) { | |
| 131 if ((*container_iter)->Contains(ignore)) { | |
| 132 starting_container_iter = container_iter; | |
| 133 break; | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 // Find next window from the front containers. | |
| 138 aura::Window* next = nullptr; | |
| 139 for (auto container_iter = starting_container_iter; | |
| 140 !next && container_iter != containers.end(); | |
| 141 container_iter++) { | |
| 142 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore); | |
| 143 } | |
| 144 | |
| 145 // Find next window from the back containers. | |
| 146 auto container_iter = starting_container_iter; | |
| 147 while (!next && container_iter != containers.begin()) { | |
| 148 container_iter--; | |
| 149 next = GetTopmostWindowToActivateInContainer(*container_iter, ignore); | |
| 150 } | |
| 151 return next; | |
| 152 } | |
| 153 | |
| 154 private: | |
| 155 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); | |
| 156 }; | |
| 157 | |
| 158 class AthenaScreenPositionClient : public wm::DefaultScreenPositionClient { | |
| 159 public: | |
| 160 AthenaScreenPositionClient() { | |
| 161 } | |
| 162 ~AthenaScreenPositionClient() override {} | |
| 163 | |
| 164 private: | |
| 165 // aura::client::ScreenPositionClient: | |
| 166 void ConvertHostPointToScreen(aura::Window* window, | |
| 167 gfx::Point* point) override { | |
| 168 // TODO(oshima): Implement this when adding multiple display support. | |
| 169 NOTREACHED(); | |
| 170 } | |
| 171 | |
| 172 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); | |
| 173 }; | |
| 174 | |
| 175 class AthenaWindowTargeter : public aura::WindowTargeter { | |
| 176 public: | |
| 177 explicit AthenaWindowTargeter(aura::Window* root_window) | |
| 178 : root_window_(root_window) {} | |
| 179 | |
| 180 ~AthenaWindowTargeter() override {} | |
| 181 | |
| 182 private: | |
| 183 // aura::WindowTargeter: | |
| 184 virtual bool SubtreeCanAcceptEvent( | |
| 185 ui::EventTarget* target, | |
| 186 const ui::LocatedEvent& event) const override { | |
| 187 const aura::Window::Windows& containers = root_window_->children(); | |
| 188 auto r_iter = | |
| 189 std::find_if(containers.rbegin(), containers.rend(), &BlockEvents); | |
| 190 if (r_iter == containers.rend()) | |
| 191 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); | |
| 192 | |
| 193 aura::Window* window = static_cast<aura::Window*>(target); | |
| 194 for (;; --r_iter) { | |
| 195 if ((*r_iter)->Contains(window)) | |
| 196 return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); | |
| 197 if (r_iter == containers.rbegin()) | |
| 198 break; | |
| 199 } | |
| 200 return false; | |
| 201 } | |
| 202 | |
| 203 virtual ui::EventTarget* FindTargetForLocatedEvent( | |
| 204 ui::EventTarget* root, | |
| 205 ui::LocatedEvent* event) override { | |
| 206 ui::EventTarget* target = | |
| 207 aura::WindowTargeter::FindTargetForLocatedEvent(root, event); | |
| 208 if (target) | |
| 209 return target; | |
| 210 // If the root target is blocking the event, return the container even if | |
| 211 // there is no target found so that windows behind it will not be searched. | |
| 212 const ScreenManager::ContainerParams* params = | |
| 213 static_cast<aura::Window*>(root)->GetProperty(kContainerParamsKey); | |
| 214 return (params && params->block_events) ? root : nullptr; | |
| 215 } | |
| 216 | |
| 217 // Not owned. | |
| 218 aura::Window* root_window_; | |
| 219 | |
| 220 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTargeter); | |
| 221 }; | |
| 222 | |
| 223 } // namespace | |
| 224 | |
| 225 ScreenManagerImpl::ScreenManagerImpl(aura::Window* root_window) | |
| 226 : root_window_(root_window), | |
| 227 last_requested_rotation_(gfx::Display::ROTATE_0), | |
| 228 rotation_locked_(false) { | |
| 229 DCHECK(root_window_); | |
| 230 DCHECK(!instance); | |
| 231 instance = this; | |
| 232 } | |
| 233 | |
| 234 ScreenManagerImpl::~ScreenManagerImpl() { | |
| 235 aura::client::SetScreenPositionClient(root_window_, nullptr); | |
| 236 aura::client::SetWindowTreeClient(root_window_, nullptr); | |
| 237 wm::FocusController* focus_controller = | |
| 238 static_cast<wm::FocusController*>(focus_client_.get()); | |
| 239 root_window_->RemovePreTargetHandler(focus_controller); | |
| 240 aura::client::SetActivationClient(root_window_, nullptr); | |
| 241 aura::client::SetFocusClient(root_window_, nullptr); | |
| 242 aura::Window::Windows children = root_window_->children(); | |
| 243 // Close All children: | |
| 244 for (aura::Window::Windows::iterator iter = children.begin(); | |
| 245 iter != children.end(); | |
| 246 ++iter) { | |
| 247 delete *iter; | |
| 248 } | |
| 249 instance = nullptr; | |
| 250 } | |
| 251 | |
| 252 void ScreenManagerImpl::Init() { | |
| 253 wm::FocusController* focus_controller = | |
| 254 new wm::FocusController(new AthenaFocusRules()); | |
| 255 | |
| 256 aura::client::SetFocusClient(root_window_, focus_controller); | |
| 257 root_window_->AddPreTargetHandler(focus_controller); | |
| 258 aura::client::SetActivationClient(root_window_, focus_controller); | |
| 259 focus_client_.reset(focus_controller); | |
| 260 | |
| 261 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_)); | |
| 262 accelerator_handler_.reset(new ScreenAcceleratorHandler()); | |
| 263 | |
| 264 aura::client::SetWindowTreeClient(root_window_, this); | |
| 265 | |
| 266 screen_position_client_.reset(new AthenaScreenPositionClient()); | |
| 267 aura::client::SetScreenPositionClient(root_window_, | |
| 268 screen_position_client_.get()); | |
| 269 root_window_->SetEventTargeter( | |
| 270 make_scoped_ptr(new AthenaWindowTargeter(root_window_))); | |
| 271 } | |
| 272 | |
| 273 aura::Window* ScreenManagerImpl::FindContainerByPriority(int priority) { | |
| 274 for (aura::Window* window : root_window_->children()) { | |
| 275 if (window->GetProperty(kContainerParamsKey)->z_order_priority == priority) | |
| 276 return window; | |
| 277 } | |
| 278 return nullptr; | |
| 279 } | |
| 280 | |
| 281 aura::Window* ScreenManagerImpl::CreateContainer( | |
| 282 const ContainerParams& params) { | |
| 283 const aura::Window::Windows& children = root_window_->children(); | |
| 284 | |
| 285 if (params.default_parent) { | |
| 286 CHECK(std::find_if(children.begin(), children.end(), &DefaultContainer) == | |
| 287 children.end()); | |
| 288 } | |
| 289 // mmodal container's priority must be higher than the container's priority. | |
| 290 DCHECK(params.modal_container_priority == -1 || | |
| 291 params.modal_container_priority > params.z_order_priority); | |
| 292 // Default parent must specify modal_container_priority. | |
| 293 DCHECK(!params.default_parent || params.modal_container_priority != -1); | |
| 294 | |
| 295 aura::Window* container = new aura::Window(nullptr); | |
| 296 CHECK_GE(params.z_order_priority, 0); | |
| 297 container->Init(aura::WINDOW_LAYER_NOT_DRAWN); | |
| 298 container->SetName(params.name); | |
| 299 | |
| 300 DCHECK(!FindContainerByPriority(params.z_order_priority)) | |
| 301 << "The container with the priority " << params.z_order_priority | |
| 302 << " already exists."; | |
| 303 | |
| 304 container->SetProperty(kContainerParamsKey, new ContainerParams(params)); | |
| 305 | |
| 306 root_window_->AddChild(container); | |
| 307 | |
| 308 aura::Window::Windows::const_iterator iter = | |
| 309 std::find_if(children.begin(), | |
| 310 children.end(), | |
| 311 HigherPriorityFinder(params.z_order_priority)); | |
| 312 if (iter != children.end()) | |
| 313 root_window_->StackChildBelow(container, *iter); | |
| 314 | |
| 315 container->Show(); | |
| 316 return container; | |
| 317 } | |
| 318 | |
| 319 aura::Window* ScreenManagerImpl::GetContext() { | |
| 320 return root_window_; | |
| 321 } | |
| 322 | |
| 323 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) { | |
| 324 last_requested_rotation_ = rotation; | |
| 325 if (rotation_locked_ || rotation == | |
| 326 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) { | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 // TODO(flackr): Use display manager to update display rotation: | |
| 331 // http://crbug.com/401044. | |
| 332 static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())-> | |
| 333 SetDisplayRotation(rotation); | |
| 334 } | |
| 335 | |
| 336 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) { | |
| 337 rotation_locked_ = rotation_locked; | |
| 338 if (!rotation_locked_) | |
| 339 SetRotation(last_requested_rotation_); | |
| 340 } | |
| 341 | |
| 342 int ScreenManagerImpl::GetModalContainerPriority(aura::Window* window, | |
| 343 aura::Window* parent) { | |
| 344 const aura::Window::Windows& children = root_window_->children(); | |
| 345 if (window->GetProperty(aura::client::kAlwaysOnTopKey)) { | |
| 346 // Use top most modal container. | |
| 347 auto iter = std::find_if( | |
| 348 children.rbegin(), children.rend(), &HasModalContainerPriority); | |
| 349 DCHECK(iter != children.rend()); | |
| 350 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; | |
| 351 } else { | |
| 352 // use the container closest to the parent which has modal | |
| 353 // container priority. | |
| 354 auto iter = std::find(children.rbegin(), children.rend(), parent); | |
| 355 DCHECK(iter != children.rend()); | |
| 356 iter = std::find_if(iter, children.rend(), &HasModalContainerPriority); | |
| 357 DCHECK(iter != children.rend()); | |
| 358 return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 aura::Window* ScreenManagerImpl::GetDefaultParent(aura::Window* context, | |
| 363 aura::Window* window, | |
| 364 const gfx::Rect& bounds) { | |
| 365 aura::Window* parent = wm::GetTransientParent(window); | |
| 366 if (parent) | |
| 367 parent = GetContainer(parent); | |
| 368 else | |
| 369 parent = GetDefaultContainer(); | |
| 370 | |
| 371 if (IsSystemModal(window)) { | |
| 372 DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL || | |
| 373 window->type() == ui::wm::WINDOW_TYPE_POPUP); | |
| 374 int priority = GetModalContainerPriority(window, parent); | |
| 375 | |
| 376 parent = FindContainerByPriority(priority); | |
| 377 if (!parent) { | |
| 378 ModalWindowController* controller = new ModalWindowController(priority); | |
| 379 parent = controller->modal_container(); | |
| 380 } | |
| 381 } | |
| 382 return parent; | |
| 383 } | |
| 384 | |
| 385 aura::Window* ScreenManagerImpl::GetDefaultContainer() { | |
| 386 const aura::Window::Windows& children = root_window_->children(); | |
| 387 return *(std::find_if(children.begin(), children.end(), &DefaultContainer)); | |
| 388 } | |
| 389 | |
| 390 ScreenManager::ContainerParams::ContainerParams(const std::string& n, | |
| 391 int priority) | |
| 392 : name(n), | |
| 393 can_activate_children(false), | |
| 394 block_events(false), | |
| 395 z_order_priority(priority), | |
| 396 default_parent(false), | |
| 397 modal_container_priority(-1) { | |
| 398 } | |
| 399 | |
| 400 // static | |
| 401 ScreenManager* ScreenManager::Create(aura::Window* root_window) { | |
| 402 (new ScreenManagerImpl(root_window))->Init(); | |
| 403 DCHECK(instance); | |
| 404 return instance; | |
| 405 } | |
| 406 | |
| 407 // static | |
| 408 ScreenManager* ScreenManager::Get() { | |
| 409 DCHECK(instance); | |
| 410 return instance; | |
| 411 } | |
| 412 | |
| 413 // static | |
| 414 void ScreenManager::Shutdown() { | |
| 415 DCHECK(instance); | |
| 416 delete instance; | |
| 417 DCHECK(!instance); | |
| 418 } | |
| 419 | |
| 420 } // namespace athena | |
| OLD | NEW |