diff options
-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 |