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..898a30f8d8b4bff66340cd95a2873df58ca5edda 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); |
sky
2017/05/22 16:06:56
move to member initializer.
riajiang
2017/05/29 23:38:07
Done.
|
+} |
+ |
+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); |
@@ -219,28 +231,21 @@ const ServerWindow* EventDispatcher::GetWindowForMouseCursor() const { |
void EventDispatcher::UpdateNonClientAreaForCurrentWindow() { |
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())); |
} |
} |
void EventDispatcher::UpdateCursorProviderByLastKnownLocation() { |
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())); |
} |
} |
@@ -308,6 +313,12 @@ void EventDispatcher::ProcessEvent(const ui::Event& event, |
return; |
} |
+bool EventDispatcher::IsHitTestInFlight() const { |
+ 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 +358,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 +391,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 +406,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); |
@@ -443,20 +464,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 +497,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 +522,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 { |
@@ -580,14 +612,91 @@ Accelerator* EventDispatcher::FindAccelerator( |
return nullptr; |
} |
-DeepestWindow EventDispatcher::FindDeepestVisibleWindowForEvents( |
- const gfx::Point& location) { |
+void EventDispatcher::FindDeepestVisibleWindowForEvents( |
+ const gfx::Point& location, |
+ HitTestCallback callback) { |
+ if (IsHitTestInFlight()) { |
+ 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( |
+ 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; |
+ } |
+ delegate_->UpdateNativeCursorFromDispatcher(); |
+} |
+ |
+void EventDispatcher::UpdateCursorProviderByLastKnownLocationOnFoundWindow( |
+ 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; |
+ } |
+ delegate_->UpdateNativeCursorFromDispatcher(); |
+} |
+ |
+void EventDispatcher::ProcessNextHittesetRequestFromQueue() { |
+ hittest_in_flight_ = false; |
+ if (hittest_request_queue_.empty()) { |
+ delegate_->ProcessNextEventFromQueue(); |
+ 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, |