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 |