• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 namespace athena {
30 namespace {
31 
32 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams,
33                                  kContainerParamsKey,
34                                  NULL);
35 
36 ScreenManager* instance = NULL;
37 
GrabsInput(aura::Window * container)38 bool 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|.
GetContainer(aura::Window * window)45 aura::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 
52 class AthenaFocusRules : public wm::BaseFocusRules {
53  public:
AthenaFocusRules()54   AthenaFocusRules() {}
~AthenaFocusRules()55   virtual ~AthenaFocusRules() {}
56 
57   // wm::BaseFocusRules:
SupportsChildActivation(aura::Window * window) const58   virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE {
59     ScreenManager::ContainerParams* params =
60         window->GetProperty(kContainerParamsKey);
61     return params && params->can_activate_children;
62   }
CanActivateWindow(aura::Window * window) const63   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 
84 class AthenaWindowTreeClient : public aura::client::WindowTreeClient {
85  public:
AthenaWindowTreeClient(aura::Window * container)86   explicit AthenaWindowTreeClient(aura::Window* container)
87       : container_(container) {}
88 
89  private:
~AthenaWindowTreeClient()90   virtual ~AthenaWindowTreeClient() {}
91 
92   // aura::client::WindowTreeClient:
GetDefaultParent(aura::Window * context,aura::Window * window,const gfx::Rect & bounds)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 
107 class AthenaScreenPositionClient : public aura::client::ScreenPositionClient {
108  public:
AthenaScreenPositionClient()109   AthenaScreenPositionClient() {
110   }
~AthenaScreenPositionClient()111   virtual ~AthenaScreenPositionClient() {
112   }
113 
114  private:
115   // aura::client::ScreenPositionClient:
ConvertPointToScreen(const aura::Window * window,gfx::Point * point)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 
ConvertPointFromScreen(const aura::Window * window,gfx::Point * point)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 
ConvertHostPointToScreen(aura::Window * window,gfx::Point * point)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 
SetBounds(aura::Window * window,const gfx::Rect & bounds,const gfx::Display & display)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 
143 class AthenaEventTargeter : public aura::WindowTargeter,
144                             public aura::WindowObserver {
145  public:
AthenaEventTargeter(aura::Window * container)146   explicit AthenaEventTargeter(aura::Window* container)
147       : container_(container) {
148     container_->AddObserver(this);
149   }
150 
~AthenaEventTargeter()151   virtual ~AthenaEventTargeter() {
152     // Removed before the container is removed.
153     if (container_)
154       container_->RemoveObserver(this);
155   }
156 
157  private:
158   // aura::WindowTargeter:
SubtreeCanAcceptEvent(ui::EventTarget * target,const ui::LocatedEvent & event) const159   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:
OnWindowDestroying(aura::Window * window)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 
194 class 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;
GetContext()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 
ScreenManagerImpl(aura::Window * root_window)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 
~ScreenManagerImpl()234 ScreenManagerImpl::~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 
Init()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   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 
CreateDefaultContainer(const ContainerParams & params)266 aura::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.
280 struct HigherPriorityFinder {
HigherPriorityFinderathena::__anonf43701900111::HigherPriorityFinder281   HigherPriorityFinder(int p) : priority(p) {}
operator ()athena::__anonf43701900111::HigherPriorityFinder282   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)
290 struct PriorityMatcher {
PriorityMatcherathena::__anonf43701900111::PriorityMatcher291   PriorityMatcher(int p) : priority(p) {}
operator ()athena::__anonf43701900111::PriorityMatcher292   bool operator()(aura::Window* window) {
293     return window->GetProperty(kContainerParamsKey)->z_order_priority ==
294            priority;
295   }
296   int priority;
297 };
298 #endif
299 
CreateContainer(const ContainerParams & params)300 aura::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 
SetRotation(gfx::Display::Rotation rotation)345 void 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 
SetRotationLocked(bool rotation_locked)358 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) {
359   rotation_locked_ = rotation_locked;
360   if (!rotation_locked_)
361     SetRotation(last_requested_rotation_);
362 }
363 
364 }  // namespace
365 
ContainerParams(const std::string & n,int priority)366 ScreenManager::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
Create(aura::Window * root_window)375 ScreenManager* ScreenManager::Create(aura::Window* root_window) {
376   (new ScreenManagerImpl(root_window))->Init();
377   DCHECK(instance);
378   return instance;
379 }
380 
381 // static
Get()382 ScreenManager* ScreenManager::Get() {
383   DCHECK(instance);
384   return instance;
385 }
386 
387 // static
Shutdown()388 void ScreenManager::Shutdown() {
389   DCHECK(instance);
390   delete instance;
391   DCHECK(!instance);
392 }
393 
394 }  // namespace athena
395