Index: ui/views/controls/menu/menu_host.cc |
diff --git a/ui/views/controls/menu/menu_host.cc b/ui/views/controls/menu/menu_host.cc |
index 9840abbdf0f650848ddac72fd05b68470f8eb1bf..d07d1efcc758ffbfc90ad68b9ed5f31d86a7b8c9 100644 |
--- a/ui/views/controls/menu/menu_host.cc |
+++ b/ui/views/controls/menu/menu_host.cc |
@@ -5,8 +5,10 @@ |
#include "ui/views/controls/menu/menu_host.h" |
#include "base/auto_reset.h" |
+#include "base/logging.h" |
#include "base/trace_event/trace_event.h" |
#include "build/build_config.h" |
+#include "ui/aura/window_observer.h" |
#include "ui/events/gestures/gesture_recognizer.h" |
#include "ui/gfx/path.h" |
#include "ui/native_theme/native_theme.h" |
@@ -19,8 +21,67 @@ |
#include "ui/views/widget/native_widget_private.h" |
#include "ui/views/widget/widget.h" |
+#if !defined(OS_MACOSX) |
+#include "ui/aura/window.h" |
+#endif |
+ |
namespace views { |
+namespace internal { |
+ |
+#if !defined(OS_MACOSX) |
+// This class adds itself as the pre target handler for the |window| |
+// passed in. It currently handles touch events and forwards them to the |
+// controller. Reason for this approach is views does not get raw touch |
+// events which we need to determine if a touch happened outside the bounds |
+// of the menu. |
+class PreMenuEventDispatchHandler : public ui::EventHandler, |
+ aura::WindowObserver { |
+ public: |
+ PreMenuEventDispatchHandler(const MenuController* controller, |
+ SubmenuView* submenu, |
+ aura::Window* window) |
+ : menu_controller_(const_cast<MenuController*>(controller)), |
+ submenu_(submenu), |
+ window_(window) { |
+ window_->AddPreTargetHandler(this); |
+ window_->AddObserver(this); |
+ } |
+ |
+ ~PreMenuEventDispatchHandler() override { |
+ StopObserving(); |
+ } |
+ |
+ // ui::EventHandler overrides. |
+ void OnTouchEvent(ui::TouchEvent* event) override { |
+ menu_controller_->OnTouchEvent(submenu_, event); |
+ } |
+ |
+ // aura::WindowObserver overrides. |
+ void OnWindowDestroying(aura::Window* window) override { |
+ DCHECK(window_ == window); |
+ StopObserving(); |
+ } |
+ |
+ private: |
+ void StopObserving() { |
+ if (!window_) |
+ return; |
+ window_->RemovePreTargetHandler(this); |
+ window_->RemoveObserver(this); |
+ window_ = nullptr; |
+ } |
+ |
+ MenuController* menu_controller_; |
+ SubmenuView* submenu_; |
+ aura::Window* window_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PreMenuEventDispatchHandler); |
+}; |
+#endif // OS_MACOSX |
+ |
+} // namespace internal |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// MenuHost, public: |
@@ -61,6 +122,11 @@ void MenuHost::InitMenuHost(Widget* parent, |
#endif |
Init(params); |
+#if !defined(OS_MACOSX) |
+ pre_dispatch_handler_.reset(new internal::PreMenuEventDispatchHandler( |
+ menu_controller, submenu_, GetNativeView())); |
+#endif |
+ |
SetContentsView(contents_view); |
ShowMenuHost(do_capture); |
} |
@@ -93,6 +159,9 @@ void MenuHost::DestroyMenuHost() { |
HideMenuHost(); |
destroying_ = true; |
static_cast<MenuHostRootView*>(GetRootView())->ClearSubmenu(); |
+#if !defined(OS_MACOSX) |
+ pre_dispatch_handler_.reset(); |
+#endif |
Close(); |
} |