| Index: services/ui/ws/event_dispatcher.cc
|
| diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
|
| index 83e8b37f26e8aafdacbec4f0fc45566195c18068..b2c2e8b2eebc93871d8ff136184bf0d037becf04 100644
|
| --- a/services/ui/ws/event_dispatcher.cc
|
| +++ b/services/ui/ws/event_dispatcher.cc
|
| @@ -6,7 +6,9 @@
|
|
|
| #include <algorithm>
|
|
|
| +#include "base/command_line.h"
|
| #include "base/memory/ptr_util.h"
|
| +#include "base/task_scheduler/post_task.h"
|
| #include "base/time/time.h"
|
| #include "services/ui/ws/accelerator.h"
|
| #include "services/ui/ws/drag_controller.h"
|
| @@ -41,6 +43,14 @@ bool IsOnlyOneMouseButtonDown(int flags) {
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| +EventDispatcher::HittestRequest::HittestRequest(const gfx::Point& location,
|
| + HittestCallback callback)
|
| + : hittest_location(location) {
|
| + hittest_callback = std::move(callback);
|
| +}
|
| +
|
| +EventDispatcher::HittestRequest::~HittestRequest() {}
|
| +
|
| EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
|
| : delegate_(delegate),
|
| capture_window_(nullptr),
|
| @@ -48,7 +58,9 @@ EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
|
| modal_window_controller_(this),
|
| mouse_button_down_(false),
|
| mouse_cursor_source_window_(nullptr),
|
| - mouse_cursor_in_non_client_area_(false) {}
|
| + mouse_cursor_in_non_client_area_(false),
|
| + hittest_in_flight_(false),
|
| + weak_ptr_factory_(this) {}
|
|
|
| EventDispatcher::~EventDispatcher() {
|
| SetMouseCursorSourceWindow(nullptr);
|
| @@ -80,7 +92,7 @@ void EventDispatcher::SetMousePointerScreenLocation(
|
| const gfx::Point& screen_location) {
|
| DCHECK(pointer_targets_.empty());
|
| mouse_pointer_last_location_ = screen_location;
|
| - UpdateCursorProviderByLastKnownLocation();
|
| + UpdateCursorProviderByLastKnownLocation(base::Closure());
|
| // Write our initial location back to our shared screen coordinate. This
|
| // shouldn't cause problems because we already read the cursor before we
|
| // process any events in views during window construction.
|
| @@ -145,7 +157,7 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window,
|
| } else {
|
| delegate_->ReleaseNativeCapture();
|
| if (!mouse_button_down_)
|
| - UpdateCursorProviderByLastKnownLocation();
|
| + UpdateCursorProviderByLastKnownLocation(base::Closure());
|
| }
|
| return true;
|
| }
|
| @@ -217,30 +229,25 @@ const ServerWindow* EventDispatcher::GetWindowForMouseCursor() const {
|
| return window;
|
| }
|
|
|
| -void EventDispatcher::UpdateNonClientAreaForCurrentWindow() {
|
| +void EventDispatcher::UpdateNonClientAreaForCurrentWindow(
|
| + const base::Closure& callback) {
|
| if (mouse_cursor_source_window_) {
|
| - DeepestWindow deepest_window =
|
| - FindDeepestVisibleWindowForEvents(mouse_pointer_last_location_);
|
| - if (deepest_window.window == mouse_cursor_source_window_) {
|
| - mouse_cursor_in_non_client_area_ = mouse_cursor_source_window_
|
| - ? deepest_window.in_non_client_area
|
| - : false;
|
| - }
|
| + FindDeepestVisibleWindowForEvents(
|
| + mouse_pointer_last_location_,
|
| + base::BindOnce(
|
| + &EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow,
|
| + weak_ptr_factory_.GetWeakPtr(), callback));
|
| }
|
| }
|
|
|
| -void EventDispatcher::UpdateCursorProviderByLastKnownLocation() {
|
| +void EventDispatcher::UpdateCursorProviderByLastKnownLocation(
|
| + const base::Closure& callback) {
|
| if (!mouse_button_down_) {
|
| - DeepestWindow deepest_window =
|
| - FindDeepestVisibleWindowForEvents(mouse_pointer_last_location_);
|
| - SetMouseCursorSourceWindow(deepest_window.window);
|
| - if (mouse_cursor_source_window_) {
|
| - mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area;
|
| - } else {
|
| - gfx::Point location = mouse_pointer_last_location_;
|
| - SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(&location));
|
| - mouse_cursor_in_non_client_area_ = true;
|
| - }
|
| + FindDeepestVisibleWindowForEvents(
|
| + mouse_pointer_last_location_,
|
| + base::BindOnce(&EventDispatcher::
|
| + UpdateCursorProviderByLastKnownLocationOnFoundWindow,
|
| + weak_ptr_factory_.GetWeakPtr(), callback));
|
| }
|
| }
|
|
|
| @@ -308,6 +315,12 @@ void EventDispatcher::ProcessEvent(const ui::Event& event,
|
| return;
|
| }
|
|
|
| +bool EventDispatcher::HittestInFlight() {
|
| + if (hittest_in_flight_ || !hittest_request_queue_.empty())
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| void EventDispatcher::SetMouseCursorSourceWindow(ServerWindow* window) {
|
| if (mouse_cursor_source_window_ == window)
|
| return;
|
| @@ -347,6 +360,16 @@ void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event,
|
|
|
| void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) {
|
| DCHECK(event.IsPointerEvent());
|
| + PointerTargetForEvent(
|
| + event, base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget,
|
| + weak_ptr_factory_.GetWeakPtr(), event));
|
| +}
|
| +
|
| +void EventDispatcher::ProcessPointerEventOnFoundTarget(
|
| + const ui::PointerEvent& event,
|
| + PointerTarget pointer_target_found) {
|
| + ProcessNextHittesetRequestFromQueue();
|
| +
|
| const bool is_mouse_event = event.IsMousePointerEvent();
|
|
|
| if (is_mouse_event) {
|
| @@ -370,8 +393,8 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) {
|
| }
|
|
|
| if (drag_controller_) {
|
| - const PointerTarget target = PointerTargetForEvent(event);
|
| - if (drag_controller_->DispatchPointerEvent(event, target.window))
|
| + if (drag_controller_->DispatchPointerEvent(event,
|
| + pointer_target_found.window))
|
| return;
|
| }
|
|
|
| @@ -385,7 +408,7 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) {
|
| if (!IsTrackingPointer(pointer_id) ||
|
| !pointer_targets_[pointer_id].is_pointer_down) {
|
| const bool any_pointers_down = AreAnyPointersDown();
|
| - UpdateTargetForPointer(pointer_id, event);
|
| + UpdateTargetForPointer(pointer_id, event, pointer_target_found);
|
| if (is_mouse_event)
|
| SetMouseCursorSourceWindow(pointer_targets_[pointer_id].window);
|
|
|
| @@ -412,7 +435,7 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) {
|
| // before we perform dispatch because the Delegate is going to read this
|
| // information from us.
|
| if (is_pointer_going_up && is_mouse_event)
|
| - UpdateCursorProviderByLastKnownLocation();
|
| + UpdateCursorProviderByLastKnownLocation(base::Closure());
|
|
|
| DispatchToPointerTarget(pointer_targets_[pointer_id], event);
|
|
|
| @@ -443,20 +466,21 @@ void EventDispatcher::StopTrackingPointer(int32_t pointer_id) {
|
| UnobserveWindow(window);
|
| }
|
|
|
| -void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id,
|
| - const ui::LocatedEvent& event) {
|
| +void EventDispatcher::UpdateTargetForPointer(
|
| + int32_t pointer_id,
|
| + const ui::PointerEvent& event,
|
| + const PointerTarget& pointer_target_found) {
|
| if (!IsTrackingPointer(pointer_id)) {
|
| - StartTrackingPointer(pointer_id, PointerTargetForEvent(event));
|
| + StartTrackingPointer(pointer_id, pointer_target_found);
|
| return;
|
| }
|
|
|
| - const PointerTarget pointer_target = PointerTargetForEvent(event);
|
| - if (pointer_target.window == pointer_targets_[pointer_id].window &&
|
| - pointer_target.in_nonclient_area ==
|
| + if (pointer_target_found.window == pointer_targets_[pointer_id].window &&
|
| + pointer_target_found.in_nonclient_area ==
|
| pointer_targets_[pointer_id].in_nonclient_area) {
|
| // The targets are the same, only set the down state to true if necessary.
|
| // Down going to up is handled by ProcessLocatedEvent().
|
| - if (pointer_target.is_pointer_down)
|
| + if (pointer_target_found.is_pointer_down)
|
| pointer_targets_[pointer_id].is_pointer_down = true;
|
| return;
|
| }
|
| @@ -475,14 +499,24 @@ void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id,
|
| // Technically we're updating in place, but calling start then stop makes for
|
| // simpler code.
|
| StopTrackingPointer(pointer_id);
|
| - StartTrackingPointer(pointer_id, pointer_target);
|
| + StartTrackingPointer(pointer_id, pointer_target_found);
|
| +}
|
| +
|
| +void EventDispatcher::PointerTargetForEvent(
|
| + const ui::PointerEvent& event,
|
| + PointerTargetForEventCallback callback) {
|
| + FindDeepestVisibleWindowForEvents(
|
| + event.root_location(),
|
| + base::BindOnce(&EventDispatcher::PointerTargetForEventOnFoundWindow,
|
| + weak_ptr_factory_.GetWeakPtr(), event,
|
| + std::move(callback)));
|
| }
|
|
|
| -EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent(
|
| - const ui::LocatedEvent& event) {
|
| +void EventDispatcher::PointerTargetForEventOnFoundWindow(
|
| + const ui::PointerEvent& event,
|
| + PointerTargetForEventCallback callback,
|
| + DeepestWindow deepest_window) {
|
| PointerTarget pointer_target;
|
| - DeepestWindow deepest_window =
|
| - FindDeepestVisibleWindowForEvents(event.root_location());
|
| pointer_target.window =
|
| modal_window_controller_.GetTargetForWindow(deepest_window.window);
|
| pointer_target.is_mouse_event = event.IsMousePointerEvent();
|
| @@ -490,7 +524,7 @@ EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent(
|
| deepest_window.window != pointer_target.window ||
|
| !pointer_target.window || deepest_window.in_non_client_area;
|
| pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
|
| - return pointer_target;
|
| + std::move(callback).Run(pointer_target);
|
| }
|
|
|
| bool EventDispatcher::AreAnyPointersDown() const {
|
| @@ -540,7 +574,7 @@ void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) {
|
| // explicit capture.
|
| delegate_->OnCaptureChanged(nullptr, window);
|
| delegate_->ReleaseNativeCapture();
|
| - UpdateCursorProviderByLastKnownLocation();
|
| + UpdateCursorProviderByLastKnownLocation(base::Closure());
|
| return;
|
| }
|
|
|
| @@ -580,14 +614,93 @@ Accelerator* EventDispatcher::FindAccelerator(
|
| return nullptr;
|
| }
|
|
|
| -DeepestWindow EventDispatcher::FindDeepestVisibleWindowForEvents(
|
| - const gfx::Point& location) {
|
| +void EventDispatcher::FindDeepestVisibleWindowForEvents(
|
| + const gfx::Point& location,
|
| + HittestCallback callback) {
|
| + if (HittestInFlight()) {
|
| + std::unique_ptr<HittestRequest> hittest_request =
|
| + base::MakeUnique<HittestRequest>(location, std::move(callback));
|
| + hittest_request_queue_.push(std::move(hittest_request));
|
| + return;
|
| + }
|
| +
|
| + FindDeepestVisibleWindowForEventsImpl(location, std::move(callback));
|
| +}
|
| +
|
| +void EventDispatcher::FindDeepestVisibleWindowForEventsImpl(
|
| + const gfx::Point& location,
|
| + HittestCallback callback) {
|
| + // TODO(riajiang): After HittestComponent is implemented, do synchronous
|
| + // hit-test for most cases using shared memory and only ask Blink
|
| + // asynchronously for hard cases. For now, assume all synchronous hit-tests
|
| + // failed if the "enable-async-event-targeting" flag is turned on.
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| + "enable-async-event-targeting")) {
|
| + DCHECK(!hittest_in_flight_);
|
| + hittest_in_flight_ = true;
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::BindOnce(&EventDispatcher::FindDeepestVisibleWindowForEventsAsync,
|
| + weak_ptr_factory_.GetWeakPtr(), location,
|
| + std::move(callback)));
|
| + } else {
|
| + FindDeepestVisibleWindowForEventsAsync(location, std::move(callback));
|
| + }
|
| +}
|
| +
|
| +void EventDispatcher::FindDeepestVisibleWindowForEventsAsync(
|
| + const gfx::Point& location,
|
| + HittestCallback callback) {
|
| gfx::Point relative_location(location);
|
| - // For the case of no root.
|
| ServerWindow* root = delegate_->GetRootWindowContaining(&relative_location);
|
| - return root ? ui::ws::FindDeepestVisibleWindowForEvents(root,
|
| - relative_location)
|
| - : DeepestWindow();
|
| + if (root) {
|
| + std::move(callback).Run(
|
| + ui::ws::FindDeepestVisibleWindowForEvents(root, relative_location));
|
| + } else {
|
| + std::move(callback).Run(DeepestWindow());
|
| + }
|
| +}
|
| +
|
| +void EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow(
|
| + const base::Closure& callback,
|
| + DeepestWindow deepest_window) {
|
| + ProcessNextHittesetRequestFromQueue();
|
| +
|
| + if (deepest_window.window == mouse_cursor_source_window_) {
|
| + mouse_cursor_in_non_client_area_ =
|
| + mouse_cursor_source_window_ ? deepest_window.in_non_client_area : false;
|
| + }
|
| + if (callback)
|
| + callback.Run();
|
| +}
|
| +
|
| +void EventDispatcher::UpdateCursorProviderByLastKnownLocationOnFoundWindow(
|
| + const base::Closure& callback,
|
| + DeepestWindow deepest_window) {
|
| + ProcessNextHittesetRequestFromQueue();
|
| +
|
| + SetMouseCursorSourceWindow(deepest_window.window);
|
| + if (mouse_cursor_source_window_) {
|
| + mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area;
|
| + } else {
|
| + gfx::Point location = mouse_pointer_last_location_;
|
| + SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(&location));
|
| + mouse_cursor_in_non_client_area_ = true;
|
| + }
|
| + if (callback)
|
| + callback.Run();
|
| +}
|
| +
|
| +void EventDispatcher::ProcessNextHittesetRequestFromQueue() {
|
| + hittest_in_flight_ = false;
|
| + if (hittest_request_queue_.empty())
|
| + return;
|
| + std::unique_ptr<HittestRequest> hittest_request =
|
| + std::move(hittest_request_queue_.front());
|
| + hittest_request_queue_.pop();
|
| + FindDeepestVisibleWindowForEventsImpl(
|
| + hittest_request->hittest_location,
|
| + std::move(hittest_request->hittest_callback));
|
| }
|
|
|
| void EventDispatcher::CancelImplicitCaptureExcept(ServerWindow* window,
|
|
|