Chromium Code Reviews| Index: components/mus/ws/event_dispatcher.cc |
| diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc |
| index c1f775f93ee174aabc7e391faa050ceed0a47573..95414c95bc9fd0df8c6f999213767b469b54a694 100644 |
| --- a/components/mus/ws/event_dispatcher.cc |
| +++ b/components/mus/ws/event_dispatcher.cc |
| @@ -4,6 +4,8 @@ |
| #include "components/mus/ws/event_dispatcher.h" |
| +#include <set> |
| + |
| #include "cc/surfaces/surface_hittest.h" |
| #include "components/mus/surfaces/surfaces_state.h" |
| #include "components/mus/ws/event_dispatcher_delegate.h" |
| @@ -141,12 +143,17 @@ class EventMatcher { |
| //////////////////////////////////////////////////////////////////////////////// |
| EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate) |
| - : delegate_(delegate), |
| - root_(nullptr), |
| - capture_window_(nullptr), |
| - capture_in_nonclient_area_(false) {} |
| - |
| -EventDispatcher::~EventDispatcher() {} |
| + : delegate_(delegate), root_(nullptr) {} |
| + |
| +EventDispatcher::~EventDispatcher() { |
| + std::set<ServerWindow*> pointer_targets; |
| + for (const auto& pair : pointer_targets_) { |
| + if (pair.second.window && |
| + pointer_targets.insert(pair.second.window).second) { |
| + pair.second.window->RemoveObserver(this); |
| + } |
| + } |
| +} |
| void EventDispatcher::AddAccelerator(uint32_t id, |
| mojo::EventMatcherPtr event_matcher) { |
| @@ -179,35 +186,111 @@ void EventDispatcher::OnEvent(mojo::EventPtr event) { |
| } |
| } |
| - ServerWindow* target = FindEventTarget(event.get()); |
| - bool in_nonclient_area = false; |
| - |
| - if (IsMouseEventFlag(event->flags)) { |
| - if (!capture_window_ && target && |
| - (event->action == mojo::EVENT_TYPE_POINTER_DOWN)) { |
| - // TODO(sky): |capture_window_| needs to be reset when window removed |
| - // from hierarchy. |
| - capture_window_ = target; |
| - // TODO(sky): this needs to happen for pointer down events too. |
| - capture_in_nonclient_area_ = |
| - IsLocationInNonclientArea(target, EventLocationToPoint(*event)); |
| - in_nonclient_area = capture_in_nonclient_area_; |
| - } else if (event->action == mojo::EVENT_TYPE_POINTER_UP && |
| - IsOnlyOneMouseButtonDown(event->flags)) { |
| - capture_window_ = nullptr; |
| + if (event->key_data) { |
| + ProcessKeyEvent(event.Pass()); |
| + return; |
| + } |
| + |
| + if (event->pointer_data.get()) { |
| + ProcessPointerEvent(event.Pass()); |
| + return; |
| + } |
| + |
| + NOTREACHED(); |
| +} |
| + |
| +void EventDispatcher::ProcessKeyEvent(mojo::EventPtr event) { |
| + ServerWindow* focused_window = |
| + delegate_->GetFocusedWindowForEventDispatcher(); |
| + if (focused_window) |
| + delegate_->DispatchInputEventToWindow(focused_window, false, event.Pass()); |
| +} |
| + |
| +void EventDispatcher::ProcessPointerEvent(mojo::EventPtr event) { |
| + const int32_t pointer_id = event->pointer_data->pointer_id; |
| + if (event->action == mojo::EVENT_TYPE_WHEEL || |
| + (event->action == mojo::EVENT_TYPE_POINTER_MOVE && |
| + pointer_targets_.count(pointer_id) == 0)) { |
| + PointerTarget pointer_target; |
| + if (pointer_targets_.count(pointer_id) != 0) { |
| + pointer_target = pointer_targets_[pointer_id]; |
| + } else { |
| + gfx::Point location(EventLocationToPoint(*event)); |
| + pointer_target.window = |
| + FindDeepestVisibleWindow(root_, surface_id_, &location); |
| } |
| - in_nonclient_area = capture_in_nonclient_area_; |
| + DispatchToPointerTarget(pointer_target, event.Pass()); |
| + return; |
| } |
| - if (target) { |
| - if (event->action == mojo::EVENT_TYPE_POINTER_DOWN) |
| + // Pointer down implicitly captures. |
| + if (pointer_targets_.count(pointer_id) == 0) { |
| + DCHECK(event->action == mojo::EVENT_TYPE_POINTER_DOWN); |
| + const bool is_first_pointer_down = pointer_targets_.empty(); |
| + gfx::Point location(EventLocationToPoint(*event)); |
| + ServerWindow* target = |
| + FindDeepestVisibleWindow(root_, surface_id_, &location); |
| + DCHECK(target); |
| + if (!IsSendingPointerEventsToTarget(target)) |
| + target->AddObserver(this); |
| + |
| + pointer_targets_[pointer_id].window = target; |
| + pointer_targets_[pointer_id].in_nonclient_area = |
| + IsLocationInNonclientArea(target, location); |
| + |
| + if (is_first_pointer_down) |
| delegate_->SetFocusedWindowFromEventDispatcher(target); |
| + } |
| - delegate_->DispatchInputEventToWindow(target, in_nonclient_area, |
| - event.Pass()); |
| + // Release capture on pointer up. For mouse we only release if there are |
| + // no buttons down. |
| + const bool should_reset_target = |
| + (event->action == mojo::EVENT_TYPE_POINTER_UP || |
| + event->action == mojo::EVENT_TYPE_POINTER_CANCEL) && |
| + (event->pointer_data->kind != mojo::POINTER_KIND_MOUSE || |
| + IsOnlyOneMouseButtonDown(event->flags)); |
| + |
| + DispatchToPointerTarget(pointer_targets_[pointer_id], event.Pass()); |
| + |
| + if (should_reset_target) { |
| + ServerWindow* target = pointer_targets_[pointer_id].window; |
| + pointer_targets_.erase(pointer_id); |
| + if (target && !IsSendingPointerEventsToTarget(target)) |
| + target->RemoveObserver(this); |
| } |
| } |
| +void EventDispatcher::DispatchToPointerTarget(const PointerTarget& target, |
| + mojo::EventPtr event) { |
| + if (!target.window) |
| + return; |
| + |
| + gfx::Point location(EventLocationToPoint(*event)); |
| + gfx::Transform transform(GetTransformToWindow(surface_id_, target.window)); |
| + transform.TransformPoint(&location); |
| + event->pointer_data->location->x = location.x(); |
| + event->pointer_data->location->y = location.y(); |
| + delegate_->DispatchInputEventToWindow(target.window, target.in_nonclient_area, |
| + event.Pass()); |
| +} |
| + |
| +void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) { |
| + window->RemoveObserver(this); |
| + |
| + for (auto& pair : pointer_targets_) { |
| + if (pair.second.window == window) |
| + pair.second.window = nullptr; |
| + } |
| +} |
| + |
| +bool EventDispatcher::IsSendingPointerEventsToTarget(ServerWindow* window) { |
|
sadrul
2015/10/29 00:48:25
Would IsObservingWindow() better explain what this
sky
2015/10/29 14:54:16
Done.
|
| + for (const auto& pair : pointer_targets_) { |
| + if (pair.second.window == window) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| bool EventDispatcher::FindAccelerator(const mojo::Event& event, |
| uint32_t* accelerator_id) { |
| DCHECK(event.key_data); |
| @@ -220,31 +303,18 @@ bool EventDispatcher::FindAccelerator(const mojo::Event& event, |
| return false; |
| } |
| -ServerWindow* EventDispatcher::FindEventTarget(mojo::Event* event) { |
| - ServerWindow* focused_window = |
| - delegate_->GetFocusedWindowForEventDispatcher(); |
| - if (event->key_data) |
| - return focused_window; |
| - |
| - DCHECK(event->pointer_data) << "Unknown event type: " << event->action; |
| - mojo::LocationData* event_location = event->pointer_data->location.get(); |
| - DCHECK(event_location); |
| - gfx::Point location(static_cast<int>(event_location->x), |
| - static_cast<int>(event_location->y)); |
| - |
| - ServerWindow* target = capture_window_; |
| - |
| - if (!target) { |
| - target = FindDeepestVisibleWindow(root_, surface_id_, &location); |
| - } else { |
| - gfx::Transform transform(GetTransformToWindow(surface_id_, target)); |
| - transform.TransformPoint(&location); |
| - } |
| +void EventDispatcher::OnWillChangeWindowHierarchy(ServerWindow* window, |
| + ServerWindow* new_parent, |
| + ServerWindow* old_parent) { |
| + CancelPointerEventsToTarget(window); |
| +} |
| - event_location->x = location.x(); |
| - event_location->y = location.y(); |
| +void EventDispatcher::OnWindowVisibilityChanged(ServerWindow* window) { |
| + CancelPointerEventsToTarget(window); |
| +} |
| - return target; |
| +void EventDispatcher::OnWindowDestroyed(ServerWindow* window) { |
| + CancelPointerEventsToTarget(window); |
| } |
| } // namespace ws |