summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/shell.cc15
-rw-r--r--ui/events/event_target.cc4
-rw-r--r--ui/events/event_target.h3
-rw-r--r--ui/views/corewm/window_modality_controller.cc8
-rw-r--r--ui/views/corewm/window_modality_controller.h5
-rw-r--r--ui/views/widget/desktop_aura/desktop_native_widget_aura.cc29
-rw-r--r--ui/views/widget/desktop_aura/desktop_native_widget_aura.h8
-rw-r--r--ui/views/widget/desktop_aura/desktop_root_window_host_win.cc1
-rw-r--r--ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc1
-rw-r--r--ui/views/widget/widget_unittest.cc89
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