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/public/screen_manager.h" 6 7#include "athena/input/public/accelerator_manager.h" 8#include "athena/screen/screen_accelerator_handler.h" 9#include "athena/util/container_priorities.h" 10#include "athena/util/fill_layout_manager.h" 11#include "base/logging.h" 12#include "base/memory/scoped_ptr.h" 13#include "ui/aura/client/screen_position_client.h" 14#include "ui/aura/client/window_tree_client.h" 15#include "ui/aura/layout_manager.h" 16#include "ui/aura/test/test_screen.h" 17#include "ui/aura/window.h" 18#include "ui/aura/window_property.h" 19#include "ui/aura/window_targeter.h" 20#include "ui/aura/window_tree_host.h" 21#include "ui/compositor/layer.h" 22#include "ui/gfx/display.h" 23#include "ui/gfx/screen.h" 24#include "ui/wm/core/base_focus_rules.h" 25#include "ui/wm/core/capture_controller.h" 26#include "ui/wm/core/focus_controller.h" 27#include "ui/wm/core/window_util.h" 28 29namespace athena { 30namespace { 31 32DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, 33 kContainerParamsKey, 34 NULL); 35 36ScreenManager* instance = NULL; 37 38bool GrabsInput(aura::Window* container) { 39 ScreenManager::ContainerParams* params = 40 container->GetProperty(kContainerParamsKey); 41 return params && params->grab_inputs; 42} 43 44// Returns the container which contains |window|. 45aura::Window* GetContainer(aura::Window* window) { 46 aura::Window* container = window; 47 while (container && !container->GetProperty(kContainerParamsKey)) 48 container = container->parent(); 49 return container; 50} 51 52class AthenaFocusRules : public wm::BaseFocusRules { 53 public: 54 AthenaFocusRules() {} 55 virtual ~AthenaFocusRules() {} 56 57 // wm::BaseFocusRules: 58 virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE { 59 ScreenManager::ContainerParams* params = 60 window->GetProperty(kContainerParamsKey); 61 return params && params->can_activate_children; 62 } 63 virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE { 64 // Check if containers of higher z-order than |window| have 'grab_inputs' 65 // fields. 66 if (window) { 67 const aura::Window::Windows& containers = 68 window->GetRootWindow()->children(); 69 aura::Window::Windows::const_iterator iter = 70 std::find(containers.begin(), containers.end(), GetContainer(window)); 71 DCHECK(iter != containers.end()); 72 for (++iter; iter != containers.end(); ++iter) { 73 if (GrabsInput(*iter)) 74 return false; 75 } 76 } 77 return BaseFocusRules::CanActivateWindow(window); 78 } 79 80 private: 81 DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); 82}; 83 84class AthenaWindowTreeClient : public aura::client::WindowTreeClient { 85 public: 86 explicit AthenaWindowTreeClient(aura::Window* container) 87 : container_(container) {} 88 89 private: 90 virtual ~AthenaWindowTreeClient() {} 91 92 // aura::client::WindowTreeClient: 93 virtual aura::Window* GetDefaultParent(aura::Window* context, 94 aura::Window* window, 95 const gfx::Rect& bounds) OVERRIDE { 96 aura::Window* transient_parent = wm::GetTransientParent(window); 97 if (transient_parent) 98 return GetContainer(transient_parent); 99 return container_; 100 } 101 102 aura::Window* container_; 103 104 DISALLOW_COPY_AND_ASSIGN(AthenaWindowTreeClient); 105}; 106 107class AthenaScreenPositionClient : public aura::client::ScreenPositionClient { 108 public: 109 AthenaScreenPositionClient() { 110 } 111 virtual ~AthenaScreenPositionClient() { 112 } 113 114 private: 115 // aura::client::ScreenPositionClient: 116 virtual void ConvertPointToScreen(const aura::Window* window, 117 gfx::Point* point) OVERRIDE { 118 const aura::Window* root = window->GetRootWindow(); 119 aura::Window::ConvertPointToTarget(window, root, point); 120 } 121 122 virtual void ConvertPointFromScreen(const aura::Window* window, 123 gfx::Point* point) OVERRIDE { 124 const aura::Window* root = window->GetRootWindow(); 125 aura::Window::ConvertPointToTarget(root, window, point); 126 } 127 128 virtual void ConvertHostPointToScreen(aura::Window* window, 129 gfx::Point* point) OVERRIDE { 130 // TODO(oshima): Implement this when adding multiple display support. 131 NOTREACHED(); 132 } 133 134 virtual void SetBounds(aura::Window* window, 135 const gfx::Rect& bounds, 136 const gfx::Display& display) OVERRIDE { 137 window->SetBounds(bounds); 138 } 139 140 DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); 141}; 142 143class AthenaEventTargeter : public aura::WindowTargeter, 144 public aura::WindowObserver { 145 public: 146 explicit AthenaEventTargeter(aura::Window* container) 147 : container_(container) { 148 container_->AddObserver(this); 149 } 150 151 virtual ~AthenaEventTargeter() { 152 // Removed before the container is removed. 153 if (container_) 154 container_->RemoveObserver(this); 155 } 156 157 private: 158 // aura::WindowTargeter: 159 virtual bool SubtreeCanAcceptEvent( 160 ui::EventTarget* target, 161 const ui::LocatedEvent& event) const OVERRIDE { 162 aura::Window* window = static_cast<aura::Window*>(target); 163 const aura::Window::Windows& containers = 164 container_->GetRootWindow()->children(); 165 aura::Window::Windows::const_iterator iter = 166 std::find(containers.begin(), containers.end(), container_); 167 DCHECK(iter != containers.end()); 168 for (; iter != containers.end(); ++iter) { 169 if ((*iter)->Contains(window)) 170 return true; 171 } 172 return false; 173 } 174 175 // aura::WindowObserver: 176 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 177 aura::Window* root_window = container_->GetRootWindow(); 178 DCHECK_EQ(window, container_); 179 DCHECK_EQ( 180 this, static_cast<ui::EventTarget*>(root_window)->GetEventTargeter()); 181 182 container_->RemoveObserver(this); 183 container_ = NULL; 184 185 // This will remove myself. 186 root_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>()); 187 } 188 189 aura::Window* container_; 190 191 DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter); 192}; 193 194class ScreenManagerImpl : public ScreenManager { 195 public: 196 explicit ScreenManagerImpl(aura::Window* root_window); 197 virtual ~ScreenManagerImpl(); 198 199 void Init(); 200 201 private: 202 // ScreenManager: 203 virtual aura::Window* CreateDefaultContainer( 204 const ContainerParams& params) OVERRIDE; 205 virtual aura::Window* CreateContainer(const ContainerParams& params) OVERRIDE; 206 virtual aura::Window* GetContext() OVERRIDE { return root_window_; } 207 virtual void SetRotation(gfx::Display::Rotation rotation) OVERRIDE; 208 virtual void SetRotationLocked(bool rotation_locked) OVERRIDE; 209 210 // Not owned. 211 aura::Window* root_window_; 212 213 scoped_ptr<aura::client::FocusClient> focus_client_; 214 scoped_ptr<aura::client::WindowTreeClient> window_tree_client_; 215 scoped_ptr<AcceleratorHandler> accelerator_handler_; 216 scoped_ptr< ::wm::ScopedCaptureClient> capture_client_; 217 scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_; 218 219 gfx::Display::Rotation last_requested_rotation_; 220 bool rotation_locked_; 221 222 DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl); 223}; 224 225ScreenManagerImpl::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 234ScreenManagerImpl::~ScreenManagerImpl() { 235 aura::client::SetScreenPositionClient(root_window_, NULL); 236 aura::client::SetWindowTreeClient(root_window_, NULL); 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_, NULL); 241 aura::client::SetFocusClient(root_window_, NULL); 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 = NULL; 250} 251 252void 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 root_window_->SetLayoutManager(new FillLayoutManager(root_window_)); 262 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_)); 263 accelerator_handler_.reset(new ScreenAcceleratorHandler(root_window_)); 264} 265 266aura::Window* ScreenManagerImpl::CreateDefaultContainer( 267 const ContainerParams& params) { 268 aura::Window* container = CreateContainer(params); 269 window_tree_client_.reset(new AthenaWindowTreeClient(container)); 270 aura::client::SetWindowTreeClient(root_window_, window_tree_client_.get()); 271 272 screen_position_client_.reset(new AthenaScreenPositionClient()); 273 aura::client::SetScreenPositionClient(root_window_, 274 screen_position_client_.get()); 275 276 return container; 277} 278 279// A functor to find a container that has the higher priority. 280struct HigherPriorityFinder { 281 HigherPriorityFinder(int p) : priority(p) {} 282 bool operator()(aura::Window* window) { 283 return window->GetProperty(kContainerParamsKey)->z_order_priority > 284 priority; 285 } 286 int priority; 287}; 288 289#if !defined(NDEBUG) 290struct PriorityMatcher { 291 PriorityMatcher(int p) : priority(p) {} 292 bool operator()(aura::Window* window) { 293 return window->GetProperty(kContainerParamsKey)->z_order_priority == 294 priority; 295 } 296 int priority; 297}; 298#endif 299 300aura::Window* ScreenManagerImpl::CreateContainer( 301 const ContainerParams& params) { 302 aura::Window* container = new aura::Window(NULL); 303 CHECK_GE(params.z_order_priority, 0); 304 container->Init(aura::WINDOW_LAYER_NOT_DRAWN); 305 container->SetName(params.name); 306 307 const aura::Window::Windows& children = root_window_->children(); 308 309#if !defined(NDEBUG) 310 DCHECK(std::find_if(children.begin(), 311 children.end(), 312 PriorityMatcher(params.z_order_priority)) 313 == children.end()) 314 << "The container with the priority " 315 << params.z_order_priority << " already exists."; 316#endif 317 318 container->SetProperty(kContainerParamsKey, new ContainerParams(params)); 319 320 // If another container is already grabbing the input, SetEventTargeter 321 // implicitly release the grabbing and remove the EventTargeter instance. 322 // TODO(mukai|oshima): think about the ideal behavior of multiple grabbing 323 // and implement it. 324 if (params.grab_inputs) { 325 DCHECK(std::find_if(children.begin(), children.end(), &GrabsInput) 326 == children.end()) 327 << "input has already been grabbed by another container"; 328 root_window_->SetEventTargeter( 329 scoped_ptr<ui::EventTargeter>(new AthenaEventTargeter(container))); 330 } 331 332 root_window_->AddChild(container); 333 334 aura::Window::Windows::const_iterator iter = 335 std::find_if(children.begin(), 336 children.end(), 337 HigherPriorityFinder(params.z_order_priority)); 338 if (iter != children.end()) 339 root_window_->StackChildBelow(container, *iter); 340 341 container->Show(); 342 return container; 343} 344 345void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) { 346 last_requested_rotation_ = rotation; 347 if (rotation_locked_ || rotation == 348 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) { 349 return; 350 } 351 352 // TODO(flackr): Use display manager to update display rotation: 353 // http://crbug.com/401044. 354 static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())-> 355 SetDisplayRotation(rotation); 356} 357 358void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) { 359 rotation_locked_ = rotation_locked; 360 if (!rotation_locked_) 361 SetRotation(last_requested_rotation_); 362} 363 364} // namespace 365 366ScreenManager::ContainerParams::ContainerParams(const std::string& n, 367 int priority) 368 : name(n), 369 can_activate_children(false), 370 grab_inputs(false), 371 z_order_priority(priority) { 372} 373 374// static 375ScreenManager* ScreenManager::Create(aura::Window* root_window) { 376 (new ScreenManagerImpl(root_window))->Init(); 377 DCHECK(instance); 378 return instance; 379} 380 381// static 382ScreenManager* ScreenManager::Get() { 383 DCHECK(instance); 384 return instance; 385} 386 387// static 388void ScreenManager::Shutdown() { 389 DCHECK(instance); 390 delete instance; 391 DCHECK(!instance); 392} 393 394} // namespace athena 395