Index: athena/screen/screen_manager_impl.cc |
diff --git a/athena/screen/screen_manager_impl.cc b/athena/screen/screen_manager_impl.cc |
index 744f0762926d2f2cd48641ea56265e173181a443..8522acfc7acd30404c8b2ce8aa0d88fad5963769 100644 |
--- a/athena/screen/screen_manager_impl.cc |
+++ b/athena/screen/screen_manager_impl.cc |
@@ -16,6 +16,7 @@ |
#include "ui/aura/layout_manager.h" |
#include "ui/aura/window.h" |
#include "ui/aura/window_property.h" |
+#include "ui/aura/window_targeter.h" |
#include "ui/aura/window_tree_host.h" |
#include "ui/wm/core/base_focus_rules.h" |
#include "ui/wm/core/capture_controller.h" |
@@ -29,6 +30,22 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, |
ScreenManager* instance = NULL; |
+bool GrabsInput(aura::Window* container) { |
+ ScreenManager::ContainerParams* params = |
+ container->GetProperty(kContainerParamsKey); |
+ return params && params->grab_inputs; |
+} |
+ |
+// Returns the container which contains |window|. |
+aura::Window* GetContainer(aura::Window* window) { |
+ // No containers for NULL or the root window itself. |
+ if (!window || !window->parent()) |
+ return NULL; |
+ if (window->parent()->IsRootWindow()) |
+ return window; |
+ return GetContainer(window->parent()); |
+} |
+ |
class AthenaFocusRules : public wm::BaseFocusRules { |
public: |
AthenaFocusRules() {} |
@@ -40,6 +57,22 @@ class AthenaFocusRules : public wm::BaseFocusRules { |
window->GetProperty(kContainerParamsKey); |
return params && params->can_activate_children; |
} |
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE { |
+ // Check if containers of higher z-order than |window| have 'grab_inputs' |
+ // fields. |
+ if (window) { |
+ const aura::Window::Windows& containers = |
+ window->GetRootWindow()->children(); |
+ aura::Window::Windows::const_iterator iter = |
+ std::find(containers.begin(), containers.end(), GetContainer(window)); |
+ DCHECK(iter != containers.end()); |
+ for (++iter; iter != containers.end(); ++iter) { |
+ if (GrabsInput(*iter)) |
+ return false; |
+ } |
+ } |
+ return BaseFocusRules::CanActivateWindow(window); |
+ } |
private: |
DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); |
@@ -101,6 +134,57 @@ class AthenaScreenPositionClient : public aura::client::ScreenPositionClient { |
DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); |
}; |
+class AthenaEventTargeter : public aura::WindowTargeter, |
+ public aura::WindowObserver { |
+ public: |
+ explicit AthenaEventTargeter(aura::Window* container) |
+ : container_(container) { |
+ container_->AddObserver(this); |
+ } |
+ |
+ virtual ~AthenaEventTargeter() { |
+ // Removed before the container is removed. |
+ if (container_) |
+ container_->RemoveObserver(this); |
+ } |
+ |
+ private: |
+ // aura::WindowTargeter: |
+ virtual bool SubtreeCanAcceptEvent( |
+ ui::EventTarget* target, |
+ const ui::LocatedEvent& event) const OVERRIDE { |
+ aura::Window* window = static_cast<aura::Window*>(target); |
+ const aura::Window::Windows& containers = |
+ container_->GetRootWindow()->children(); |
+ aura::Window::Windows::const_iterator iter = |
+ std::find(containers.begin(), containers.end(), container_); |
+ DCHECK(iter != containers.end()); |
+ for (; iter != containers.end(); ++iter) { |
+ if ((*iter)->Contains(window)) |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ // aura::WindowObserver: |
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { |
+ aura::Window* root_window = container_->GetRootWindow(); |
+ DCHECK_EQ(window, container_); |
+ DCHECK_EQ( |
+ this, static_cast<ui::EventTarget*>(root_window)->GetEventTargeter()); |
+ |
+ container_->RemoveObserver(this); |
+ container_ = NULL; |
+ |
+ // This will remove myself. |
+ root_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>()); |
+ } |
+ |
+ aura::Window* container_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter); |
+}; |
+ |
class ScreenManagerImpl : public ScreenManager { |
public: |
explicit ScreenManagerImpl(aura::Window* root_window); |
@@ -208,6 +292,19 @@ aura::Window* ScreenManagerImpl::CreateContainer( |
#endif |
container->SetProperty(kContainerParamsKey, new ContainerParams(params)); |
+ |
+ // If another container is already grabbing the input, SetEventTargeter |
+ // implicitly release the grabbing and remove the EventTargeter instance. |
+ // TODO(mukai|oshima): think about the ideal behavior of multiple grabbing |
+ // and implement it. |
+ if (params.grab_inputs) { |
+ DCHECK(std::find_if(children.begin(), children.end(), &GrabsInput) |
+ == children.end()) |
+ << "input has already been grabbed by another container"; |
+ root_window_->SetEventTargeter( |
+ scoped_ptr<ui::EventTargeter>(new AthenaEventTargeter(container))); |
+ } |
+ |
root_window_->AddChild(container); |
aura::Window::Windows::const_iterator iter = |
@@ -229,7 +326,10 @@ void ScreenManagerImpl::SetBackgroundImage(const gfx::ImageSkia& image) { |
ScreenManager::ContainerParams::ContainerParams(const std::string& n, |
int priority) |
- : name(n), can_activate_children(false), z_order_priority(priority) { |
+ : name(n), |
+ can_activate_children(false), |
+ grab_inputs(false), |
+ z_order_priority(priority) { |
} |
// static |