diff --git a/services/ui/ws2/BUILD.gn b/services/ui/ws2/BUILD.gn index af4d58e31d88f7..61d4f2c1abab0b 100644 --- a/services/ui/ws2/BUILD.gn +++ b/services/ui/ws2/BUILD.gn @@ -29,6 +29,8 @@ component("lib") { "client_root.h", "client_window.cc", "client_window.h", + "pointer_watcher.cc", + "pointer_watcher.h", "screen_provider.cc", "screen_provider.h", "window_host_frame_sink_client.cc", @@ -127,6 +129,7 @@ source_set("tests") { "//third_party/mesa:osmesa", "//ui/aura:test_support", "//ui/compositor:test_support", + "//ui/events:test_support", "//ui/gl:test_support", ] diff --git a/services/ui/ws2/pointer_watcher.cc b/services/ui/ws2/pointer_watcher.cc new file mode 100644 index 00000000000000..a17719711aab69 --- /dev/null +++ b/services/ui/ws2/pointer_watcher.cc @@ -0,0 +1,66 @@ +// Copyright 2018 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 "services/ui/ws2/pointer_watcher.h" + +#include "services/ui/ws2/window_service_client.h" +#include "ui/aura/env.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tree_host.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" + +namespace ui { +namespace ws2 { + +PointerWatcher::PointerWatcher(WindowServiceClient* client) : client_(client) { + aura::Env::GetInstance()->AddWindowEventDispatcherObserver(this); +} + +PointerWatcher::~PointerWatcher() { + aura::Env::GetInstance()->RemoveWindowEventDispatcherObserver(this); +} + +bool PointerWatcher::ShouldSendEventToClient(const ui::Event& event) const { + switch (event.type()) { + case ui::ET_MOUSE_PRESSED: + case ui::ET_MOUSE_RELEASED: + case ui::ET_TOUCH_PRESSED: + case ui::ET_TOUCH_RELEASED: + return true; + + case ui::ET_MOUSE_MOVED: + case ui::ET_TOUCH_MOVED: + case ui::ET_MOUSEWHEEL: + return types_to_watch_ == TypesToWatch::kUpDownMoveWheel; + + default: + break; + } + return false; +} + +void PointerWatcher::OnWindowEventDispatcherStartedProcessing( + aura::WindowEventDispatcher* dispatcher, + const ui::Event& event) { + if (!ShouldSendEventToClient(event)) + return; + + // TODO(sky): this needs to interact with actual event sending so that we + // only send pointer events if an event wasn't also sent to the client. + // Part of https://crbug.com/837692 + std::unique_ptr event_to_send; + // Client code expects to get PointerEvents. + if (event.IsMouseEvent()) + event_to_send = std::make_unique(*event.AsMouseEvent()); + else if (event.IsTouchEvent()) + event_to_send = std::make_unique(*event.AsTouchEvent()); + else + NOTREACHED(); + client_->SendPointerWatcherEventToClient(dispatcher->host()->GetDisplayId(), + std::move(event_to_send)); +} + +} // namespace ws2 +} // namespace ui diff --git a/services/ui/ws2/pointer_watcher.h b/services/ui/ws2/pointer_watcher.h new file mode 100644 index 00000000000000..80b3925df63ecc --- /dev/null +++ b/services/ui/ws2/pointer_watcher.h @@ -0,0 +1,58 @@ +// Copyright 2018 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 SERVICES_UI_WS2_POINTER_WATCHER_H_ +#define SERVICES_UI_WS2_POINTER_WATCHER_H_ + +#include "base/macros.h" +#include "ui/aura/window_event_dispatcher_observer.h" + +namespace ui { +namespace ws2 { + +class WindowServiceClient; + +// PointerWatcher is used when a client has requested to observe pointer events +// that the client would not normally receive. PointerWatcher observes events +// by way of aura::WindowEventDispatcherObserver and forwards them to the +// client. +// +// This class provides the server implementation of +// ui::mojom::WindowTree::StartPointerWatcher(), see it for more information. +class PointerWatcher : public aura::WindowEventDispatcherObserver { + public: + enum class TypesToWatch { + // Pointer up/down events. + kUpDown, + + // Pointer up, down, move (including drag) and wheel events. + kUpDownMoveWheel, + }; + + explicit PointerWatcher(WindowServiceClient* client); + ~PointerWatcher() override; + + void set_types_to_watch(TypesToWatch types) { types_to_watch_ = types; } + + private: + // Returns true if |event| matches the types the PointerWatcher has been + // configured to monitor. + bool ShouldSendEventToClient(const ui::Event& event) const; + + // aura::WindowEventDispatcherObserver: + void OnWindowEventDispatcherStartedProcessing( + aura::WindowEventDispatcher* dispatcher, + const ui::Event& event) override; + + TypesToWatch types_to_watch_ = TypesToWatch::kUpDown; + + WindowServiceClient* client_; + + DISALLOW_COPY_AND_ASSIGN(PointerWatcher); +}; + +} // namespace ws2 +} // namespace ui + +#endif // SERVICES_UI_WS2_POINTER_WATCHER_H_ diff --git a/services/ui/ws2/test_window_tree_client.cc b/services/ui/ws2/test_window_tree_client.cc index e7be46eadc4e6a..97ba2ac7a3c8d0 100644 --- a/services/ui/ws2/test_window_tree_client.cc +++ b/services/ui/ws2/test_window_tree_client.cc @@ -12,12 +12,29 @@ namespace ui { namespace ws2 { +TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent() = default; + +TestWindowTreeClient::ObservedPointerEvent::ObservedPointerEvent( + ObservedPointerEvent&& other) = default; + +TestWindowTreeClient::ObservedPointerEvent::~ObservedPointerEvent() = default; + TestWindowTreeClient::TestWindowTreeClient() { tracker_.set_delegate(this); } TestWindowTreeClient::~TestWindowTreeClient() = default; +TestWindowTreeClient::ObservedPointerEvent +TestWindowTreeClient::PopObservedPointerEvent() { + if (observed_pointer_events_.empty()) + return ObservedPointerEvent(); + + ObservedPointerEvent event = std::move(observed_pointer_events_.front()); + observed_pointer_events_.pop(); + return event; +} + void TestWindowTreeClient::OnChangeAdded() {} void TestWindowTreeClient::OnEmbed( @@ -145,9 +162,16 @@ void TestWindowTreeClient::OnWindowInputEvent( tree_->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED); } -void TestWindowTreeClient::OnPointerEventObserved(std::unique_ptr, - Id window_id, - int64_t display_id) {} +void TestWindowTreeClient::OnPointerEventObserved( + std::unique_ptr event, + Id window_id, + int64_t display_id) { + ObservedPointerEvent observed_pointer_event; + observed_pointer_event.window_id = window_id; + observed_pointer_event.display_id = display_id; + observed_pointer_event.event = std::move(event); + observed_pointer_events_.push(std::move(observed_pointer_event)); +} void TestWindowTreeClient::OnWindowSharedPropertyChanged( Id window, diff --git a/services/ui/ws2/test_window_tree_client.h b/services/ui/ws2/test_window_tree_client.h index db24d5eb7f4d23..0813840f5e9a86 100644 --- a/services/ui/ws2/test_window_tree_client.h +++ b/services/ui/ws2/test_window_tree_client.h @@ -5,6 +5,10 @@ #ifndef SERVICES_UI_WS2_TEST_WINDOW_TREE_CLIENT_H_ #define SERVICES_UI_WS2_TEST_WINDOW_TREE_CLIENT_H_ +#include + +#include + #include "base/component_export.h" #include "base/macros.h" #include "services/ui/public/interfaces/window_tree.mojom.h" @@ -17,9 +21,30 @@ namespace ws2 { class TestWindowTreeClient : public mojom::WindowTreeClient, public TestChangeTracker::Delegate { public: + // An ObservedPointerEvent is created for each call to + // OnPointerEventObserved() + struct ObservedPointerEvent { + ObservedPointerEvent(); + ObservedPointerEvent(ObservedPointerEvent&& other); + ~ObservedPointerEvent(); + + std::unique_ptr event; + Id window_id = 0; + int64_t display_id = 0; + }; + TestWindowTreeClient(); ~TestWindowTreeClient() override; + std::queue& observed_pointer_events() { + return observed_pointer_events_; + } + + // Returns the oldest ObservedPointerEvent that was received by way of + // OnPointerEventObserved(). If no pointer events have been observed, |event| + // in the returned object is null. + ObservedPointerEvent PopObservedPointerEvent(); + mojom::WindowTree* tree() { return tree_.get(); } TestChangeTracker* tracker() { return &tracker_; } Id root_window_id() const { return root_window_id_; } @@ -95,7 +120,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient, const gfx::PointF& event_location_in_screen_pixel_layout, std::unique_ptr event, bool matches_pointer_watcher) override; - void OnPointerEventObserved(std::unique_ptr, + void OnPointerEventObserved(std::unique_ptr event, Id window_id, int64_t display_id) override; void OnWindowSharedPropertyChanged( @@ -138,6 +163,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient, mojom::WindowTreePtr tree_; Id root_window_id_ = 0; bool track_root_bounds_changes_ = false; + std::queue observed_pointer_events_; DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient); }; diff --git a/services/ui/ws2/window_service_client.cc b/services/ui/ws2/window_service_client.cc index 4304bbff08ea3c..79d9017772b48e 100644 --- a/services/ui/ws2/window_service_client.cc +++ b/services/ui/ws2/window_service_client.cc @@ -13,6 +13,7 @@ #include "services/ui/ws2/client_change_tracker.h" #include "services/ui/ws2/client_root.h" #include "services/ui/ws2/client_window.h" +#include "services/ui/ws2/pointer_watcher.h" #include "services/ui/ws2/window_service.h" #include "services/ui/ws2/window_service_client_binding.h" #include "services/ui/ws2/window_service_delegate.h" @@ -21,6 +22,7 @@ #include "ui/aura/mus/property_converter.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" +#include "ui/aura/window_tree_host.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_type.h" #include "ui/display/display.h" @@ -74,6 +76,13 @@ WindowServiceClient::~WindowServiceClient() { } } +void WindowServiceClient::SendPointerWatcherEventToClient( + int64_t display_id, + std::unique_ptr event) { + window_tree_client_->OnPointerEventObserved(std::move(event), + kInvalidTransportId, display_id); +} + ClientRoot* WindowServiceClient::CreateClientRoot( aura::Window* window, mojom::WindowTreePtr window_tree) { @@ -724,11 +733,15 @@ void WindowServiceClient::ReleaseCapture(uint32_t change_id, Id window_id) { } void WindowServiceClient::StartPointerWatcher(bool want_moves) { - NOTIMPLEMENTED(); + if (!pointer_watcher_) + pointer_watcher_ = std::make_unique(this); + pointer_watcher_->set_types_to_watch( + want_moves ? PointerWatcher::TypesToWatch::kUpDownMoveWheel + : PointerWatcher::TypesToWatch::kUpDown); } void WindowServiceClient::StopPointerWatcher() { - NOTIMPLEMENTED(); + pointer_watcher_.reset(); } void WindowServiceClient::SetWindowBounds( @@ -926,9 +939,12 @@ void WindowServiceClient::SetImeVisibility( } void WindowServiceClient::SetEventTargetingPolicy( - Id window_id, + Id transport_window_id, ::ui::mojom::EventTargetingPolicy policy) { - NOTIMPLEMENTED(); + aura::Window* window = + GetWindowByClientId(MakeClientWindowId(transport_window_id)); + if (IsClientCreatedWindow(window) || IsClientRootWindow(window)) + window->SetEventTargetingPolicy(policy); } void WindowServiceClient::OnWindowInputEventAck( diff --git a/services/ui/ws2/window_service_client.h b/services/ui/ws2/window_service_client.h index cfb1447786efe8..594bd17a0df0bb 100644 --- a/services/ui/ws2/window_service_client.h +++ b/services/ui/ws2/window_service_client.h @@ -22,10 +22,14 @@ class Window; } namespace ui { + +class Event; + namespace ws2 { class ClientChangeTracker; class ClientRoot; +class PointerWatcher; class WindowService; class WindowServiceClientBinding; @@ -52,7 +56,7 @@ class WindowServiceClientBinding; // WindowServiceClientBinding). class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient : public mojom::WindowTree, - aura::WindowObserver { + public aura::WindowObserver { public: WindowServiceClient(WindowService* window_service, ClientSpecificId client_id, @@ -64,6 +68,11 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient void InitForEmbed(aura::Window* root, mojom::WindowTreePtr window_tree_ptr); void InitFromFactory(); + // Notifies the client that an event matching a pointer watcher has been + // received. + void SendPointerWatcherEventToClient(int64_t display_id, + std::unique_ptr event); + private: friend class ClientRoot; friend class WindowServiceClientTestHelper; @@ -282,11 +291,10 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient void SetImeVisibility(Id window_id, bool visible, ::ui::mojom::TextInputStatePtr state) override; - void SetEventTargetingPolicy( - Id window_id, - ::ui::mojom::EventTargetingPolicy policy) override; + void SetEventTargetingPolicy(Id transport_window_id, + ui::mojom::EventTargetingPolicy policy) override; void OnWindowInputEventAck(uint32_t event_id, - ::ui::mojom::EventResult result) override; + mojom::EventResult result) override; void DeactivateWindow(Id window_id) override; void StackAbove(uint32_t change_id, Id above_id, Id below_id) override; void StackAtTop(uint32_t change_id, Id window_id) override; @@ -355,6 +363,10 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowServiceClient // Used to track the active change from the client. std::unique_ptr property_change_tracker_; + // If non-null the client has requested pointer events the client would not + // normally get. + std::unique_ptr pointer_watcher_; + DISALLOW_COPY_AND_ASSIGN(WindowServiceClient); }; diff --git a/services/ui/ws2/window_service_client_test_helper.cc b/services/ui/ws2/window_service_client_test_helper.cc index b7a03f06de4d65..15f3a26bdf7e36 100644 --- a/services/ui/ws2/window_service_client_test_helper.cc +++ b/services/ui/ws2/window_service_client_test_helper.cc @@ -15,6 +15,10 @@ WindowServiceClientTestHelper::WindowServiceClientTestHelper( WindowServiceClientTestHelper::~WindowServiceClientTestHelper() = default; +mojom::WindowTree* WindowServiceClientTestHelper::window_tree() { + return static_cast(window_service_client_); +} + aura::Window* WindowServiceClientTestHelper::NewTopLevelWindow( Id transport_window_id) { base::flat_map> properties; @@ -34,6 +38,13 @@ void WindowServiceClientTestHelper::SetWindowBounds(aura::Window* window, local_surface_id); } +void WindowServiceClientTestHelper::SetEventTargetingPolicy( + aura::Window* window, + mojom::EventTargetingPolicy policy) { + window_service_client_->SetEventTargetingPolicy( + window_service_client_->TransportIdForWindow(window), policy); +} + void WindowServiceClientTestHelper::SetWindowProperty( aura::Window* window, const std::string& name, diff --git a/services/ui/ws2/window_service_client_test_helper.h b/services/ui/ws2/window_service_client_test_helper.h index 9a6b71cca3a367..4a31845d8c86e8 100644 --- a/services/ui/ws2/window_service_client_test_helper.h +++ b/services/ui/ws2/window_service_client_test_helper.h @@ -5,6 +5,8 @@ #ifndef SERVICES_UI_WS2_WINDOW_SERVICE_CLIENT_TEST_HELPER_H_ #define SERVICES_UI_WS2_WINDOW_SERVICE_CLIENT_TEST_HELPER_H_ +#include + #include "base/macros.h" #include "services/ui/ws2/ids.h" @@ -17,6 +19,13 @@ class Rect; } namespace ui { + +namespace mojom { +class WindowTree; + +enum class EventTargetingPolicy; +} // namespace mojom + namespace ws2 { class WindowServiceClient; @@ -28,10 +37,14 @@ class WindowServiceClientTestHelper { WindowServiceClient* window_service_client); ~WindowServiceClientTestHelper(); + mojom::WindowTree* window_tree(); + aura::Window* NewTopLevelWindow(Id transport_window_id); void SetWindowBounds(aura::Window* window, const gfx::Rect& bounds, uint32_t change_id = 1); + void SetEventTargetingPolicy(aura::Window* window, + mojom::EventTargetingPolicy policy); void SetWindowProperty(aura::Window* window, const std::string& name, const std::vector& value, diff --git a/services/ui/ws2/window_service_client_unittest.cc b/services/ui/ws2/window_service_client_unittest.cc index e6885c2972012b..8c648aaa70912c 100644 --- a/services/ui/ws2/window_service_client_unittest.cc +++ b/services/ui/ws2/window_service_client_unittest.cc @@ -8,6 +8,7 @@ #include #include +#include #include "base/test/scoped_task_environment.h" #include "services/ui/public/cpp/property_type_converters.h" @@ -21,8 +22,10 @@ #include "ui/aura/client/aura_constants.h" #include "ui/aura/layout_manager.h" #include "ui/aura/test/aura_test_helper.h" +#include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/compositor/test/context_factories_for_test.h" +#include "ui/events/test/event_generator.h" #include "ui/gl/test/gl_surface_test_support.h" namespace ui { @@ -54,11 +57,16 @@ class WindowServiceTestHelper { } ~WindowServiceTestHelper() { + window_service_client_.reset(); service_.reset(); aura_test_helper_.TearDown(); ui::TerminateContextFactoryForTests(); } + aura::Window* root() { return aura_test_helper_.root_window(); } + TestWindowServiceDelegate* delegate() { return &delegate_; } + TestWindowTreeClient* window_tree_client() { return &window_tree_client_; } + std::vector* changes() { return window_tree_client_.tracker()->changes(); } @@ -173,6 +181,68 @@ TEST(WindowServiceClientTest, SetProperty) { helper.changes()->clear(); } +TEST(WindowServiceClientTest, PointerWatcher) { + WindowServiceTestHelper helper; + TestWindowTreeClient* window_tree_client = helper.window_tree_client(); + aura::Window* top_level = helper.helper_->NewTopLevelWindow(1); + ASSERT_TRUE(top_level); + helper.helper_->SetEventTargetingPolicy(top_level, + mojom::EventTargetingPolicy::NONE); + EXPECT_EQ(mojom::EventTargetingPolicy::NONE, + top_level->event_targeting_policy()); + // Start the pointer watcher only for pointer down/up. + helper.helper_->window_tree()->StartPointerWatcher(false); + + top_level->Show(); + top_level->SetBounds(gfx::Rect(10, 10, 100, 100)); + + test::EventGenerator event_generator(helper.root()); + event_generator.MoveMouseTo(50, 50); + ASSERT_TRUE(window_tree_client->observed_pointer_events().empty()); + + event_generator.MoveMouseTo(5, 6); + ASSERT_TRUE(window_tree_client->observed_pointer_events().empty()); + + event_generator.PressLeftButton(); + { + ASSERT_EQ(1u, window_tree_client->observed_pointer_events().size()); + auto event = std::move(window_tree_client->PopObservedPointerEvent().event); + ASSERT_TRUE(event); + EXPECT_EQ(ET_POINTER_DOWN, event->type()); + EXPECT_EQ(gfx::Point(5, 6), event->AsLocatedEvent()->location()); + } + + event_generator.ReleaseLeftButton(); + { + ASSERT_EQ(1u, window_tree_client->observed_pointer_events().size()); + auto event = std::move(window_tree_client->PopObservedPointerEvent().event); + ASSERT_TRUE(event); + EXPECT_EQ(ET_POINTER_UP, event->type()); + EXPECT_EQ(gfx::Point(5, 6), event->AsLocatedEvent()->location()); + } + + // Enable observing move events. + helper.helper_->window_tree()->StartPointerWatcher(true); + event_generator.MoveMouseTo(8, 9); + { + ASSERT_EQ(1u, window_tree_client->observed_pointer_events().size()); + auto event = std::move(window_tree_client->PopObservedPointerEvent().event); + ASSERT_TRUE(event); + EXPECT_EQ(ET_POINTER_MOVED, event->type()); + EXPECT_EQ(gfx::Point(8, 9), event->AsLocatedEvent()->location()); + } + + const int kTouchId = 11; + event_generator.MoveTouchId(gfx::Point(2, 3), kTouchId); + { + ASSERT_EQ(1u, window_tree_client->observed_pointer_events().size()); + auto event = std::move(window_tree_client->PopObservedPointerEvent().event); + ASSERT_TRUE(event); + EXPECT_EQ(ET_POINTER_MOVED, event->type()); + EXPECT_EQ(gfx::Point(2, 3), event->AsLocatedEvent()->location()); + } +} + } // namespace } // namespace ws2 } // namespace ui diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index e6aa8fcbe02501..0a6f3bf784410e 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn @@ -74,6 +74,7 @@ jumbo_component("aura") { "window.h", "window_delegate.h", "window_event_dispatcher.h", + "window_event_dispatcher_observer.h", "window_observer.h", "window_occlusion_tracker.h", "window_port.h", diff --git a/ui/aura/env.cc b/ui/aura/env.cc index 0c64435f56a98f..2794ccede4ba19 100644 --- a/ui/aura/env.cc +++ b/ui/aura/env.cc @@ -20,6 +20,7 @@ #include "ui/aura/mus/window_port_mus.h" #include "ui/aura/mus/window_tree_client.h" #include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher_observer.h" #include "ui/aura/window_port_for_shutdown.h" #include "ui/events/event_target_iterator.h" #include "ui/events/platform/platform_event_source.h" @@ -115,6 +116,16 @@ void Env::RemoveObserver(EnvObserver* observer) { observers_.RemoveObserver(observer); } +void Env::AddWindowEventDispatcherObserver( + WindowEventDispatcherObserver* observer) { + window_event_dispatcher_observers_.AddObserver(observer); +} + +void Env::RemoveWindowEventDispatcherObserver( + WindowEventDispatcherObserver* observer) { + window_event_dispatcher_observers_.RemoveObserver(observer); +} + bool Env::IsMouseButtonDown() const { return input_state_lookup_.get() ? input_state_lookup_->IsMouseButtonDown() : mouse_button_flags_ != 0; diff --git a/ui/aura/env.h b/ui/aura/env.h index 7971256e419ce7..840bfeb6969709 100644 --- a/ui/aura/env.h +++ b/ui/aura/env.h @@ -48,6 +48,7 @@ class InputStateLookup; class MouseLocationManager; class MusMouseLocationUpdater; class Window; +class WindowEventDispatcherObserver; class WindowPort; class WindowTreeClient; class WindowTreeHost; @@ -83,6 +84,15 @@ class AURA_EXPORT Env : public ui::EventTarget, void AddObserver(EnvObserver* observer); void RemoveObserver(EnvObserver* observer); + void AddWindowEventDispatcherObserver( + WindowEventDispatcherObserver* observer); + void RemoveWindowEventDispatcherObserver( + WindowEventDispatcherObserver* observer); + base::ObserverList& + window_event_dispatcher_observers() { + return window_event_dispatcher_observers_; + } + EnvInputStateController* env_controller() const { return env_controller_.get(); } @@ -202,6 +212,12 @@ class AURA_EXPORT Env : public ui::EventTarget, base::ObserverList observers_; + // Code wanting to observe WindowEventDispatcher typically wants to observe + // all WindowEventDispatchers. This is made easier by having Env own all the + // observers. + base::ObserverList + window_event_dispatcher_observers_; + std::unique_ptr env_controller_; int mouse_button_flags_; // Location of last mouse event, in screen coordinates. diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index dd79a6286cb8eb..eab534452aca29 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc @@ -22,6 +22,7 @@ #include "ui/aura/mus/mus_mouse_location_updater.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/aura/window_event_dispatcher_observer.h" #include "ui/aura/window_targeter.h" #include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" @@ -77,6 +78,23 @@ void ConvertEventLocationToTarget(ui::EventTarget* event_target, } // namespace +WindowEventDispatcher::ObserverNotifier::ObserverNotifier( + WindowEventDispatcher* dispatcher, + const ui::Event& event) + : dispatcher_(dispatcher) { + for (WindowEventDispatcherObserver& observer : + Env::GetInstance()->window_event_dispatcher_observers()) { + observer.OnWindowEventDispatcherStartedProcessing(dispatcher, event); + } +} + +WindowEventDispatcher::ObserverNotifier::~ObserverNotifier() { + for (WindowEventDispatcherObserver& observer : + Env::GetInstance()->window_event_dispatcher_observers()) { + observer.OnWindowEventDispatcherFinishedProcessingEvent(dispatcher_); + } +} + //////////////////////////////////////////////////////////////////////////////// // WindowEventDispatcher, public: @@ -536,11 +554,14 @@ void WindowEventDispatcher::OnEventProcessingStarted(ui::Event* event) { if (mus_mouse_location_updater_) mus_mouse_location_updater_->OnEventProcessingStarted(*event); + + observer_notifiers_.push(std::make_unique(this, *event)); } void WindowEventDispatcher::OnEventProcessingFinished(ui::Event* event) { if (mus_mouse_location_updater_) mus_mouse_location_updater_->OnEventProcessingFinished(); + observer_notifiers_.pop(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h index a16b9180be8b7c..cb803d59b19a82 100644 --- a/ui/aura/window_event_dispatcher.h +++ b/ui/aura/window_event_dispatcher.h @@ -6,6 +6,7 @@ #define UI_AURA_WINDOW_EVENT_DISPATCHER_H_ #include +#include #include #include "base/callback.h" @@ -29,6 +30,7 @@ #include "ui/gfx/native_widget_types.h" namespace ui { +class Event; class GestureEvent; class GestureRecognizer; class MouseEvent; @@ -58,6 +60,8 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor, explicit WindowEventDispatcher(WindowTreeHost* host); ~WindowEventDispatcher() override; + WindowTreeHost* host() { return host_; } + Window* mouse_pressed_handler() { return mouse_pressed_handler_; } Window* mouse_moved_handler() { return mouse_moved_handler_; } Window* touchpad_pinch_handler() { return touchpad_pinch_handler_; } @@ -136,6 +140,21 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor, friend class Window; friend class TestScreen; + // Used to call WindowEventDispatcherObserver when event processing starts + // (from the constructor) and finishes (from the destructor). Notification is + // handled by this object to ensure notification happens if the associated + // WindowEventDispatcher is destroyed during processing of the event. + class ObserverNotifier { + public: + ObserverNotifier(WindowEventDispatcher* dispatcher, const ui::Event& event); + ~ObserverNotifier(); + + private: + WindowEventDispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ObserverNotifier); + }; + // The parameter for OnWindowHidden() to specify why window is hidden. enum WindowHiddenReason { WINDOW_DESTROYED, // Window is destroyed. @@ -301,6 +320,10 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor, // pointer moves are released and there is no held move event. base::OnceClosure did_dispatch_held_move_event_callback_; + // See ObserverNotifier for details. This is a queue to handle the case of + // nested event dispatch. + std::queue> observer_notifiers_; + // Used to schedule reposting an event. base::WeakPtrFactory repost_event_factory_; diff --git a/ui/aura/window_event_dispatcher_observer.h b/ui/aura/window_event_dispatcher_observer.h new file mode 100644 index 00000000000000..4c1587d8c25059 --- /dev/null +++ b/ui/aura/window_event_dispatcher_observer.h @@ -0,0 +1,41 @@ +// Copyright 2018 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 UI_AURA_WINDOW_EVENT_DISPATCHER_OBSERVER_H_ +#define UI_AURA_WINDOW_EVENT_DISPATCHER_OBSERVER_H_ + +#include "ui/aura/aura_export.h" + +namespace ui { +class Event; +} + +namespace aura { + +class WindowEventDispatcher; + +// WindowEventDispatcherObservers are added to Env and observe *all* +// WindowEventDispatchers. +class AURA_EXPORT WindowEventDispatcherObserver { + public: + // Called when WindowEventDispatcher starts processing an event. + // + // NOTE: this function is called *after* the location has been transformed + // (assuming the event is a located event). In other words, the coordinates + // are DIPs when this is called. + virtual void OnWindowEventDispatcherStartedProcessing( + WindowEventDispatcher* dispatcher, + const ui::Event& event) {} + + // Called when WindowEventDispatcher finishes processing an event. + virtual void OnWindowEventDispatcherFinishedProcessingEvent( + WindowEventDispatcher* dispatcher) {} + + protected: + virtual ~WindowEventDispatcherObserver() {} +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_EVENT_DISPATCHER_OBSERVER_H_ diff --git a/ui/aura/window_targeter.h b/ui/aura/window_targeter.h index ead1801cf50209..5f38c4828f81d2 100644 --- a/ui/aura/window_targeter.h +++ b/ui/aura/window_targeter.h @@ -89,8 +89,8 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter { protected: // Same as FindTargetForEvent(), but used for positional events. The location - // etc. of |event| are in |root|'s coordinate system. When finding the target - // for the event, the targeter can mutate the |event| (e.g. change the + // etc. of |event| are in |window|'s coordinate system. When finding the + // target for the event, the targeter can mutate the |event| (e.g. change the // coordinate to be in the returned target's coordinate system) so that it can // be dispatched to the target without any further modification. virtual Window* FindTargetForLocatedEvent(Window* window,