diff options
author | oshima <oshima@chromium.org> | 2014-10-20 10:19:18 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-20 17:20:09 +0000 |
commit | 44bf2fd5fb11d3777e522fae68de024c8f6ce46f (patch) | |
tree | ee959cfe4065367147ab432ddd4b22a51f504004 /athena | |
parent | 3f5d1eae967412133ff221d2aea6dd325b45928c (diff) | |
download | chromium_src-44bf2fd5fb11d3777e522fae68de024c8f6ce46f.zip chromium_src-44bf2fd5fb11d3777e522fae68de024c8f6ce46f.tar.gz chromium_src-44bf2fd5fb11d3777e522fae68de024c8f6ce46f.tar.bz2 |
Support modal windows
* New ContainerParams
- default_parent to specify the default parent when no
transient parent is specified.
- modal_container_priority now controls the modal container
used for a modal window created for the given container.
- if not specified, it will fallback downwards to find one.
- if window is specified as always_on_top, it will use top
most modal container.
* Changed network selector/shutdown dialog to use the new API.
* Other change:
Separated test windows to athena/test/base/test_windows.h
BUG=410499
TBR=sky@chromium.org,reed@chromium.org
TEST=coverd by unit tests
Committed: https://crrev.com/4903fd36b2b36f00efeb1b7bba81b7de6e9457a3
Cr-Commit-Position: refs/heads/master@{#300192}
Review URL: https://codereview.chromium.org/662763002
Cr-Commit-Position: refs/heads/master@{#300288}
Diffstat (limited to 'athena')
29 files changed, 933 insertions, 395 deletions
diff --git a/athena/activity/activity_manager_unittest.cc b/athena/activity/activity_manager_unittest.cc index 0ed2a9a..37f73f6 100644 --- a/athena/activity/activity_manager_unittest.cc +++ b/athena/activity/activity_manager_unittest.cc @@ -7,6 +7,7 @@ #include "athena/activity/public/activity.h" #include "athena/activity/public/activity_factory.h" #include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" #include "ui/aura/window.h" namespace athena { @@ -53,7 +54,7 @@ TEST_F(ActivityManagerTest, GetActivityForWindow) { EXPECT_EQ(NULL, manager->GetActivityForWindow(NULL)); - scoped_ptr<aura::Window> window = CreateTestWindow(NULL, gfx::Rect()); + scoped_ptr<aura::Window> window = test::CreateNormalWindow(NULL, NULL); EXPECT_EQ(NULL, manager->GetActivityForWindow(window.get())); } diff --git a/athena/athena.gyp b/athena/athena.gyp index 4084fb2..ba463af 100644 --- a/athena/athena.gyp +++ b/athena/athena.gyp @@ -84,6 +84,8 @@ 'screen/screen_accelerator_handler.cc', 'screen/screen_accelerator_handler.h', 'screen/screen_manager_impl.cc', + 'screen/modal_window_controller.cc', + 'screen/modal_window_controller.h', 'system/background_controller.cc', 'system/background_controller.h', 'system/network_selector.cc', @@ -274,6 +276,8 @@ 'test/base/test_app_model_builder.cc', 'test/base/test_app_model_builder.h', 'test/base/test_resource_manager_delegate.cc', + 'test/base/test_windows.cc', + 'test/base/test_windows.h', 'wm/test/window_manager_impl_test_api.cc', 'wm/test/window_manager_impl_test_api.h', ], @@ -301,6 +305,7 @@ 'input/input_manager_unittest.cc', 'resource_manager/memory_pressure_notifier_unittest.cc', 'resource_manager/resource_manager_unittest.cc', + 'screen/modal_window_controller_unittest.cc', 'screen/screen_manager_unittest.cc', 'test/base/athena_unittests.cc', 'util/drag_handle_unittest.cc', diff --git a/athena/main/athena_launcher.cc b/athena/main/athena_launcher.cc index 2634489..28059df 100644 --- a/athena/main/athena_launcher.cc +++ b/athena/main/athena_launcher.cc @@ -115,8 +115,8 @@ void StartAthenaEnv(scoped_refptr<base::TaskRunner> blocking_task_runner) { athena::InputManager::Create()->OnRootWindowCreated(root_window); athena::ScreenManager::Create(root_window); - athena::SystemUI::Create(blocking_task_runner); athena::WindowManager::Create(); + athena::SystemUI::Create(blocking_task_runner); athena::AppRegistry::Create(); SetupBackgroundImage(); @@ -166,8 +166,8 @@ void ShutdownAthena() { session_started = false; } athena::AppRegistry::ShutDown(); - athena::WindowManager::Shutdown(); athena::SystemUI::Shutdown(); + athena::WindowManager::Shutdown(); athena::ScreenManager::Shutdown(); athena::InputManager::Shutdown(); athena::AthenaEnv::Shutdown(); diff --git a/athena/screen/DEPS b/athena/screen/DEPS index 1809145..423ee38 100644 --- a/athena/screen/DEPS +++ b/athena/screen/DEPS @@ -5,4 +5,7 @@ include_rules = [ "+ui/events", "+ui/gfx", "+ui/wm", + "+third_party/skia/include", + # for tests. + "+athena/athena_export.h", ] diff --git a/athena/screen/modal_window_controller.cc b/athena/screen/modal_window_controller.cc new file mode 100644 index 0000000..71a19ff --- /dev/null +++ b/athena/screen/modal_window_controller.cc @@ -0,0 +1,146 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "athena/screen/modal_window_controller.h" + +#include "athena/screen/public/screen_manager.h" +#include "base/message_loop/message_loop.h" +#include "ui/aura/window.h" +#include "ui/aura/window_property.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/wm/core/window_animations.h" + +namespace athena { +namespace { + +DEFINE_OWNED_WINDOW_PROPERTY_KEY(ModalWindowController, + kModalWindowControllerKey, + NULL); + +} // namespace + +// static +ModalWindowController* ModalWindowController::Get(aura::Window* container) { + ModalWindowController* controller = + container->GetProperty(kModalWindowControllerKey); + CHECK(controller); + return controller; +} + +ModalWindowController::ModalWindowController(int priority) + : modal_container_(NULL), + dimmer_window_(new aura::Window(NULL)), + dimmed_(false) { + ScreenManager::ContainerParams params("ModalContainer", priority); + params.can_activate_children = true; + params.block_events = true; + modal_container_ = ScreenManager::Get()->CreateContainer(params); + modal_container_->SetProperty(kModalWindowControllerKey, this); + + dimmer_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL); + dimmer_window_->Init(aura::WINDOW_LAYER_SOLID_COLOR); + dimmer_window_->layer()->SetColor(SK_ColorBLACK); + dimmer_window_->layer()->SetOpacity(0.0f); + dimmer_window_->Show(); + + modal_container_->AddChild(dimmer_window_); + modal_container_->AddObserver(this); + + UpdateDimmerWindowBounds(); +} + +ModalWindowController::~ModalWindowController() { + if (modal_container_) + modal_container_->RemoveObserver(this); +} + +void ModalWindowController::OnWindowAdded(aura::Window* child) { + DCHECK_NE(child, dimmer_window_); + if (IsChildWindow(child)) { + child->AddObserver(this); + UpdateDimming(NULL); + } +} + +void ModalWindowController::OnWindowVisibilityChanged(aura::Window* window, + bool visible) { + if (IsChildWindow(window)) + UpdateDimming(NULL); +} + +void ModalWindowController::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (window == modal_container_) + UpdateDimmerWindowBounds(); +} + +void ModalWindowController::OnWindowDestroyed(aura::Window* window) { + UpdateDimming(window); +} + +bool ModalWindowController::IsChildWindow(aura::Window* child) const { + return child->parent() == modal_container_ && child != dimmer_window_; +} + +void ModalWindowController::UpdateDimmerWindowBounds() { + gfx::Rect bounds(modal_container_->bounds().size()); + dimmer_window_->SetBounds(bounds); +} + +void ModalWindowController::UpdateDimming(aura::Window* ignore) { + if (!modal_container_ || !dimmer_window_) + return; + bool should_delete = true; + for (aura::Window* window : modal_container_->children()) { + if (window == dimmer_window_ || window == ignore) + continue; + should_delete = false; + if (window->TargetVisibility()) { + SetDimmed(true); + return; + } + } + SetDimmed(false); + + if (should_delete) { + // Remove the container from root so that the container becomes + // invisible, but don't delete it until next event execution + // because the call stack may still have and use the pointer. + modal_container_->RemoveObserver(this); + modal_container_->parent()->RemoveChild(modal_container_); + base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE, modal_container_); + modal_container_ = NULL; + dimmer_window_ = NULL; + } +} + +void ModalWindowController::SetDimmed(bool dimmed) { + const float kDimmedOpacity = 0.4f; + + if (!dimmer_window_ || dimmed_ == dimmed) + return; + dimmed_ = dimmed; + + const int kDimmAnimationDurationMs = 500; + if (dimmed) { + ui::ScopedLayerAnimationSettings settings( + dimmer_window_->layer()->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDimmAnimationDurationMs)); + dimmer_window_->layer()->SetOpacity(kDimmedOpacity); + } else { + // ScopedHidingAnimationSettings will detach the animating and + // recreate layers for the container so that animation can continue + // even if the container is removed immediately. + wm::ScopedHidingAnimationSettings settings(modal_container_); + settings.layer_animation_settings()->SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDimmAnimationDurationMs)); + modal_container_->layer()->SetOpacity(0.0f); + } +} + +} // namespace athena diff --git a/athena/screen/modal_window_controller.h b/athena/screen/modal_window_controller.h new file mode 100644 index 0000000..b4c7ec5 --- /dev/null +++ b/athena/screen/modal_window_controller.h @@ -0,0 +1,59 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATHENA_SCREEN_MODAL_WINDOW_CONTROLLER_H_ +#define ATHENA_SCREEN_MODAL_WINDOW_CONTROLLER_H_ + +#include "athena/athena_export.h" +#include "ui/aura/window_observer.h" + +namespace athena { + +// ModalWindow controller manages the modal window and +// its container. This gets created when a modal window is opened +// and deleted when all modal windows are deleted. +class ATHENA_EXPORT ModalWindowController : public aura::WindowObserver { + public: + // Returns the ModalWindowController associated with the container. + static ModalWindowController* Get(aura::Window* container); + + explicit ModalWindowController(int container_priority); + virtual ~ModalWindowController(); + + aura::Window* modal_container() { return modal_container_; } + + bool dimmed() const { return dimmed_; } + + private: + // aura::WindowObserver: + virtual void OnWindowAdded(aura::Window* child) override; + virtual void OnWindowVisibilityChanged(aura::Window* window, + bool visible) override; + virtual void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + virtual void OnWindowDestroyed(aura::Window* window) override; + + // Tells if the child is not a dimmer window and a child of the modal + // container. + bool IsChildWindow(aura::Window* child) const; + + void UpdateDimmerWindowBounds(); + + // Change dimming state based on the visible window in the container. + void UpdateDimming(aura::Window* ignore); + + // Note: changing true -> false will delete the modal_container_. + void SetDimmed(bool dimmed); + + aura::Window* modal_container_; // not owned. + aura::Window* dimmer_window_; // not owned. + + bool dimmed_; + DISALLOW_COPY_AND_ASSIGN(ModalWindowController); +}; + +} // namespace athena + +#endif // ATHENA_SCREEN_MODAL_WINDOW_CONTROLLER_H_ diff --git a/athena/screen/modal_window_controller_unittest.cc b/athena/screen/modal_window_controller_unittest.cc new file mode 100644 index 0000000..b73399a --- /dev/null +++ b/athena/screen/modal_window_controller_unittest.cc @@ -0,0 +1,144 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "athena/screen/modal_window_controller.h" +#include "athena/screen/screen_manager_impl.h" +#include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" +#include "athena/util/container_priorities.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/aura/window.h" + +namespace athena { + +typedef test::AthenaTestBase ModalWindowControllerTest; + +aura::Window* FindContainerByPriority(int priority) { + ScreenManagerImpl* screen_manager = + static_cast<ScreenManagerImpl*>(ScreenManager::Get()); + return screen_manager->FindContainerByPriority(priority); +} + +TEST_F(ModalWindowControllerTest, ModalContainer) { + aura::test::EventCountDelegate delegate; + scoped_ptr<aura::Window> modal(test::CreateTransientWindow( + &delegate, NULL, ui::MODAL_TYPE_SYSTEM, false)); + + aura::Window* modal_container = FindContainerByPriority(CP_SYSTEM_MODAL); + EXPECT_TRUE(modal_container); + + ModalWindowController* modal_controller = + ModalWindowController::Get(modal_container); + ASSERT_TRUE(modal_controller); + EXPECT_EQ(modal_container, modal->parent()); + EXPECT_FALSE(modal_controller->dimmed()); + modal->Show(); + EXPECT_TRUE(modal_controller->dimmed()); + + modal->Hide(); + EXPECT_TRUE(FindContainerByPriority(CP_SYSTEM_MODAL)); + EXPECT_FALSE(modal_controller->dimmed()); + + modal->Show(); + EXPECT_TRUE(FindContainerByPriority(CP_SYSTEM_MODAL)); + EXPECT_TRUE(modal_controller->dimmed()); + + modal.reset(); + EXPECT_FALSE(FindContainerByPriority(CP_SYSTEM_MODAL)); + + // Create two. + modal = test::CreateTransientWindow( + &delegate, NULL, ui::MODAL_TYPE_SYSTEM, false).Pass(); + scoped_ptr<aura::Window> modal2(test::CreateTransientWindow( + &delegate, NULL, ui::MODAL_TYPE_SYSTEM, false)); + + modal_container = FindContainerByPriority(CP_SYSTEM_MODAL); + EXPECT_TRUE(modal_container); + modal_controller = ModalWindowController::Get(modal_container); + ASSERT_TRUE(modal_controller); + EXPECT_EQ(modal_container, modal->parent()); + EXPECT_EQ(modal_container, modal2->parent()); + + EXPECT_FALSE(modal_controller->dimmed()); + modal->Show(); + EXPECT_TRUE(modal_controller->dimmed()); + modal2->Show(); + EXPECT_TRUE(modal_controller->dimmed()); + + modal->Hide(); + EXPECT_TRUE(modal_controller->dimmed()); + modal2->Hide(); + EXPECT_FALSE(modal_controller->dimmed()); + EXPECT_TRUE(FindContainerByPriority(CP_SYSTEM_MODAL)); + + modal2.reset(); + EXPECT_TRUE(FindContainerByPriority(CP_SYSTEM_MODAL)); + EXPECT_FALSE(modal_controller->dimmed()); + + modal.reset(); + EXPECT_FALSE(FindContainerByPriority(CP_SYSTEM_MODAL)); +} + +TEST_F(ModalWindowControllerTest, NestedModalWindows) { + ScreenManager::ContainerParams params("top", CP_END); + params.can_activate_children = true; + params.modal_container_priority = CP_END + 1; + aura::Window* top_container = ScreenManager::Get()->CreateContainer(params); + + aura::test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> top_w1( + test::CreateNormalWindow(&delegate, top_container)); + EXPECT_EQ(top_container, top_w1->parent()); + + aura::Window* default_container = FindContainerByPriority(CP_DEFAULT); + EXPECT_TRUE(default_container); + + scoped_ptr<aura::Window> normal_w1(test::CreateNormalWindow(&delegate, NULL)); + EXPECT_EQ(default_container, normal_w1->parent()); + + scoped_ptr<aura::Window> normal_m1(test::CreateTransientWindow( + &delegate, normal_w1.get(), ui::MODAL_TYPE_SYSTEM, false)); + aura::Window* default_modal_container = + FindContainerByPriority(CP_SYSTEM_MODAL); + EXPECT_EQ(default_modal_container, normal_m1->parent()); + + // A modal window with the transient parent which doesn't specify + // the modal container should fallback the default container's modal + // container. + aura::Window* home_container = FindContainerByPriority(CP_DEFAULT); + EXPECT_TRUE(home_container); + + scoped_ptr<aura::Window> normal_m2(test::CreateTransientWindow( + &delegate, home_container, ui::MODAL_TYPE_SYSTEM, false)); + EXPECT_EQ(default_modal_container, normal_m2->parent()); + + // No modal container for top container yet. + EXPECT_FALSE(FindContainerByPriority(CP_END + 1)); + + // Creating a modal with always on top creates the modal dialog on top + // most dialog container. + scoped_ptr<aura::Window> top_m0(test::CreateTransientWindow( + &delegate, NULL, ui::MODAL_TYPE_SYSTEM, true)); + + aura::Window* top_modal_container = FindContainerByPriority(CP_END + 1); + EXPECT_EQ(top_modal_container, top_m0->parent()); + + // Creating a modal dialog with transient parent on the top container + // creates the winodw on the top container's modal container. + scoped_ptr<aura::Window> top_m1(test::CreateTransientWindow( + &delegate, top_w1.get(), ui::MODAL_TYPE_SYSTEM, true)); + EXPECT_EQ(top_modal_container, top_m1->parent()); + + normal_m1.reset(); + EXPECT_TRUE(FindContainerByPriority(CP_SYSTEM_MODAL)); + normal_m2.reset(); + EXPECT_FALSE(FindContainerByPriority(CP_SYSTEM_MODAL)); + + top_m0.reset(); + EXPECT_TRUE(FindContainerByPriority(CP_END + 1)); + top_m1.reset(); + EXPECT_FALSE(FindContainerByPriority(CP_END + 1)); +} + +} // namespace athena diff --git a/athena/screen/public/screen_manager.h b/athena/screen/public/screen_manager.h index e263782..11dda1f 100644 --- a/athena/screen/public/screen_manager.h +++ b/athena/screen/public/screen_manager.h @@ -29,11 +29,37 @@ class ATHENA_EXPORT ScreenManager { // True if the container can activate its child window. bool can_activate_children; - // True if the container will grab all of input events. - bool grab_inputs; + // True if the container will block evnets from containers behind it. + bool block_events; // Defines the z_order priority of the container. int z_order_priority; + + // True if this container should be used as a default parent. + bool default_parent; + + // The container priority used to open modal dialog window + // created with this container as a transient parent (Note: A modal window + // should + // use a trnasient parent, not a direct parent, or no transient parent.) + // + // Default is -1, and it will fallback to the container behind this + // container, + // that has the modal container proiroty. + // + // The modal container for modal window is selected as follows. + // 1) a window must be created with |aura::client::kModalKey| property + // without explicit parent set. + // 2.a) If aura::client::kAlwaysOnTopKey is NOT set, it uses the stand flow + // described above. (fallback to containers behind this). + // 2.b) If aura::client::kAlwaysOnTopKey is set, it searches the top most + // container which has |modal_container_priority| != -1. + // 3) Look for the container with |modal_container_priority|, and create + // one if it doesn't exist. + // + // Created modal container will self destruct if last modal window + // is deleted. + int modal_container_priority; }; // Creates, returns and deletes the singleton object of the ScreenManager @@ -44,11 +70,6 @@ class ATHENA_EXPORT ScreenManager { virtual ~ScreenManager() {} - // Creates the container window that is used when creating a normal - // widget without specific parent. - virtual aura::Window* CreateDefaultContainer( - const ContainerParams& params) = 0; - // Creates the container window on the screen. virtual aura::Window* CreateContainer(const ContainerParams& params) = 0; diff --git a/athena/screen/screen_accelerator_handler.h b/athena/screen/screen_accelerator_handler.h index ab57879..fcde448 100644 --- a/athena/screen/screen_accelerator_handler.h +++ b/athena/screen/screen_accelerator_handler.h @@ -1,6 +1,8 @@ // Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef ATHENA_SCREEN_SCREEN_ACCELERATOR_HANDLER_H_ +#define ATHENA_SCREEN_SCREEN_ACCELERATOR_HANDLER_H_ #include "athena/input/public/accelerator_manager.h" @@ -31,3 +33,5 @@ class ScreenAcceleratorHandler : public AcceleratorHandler { }; } // namespace athena + +#endif // ATHENA_SCREEN_SCREEN_ACCELERATOR_HANDLER_H_ diff --git a/athena/screen/screen_manager_impl.cc b/athena/screen/screen_manager_impl.cc index 3ece198..5182b7e 100644 --- a/athena/screen/screen_manager_impl.cc +++ b/athena/screen/screen_manager_impl.cc @@ -2,23 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "athena/screen/public/screen_manager.h" +#include "athena/screen/screen_manager_impl.h" #include "athena/input/public/accelerator_manager.h" +#include "athena/screen/modal_window_controller.h" #include "athena/screen/screen_accelerator_handler.h" #include "athena/util/container_priorities.h" #include "athena/util/fill_layout_manager.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/screen_position_client.h" -#include "ui/aura/client/window_tree_client.h" -#include "ui/aura/layout_manager.h" #include "ui/aura/test/test_screen.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/compositor/layer.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" #include "ui/wm/core/base_focus_rules.h" @@ -26,6 +25,9 @@ #include "ui/wm/core/focus_controller.h" #include "ui/wm/core/window_util.h" +// This is to avoid creating type definitoin for kAlwaysOnTopKey. +DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(ATHENA_EXPORT, bool); + namespace athena { namespace { @@ -33,12 +35,38 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, kContainerParamsKey, NULL); -ScreenManager* instance = NULL; +ScreenManagerImpl* instance = NULL; + +// A functor to find a container that has the higher priority. +struct HigherPriorityFinder { + HigherPriorityFinder(int p) : priority(p) {} + bool operator()(aura::Window* window) { + return window->GetProperty(kContainerParamsKey)->z_order_priority > + priority; + } + int priority; +}; -bool GrabsInput(aura::Window* container) { +bool BlockEvents(aura::Window* container) { ScreenManager::ContainerParams* params = container->GetProperty(kContainerParamsKey); - return params && params->grab_inputs; + return params && params->block_events; +} + +bool DefaultContainer(aura::Window* container) { + ScreenManager::ContainerParams* params = + container->GetProperty(kContainerParamsKey); + return params && params->default_parent; +} + +bool HasModalContainerPriority(aura::Window* container) { + ScreenManager::ContainerParams* params = + container->GetProperty(kContainerParamsKey); + return params && params->modal_container_priority != -1; +} + +bool IsSystemModal(aura::Window* window) { + return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM; } // Returns the container which contains |window|. @@ -61,47 +89,34 @@ class AthenaFocusRules : public wm::BaseFocusRules { 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' + if (!window) + return true; + + // Check if containers of higher z-order than |window| have 'block_events' // fields. - if (window) { + if (window->GetRootWindow()) { 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)) + if (BlockEvents(*iter)) return false; } } return BaseFocusRules::CanActivateWindow(window); } - private: - DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); -}; - -class AthenaWindowTreeClient : public aura::client::WindowTreeClient { - public: - explicit AthenaWindowTreeClient(aura::Window* container) - : container_(container) {} - - private: - virtual ~AthenaWindowTreeClient() {} - - // aura::client::WindowTreeClient: - virtual aura::Window* GetDefaultParent(aura::Window* context, - aura::Window* window, - const gfx::Rect& bounds) override { - aura::Window* transient_parent = wm::GetTransientParent(window); - if (transient_parent) - return GetContainer(transient_parent); - return container_; + virtual aura::Window* GetNextActivatableWindow( + aura::Window* ignore) const override { + aura::Window* next = wm::BaseFocusRules::GetNextActivatableWindow(ignore); + // TODO(oshima): Search from activatable containers if |next| is NULL. + return next; } - aura::Window* container_; - - DISALLOW_COPY_AND_ASSIGN(AthenaWindowTreeClient); + private: + DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); }; class AthenaScreenPositionClient : public aura::client::ScreenPositionClient { @@ -140,93 +155,56 @@ class AthenaScreenPositionClient : public aura::client::ScreenPositionClient { DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); }; -class AthenaEventTargeter : public aura::WindowTargeter, - public aura::WindowObserver { +class AthenaWindowTargeter : public aura::WindowTargeter { public: - explicit AthenaEventTargeter(aura::Window* container) - : container_(container) { - container_->AddObserver(this); - } + explicit AthenaWindowTargeter(aura::Window* root_window) + : root_window_(root_window) {} - virtual ~AthenaEventTargeter() { - // Removed before the container is removed. - if (container_) - container_->RemoveObserver(this); - } - - void SetPreviousEventTargeter(scoped_ptr<ui::EventTargeter> targeter) { - previous_root_event_targeter_ = targeter.Pass(); - } + virtual ~AthenaWindowTargeter() {} private: // aura::WindowTargeter: virtual bool SubtreeCanAcceptEvent( ui::EventTarget* target, const ui::LocatedEvent& event) const override { + const aura::Window::Windows& containers = root_window_->children(); + auto r_iter = + std::find_if(containers.rbegin(), containers.rend(), &BlockEvents); + if (r_iter == containers.rend()) + return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); + 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; + for (;; --r_iter) { + if ((*r_iter)->Contains(window)) + return aura::WindowTargeter::SubtreeCanAcceptEvent(target, event); + if (r_iter == containers.rbegin()) + break; } 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(previous_root_event_targeter_.Pass()); + virtual ui::EventTarget* FindTargetForLocatedEvent( + ui::EventTarget* root, + ui::LocatedEvent* event) override { + ui::EventTarget* target = + aura::WindowTargeter::FindTargetForLocatedEvent(root, event); + if (target) + return target; + // If the root target is blocking the event, return the container even if + // there is no target found so that windows behind it will not be searched. + const ScreenManager::ContainerParams* params = + static_cast<aura::Window*>(root)->GetProperty(kContainerParamsKey); + return (params && params->block_events) ? root : NULL; } - aura::Window* container_; - scoped_ptr<ui::EventTargeter> previous_root_event_targeter_; - - DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter); -}; - -class ScreenManagerImpl : public ScreenManager { - public: - explicit ScreenManagerImpl(aura::Window* root_window); - virtual ~ScreenManagerImpl(); - - void Init(); - - private: - // ScreenManager: - virtual aura::Window* CreateDefaultContainer( - const ContainerParams& params) override; - virtual aura::Window* CreateContainer(const ContainerParams& params) override; - virtual aura::Window* GetContext() override { return root_window_; } - virtual void SetRotation(gfx::Display::Rotation rotation) override; - virtual void SetRotationLocked(bool rotation_locked) override; - // Not owned. aura::Window* root_window_; - scoped_ptr<aura::client::FocusClient> focus_client_; - scoped_ptr<aura::client::WindowTreeClient> window_tree_client_; - scoped_ptr<AcceleratorHandler> accelerator_handler_; - scoped_ptr< ::wm::ScopedCaptureClient> capture_client_; - scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_; - - gfx::Display::Rotation last_requested_rotation_; - bool rotation_locked_; - - DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl); + DISALLOW_COPY_AND_ASSIGN(AthenaWindowTargeter); }; +} // namespace + ScreenManagerImpl::ScreenManagerImpl(aura::Window* root_window) : root_window_(root_window), last_requested_rotation_(gfx::Display::ROTATE_0), @@ -266,77 +244,49 @@ void ScreenManagerImpl::Init() { root_window_->SetLayoutManager(new FillLayoutManager(root_window_)); capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_)); accelerator_handler_.reset(new ScreenAcceleratorHandler(root_window_)); -} -aura::Window* ScreenManagerImpl::CreateDefaultContainer( - const ContainerParams& params) { - aura::Window* container = CreateContainer(params); - window_tree_client_.reset(new AthenaWindowTreeClient(container)); - aura::client::SetWindowTreeClient(root_window_, window_tree_client_.get()); + aura::client::SetWindowTreeClient(root_window_, this); screen_position_client_.reset(new AthenaScreenPositionClient()); aura::client::SetScreenPositionClient(root_window_, screen_position_client_.get()); - - return container; + root_window_->SetEventTargeter( + make_scoped_ptr(new AthenaWindowTargeter(root_window_))); } -// A functor to find a container that has the higher priority. -struct HigherPriorityFinder { - HigherPriorityFinder(int p) : priority(p) {} - bool operator()(aura::Window* window) { - return window->GetProperty(kContainerParamsKey)->z_order_priority > - priority; +aura::Window* ScreenManagerImpl::FindContainerByPriority(int priority) { + for (aura::Window* window : root_window_->children()) { + if (window->GetProperty(kContainerParamsKey)->z_order_priority == priority) + return window; } - int priority; -}; - -#if !defined(NDEBUG) -struct PriorityMatcher { - PriorityMatcher(int p) : priority(p) {} - bool operator()(aura::Window* window) { - return window->GetProperty(kContainerParamsKey)->z_order_priority == - priority; - } - int priority; -}; -#endif + return NULL; +} aura::Window* ScreenManagerImpl::CreateContainer( const ContainerParams& params) { + const aura::Window::Windows& children = root_window_->children(); + + if (params.default_parent) { + CHECK(std::find_if(children.begin(), children.end(), &DefaultContainer) == + children.end()); + } + // mmodal container's priority must be higher than the container's priority. + DCHECK(params.modal_container_priority == -1 || + params.modal_container_priority > params.z_order_priority); + // Default parent must specify modal_container_priority. + DCHECK(!params.default_parent || params.modal_container_priority != -1); + aura::Window* container = new aura::Window(NULL); CHECK_GE(params.z_order_priority, 0); container->Init(aura::WINDOW_LAYER_NOT_DRAWN); container->SetName(params.name); - const aura::Window::Windows& children = root_window_->children(); - -#if !defined(NDEBUG) - DCHECK(std::find_if(children.begin(), - children.end(), - PriorityMatcher(params.z_order_priority)) - == children.end()) - << "The container with the priority " - << params.z_order_priority << " already exists."; -#endif + DCHECK(!FindContainerByPriority(params.z_order_priority)) + << "The container with the priority " << params.z_order_priority + << " already exists."; 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"; - AthenaEventTargeter* athena_event_targeter = - new AthenaEventTargeter(container); - athena_event_targeter->SetPreviousEventTargeter( - root_window_->SetEventTargeter( - scoped_ptr<ui::EventTargeter>(athena_event_targeter))); - } - root_window_->AddChild(container); aura::Window::Windows::const_iterator iter = @@ -350,6 +300,10 @@ aura::Window* ScreenManagerImpl::CreateContainer( return container; } +aura::Window* ScreenManagerImpl::GetContext() { + return root_window_; +} + void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) { last_requested_rotation_ = rotation; if (rotation_locked_ || rotation == @@ -369,14 +323,62 @@ void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) { SetRotation(last_requested_rotation_); } -} // namespace +int ScreenManagerImpl::GetModalContainerPriority(aura::Window* window, + aura::Window* parent) { + const aura::Window::Windows& children = root_window_->children(); + if (window->GetProperty(aura::client::kAlwaysOnTopKey)) { + // Use top most modal container. + auto iter = std::find_if( + children.rbegin(), children.rend(), &HasModalContainerPriority); + DCHECK(iter != children.rend()); + return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; + } else { + // use the container closest to the parent which has modal + // container priority. + auto iter = std::find(children.rbegin(), children.rend(), parent); + DCHECK(iter != children.rend()); + iter = std::find_if(iter, children.rend(), &HasModalContainerPriority); + DCHECK(iter != children.rend()); + return (*iter)->GetProperty(kContainerParamsKey)->modal_container_priority; + } +} + +aura::Window* ScreenManagerImpl::GetDefaultParent(aura::Window* context, + aura::Window* window, + const gfx::Rect& bounds) { + aura::Window* parent = wm::GetTransientParent(window); + if (parent) + parent = GetContainer(parent); + else + parent = GetDefaultContainer(); + + if (IsSystemModal(window)) { + DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL || + window->type() == ui::wm::WINDOW_TYPE_POPUP); + int priority = GetModalContainerPriority(window, parent); + + parent = FindContainerByPriority(priority); + if (!parent) { + ModalWindowController* controller = new ModalWindowController(priority); + parent = controller->modal_container(); + } + } + return parent; +} + +aura::Window* ScreenManagerImpl::GetDefaultContainer() { + const aura::Window::Windows& children = root_window_->children(); + return *(std::find_if(children.begin(), children.end(), &DefaultContainer)); +} ScreenManager::ContainerParams::ContainerParams(const std::string& n, int priority) : name(n), can_activate_children(false), - grab_inputs(false), - z_order_priority(priority) { + block_events(false), + z_order_priority(priority), + default_parent(false), + modal_container_priority(-1) { } // static diff --git a/athena/screen/screen_manager_impl.h b/athena/screen/screen_manager_impl.h new file mode 100644 index 0000000..1738542 --- /dev/null +++ b/athena/screen/screen_manager_impl.h @@ -0,0 +1,72 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATHENA_SCREEN_SCREEN_MANAGER_IMPL_H_ +#define ATHENA_SCREEN_SCREEN_MANAGER_IMPL_H_ + +#include "athena/athena_export.h" +#include "athena/screen/public/screen_manager.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/client/window_tree_client.h" + +namespace aura { +namespace client { +class FocusClient; +class ScreenPositionClient; +} +} + +namespace wm { +class ScopedCaptureClient; +} + +namespace athena { +class AcceleratorHandler; + +class ATHENA_EXPORT ScreenManagerImpl : public ScreenManager, + public aura::client::WindowTreeClient { + public: + explicit ScreenManagerImpl(aura::Window* root_window); + virtual ~ScreenManagerImpl(); + + void Init(); + + // Returns a container which has |priority|. Null if such container + // doesn't exist. + aura::Window* FindContainerByPriority(int priority); + + private: + // ScreenManager: + virtual aura::Window* CreateContainer(const ContainerParams& params) override; + virtual aura::Window* GetContext() override; + virtual void SetRotation(gfx::Display::Rotation rotation) override; + virtual void SetRotationLocked(bool rotation_locked) override; + + // aura::client::WindowTreeClient: + virtual aura::Window* GetDefaultParent(aura::Window* context, + aura::Window* window, + const gfx::Rect& bounds) override; + + int GetModalContainerPriority(aura::Window* window, aura::Window* parent); + + // Returns a container with |params.default_parent| == true. + aura::Window* GetDefaultContainer(); + + // Not owned. + aura::Window* root_window_; + + scoped_ptr<aura::client::FocusClient> focus_client_; + scoped_ptr<AcceleratorHandler> accelerator_handler_; + scoped_ptr<::wm::ScopedCaptureClient> capture_client_; + scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_; + + gfx::Display::Rotation last_requested_rotation_; + bool rotation_locked_; + + DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl); +}; + +} // namespace athena + +#endif // ATHENA_SCREEN_SCREEN_MANAGER_IMPL_H_ diff --git a/athena/screen/screen_manager_unittest.cc b/athena/screen/screen_manager_unittest.cc index ed8b248..c8787da 100644 --- a/athena/screen/screen_manager_unittest.cc +++ b/athena/screen/screen_manager_unittest.cc @@ -2,15 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "athena/screen/public/screen_manager.h" - #include <algorithm> #include <string> +#include "athena/screen/screen_manager_impl.h" #include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" #include "athena/util/container_priorities.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" +#include "ui/aura/window_targeter.h" #include "ui/events/test/event_generator.h" #include "ui/wm/core/window_util.h" @@ -111,12 +112,83 @@ TEST_F(ScreenManagerTest, NonActivatableContainer) { EXPECT_TRUE(wm::CanActivateWindow(window.get())); } -TEST_F(ScreenManagerTest, GrabInputContainer) { +TEST_F(ScreenManagerTest, BlockInputsShouldNotBlockVirtualKeyboard) { + ScreenManager::ContainerParams block_params("blocking", kTestZOrderPriority); + block_params.can_activate_children = true; + block_params.block_events = true; + aura::Window* block_container = + ScreenManager::Get()->CreateContainer(block_params); + + aura::test::EventCountDelegate block_delegate; + scoped_ptr<aura::Window> block_window(CreateWindow( + block_container, &block_delegate, gfx::Rect(0, 0, 100, 100))); + EXPECT_TRUE(wm::CanActivateWindow(block_window.get())); + + // Create a normal container appearing over the |block_container|. This is + // essentially the case of virtual keyboard. + ScreenManager::ContainerParams vk_params("virtual keyboard", + kTestZOrderPriority + 1); + vk_params.can_activate_children = true; + aura::Window* vk_container = ScreenManager::Get()->CreateContainer(vk_params); + + aura::test::EventCountDelegate vk_delegate; + scoped_ptr<aura::Window> vk_window( + CreateWindow(vk_container, &vk_delegate, gfx::Rect(0, 20, 100, 80))); + EXPECT_TRUE(wm::CanActivateWindow(vk_window.get())); + + ui::test::EventGenerator event_generator(root_window()); + event_generator.MoveMouseTo(10, 25); + event_generator.ClickLeftButton(); + EXPECT_EQ("0 0", block_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("1 1", vk_delegate.GetMouseButtonCountsAndReset()); +} + +TEST_F(ScreenManagerTest, DefaultContainer) { + ScreenManagerImpl* impl = + static_cast<ScreenManagerImpl*>(ScreenManager::Get()); + aura::Window* original_default = impl->FindContainerByPriority(CP_DEFAULT); + aura::Window* parent = original_default->parent(); + // Temporarily remove the original default container from tree. + parent->RemoveChild(original_default); + + ScreenManager::ContainerParams params("new_default", CP_END + 1); + params.default_parent = true; + params.modal_container_priority = CP_END + 2; + aura::Window* new_default = ScreenManager::Get()->CreateContainer(params); + aura::Window* w = test::CreateNormalWindow(NULL, NULL).release(); + EXPECT_EQ(new_default, w->parent()); + delete new_default; + + // Add the original back to shutdown properly. + parent->AddChild(original_default); +} + +namespace { + +class ScreenManagerTargeterTest + : public athena::test::AthenaTestBase, + public testing::WithParamInterface<bool> { + public: + ScreenManagerTargeterTest() + : targeter_(GetParam() ? NULL : new aura::WindowTargeter) {} + virtual ~ScreenManagerTargeterTest() {} + + protected: + scoped_ptr<ui::EventTargeter> targeter_; + + private: + DISALLOW_COPY_AND_ASSIGN(ScreenManagerTargeterTest); +}; + +} // namespace + +TEST_P(ScreenManagerTargeterTest, BlockContainer) { ScreenManager::ContainerParams normal_params( "normal", kTestZOrderPriority); normal_params.can_activate_children = true; aura::Window* normal_container = ScreenManager::Get()->CreateContainer(normal_params); + normal_container->SetEventTargeter(targeter_.Pass()); aura::test::EventCountDelegate normal_delegate; scoped_ptr<aura::Window> normal_window(CreateWindow( @@ -132,76 +204,48 @@ TEST_F(ScreenManagerTest, GrabInputContainer) { event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE); EXPECT_EQ("1 1", normal_delegate.GetKeyCountsAndReset()); - ScreenManager::ContainerParams grab_params( - "grabbing", kTestZOrderPriority + 1); - grab_params.can_activate_children = true; - grab_params.grab_inputs = true; - aura::Window* grab_container = - ScreenManager::Get()->CreateContainer(grab_params); + ScreenManager::ContainerParams block_params("blocking", + kTestZOrderPriority + 1); + block_params.can_activate_children = true; + block_params.block_events = true; + aura::Window* block_container = + ScreenManager::Get()->CreateContainer(block_params); EXPECT_FALSE(wm::CanActivateWindow(normal_window.get())); - aura::test::EventCountDelegate grab_delegate; - scoped_ptr<aura::Window> grab_window(CreateWindow( - grab_container, &grab_delegate, gfx::Rect(10, 10, 100, 100))); - EXPECT_TRUE(wm::CanActivateWindow(grab_window.get())); + aura::test::EventCountDelegate block_delegate; + scoped_ptr<aura::Window> block_window(CreateWindow( + block_container, &block_delegate, gfx::Rect(10, 10, 100, 100))); + EXPECT_TRUE(wm::CanActivateWindow(block_window.get())); - wm::ActivateWindow(grab_window.get()); + wm::ActivateWindow(block_window.get()); // (0, 0) is still on normal_window, but the event should not go there - // because grabbing_container prevents it. + // because blockbing_container prevents it. event_generator.MoveMouseTo(0, 0); event_generator.ClickLeftButton(); EXPECT_EQ("0 0", normal_delegate.GetMouseButtonCountsAndReset()); - EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", block_delegate.GetMouseButtonCountsAndReset()); + event_generator.MoveMouseWheel(0, 10); + // EXPECT_EQ(0, normal_event_counter.num_scroll_events()); event_generator.MoveMouseTo(20, 20); event_generator.ClickLeftButton(); - EXPECT_EQ("1 1", grab_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("1 1", block_delegate.GetMouseButtonCountsAndReset()); event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE); EXPECT_EQ("0 0", normal_delegate.GetKeyCountsAndReset()); - EXPECT_EQ("1 1", grab_delegate.GetKeyCountsAndReset()); -} - -TEST_F(ScreenManagerTest, GrabShouldNotBlockVirtualKeyboard) { - ScreenManager::ContainerParams grab_params("grabbing", kTestZOrderPriority); - grab_params.can_activate_children = true; - grab_params.grab_inputs = true; - aura::Window* grab_container = - ScreenManager::Get()->CreateContainer(grab_params); - - aura::test::EventCountDelegate grab_delegate; - scoped_ptr<aura::Window> grab_window( - CreateWindow(grab_container, &grab_delegate, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(wm::CanActivateWindow(grab_window.get())); - - // Create a normal container appearing over the |grab_container|. This is - // essentially the case of virtual keyboard. - ScreenManager::ContainerParams vk_params( - "virtual keyboard", kTestZOrderPriority + 1); - vk_params.can_activate_children = true; - aura::Window* vk_container = ScreenManager::Get()->CreateContainer(vk_params); - - aura::test::EventCountDelegate vk_delegate; - scoped_ptr<aura::Window> vk_window( - CreateWindow(vk_container, &vk_delegate, gfx::Rect(0, 20, 100, 80))); - EXPECT_TRUE(wm::CanActivateWindow(vk_window.get())); - - ui::test::EventGenerator event_generator(root_window()); - event_generator.MoveMouseTo(10, 25); - event_generator.ClickLeftButton(); - EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); - EXPECT_EQ("1 1", vk_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("1 1", block_delegate.GetKeyCountsAndReset()); } -TEST_F(ScreenManagerTest, GrabAndMouseCapture) { +TEST_P(ScreenManagerTargeterTest, BlockAndMouseCapture) { ScreenManager::ContainerParams normal_params( "normal", kTestZOrderPriority); normal_params.can_activate_children = true; aura::Window* normal_container = ScreenManager::Get()->CreateContainer(normal_params); + normal_container->SetEventTargeter(targeter_.Pass()); aura::test::EventCountDelegate normal_delegate; scoped_ptr<aura::Window> normal_window(CreateWindow( @@ -211,29 +255,33 @@ TEST_F(ScreenManagerTest, GrabAndMouseCapture) { event_generator.MoveMouseTo(0, 0); event_generator.PressLeftButton(); - // Creating grabbing container while mouse pressing. - ScreenManager::ContainerParams grab_params( - "grabbing", kTestZOrderPriority + 1); - grab_params.can_activate_children = true; - grab_params.grab_inputs = true; - aura::Window* grab_container = - ScreenManager::Get()->CreateContainer(grab_params); + // Creating blocking container while mouse pressing. + ScreenManager::ContainerParams block_params("blocking", + kTestZOrderPriority + 1); + block_params.can_activate_children = true; + block_params.block_events = true; + aura::Window* block_container = + ScreenManager::Get()->CreateContainer(block_params); - aura::test::EventCountDelegate grab_delegate; - scoped_ptr<aura::Window> grab_window(CreateWindow( - grab_container, &grab_delegate, gfx::Rect(10, 10, 100, 100))); + aura::test::EventCountDelegate block_delegate; + scoped_ptr<aura::Window> block_window(CreateWindow( + block_container, &block_delegate, gfx::Rect(10, 10, 100, 100))); // Release event should be sent to |normal_window| because it captures the // mouse event. event_generator.ReleaseLeftButton(); EXPECT_EQ("1 1", normal_delegate.GetMouseButtonCountsAndReset()); - EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", block_delegate.GetMouseButtonCountsAndReset()); // After release, further mouse events should not be sent to |normal_window| - // because grab_container grabs the input. + // because block_container blocks the input. event_generator.ClickLeftButton(); EXPECT_EQ("0 0", normal_delegate.GetMouseButtonCountsAndReset()); - EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", block_delegate.GetMouseButtonCountsAndReset()); } +INSTANTIATE_TEST_CASE_P(WithOrWithoutTargeter, + ScreenManagerTargeterTest, + testing::Values(false, true)); + } // namespace athena diff --git a/athena/system/network_selector.cc b/athena/system/network_selector.cc index 7519968..ef45bfb 100644 --- a/athena/system/network_selector.cc +++ b/athena/system/network_selector.cc @@ -4,6 +4,7 @@ #include "athena/system/network_selector.h" +#include "athena/screen/public/screen_manager.h" #include "base/memory/weak_ptr.h" #include "base/strings/utf_string_conversions.h" #include "chromeos/network/network_configuration_handler.h" @@ -38,6 +39,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" using chromeos::NetworkConfigurationHandler; using chromeos::NetworkConnectionHandler; @@ -47,18 +49,14 @@ using chromeos::NetworkState; namespace { -const int kBackgroundColor = SkColorSetARGB(0x7f, 0, 0, 0); - // The View for the user to enter the password for connceting to a network. This // view also shows an error message if the network connection fails. class PasswordView : public views::View, public views::ButtonListener { public: PasswordView(const ui::NetworkInfo& network, - const base::Callback<void(bool)>& callback, - views::View* parent_container) + const base::Callback<void(bool)>& callback) : network_(network), callback_(callback), - parent_container_(parent_container), connect_(NULL), cancel_(NULL), textfield_(NULL), @@ -102,7 +100,7 @@ class PasswordView : public views::View, public views::ButtonListener { virtual ~PasswordView() {} private: - void Close(bool successful) { callback_.Run(successful); } + void CloseDialog(bool successful) { callback_.Run(successful); } void OnKnownError(const std::string& error_name, scoped_ptr<base::DictionaryValue> error_data) { @@ -122,7 +120,7 @@ class PasswordView : public views::View, public views::ButtonListener { if (!error_msg_->parent()) { AddChildView(error_msg_); InvalidateLayout(); - parent_container_->Layout(); + GetWidget()->GetRootView()->Layout(); ScrollRectToVisible(error_msg_->bounds()); } connect_->SetEnabled(true); @@ -149,7 +147,7 @@ class PasswordView : public views::View, public views::ButtonListener { check_error_state); } - void OnConnectionSucceed() { Close(true); } + void OnConnectionSucceed() { CloseDialog(true); } // views::View: virtual void ViewHierarchyChanged( @@ -176,7 +174,7 @@ class PasswordView : public views::View, public views::ButtonListener { textfield_->text()), base::Bind(&PasswordView::OnKnownError, weak_ptr_.GetWeakPtr())); } else if (sender == cancel_) { - Close(false); + CloseDialog(false); } else { NOTREACHED(); } @@ -184,7 +182,6 @@ class PasswordView : public views::View, public views::ButtonListener { ui::NetworkInfo network_; base::Callback<void(bool)> callback_; - views::View* parent_container_; views::BlueButton* connect_; views::LabelButton* cancel_; @@ -199,8 +196,8 @@ class PasswordView : public views::View, public views::ButtonListener { // contains the View for taking password for password-protected networks. class NetworkRow : public views::View { public: - NetworkRow(const ui::NetworkInfo& network, views::View* container) - : network_(network), container_(container), weak_ptr_(this) { + NetworkRow(const ui::NetworkInfo& network) + : network_(network), weak_ptr_(this) { SetBorder(views::Border::CreateEmptyBorder(10, 5, 10, 5)); SetLayoutManager( new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 10)); @@ -230,7 +227,7 @@ class NetworkRow : public views::View { void OnPasswordComplete(bool successful) { password_view_.reset(); InvalidateLayout(); - container_->Layout(); + GetWidget()->GetRootView()->Layout(); ScrollRectToVisible(GetContentsBounds()); } @@ -249,12 +246,11 @@ class NetworkRow : public views::View { password_view_.reset(new PasswordView( network_, - base::Bind(&NetworkRow::OnPasswordComplete, weak_ptr_.GetWeakPtr()), - container_)); + base::Bind(&NetworkRow::OnPasswordComplete, weak_ptr_.GetWeakPtr()))); password_view_->set_owned_by_client(); AddChildView(password_view_.get()); PreferredSizeChanged(); - container_->Layout(); + GetWidget()->GetRootView()->Layout(); ScrollRectToVisible(password_view_->bounds()); } @@ -310,7 +306,6 @@ class NetworkRow : public views::View { } ui::NetworkInfo network_; - views::View* container_; scoped_ptr<views::View> password_view_; base::WeakPtrFactory<NetworkRow> weak_ptr_; @@ -319,15 +314,12 @@ class NetworkRow : public views::View { class NetworkSelector : public ui::NetworkListDelegate, public chromeos::NetworkStateHandlerObserver, - public ui::EventHandler { + public views::DialogDelegate { public: - explicit NetworkSelector(aura::Window* container) - : background_view_(NULL), - scroll_content_(NULL), - scroller_(NULL), - network_list_(this) { - CreateWidget(container); + NetworkSelector() + : scroll_content_(NULL), scroller_(NULL), network_list_(this) { CreateNetworkList(); + CreateWidget(); NetworkHandler::Get()->network_state_handler()->RequestScan(); NetworkHandler::Get()->network_state_handler()->AddObserver(this, @@ -340,36 +332,19 @@ class NetworkSelector : public ui::NetworkListDelegate, } private: - void CreateWidget(aura::Window* container) { - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.activatable = views::Widget::InitParams::ACTIVATABLE_DEFAULT; - params.accept_events = true; - params.bounds = gfx::Rect(container->bounds().size()); - params.parent = container; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget_.reset(new views::Widget()); - widget_->Init(params); - widget_->Show(); - - background_view_ = new views::View; - background_view_->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - background_view_->SetBorder( - views::Border::CreateEmptyBorder(100, 300, 300, 300)); - background_view_->SetLayoutManager(new views::FillLayout()); - background_view_->set_target_handler(this); - - widget_->SetContentsView(background_view_); + void CreateWidget() { + // Same as CreateDialogWidgetWithBounds() with an empty |bounds|. + views::Widget* widget = views::DialogDelegate::CreateDialogWidget( + this, athena::ScreenManager::Get()->GetContext(), NULL); + widget->Show(); + widget->CenterWindow(gfx::Size(400, 400)); } void CreateNetworkList() { - const int kListHeight = 500; + const int kListHeight = 400; scroller_ = new views::ScrollView(); scroller_->set_background( views::Background::CreateSolidBackground(SK_ColorWHITE)); - scroller_->SetBounds(0, 0, 400, kListHeight); scroll_content_ = new views::View; scroll_content_->SetLayoutManager( @@ -378,21 +353,16 @@ class NetworkSelector : public ui::NetworkListDelegate, scroller_->ClipHeightTo(kListHeight, kListHeight); scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false)); - background_view_->AddChildView(scroller_); - - background_view_->Layout(); network_list_.set_content_view(scroll_content_); } void UpdateNetworkList() { network_list_.UpdateNetworkList(); } - void Close() { delete this; } - // ui::NetworkListDelegate: virtual views::View* CreateViewForNetwork( const ui::NetworkInfo& info) override { - return new NetworkRow(info, background_view_); + return new NetworkRow(info); } virtual bool IsViewHovered(views::View* view) override { @@ -429,25 +399,19 @@ class NetworkSelector : public ui::NetworkListDelegate, virtual void NetworkPropertiesUpdated( const chromeos::NetworkState* network) override {} - // ui::EventHandler: - virtual void OnMouseEvent(ui::MouseEvent* mouse) override { - CHECK_EQ(background_view_, mouse->target()); - if (mouse->type() == ui::ET_MOUSE_PRESSED && !mouse->handled()) { - Close(); - mouse->SetHandled(); - } + // views::DialogDelegate: + virtual ui::ModalType GetModalType() const override { + return ui::MODAL_TYPE_SYSTEM; } - - virtual void OnGestureEvent(ui::GestureEvent* gesture) override { - CHECK_EQ(background_view_, gesture->target()); - if (gesture->type() == ui::ET_GESTURE_TAP && !gesture->handled()) { - Close(); - gesture->SetHandled(); - } + virtual void DeleteDelegate() override { delete this; } + virtual views::Widget* GetWidget() override { return scroller_->GetWidget(); } + virtual const views::Widget* GetWidget() const override { + return scroller_->GetWidget(); } + virtual views::View* GetContentsView() override { return scroller_; } + virtual int GetDialogButtons() const override { return ui::DIALOG_BUTTON_OK; } + virtual bool Close() override { return true; } - scoped_ptr<views::Widget> widget_; - views::View* background_view_; views::View* scroll_content_; views::ScrollView* scroller_; @@ -462,8 +426,8 @@ class NetworkSelector : public ui::NetworkListDelegate, namespace athena { -void CreateNetworkSelector(aura::Window* container) { - new NetworkSelector(container); +void CreateNetworkSelector() { + new NetworkSelector(); } } // namespace athena diff --git a/athena/system/network_selector.h b/athena/system/network_selector.h index 90aaf7f..01cf94b 100644 --- a/athena/system/network_selector.h +++ b/athena/system/network_selector.h @@ -5,13 +5,9 @@ #ifndef ATHENA_SYSTEM_NETWORK_SELECTOR_H_ #define ATHENA_SYSTEM_NETWORK_SELECTOR_H_ -namespace aura { -class Window; -} - namespace athena { -void CreateNetworkSelector(aura::Window* window); +void CreateNetworkSelector(); } // namespace athena diff --git a/athena/system/shutdown_dialog.cc b/athena/system/shutdown_dialog.cc index 865349e..d4648d7e 100644 --- a/athena/system/shutdown_dialog.cc +++ b/athena/system/shutdown_dialog.cc @@ -15,6 +15,7 @@ #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" namespace athena { namespace { @@ -23,10 +24,33 @@ namespace { // device after shutdown dialog is shown. const int kShutdownTimeoutMs = 4000; +class ModalWidgetDelegate : public views::WidgetDelegate { + public: + explicit ModalWidgetDelegate(views::View* contents_view) + : contents_view_(contents_view) {} + virtual ~ModalWidgetDelegate() {} + + // Overridden from WidgetDelegate: + virtual views::Widget* GetWidget() override { + return contents_view_->GetWidget(); + } + virtual const views::Widget* GetWidget() const override { + return contents_view_->GetWidget(); + } + virtual views::View* GetContentsView() override { return contents_view_; } + virtual ui::ModalType GetModalType() const override { + return ui::MODAL_TYPE_SYSTEM; + } + + private: + views::View* contents_view_; + + DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate); +}; + } // namespace -ShutdownDialog::ShutdownDialog(aura::Window* dialog_container) - : warning_message_container_(dialog_container), state_(STATE_OTHER) { +ShutdownDialog::ShutdownDialog() : state_(STATE_OTHER) { InputManager::Get()->AddPowerButtonObserver(this); } @@ -37,13 +61,6 @@ ShutdownDialog::~ShutdownDialog() { void ShutdownDialog::ShowShutdownWarningDialog() { state_ = STATE_SHUTDOWN_WARNING_VISIBLE; - shutdown_warning_message_.reset(new views::Widget); - - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = warning_message_container_; - shutdown_warning_message_->Init(params); - views::Label* label = new views::Label(l10n_util::GetStringUTF16(IDS_ATHENA_SHUTDOWN_WARNING)); label->SetBackgroundColor(SK_ColorWHITE); @@ -59,9 +76,18 @@ void ShutdownDialog::ShowShutdownWarningDialog() { views::Background::CreateSolidBackground(SK_ColorWHITE)); container->SetBorder(views::Border::CreateSolidBorder(1, SK_ColorBLACK)); - shutdown_warning_message_->SetContentsView(container); - shutdown_warning_message_->CenterWindow(container->GetPreferredSize()); + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.delegate = new ModalWidgetDelegate(container); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.context = ScreenManager::Get()->GetContext(); + // Use top most modal container. + params.keep_on_top = true; + + shutdown_warning_message_.reset(new views::Widget); + shutdown_warning_message_->Init(params); shutdown_warning_message_->Show(); + shutdown_warning_message_->CenterWindow(container->GetPreferredSize()); + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShutdownTimeoutMs), this, diff --git a/athena/system/shutdown_dialog.h b/athena/system/shutdown_dialog.h index bda5add..fb8d168 100644 --- a/athena/system/shutdown_dialog.h +++ b/athena/system/shutdown_dialog.h @@ -23,7 +23,7 @@ namespace athena { // Shuts down in response to the power button being pressed. class ShutdownDialog : public PowerButtonObserver { public: - explicit ShutdownDialog(aura::Window* dialog_container); + explicit ShutdownDialog(); virtual ~ShutdownDialog(); private: diff --git a/athena/system/status_icon_container_view.cc b/athena/system/status_icon_container_view.cc index 811c645c..a7c5f85 100644 --- a/athena/system/status_icon_container_view.cc +++ b/athena/system/status_icon_container_view.cc @@ -208,9 +208,7 @@ class StatusIconContainerView::UpdateStatus }; StatusIconContainerView::StatusIconContainerView( - SystemUI::ColorScheme color_scheme, - aura::Window* system_modal_container) - : system_modal_container_(system_modal_container) { + SystemUI::ColorScheme color_scheme) { const int kHorizontalSpacing = 10; const int kVerticalSpacing = 3; const int kBetweenChildSpacing = 10; @@ -241,13 +239,13 @@ StatusIconContainerView::~StatusIconContainerView() { } bool StatusIconContainerView::OnMousePressed(const ui::MouseEvent& event) { - CreateNetworkSelector(system_modal_container_); + CreateNetworkSelector(); return true; } void StatusIconContainerView::OnGestureEvent(ui::GestureEvent* event) { if (event->type() == ui::ET_GESTURE_TAP) { - CreateNetworkSelector(system_modal_container_); + CreateNetworkSelector(); event->SetHandled(); } } diff --git a/athena/system/status_icon_container_view.h b/athena/system/status_icon_container_view.h index ec60488..6e77b49 100644 --- a/athena/system/status_icon_container_view.h +++ b/athena/system/status_icon_container_view.h @@ -9,17 +9,12 @@ #include "base/memory/scoped_ptr.h" #include "ui/views/view.h" -namespace aura { -class Window; -} - namespace athena { // View which displays the system tray icons. class StatusIconContainerView : public views::View { public: - StatusIconContainerView(SystemUI::ColorScheme color_scheme, - aura::Window* popup_container); + StatusIconContainerView(SystemUI::ColorScheme color_scheme); virtual ~StatusIconContainerView(); private: @@ -28,9 +23,6 @@ class StatusIconContainerView : public views::View { virtual void OnGestureEvent(ui::GestureEvent* event) override; virtual void ChildPreferredSizeChanged(views::View* child) override; - // Parent container that the "select network" dialog should use. - aura::Window* system_modal_container_; - class PowerStatus; scoped_ptr<PowerStatus> power_status_; diff --git a/athena/system/system_ui_impl.cc b/athena/system/system_ui_impl.cc index 353a45b..64653ba 100644 --- a/athena/system/system_ui_impl.cc +++ b/athena/system/system_ui_impl.cc @@ -27,11 +27,9 @@ SystemUI* instance = NULL; // right. class SystemInfoView : public views::View { public: - SystemInfoView(SystemUI::ColorScheme color_scheme, - aura::Window* system_modal_container) + SystemInfoView(SystemUI::ColorScheme color_scheme) : time_view_(new TimeView(color_scheme)), - status_icon_view_( - new StatusIconContainerView(color_scheme, system_modal_container)) { + status_icon_view_(new StatusIconContainerView(color_scheme)) { AddChildView(time_view_); AddChildView(status_icon_view_); } @@ -76,8 +74,7 @@ class SystemUIImpl : public SystemUI { public: SystemUIImpl(scoped_refptr<base::TaskRunner> blocking_task_runner) : orientation_controller_(new OrientationController()), - background_container_(NULL), - system_modal_container_(NULL) { + background_container_(NULL) { orientation_controller_->InitWith(blocking_task_runner); } @@ -93,34 +90,22 @@ class SystemUIImpl : public SystemUI { ScreenManager::ContainerParams("AthenaBackground", CP_BACKGROUND)); background_container_->SetLayoutManager( new FillLayoutManager(background_container_)); - ScreenManager::ContainerParams system_modal_params( - "AthenaSystemModalContainer", CP_SYSTEM_MODAL); - system_modal_params.can_activate_children = true; - system_modal_container_ = - screen_manager->CreateContainer(system_modal_params); - login_screen_system_modal_container_ = screen_manager->CreateContainer( - ScreenManager::ContainerParams("AthenaLoginScreenSystemModalContainer", - CP_LOGIN_SCREEN_SYSTEM_MODAL)); - - // Use |login_screen_system_modal_container_| for the power button's dialog - // because it needs to show over the login screen. - // TODO(pkotwicz): Pick the most appropriate container based on whether the - // user has logged in. - shutdown_dialog_.reset( - new ShutdownDialog(login_screen_system_modal_container_)); + + shutdown_dialog_.reset(new ShutdownDialog()); background_controller_.reset( new BackgroundController(background_container_)); } + private: + // SystemUI: virtual void SetBackgroundImage(const gfx::ImageSkia& image) override { background_controller_->SetImage(image); } virtual views::View* CreateSystemInfoView(ColorScheme color_scheme) override { - return new SystemInfoView(color_scheme, system_modal_container_); + return new SystemInfoView(color_scheme); } - private: scoped_ptr<OrientationController> orientation_controller_; scoped_ptr<ShutdownDialog> shutdown_dialog_; scoped_ptr<BackgroundController> background_controller_; diff --git a/athena/test/DEPS b/athena/test/DEPS index 9fc07db..39df6ee 100644 --- a/athena/test/DEPS +++ b/athena/test/DEPS @@ -16,6 +16,6 @@ include_rules = [ "+ui/gfx", "+ui/gl", "+ui/views", - "+ui/wm/core", + "+ui/wm", ] diff --git a/athena/test/base/athena_test_base.cc b/athena/test/base/athena_test_base.cc index a6f88b1..180baea 100644 --- a/athena/test/base/athena_test_base.cc +++ b/athena/test/base/athena_test_base.cc @@ -5,11 +5,8 @@ #include "athena/test/base/athena_test_base.h" #include "athena/env/public/athena_env.h" -#include "athena/screen/public/screen_manager.h" #include "athena/test/base/athena_test_helper.h" -#include "ui/aura/client/window_tree_client.h" #include "ui/aura/test/event_generator_delegate_aura.h" -#include "ui/aura/window.h" #include "ui/compositor/test/context_factories_for_test.h" #if defined(USE_X11) @@ -65,16 +62,5 @@ void AthenaTestBase::RunAllPendingInMessageLoop() { helper_->RunAllPendingInMessageLoop(); } -scoped_ptr<aura::Window> AthenaTestBase::CreateTestWindow( - aura::WindowDelegate* delegate, - const gfx::Rect& bounds) { - scoped_ptr<aura::Window> window(new aura::Window(delegate)); - window->SetType(ui::wm::WINDOW_TYPE_NORMAL); - window->Init(aura::WINDOW_LAYER_SOLID_COLOR); - aura::client::ParentWindowWithContext( - window.get(), ScreenManager::Get()->GetContext(), bounds); - return window.Pass(); -} - } // namespace test } // namespace athena diff --git a/athena/test/base/athena_test_base.h b/athena/test/base/athena_test_base.h index 1ca1cd8..f1abab0 100644 --- a/athena/test/base/athena_test_base.h +++ b/athena/test/base/athena_test_base.h @@ -31,9 +31,6 @@ class AthenaTestBase : public testing::Test { protected: void RunAllPendingInMessageLoop(); - scoped_ptr<aura::Window> CreateTestWindow(aura::WindowDelegate* delegate, - const gfx::Rect& bounds); - aura::Window* root_window() { return helper_->GetRootWindow(); } aura::WindowTreeHost* host() { return helper_->GetHost(); } diff --git a/athena/test/base/test_windows.cc b/athena/test/base/test_windows.cc new file mode 100644 index 0000000..9559b85 --- /dev/null +++ b/athena/test/base/test_windows.cc @@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "athena/test/base/test_windows.h" + +#include "athena/screen/public/screen_manager.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/window_tree_client.h" +#include "ui/aura/window.h" +#include "ui/wm/core/window_util.h" + +namespace athena { +namespace test { + +scoped_ptr<aura::Window> CreateNormalWindow(aura::WindowDelegate* delegate, + aura::Window* parent) { + return CreateWindowWithType(delegate, parent, ui::wm::WINDOW_TYPE_NORMAL); +} + +scoped_ptr<aura::Window> CreateWindowWithType(aura::WindowDelegate* delegate, + aura::Window* parent, + ui::wm::WindowType window_type) { + scoped_ptr<aura::Window> window(new aura::Window(delegate)); + window->SetType(window_type); + window->Init(aura::WINDOW_LAYER_SOLID_COLOR); + if (parent) { + parent->AddChild(window.get()); + } else { + aura::client::ParentWindowWithContext( + window.get(), ScreenManager::Get()->GetContext(), gfx::Rect()); + } + return window.Pass(); +} + +scoped_ptr<aura::Window> CreateTransientWindow(aura::WindowDelegate* delegate, + aura::Window* transient_parent, + ui::ModalType modal_type, + bool top_most) { + scoped_ptr<aura::Window> window(new aura::Window(delegate)); + window->SetType(ui::wm::WINDOW_TYPE_NORMAL); + window->Init(aura::WINDOW_LAYER_SOLID_COLOR); + window->SetProperty(aura::client::kModalKey, modal_type); + window->SetProperty(aura::client::kAlwaysOnTopKey, top_most); + if (transient_parent) + wm::AddTransientChild(transient_parent, window.get()); + aura::client::ParentWindowWithContext( + window.get(), ScreenManager::Get()->GetContext(), gfx::Rect()); + return window.Pass(); +} + +} // namespace test +} // namespace athena diff --git a/athena/test/base/test_windows.h b/athena/test/base/test_windows.h new file mode 100644 index 0000000..86d49bf --- /dev/null +++ b/athena/test/base/test_windows.h @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATHENA_TEST_BASE_TEST_WINDOWS_H_ +#define ATHENA_TEST_BASE_TEST_WINDOWS_H_ + +#include "base/memory/scoped_ptr.h" +#include "ui/base/ui_base_types.h" +#include "ui/wm/public/window_types.h" + +namespace aura { +class Window; +class WindowDelegate; +} + +namespace gfx { +class Rect; +} + +namespace athena { +namespace test { + +scoped_ptr<aura::Window> CreateNormalWindow(aura::WindowDelegate* delegate, + aura::Window* parent); + +scoped_ptr<aura::Window> CreateWindowWithType(aura::WindowDelegate* delegate, + aura::Window* parent, + ui::wm::WindowType window_type); + +scoped_ptr<aura::Window> CreateTransientWindow(aura::WindowDelegate* delegate, + aura::Window* transient_parent, + ui::ModalType modal_type, + bool top_most); + +} // namespace test +} // namespace athena + +#endif // ATHENA_TEST_BASE_TEST_WINDOWS_H_ diff --git a/athena/util/container_priorities.h b/athena/util/container_priorities.h index 33b687d..8b30300 100644 --- a/athena/util/container_priorities.h +++ b/athena/util/container_priorities.h @@ -12,9 +12,11 @@ enum ContainerPriorities { CP_DEFAULT, CP_HOME_CARD, CP_SYSTEM_MODAL, + // TODO(oshima): rename LOGIN_xxx to something more generic. CP_LOGIN_SCREEN, CP_LOGIN_SCREEN_SYSTEM_MODAL, CP_VIRTUAL_KEYBOARD, + CP_END, }; } // namespace athena diff --git a/athena/wm/split_view_controller_unittest.cc b/athena/wm/split_view_controller_unittest.cc index 91e7ee5..c90a3cf 100644 --- a/athena/wm/split_view_controller_unittest.cc +++ b/athena/wm/split_view_controller_unittest.cc @@ -6,6 +6,7 @@ #include "athena/screen/public/screen_manager.h" #include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" #include "athena/wm/public/window_list_provider.h" #include "athena/wm/test/window_manager_impl_test_api.h" #include "base/memory/scoped_vector.h" @@ -102,7 +103,7 @@ TEST_F(SplitViewControllerTest, SplitModeActivation) { ScopedVector<aura::Window> windows; const int kNumWindows = 6; for (size_t i = 0; i < kNumWindows; ++i) { - scoped_ptr<aura::Window> window = CreateTestWindow(NULL, gfx::Rect()); + scoped_ptr<aura::Window> window = test::CreateNormalWindow(NULL, NULL); windows.push_back(window.release()); windows[i]->Hide(); } @@ -194,7 +195,7 @@ TEST_F(SplitViewControllerTest, ScrollDragHandle) { ScopedVector<aura::Window> windows; const int kNumWindows = 2; for (size_t i = 0; i < kNumWindows; ++i) { - scoped_ptr<aura::Window> window = CreateTestWindow(NULL, gfx::Rect()); + scoped_ptr<aura::Window> window = test::CreateNormalWindow(NULL, NULL); windows.push_back(window.release()); windows[i]->Hide(); } @@ -290,7 +291,7 @@ TEST_F(SplitViewControllerTest, LandscapeOnly) { ScopedVector<aura::Window> windows; const int kNumWindows = 2; for (size_t i = 0; i < kNumWindows; ++i) { - scoped_ptr<aura::Window> window = CreateTestWindow(NULL, gfx::Rect()); + scoped_ptr<aura::Window> window = test::CreateNormalWindow(NULL, NULL); window->Hide(); windows.push_back(window.release()); } diff --git a/athena/wm/window_list_provider_impl_unittest.cc b/athena/wm/window_list_provider_impl_unittest.cc index 5b03d2d..d3dd285 100644 --- a/athena/wm/window_list_provider_impl_unittest.cc +++ b/athena/wm/window_list_provider_impl_unittest.cc @@ -8,6 +8,7 @@ #include "athena/screen/public/screen_manager.h" #include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" #include "athena/wm/public/window_list_provider_observer.h" #include "athena/wm/public/window_manager.h" #include "ui/aura/client/window_tree_client.h" @@ -36,18 +37,6 @@ scoped_ptr<aura::Window> CreateWindow(aura::Window* parent, return window.Pass(); } -scoped_ptr<aura::Window> CreateTransientWindow(aura::Window* transient_parent, - aura::WindowDelegate* delegate, - ui::wm::WindowType window_type) { - scoped_ptr<aura::Window> window(new aura::Window(delegate)); - window->SetType(window_type); - window->Init(aura::WINDOW_LAYER_SOLID_COLOR); - wm::AddTransientChild(transient_parent, window.get()); - aura::client::ParentWindowWithContext( - window.get(), ScreenManager::Get()->GetContext(), gfx::Rect()); - return window.Pass(); -} - // Return a string which defines the order of windows in |now| using the indices // of |original|. The string will then have the lowest/oldest window on the left // and the highest / newest on the right. @@ -116,8 +105,8 @@ TEST_F(WindowListProviderImplTest, StackingOrder) { scoped_ptr<WindowListProvider> list_provider( new WindowListProviderImpl(container.get())); - scoped_ptr<aura::Window> first = - CreateWindow(container.get(), &delegate, ui::wm::WINDOW_TYPE_NORMAL); + scoped_ptr<aura::Window> first = test::CreateWindowWithType( + &delegate, container.get(), ui::wm::WINDOW_TYPE_NORMAL); scoped_ptr<aura::Window> second = CreateWindow(container.get(), &delegate, ui::wm::WINDOW_TYPE_NORMAL); scoped_ptr<aura::Window> third = @@ -307,12 +296,12 @@ TEST_F(WindowListProviderImplTest, TransientWindows) { scoped_ptr<WindowListObserver> observer( new WindowListObserver(list_provider)); - scoped_ptr<aura::Window> w1 = CreateTestWindow(&delegate, gfx::Rect()); + scoped_ptr<aura::Window> w1 = test::CreateNormalWindow(&delegate, NULL); w1->Show(); - scoped_ptr<aura::Window> w2 = CreateTestWindow(&delegate, gfx::Rect()); + scoped_ptr<aura::Window> w2 = test::CreateNormalWindow(&delegate, NULL); w2->Show(); - scoped_ptr<aura::Window> t1 = - CreateTransientWindow(w1.get(), &delegate, ui::wm::WINDOW_TYPE_NORMAL); + scoped_ptr<aura::Window> t1 = test::CreateTransientWindow( + &delegate, w1.get(), ui::MODAL_TYPE_NONE, false); t1->Show(); EXPECT_EQ(2u, list_provider->GetWindowList().size()); diff --git a/athena/wm/window_manager_impl.cc b/athena/wm/window_manager_impl.cc index 3e6e390..f0020c4 100644 --- a/athena/wm/window_manager_impl.cc +++ b/athena/wm/window_manager_impl.cc @@ -150,7 +150,9 @@ void AthenaContainerLayoutManager::SetChildBounds( WindowManagerImpl::WindowManagerImpl() { ScreenManager::ContainerParams params("DefaultContainer", CP_DEFAULT); params.can_activate_children = true; - container_.reset(ScreenManager::Get()->CreateDefaultContainer(params)); + params.default_parent = true; + params.modal_container_priority = CP_SYSTEM_MODAL; + container_.reset(ScreenManager::Get()->CreateContainer(params)); container_->SetLayoutManager(new AthenaContainerLayoutManager); container_->AddObserver(this); window_list_provider_.reset(new WindowListProviderImpl(container_.get())); @@ -164,6 +166,8 @@ WindowManagerImpl::WindowManagerImpl() { wm_state_.reset(new wm::WMState()); aura::client::ActivationClient* activation_client = aura::client::GetActivationClient(container_->GetRootWindow()); + DCHECK(container_->GetRootWindow()); + DCHECK(activation_client); shadow_controller_.reset(new wm::ShadowController(activation_client)); instance = this; InstallAccelerators(); diff --git a/athena/wm/window_manager_unittest.cc b/athena/wm/window_manager_unittest.cc index 7adda80..9cbedaa 100644 --- a/athena/wm/window_manager_unittest.cc +++ b/athena/wm/window_manager_unittest.cc @@ -6,6 +6,7 @@ #include "athena/screen/public/screen_manager.h" #include "athena/test/base/athena_test_base.h" +#include "athena/test/base/test_windows.h" #include "athena/wm/public/window_list_provider.h" #include "athena/wm/split_view_controller.h" #include "athena/wm/test/window_manager_impl_test_api.h" @@ -28,7 +29,7 @@ class WindowManagerTest : public test::AthenaTestBase { scoped_ptr<aura::Window> CreateAndActivateWindow( aura::WindowDelegate* delegate) { - scoped_ptr<aura::Window> window(CreateTestWindow(delegate, gfx::Rect())); + scoped_ptr<aura::Window> window(test::CreateNormalWindow(delegate, NULL)); window->Show(); wm::ActivateWindow(window.get()); return window.Pass(); |