diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-02 23:17:06 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-02 23:17:06 +0000 |
commit | 8a698cedf44eaba88fbbb727ea1eaa32cbced8b7 (patch) | |
tree | 15c0f84e1ed80eb71e1ba04e5b00a979f5719165 | |
parent | 224a8ebfccc24b073455a92c41fd25d65a6b9d75 (diff) | |
download | chromium_src-8a698cedf44eaba88fbbb727ea1eaa32cbced8b7.zip chromium_src-8a698cedf44eaba88fbbb727ea1eaa32cbced8b7.tar.gz chromium_src-8a698cedf44eaba88fbbb727ea1eaa32cbced8b7.tar.bz2 |
Ensure that in Desktop AURA the WindowModalityController class is at the head of the event pre target handlers list.
This ensures that it handles input events first when modal windows are at the top of the Zorder.
This logic has been added to the DesktopNativeWidgetAura::InstallWindowModalityController function which is called by the
DesktopRootWindowHost implementations on windows and linux when the root window is created.
The logic in ash shell.cc has also been changed to instantiate the WindowModalityController object at the beginning. The
class WindowModalityController now takes the EventTarget as an argument in its ctor and adds itself to the pre target
list. Added a DCHECK here to check if the pre target list in the EventTarget is empty. The WindowModalityController removes
itself from the pre target list in its dtor.
BUG=299662
R=sky@chromium.org, sky
TEST=Covered by Desktop AURA widget test WindowMouseModalityTest
Review URL: https://codereview.chromium.org/25445002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226609 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/shell.cc | 15 | ||||
-rw-r--r-- | ui/events/event_target.cc | 4 | ||||
-rw-r--r-- | ui/events/event_target.h | 3 | ||||
-rw-r--r-- | ui/views/corewm/window_modality_controller.cc | 8 | ||||
-rw-r--r-- | ui/views/corewm/window_modality_controller.h | 5 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_native_widget_aura.cc | 29 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_native_widget_aura.h | 8 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_win.cc | 1 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc | 1 | ||||
-rw-r--r-- | ui/views/widget/widget_unittest.cc | 89 |
10 files changed, 145 insertions, 18 deletions
diff --git a/ash/shell.cc b/ash/shell.cc index bea797a..5b337e7 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -192,7 +192,6 @@ Shell::Shell(ShellDelegate* delegate) // messages don't have a target window. base::MessagePumpX11::Current()->AddObserver(output_configurator()); #endif // defined(OS_CHROMEOS) - AddPreTargetHandler(this); #if defined(OS_CHROMEOS) internal::PowerStatus::Initialize(); @@ -210,11 +209,12 @@ Shell::~Shell() { aura::client::GetFocusClient(GetPrimaryRootWindow())->FocusWindow(NULL); // Please keep in same order as in Init() because it's easy to miss one. + if (window_modality_controller_) + window_modality_controller_.reset(); RemovePreTargetHandler(event_rewriter_filter_.get()); RemovePreTargetHandler(user_activity_detector_.get()); RemovePreTargetHandler(overlay_filter_.get()); RemovePreTargetHandler(input_method_filter_.get()); - RemovePreTargetHandler(window_modality_controller_.get()); if (mouse_cursor_filter_) RemovePreTargetHandler(mouse_cursor_filter_.get()); RemovePreTargetHandler(system_gesture_filter_.get()); @@ -427,6 +427,14 @@ void Shell::Init() { // Launcher, and WallPaper could be created by the factory. views::FocusManagerFactory::Install(new AshFocusManagerFactory); + // The WindowModalityController needs to be at the front of the input event + // pretarget handler list to ensure that it processes input events when modal + // windows are active. + window_modality_controller_.reset( + new views::corewm::WindowModalityController(this)); + + AddPreTargetHandler(this); + env_filter_.reset(new views::corewm::CompoundEventFilter); AddPreTargetHandler(env_filter_.get()); @@ -505,9 +513,6 @@ void Shell::Init() { // RootWindowController as possible. visibility_controller_.reset(new AshVisibilityController); user_action_client_.reset(delegate_->CreateUserActionClient()); - window_modality_controller_.reset( - new views::corewm::WindowModalityController); - AddPreTargetHandler(window_modality_controller_.get()); magnification_controller_.reset( MagnificationController::CreateInstance()); diff --git a/ui/events/event_target.cc b/ui/events/event_target.cc index 9aa53902..56b7a16 100644 --- a/ui/events/event_target.cc +++ b/ui/events/event_target.cc @@ -48,6 +48,10 @@ void EventTarget::RemovePostTargetHandler(EventHandler* handler) { post_target_list_.erase(find); } +bool EventTarget::IsPreTargetListEmpty() const { + return pre_target_list_.empty(); +} + void EventTarget::OnEvent(Event* event) { CHECK_EQ(this, event->target()); if (target_handler_) diff --git a/ui/events/event_target.h b/ui/events/event_target.h index 39671e2..12dbb35 100644 --- a/ui/events/event_target.h +++ b/ui/events/event_target.h @@ -70,6 +70,9 @@ class EVENTS_EXPORT EventTarget : public EventHandler { void AddPostTargetHandler(EventHandler* handler); void RemovePostTargetHandler(EventHandler* handler); + // Returns true if the event pre target list is empty. + bool IsPreTargetListEmpty() const; + protected: void set_target_handler(EventHandler* handler) { target_handler_ = handler; diff --git a/ui/views/corewm/window_modality_controller.cc b/ui/views/corewm/window_modality_controller.cc index 8a3a7ff..e177b88 100644 --- a/ui/views/corewm/window_modality_controller.cc +++ b/ui/views/corewm/window_modality_controller.cc @@ -14,6 +14,7 @@ #include "ui/aura/window_property.h" #include "ui/base/ui_base_types.h" #include "ui/events/event.h" +#include "ui/events/event_target.h" #include "ui/views/corewm/window_animations.h" #include "ui/views/corewm/window_util.h" @@ -95,11 +96,16 @@ aura::Window* GetModalTransient(aura::Window* window) { //////////////////////////////////////////////////////////////////////////////// // WindowModalityController, public: -WindowModalityController::WindowModalityController() { +WindowModalityController::WindowModalityController( + ui::EventTarget* event_target) + : event_target_(event_target) { aura::Env::GetInstance()->AddObserver(this); + DCHECK(event_target->IsPreTargetListEmpty()); + event_target_->AddPreTargetHandler(this); } WindowModalityController::~WindowModalityController() { + event_target_->RemovePreTargetHandler(this); aura::Env::GetInstance()->RemoveObserver(this); for (size_t i = 0; i < windows_.size(); ++i) windows_[i]->RemoveObserver(this); diff --git a/ui/views/corewm/window_modality_controller.h b/ui/views/corewm/window_modality_controller.h index 07fe308..88150a5 100644 --- a/ui/views/corewm/window_modality_controller.h +++ b/ui/views/corewm/window_modality_controller.h @@ -14,6 +14,7 @@ #include "ui/views/views_export.h" namespace ui { +class EventTarget; class LocatedEvent; } @@ -34,7 +35,7 @@ class VIEWS_EXPORT WindowModalityController : public ui::EventHandler, public aura::EnvObserver, public aura::WindowObserver { public: - WindowModalityController(); + explicit WindowModalityController(ui::EventTarget* event_target); virtual ~WindowModalityController(); // Overridden from ui::EventHandler: @@ -61,6 +62,8 @@ class VIEWS_EXPORT WindowModalityController : public ui::EventHandler, std::vector<aura::Window*> windows_; + ui::EventTarget* event_target_; + DISALLOW_COPY_AND_ASSIGN(WindowModalityController); }; diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 629c196..d401511 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -185,7 +185,8 @@ DesktopNativeWidgetAura::DesktopNativeWidgetAura( native_widget_delegate_(delegate), last_drop_operation_(ui::DragDropTypes::DRAG_NONE), restore_focus_on_activate_(false), - cursor_(gfx::kNullCursor) { + cursor_(gfx::kNullCursor), + widget_type_(Widget::InitParams::TYPE_WINDOW) { window_->SetProperty(kDesktopNativeWidgetAuraKey, this); aura::client::SetFocusChangeObserver(window_, this); aura::client::SetActivationChangeObserver(window_, this); @@ -208,6 +209,11 @@ void DesktopNativeWidgetAura::OnHostClosed() { // Don't invoke Widget::OnNativeWidgetDestroying(), its done by // DesktopRootWindowHost. + // The WindowModalityController is at the front of the event pretarget + // handler list. We destroy it first to preserve order symantics. + if (window_modality_controller_) + window_modality_controller_.reset(); + // Make sure we don't still have capture. Otherwise CaptureController and // RootWindow are left referencing a deleted Window. { @@ -222,10 +228,6 @@ void DesktopNativeWidgetAura::OnHostClosed() { shadow_controller_.reset(); tooltip_manager_.reset(); scoped_tooltip_client_.reset(); - if (window_modality_controller_) { - root_window_->RemovePreTargetHandler(window_modality_controller_.get()); - window_modality_controller_.reset(); - } root_window_event_filter_->RemoveHandler(input_method_event_filter_.get()); @@ -296,12 +298,23 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) { } } +void DesktopNativeWidgetAura::InstallWindowModalityController( + aura::RootWindow* root) { + // The WindowsModalityController event filter should be at the head of the + // pre target handlers list. This ensures that it handles input events first + // when modal windows are at the top of the Zorder. + if (widget_type_ == Widget::InitParams::TYPE_WINDOW) + window_modality_controller_.reset( + new views::corewm::WindowModalityController(root)); +} + //////////////////////////////////////////////////////////////////////////////// // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation: void DesktopNativeWidgetAura::InitNativeWidget( const Widget::InitParams& params) { ownership_ = params.ownership; + widget_type_ = params.type; NativeWidgetAura::RegisterNativeWidgetForWindow(this, window_); // Animations on TYPE_WINDOW are handled by the OS. Additionally if we animate @@ -354,12 +367,6 @@ void DesktopNativeWidgetAura::InitNativeWidget( GetNativeView()->GetRootWindow()); } - if (params.type == Widget::InitParams::TYPE_WINDOW) { - window_modality_controller_.reset( - new views::corewm::WindowModalityController); - root_window_->AddPreTargetHandler(window_modality_controller_.get()); - } - window_->Show(); desktop_root_window_host_->InitFocus(window_); diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index ec7a640..023e3db 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -81,6 +81,11 @@ class VIEWS_EXPORT DesktopNativeWidgetAura // we are being activated/deactivated. void HandleActivationChanged(bool active); + // Installs the window modality controller event filter on the |root|. This + // should be invoked by the DesktopRootWindowHost implementation immediately + // after creation of the RootWindow. + void InstallWindowModalityController(aura::RootWindow* root); + protected: // Overridden from internal::NativeWidgetPrivate: virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE; @@ -286,6 +291,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura // order of the associated views in the widget's view hierarchy. scoped_ptr<WindowReorderer> window_reorderer_; + // See class documentation for Widget in widget.h for a note about type. + Widget::InitParams::Type widget_type_; + DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAura); }; diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc index 0e687a4..4cedc42 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc @@ -123,6 +123,7 @@ aura::RootWindow* DesktopRootWindowHostWin::Init( root_window_->Init(); root_window_->AddChild(content_window_); + desktop_native_widget_aura_->InstallWindowModalityController(root_window_); desktop_native_widget_aura_->CreateCaptureClient(root_window_); corewm::FocusController* focus_controller = diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc index 26cd311..277f5f9 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc @@ -932,6 +932,7 @@ aura::RootWindow* DesktopRootWindowHostX11::InitRootWindow( native_widget_delegate_->OnNativeWidgetCreated(true); + desktop_native_widget_aura_->InstallWindowModalityController(root_window_); desktop_native_widget_aura_->CreateCaptureClient(root_window_); // Ensure that the X11DesktopHandler exists so that it dispatches activation diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index 05f36a9..5cdaffc 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc @@ -22,6 +22,7 @@ #include "ui/views/views_delegate.h" #include "ui/views/widget/native_widget_delegate.h" #include "ui/views/widget/root_view.h" +#include "ui/views/window/dialog_delegate.h" #include "ui/views/window/native_frame_view.h" #if defined(USE_AURA) @@ -1966,5 +1967,93 @@ TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) { RunDestroyChildWidgetsTest(false, false); } +#if defined(USE_AURA) && !defined(OS_CHROMEOS) +// Provides functionality to create a window modal dialog. +class ModalDialogDelegate : public DialogDelegateView { + public: + ModalDialogDelegate() {} + virtual ~ModalDialogDelegate() {} + + // WidgetDelegate overrides. + virtual ui::ModalType GetModalType() const OVERRIDE { + return ui::MODAL_TYPE_WINDOW; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate); +}; + +// This test verifies that whether mouse events when a modal dialog is +// displayed are eaten or recieved by the dialog. +TEST_F(WidgetTest, WindowMouseModalityTest) { + // Create a top level widget. + Widget top_level_widget; + Widget::InitParams init_params = + CreateParams(Widget::InitParams::TYPE_WINDOW); + init_params.show_state = ui::SHOW_STATE_NORMAL; + gfx::Rect initial_bounds(0, 0, 500, 500); + init_params.bounds = initial_bounds; + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget); + top_level_widget.Init(init_params); + top_level_widget.Show(); + EXPECT_TRUE(top_level_widget.IsVisible()); + + // Create a view and validate that a mouse moves makes it to the view. + EventCountView* widget_view = new EventCountView(); + widget_view->SetBounds(0, 0, 10, 10); + top_level_widget.GetRootView()->AddChildView(widget_view); + + gfx::Point cursor_location_main(5, 5); + ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, + cursor_location_main, + cursor_location_main, + ui::EF_NONE); + top_level_widget.GetNativeView()->GetRootWindow()-> + AsRootWindowHostDelegate()->OnHostMouseEvent(&move_main); + + EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED)); + widget_view->ResetCounts(); + + // Create a modal dialog and validate that a mouse down message makes it to + // the main view within the dialog. + + // This instance will be destroyed when the dialog is destroyed. + ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; + + Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( + dialog_delegate, NULL, top_level_widget.GetNativeWindow()); + modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); + EventCountView* dialog_widget_view = new EventCountView(); + dialog_widget_view->SetBounds(0, 0, 50, 50); + modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view); + modal_dialog_widget->Show(); + EXPECT_TRUE(modal_dialog_widget->IsVisible()); + + gfx::Point cursor_location_dialog(100, 100); + ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED, + cursor_location_dialog, + cursor_location_dialog, + ui::EF_NONE); + top_level_widget.GetNativeView()->GetRootWindow()-> + AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_dialog); + EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED)); + + // Send a mouse move message to the main window. It should not be received by + // the main window as the modal dialog is still active. + gfx::Point cursor_location_main2(6, 6); + ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, + cursor_location_main2, + cursor_location_main2, + ui::EF_NONE); + top_level_widget.GetNativeView()->GetRootWindow()-> + AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_main); + EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED)); + + modal_dialog_widget->CloseNow(); + top_level_widget.CloseNow(); +} +#endif + } // namespace test } // namespace views |