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..3101bbebbc2ed1e95fdba76553c137abada058b2 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(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,8 @@ 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) {} |
EventDispatcher::~EventDispatcher() { |
SetMouseCursorSourceWindow(nullptr); |
@@ -80,7 +91,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 +156,7 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window, |
} else { |
delegate_->ReleaseNativeCapture(); |
if (!mouse_button_down_) |
- UpdateCursorProviderByLastKnownLocation(); |
+ UpdateCursorProviderByLastKnownLocation(base::Closure()); |
} |
return true; |
} |
@@ -217,30 +228,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, |
+ base::Unretained(this), 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, |
+ base::Unretained(this), callback)); |
} |
} |
@@ -347,6 +353,16 @@ void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event, |
void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) { |
DCHECK(event.IsPointerEvent()); |
+ PointerTargetForEvent( |
+ event, base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget, |
+ base::Unretained(this), 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 +386,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 +401,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 +428,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 +459,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 +492,23 @@ 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); |
} |
-EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent( |
- const ui::LocatedEvent& event) { |
+void EventDispatcher::PointerTargetForEvent( |
+ const ui::PointerEvent& event, |
+ PointerTargetForEventCallback callback) { |
+ FindDeepestVisibleWindowForEvents( |
+ event.root_location(), |
+ base::BindOnce(&EventDispatcher::PointerTargetForEventOnFoundWindow, |
+ base::Unretained(this), event, std::move(callback))); |
+} |
+ |
+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 +516,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 +566,7 @@ void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) { |
// explicit capture. |
delegate_->OnCaptureChanged(nullptr, window); |
delegate_->ReleaseNativeCapture(); |
- UpdateCursorProviderByLastKnownLocation(); |
+ UpdateCursorProviderByLastKnownLocation(base::Closure()); |
return; |
} |
@@ -580,14 +606,92 @@ Accelerator* EventDispatcher::FindAccelerator( |
return nullptr; |
} |
-DeepestWindow EventDispatcher::FindDeepestVisibleWindowForEvents( |
- const gfx::Point& location) { |
+void EventDispatcher::FindDeepestVisibleWindowForEvents( |
+ const gfx::Point& location, |
+ HittestCallback callback) { |
+ if (hittest_in_flight_ || !hittest_request_queue_.empty()) { |
+ 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, |
+ base::Unretained(this), location, std::move(callback))); |
sky
2017/05/14 15:59:05
What guarantees this is valid by the time the call
riajiang
2017/05/15 18:34:41
As discussed, changed to use WeakPtrFactory.
|
+ } 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, |