| Index: mojo/services/view_manager/gesture_manager.cc
|
| diff --git a/mojo/services/view_manager/gesture_manager.cc b/mojo/services/view_manager/gesture_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1b312bd6b0e4d9c1567df0aff3b6f20fdaa4e26d
|
| --- /dev/null
|
| +++ b/mojo/services/view_manager/gesture_manager.cc
|
| @@ -0,0 +1,701 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "mojo/services/view_manager/gesture_manager.h"
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "mojo/services/view_manager/gesture_manager_delegate.h"
|
| +#include "mojo/services/view_manager/server_view.h"
|
| +#include "mojo/services/view_manager/view_coordinate_conversions.h"
|
| +#include "mojo/services/view_manager/view_locator.h"
|
| +#include "third_party/mojo_services/src/input_events/public/interfaces/input_events.mojom.h"
|
| +#include "third_party/mojo_services/src/view_manager/public/cpp/keys.h"
|
| +#include "ui/gfx/geometry/point_f.h"
|
| +
|
| +namespace view_manager {
|
| +
|
| +using Views = std::vector<const ServerView*>;
|
| +
|
| +namespace {
|
| +
|
| +GestureManager::GestureAndConnectionId MakeGestureAndConnectionId(
|
| + const ServerView* view,
|
| + uint32_t gesture_id) {
|
| + return (static_cast<GestureManager::GestureAndConnectionId>(
|
| + view->id().connection_id)
|
| + << 32) |
|
| + gesture_id;
|
| +}
|
| +
|
| +// Returns the views (deepest first) that should receive touch events. This only
|
| +// returns one view per connection. If multiple views from the same connection
|
| +// are interested in touch events the shallowest view is returned.
|
| +Views GetTouchTargets(const ServerView* deepest) {
|
| + Views result;
|
| + const ServerView* view = deepest;
|
| + while (view) {
|
| + if (view->properties().count(mojo::kViewManagerKeyWantsTouchEvents)) {
|
| + if (!result.empty() &&
|
| + result.back()->id().connection_id == view->id().connection_id) {
|
| + result.pop_back();
|
| + }
|
| + result.push_back(view);
|
| + }
|
| + view = view->parent();
|
| + }
|
| + // TODO(sky): I'm doing this until things are converted. Seems as though we
|
| + // shouldn't do this long term.
|
| + if (result.empty())
|
| + result.push_back(deepest);
|
| + return result;
|
| +}
|
| +
|
| +mojo::EventPtr CloneEventForView(const mojo::Event& event,
|
| + const ServerView* view) {
|
| + mojo::EventPtr result(event.Clone());
|
| + const gfx::PointF location(event.pointer_data->x, event.pointer_data->y);
|
| + const gfx::PointF target_location(
|
| + ConvertPointFBetweenViews(view->GetRoot(), view, location));
|
| + result->pointer_data->x = target_location.x();
|
| + result->pointer_data->y = target_location.y();
|
| + return result.Pass();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// GestureStateChange ----------------------------------------------------------
|
| +
|
| +GestureStateChange::GestureStateChange()
|
| + : chosen_gesture(GestureManager::kInvalidGestureId) {
|
| +}
|
| +
|
| +GestureStateChange::~GestureStateChange() {
|
| +}
|
| +
|
| +// ViewIterator ----------------------------------------------------------------
|
| +
|
| +// Used to iterate over a set of views.
|
| +class ViewIterator {
|
| + public:
|
| + explicit ViewIterator(const Views& views)
|
| + : views_(views), current_(views_.begin()) {}
|
| +
|
| + // Advances to the next view. Returns true if there are no more views (at
|
| + // the end).
|
| + bool advance() { return ++current_ != views_.end(); }
|
| +
|
| + bool at_end() const { return current_ == views_.end(); }
|
| +
|
| + bool empty() const { return views_.empty(); }
|
| +
|
| + const ServerView* current() const { return *current_; }
|
| +
|
| + void reset_to_beginning() { current_ = views_.begin(); }
|
| +
|
| + void remove(const ServerView* view) {
|
| + Views::iterator iter = std::find(views_.begin(), views_.end(), view);
|
| + DCHECK(iter != views_.end());
|
| + if (iter == current_) {
|
| + current_ = views_.erase(current_);
|
| + } else if (!at_end()) {
|
| + size_t index = current_ - views_.begin();
|
| + if (current_ > iter)
|
| + index--;
|
| + views_.erase(iter);
|
| + current_ = views_.begin() + index;
|
| + } else {
|
| + views_.erase(iter);
|
| + current_ = views_.end();
|
| + }
|
| + }
|
| +
|
| + bool contains(const ServerView* view) const {
|
| + return std::find(views_.begin(), views_.end(), view) != views_.end();
|
| + }
|
| +
|
| + private:
|
| + Views views_;
|
| + Views::iterator current_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ViewIterator);
|
| +};
|
| +
|
| +// PointerAndView --------------------------------------------------------------
|
| +
|
| +struct GestureManager::PointerAndView {
|
| + PointerAndView();
|
| + PointerAndView(Pointer* pointer, const ServerView* view);
|
| +
|
| + // Compares two PointerAndView instances based on pointer id, then view id.
|
| + // This is really only interesting for unit tests so that they get a known
|
| + // order of events.
|
| + bool operator<(const PointerAndView& other) const;
|
| +
|
| + Pointer* pointer;
|
| + const ServerView* view;
|
| +};
|
| +
|
| +// Gesture ---------------------------------------------------------------------
|
| +
|
| +// Gesture maintains the set of pointers and views it is attached to.
|
| +class GestureManager::Gesture {
|
| + public:
|
| + enum State { STATE_INITIAL, STATE_CANCELED, STATE_CHOSEN };
|
| +
|
| + explicit Gesture(uint32_t id);
|
| + ~Gesture();
|
| +
|
| + uint32_t id() const { return id_; }
|
| +
|
| + void Attach(Pointer* pointer, const ServerView* view);
|
| + void Detach(Pointer* pointer, const ServerView* view);
|
| +
|
| + void set_state(State state) { state_ = state; }
|
| + State state() const { return state_; }
|
| +
|
| + const std::set<PointerAndView>& pointers_and_views() const {
|
| + return pointers_and_views_;
|
| + }
|
| +
|
| + private:
|
| + const uint32_t id_;
|
| + State state_;
|
| + std::set<PointerAndView> pointers_and_views_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Gesture);
|
| +};
|
| +
|
| +GestureManager::Gesture::Gesture(uint32_t id) : id_(id), state_(STATE_INITIAL) {
|
| +}
|
| +
|
| +GestureManager::Gesture::~Gesture() {
|
| +}
|
| +
|
| +void GestureManager::Gesture::Attach(Pointer* pointer, const ServerView* view) {
|
| + pointers_and_views_.insert(PointerAndView(pointer, view));
|
| +}
|
| +
|
| +void GestureManager::Gesture::Detach(Pointer* pointer, const ServerView* view) {
|
| + pointers_and_views_.erase(PointerAndView(pointer, view));
|
| +}
|
| +
|
| +// Pointer ---------------------------------------------------------------------
|
| +
|
| +// Pointer manages the state associated with a particular pointer from the time
|
| +// of the POINTER_DOWN to the time of the POINTER_UP (or POINTER_CANCEL). This
|
| +// state includes a mapping from view to the set of gestures the view is
|
| +// interested in. It also manages choosing gestures at the appropriate point as
|
| +// well as which view to dispatch to and the events to dispatch.
|
| +// See description in GestureManager for more.
|
| +class GestureManager::Pointer {
|
| + public:
|
| + Pointer(GestureManager* gesture_manager,
|
| + int32_t pointer_id,
|
| + const mojo::Event& event,
|
| + const Views& views);
|
| + ~Pointer();
|
| +
|
| + int32_t pointer_id() const { return pointer_id_; }
|
| + bool was_chosen_or_canceled() const { return was_chosen_or_canceled_; }
|
| +
|
| + // Sets the set of gestures for this pointer.
|
| + void SetGestures(const ServerView* view,
|
| + uint32_t chosen_gesture_id,
|
| + const std::set<uint32_t>& possible_gesture_ids,
|
| + const std::set<uint32_t>& canceled_ids);
|
| +
|
| + // Called when a Gesture we contain has been canceled.
|
| + void GestureCanceled(Gesture* gesture);
|
| +
|
| + // Called when a Gesture we contain has been chosen.
|
| + void GestureChosen(Gesture* gesture, const ServerView* view);
|
| +
|
| + // Process a move or up event. This may delay processing if we're waiting for
|
| + // previous results.
|
| + void ProcessEvent(const mojo::Event& event);
|
| +
|
| + private:
|
| + // Corresponds to the type of event we're dispatching.
|
| + enum Phase {
|
| + // We're dispatching the initial down.
|
| + PHASE_DOWN,
|
| +
|
| + // We're dispatching a move.
|
| + PHASE_MOVE,
|
| + };
|
| +
|
| + // Sends the event for the current phase to the delegate.
|
| + void ForwardCurrentEvent();
|
| +
|
| + // Moves |pending_event_| to |current_event_| and notifies the delegate.
|
| + void MovePendingToCurrentAndProcess();
|
| +
|
| + // If |was_chosen_or_canceled_| is false and there is only one possible
|
| + // gesture and it is in the initial state, choose it. Otherwise do nothing.
|
| + void ChooseGestureIfPossible();
|
| +
|
| + bool ScheduleDeleteIfNecessary();
|
| +
|
| + GestureManager* gesture_manager_;
|
| + const int32_t pointer_id_;
|
| + Phase phase_;
|
| +
|
| + // Used to iterate over the set of views that potentially have gestures.
|
| + ViewIterator view_iter_;
|
| +
|
| + // Maps from the view to the set of possible gestures for the view.
|
| + std::map<const ServerView*, std::set<Gesture*>> view_to_gestures_;
|
| +
|
| + Gesture* chosen_gesture_;
|
| +
|
| + bool was_chosen_or_canceled_;
|
| +
|
| + // The event we're processing. When initially created this is the supplied
|
| + // down event. When in PHASE_MOVE this is a move event.
|
| + mojo::EventPtr current_event_;
|
| +
|
| + // Incoming events (move or up) are added here while while waiting for
|
| + // responses.
|
| + mojo::EventPtr pending_event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Pointer);
|
| +};
|
| +
|
| +GestureManager::Pointer::Pointer(GestureManager* gesture_manager,
|
| + int32_t pointer_id,
|
| + const mojo::Event& event,
|
| + const Views& views)
|
| + : gesture_manager_(gesture_manager),
|
| + pointer_id_(pointer_id),
|
| + phase_(PHASE_DOWN),
|
| + view_iter_(views),
|
| + chosen_gesture_(nullptr),
|
| + was_chosen_or_canceled_(false),
|
| + current_event_(event.Clone()) {
|
| + ForwardCurrentEvent();
|
| +}
|
| +
|
| +GestureManager::Pointer::~Pointer() {
|
| + for (auto& pair : view_to_gestures_) {
|
| + for (Gesture* gesture : pair.second)
|
| + gesture_manager_->DetachGesture(gesture, this, pair.first);
|
| + }
|
| +}
|
| +
|
| +void GestureManager::Pointer::SetGestures(
|
| + const ServerView* view,
|
| + uint32_t chosen_gesture_id,
|
| + const std::set<uint32_t>& possible_gesture_ids,
|
| + const std::set<uint32_t>& canceled_gesture_ids) {
|
| + if (!view_iter_.contains(view)) {
|
| + // We don't know about this view.
|
| + return;
|
| + }
|
| +
|
| + // True if this is the view we're waiting for a response from.
|
| + const bool was_waiting_on =
|
| + (!was_chosen_or_canceled_ &&
|
| + (!view_iter_.at_end() && view_iter_.current() == view));
|
| +
|
| + if (possible_gesture_ids.empty()) {
|
| + // The view no longer wants to be notified.
|
| + for (Gesture* gesture : view_to_gestures_[view])
|
| + gesture_manager_->DetachGesture(gesture, this, view);
|
| + view_to_gestures_.erase(view);
|
| + view_iter_.remove(view);
|
| + if (view_iter_.empty()) {
|
| + gesture_manager_->PointerHasNoGestures(this);
|
| + // WARNING: we've been deleted.
|
| + return;
|
| + }
|
| + } else {
|
| + if (was_waiting_on)
|
| + view_iter_.advance();
|
| +
|
| + Gesture* to_choose = nullptr;
|
| + std::set<Gesture*> gestures;
|
| + for (auto gesture_id : possible_gesture_ids) {
|
| + Gesture* gesture = gesture_manager_->GetGesture(view, gesture_id);
|
| + gesture_manager_->AttachGesture(gesture, this, view);
|
| + gestures.insert(gesture);
|
| + if (gesture->state() == Gesture::STATE_CHOSEN &&
|
| + !was_chosen_or_canceled_) {
|
| + to_choose = gesture;
|
| + }
|
| + }
|
| +
|
| + // Give preference to the supplied |chosen_gesture_id|.
|
| + if (!was_chosen_or_canceled_ && chosen_gesture_id != kInvalidGestureId) {
|
| + Gesture* gesture = gesture_manager_->GetGesture(view, chosen_gesture_id);
|
| + if (gesture->state() != Gesture::STATE_CANCELED)
|
| + to_choose = gesture;
|
| +
|
| + DCHECK(possible_gesture_ids.count(gesture->id()));
|
| + gesture_manager_->AttachGesture(gesture, this, view);
|
| + }
|
| +
|
| + // Tell GestureManager of any Gestures we're no longer associated with.
|
| + std::set<Gesture*> removed_gestures;
|
| + std::set_difference(
|
| + view_to_gestures_[view].begin(), view_to_gestures_[view].end(),
|
| + gestures.begin(), gestures.end(),
|
| + std::inserter(removed_gestures, removed_gestures.begin()));
|
| + view_to_gestures_[view].swap(gestures);
|
| + for (Gesture* gesture : removed_gestures)
|
| + gesture_manager_->DetachGesture(gesture, this, view);
|
| +
|
| + if (chosen_gesture_ && removed_gestures.count(chosen_gesture_))
|
| + chosen_gesture_ = nullptr;
|
| +
|
| + if (to_choose) {
|
| + gesture_manager_->ChooseGesture(to_choose, this, view);
|
| + } else {
|
| + // Choosing a gesture implicitly cancels all other gestures. If we didn't
|
| + // choose a gesture we need to update the state of any newly added
|
| + // gestures.
|
| + for (Gesture* gesture : gestures) {
|
| + if (gesture != chosen_gesture_ &&
|
| + (was_chosen_or_canceled_ ||
|
| + canceled_gesture_ids.count(gesture->id()))) {
|
| + gesture_manager_->CancelGesture(gesture, this, view);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (was_waiting_on && !was_chosen_or_canceled_) {
|
| + if (view_iter_.at_end()) {
|
| + if (ScheduleDeleteIfNecessary())
|
| + return;
|
| + // If we're got all the responses, check if there is only one valid
|
| + // gesture.
|
| + ChooseGestureIfPossible();
|
| + if (!was_chosen_or_canceled_) {
|
| + // There is more than one valid gesture and none chosen. Continue
|
| + // synchronous dispatch of move events.
|
| + phase_ = PHASE_MOVE;
|
| + MovePendingToCurrentAndProcess();
|
| + }
|
| + } else {
|
| + ForwardCurrentEvent();
|
| + }
|
| + } else if (!was_chosen_or_canceled_ && phase_ != PHASE_DOWN) {
|
| + // We weren't waiting on this view but we're in the move phase. The set of
|
| + // gestures may have changed such that we only have one valid gesture. Check
|
| + // for that.
|
| + ChooseGestureIfPossible();
|
| + }
|
| +}
|
| +
|
| +void GestureManager::Pointer::GestureCanceled(Gesture* gesture) {
|
| + if (was_chosen_or_canceled_ && gesture == chosen_gesture_) {
|
| + chosen_gesture_ = nullptr;
|
| + // No need to cancel other gestures as they are already canceled by virtue
|
| + // of us having been chosen.
|
| + } else if (!was_chosen_or_canceled_ && phase_ == PHASE_MOVE) {
|
| + ChooseGestureIfPossible();
|
| + }
|
| +}
|
| +
|
| +void GestureManager::Pointer::GestureChosen(Gesture* gesture,
|
| + const ServerView* view) {
|
| + DCHECK(!was_chosen_or_canceled_);
|
| + was_chosen_or_canceled_ = true;
|
| + chosen_gesture_ = gesture;
|
| + for (auto& pair : view_to_gestures_) {
|
| + for (Gesture* g : pair.second) {
|
| + if (g != gesture)
|
| + gesture_manager_->CancelGesture(g, this, pair.first);
|
| + }
|
| + }
|
| +
|
| + while (!view_iter_.at_end()) {
|
| + ForwardCurrentEvent();
|
| + view_iter_.advance();
|
| + }
|
| + if (ScheduleDeleteIfNecessary())
|
| + return;
|
| + phase_ = PHASE_MOVE;
|
| + MovePendingToCurrentAndProcess();
|
| +}
|
| +
|
| +void GestureManager::Pointer::ProcessEvent(const mojo::Event& event) {
|
| + // |event| is either a move or up. In either case it has the new coordinates
|
| + // and is safe to replace the existing one with.
|
| + pending_event_ = event.Clone();
|
| + if (was_chosen_or_canceled_) {
|
| + MovePendingToCurrentAndProcess();
|
| + } else if (view_iter_.at_end()) {
|
| + view_iter_.reset_to_beginning();
|
| + MovePendingToCurrentAndProcess();
|
| + }
|
| + // The else case is we are waiting on a response from a view before we
|
| + // continue dispatching. When we get the response for the last view in the
|
| + // stack we'll move pending to current and start dispatching it.
|
| +}
|
| +
|
| +void GestureManager::Pointer::ForwardCurrentEvent() {
|
| + DCHECK(!view_iter_.at_end());
|
| + const ServerView* view = view_iter_.current();
|
| + gesture_manager_->delegate_->ProcessEvent(
|
| + view, CloneEventForView(*current_event_, view), was_chosen_or_canceled_);
|
| +}
|
| +
|
| +void GestureManager::Pointer::MovePendingToCurrentAndProcess() {
|
| + if (!pending_event_.get()) {
|
| + current_event_ = nullptr;
|
| + return;
|
| + }
|
| + current_event_ = pending_event_.Pass();
|
| + view_iter_.reset_to_beginning();
|
| + ForwardCurrentEvent();
|
| + if (was_chosen_or_canceled_) {
|
| + while (view_iter_.advance())
|
| + ForwardCurrentEvent();
|
| + if (ScheduleDeleteIfNecessary())
|
| + return;
|
| + current_event_ = nullptr;
|
| + }
|
| +}
|
| +
|
| +void GestureManager::Pointer::ChooseGestureIfPossible() {
|
| + if (was_chosen_or_canceled_)
|
| + return;
|
| +
|
| + Gesture* gesture_to_choose = nullptr;
|
| + const ServerView* view = nullptr;
|
| + for (auto& pair : view_to_gestures_) {
|
| + for (Gesture* gesture : pair.second) {
|
| + if (gesture->state() == Gesture::STATE_INITIAL) {
|
| + if (gesture_to_choose)
|
| + return;
|
| + view = pair.first;
|
| + gesture_to_choose = gesture;
|
| + }
|
| + }
|
| + }
|
| + if (view)
|
| + gesture_manager_->ChooseGesture(gesture_to_choose, this, view);
|
| +}
|
| +
|
| +bool GestureManager::Pointer::ScheduleDeleteIfNecessary() {
|
| + if (current_event_ &&
|
| + (current_event_->action == mojo::EVENT_TYPE_POINTER_UP ||
|
| + current_event_->action == mojo::EVENT_TYPE_POINTER_CANCEL)) {
|
| + gesture_manager_->ScheduleDelete(this);
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +// ScheduledDeleteProcessor ---------------------------------------------------
|
| +
|
| +class GestureManager::ScheduledDeleteProcessor {
|
| + public:
|
| + explicit ScheduledDeleteProcessor(GestureManager* manager)
|
| + : manager_(manager) {}
|
| +
|
| + ~ScheduledDeleteProcessor() { manager_->pointers_to_delete_.clear(); }
|
| +
|
| + private:
|
| + GestureManager* manager_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ScheduledDeleteProcessor);
|
| +};
|
| +
|
| +// PointerAndView --------------------------------------------------------------
|
| +
|
| +GestureManager::PointerAndView::PointerAndView()
|
| + : pointer(nullptr), view(nullptr) {
|
| +}
|
| +
|
| +GestureManager::PointerAndView::PointerAndView(Pointer* pointer,
|
| + const ServerView* view)
|
| + : pointer(pointer), view(view) {
|
| +}
|
| +
|
| +bool GestureManager::PointerAndView::operator<(
|
| + const PointerAndView& other) const {
|
| + if (other.pointer->pointer_id() == pointer->pointer_id())
|
| + return view->id().connection_id < other.view->id().connection_id;
|
| + return pointer->pointer_id() < other.pointer->pointer_id();
|
| +}
|
| +
|
| +// GestureManager --------------------------------------------------------------
|
| +
|
| +// static
|
| +const uint32_t GestureManager::kInvalidGestureId = 0u;
|
| +
|
| +GestureManager::GestureManager(GestureManagerDelegate* delegate,
|
| + const ServerView* root)
|
| + : delegate_(delegate), root_view_(root) {
|
| +}
|
| +
|
| +GestureManager::~GestureManager() {
|
| + // Explicitly delete the pointers first as this may result in calling back to
|
| + // us to cleanup and delete gestures.
|
| + active_pointers_.clear();
|
| +}
|
| +
|
| +bool GestureManager::ProcessEvent(const mojo::Event& event) {
|
| + if (!event.pointer_data)
|
| + return false;
|
| +
|
| + ScheduledDeleteProcessor delete_processor(this);
|
| + const gfx::Point location(static_cast<int>(event.pointer_data->x),
|
| + static_cast<int>(event.pointer_data->y));
|
| + switch (event.action) {
|
| + case mojo::EVENT_TYPE_POINTER_DOWN: {
|
| + if (GetPointerById(event.pointer_data->pointer_id)) {
|
| + DVLOG(1) << "received more than one down for a pointer without a "
|
| + << "corresponding up, id=" << event.pointer_data->pointer_id;
|
| + NOTREACHED();
|
| + return true;
|
| + }
|
| +
|
| + const ServerView* deepest = FindDeepestVisibleView(root_view_, location);
|
| + Views targets(GetTouchTargets(deepest));
|
| + if (targets.empty())
|
| + return true;
|
| +
|
| + scoped_ptr<Pointer> pointer(
|
| + new Pointer(this, event.pointer_data->pointer_id, event, targets));
|
| + active_pointers_.push_back(pointer.Pass());
|
| + return true;
|
| + }
|
| +
|
| + case mojo::EVENT_TYPE_POINTER_CANCEL:
|
| + case mojo::EVENT_TYPE_POINTER_MOVE:
|
| + case mojo::EVENT_TYPE_POINTER_UP: {
|
| + Pointer* pointer = GetPointerById(event.pointer_data->pointer_id);
|
| + // We delete a pointer when it has no gestures, so it's possible to get
|
| + // here with no gestures. Additionally there is no need to explicitly
|
| + // delete |pointer| as it'll tell us when it's ready to be deleted.
|
| + if (pointer)
|
| + pointer->ProcessEvent(event);
|
| + return true;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +scoped_ptr<ChangeMap> GestureManager::SetGestures(
|
| + const ServerView* view,
|
| + int32_t pointer_id,
|
| + uint32_t chosen_gesture_id,
|
| + const std::set<uint32_t>& possible_gesture_ids,
|
| + const std::set<uint32_t>& canceled_gesture_ids) {
|
| + // TODO(sky): caller should validate ids and make sure possible contains
|
| + // canceled and chosen.
|
| + DCHECK(!canceled_gesture_ids.count(kInvalidGestureId));
|
| + DCHECK(!possible_gesture_ids.count(kInvalidGestureId));
|
| + DCHECK(chosen_gesture_id == kInvalidGestureId ||
|
| + possible_gesture_ids.count(chosen_gesture_id));
|
| + DCHECK(chosen_gesture_id == kInvalidGestureId ||
|
| + !canceled_gesture_ids.count(chosen_gesture_id));
|
| + ScheduledDeleteProcessor delete_processor(this);
|
| + Pointer* pointer = GetPointerById(pointer_id);
|
| + current_change_.reset(new ChangeMap);
|
| + if (pointer) {
|
| + pointer->SetGestures(view, chosen_gesture_id, possible_gesture_ids,
|
| + canceled_gesture_ids);
|
| + }
|
| + return current_change_.Pass();
|
| +}
|
| +
|
| +GestureManager::Pointer* GestureManager::GetPointerById(int32_t pointer_id) {
|
| + for (Pointer* pointer : active_pointers_) {
|
| + if (pointer->pointer_id() == pointer_id)
|
| + return pointer;
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +void GestureManager::PointerHasNoGestures(Pointer* pointer) {
|
| + auto iter =
|
| + std::find(active_pointers_.begin(), active_pointers_.end(), pointer);
|
| + CHECK(iter != active_pointers_.end());
|
| + active_pointers_.erase(iter);
|
| +}
|
| +
|
| +GestureManager::Gesture* GestureManager::GetGesture(const ServerView* view,
|
| + uint32_t gesture_id) {
|
| + GestureAndConnectionId gesture_and_connection_id =
|
| + MakeGestureAndConnectionId(view, gesture_id);
|
| + Gesture* gesture = gesture_map_[gesture_and_connection_id];
|
| + if (!gesture) {
|
| + gesture = new Gesture(gesture_id);
|
| + gesture_map_[gesture_and_connection_id] = gesture;
|
| + }
|
| + return gesture;
|
| +}
|
| +
|
| +void GestureManager::AttachGesture(Gesture* gesture,
|
| + Pointer* pointer,
|
| + const ServerView* view) {
|
| + gesture->Attach(pointer, view);
|
| +}
|
| +
|
| +void GestureManager::DetachGesture(Gesture* gesture,
|
| + Pointer* pointer,
|
| + const ServerView* view) {
|
| + gesture->Detach(pointer, view);
|
| + if (gesture->pointers_and_views().empty()) {
|
| + gesture_map_.erase(MakeGestureAndConnectionId(view, gesture->id()));
|
| + delete gesture;
|
| + }
|
| +}
|
| +
|
| +void GestureManager::CancelGesture(Gesture* gesture,
|
| + Pointer* pointer,
|
| + const ServerView* view) {
|
| + if (gesture->state() == Gesture::STATE_CANCELED)
|
| + return;
|
| +
|
| + gesture->set_state(Gesture::STATE_CANCELED);
|
| + for (auto& pointer_and_view : gesture->pointers_and_views()) {
|
| + (*current_change_)[pointer_and_view.view].canceled_gestures.insert(
|
| + gesture->id());
|
| + if (pointer_and_view.pointer != pointer)
|
| + pointer_and_view.pointer->GestureCanceled(gesture);
|
| + }
|
| +}
|
| +
|
| +void GestureManager::ChooseGesture(Gesture* gesture,
|
| + Pointer* pointer,
|
| + const ServerView* view) {
|
| + if (gesture->state() == Gesture::STATE_CHOSEN) {
|
| + // This happens when |pointer| is supplied a gesture that is already
|
| + // chosen.
|
| + DCHECK((*current_change_)[view].chosen_gesture == kInvalidGestureId ||
|
| + (*current_change_)[view].chosen_gesture == gesture->id());
|
| + (*current_change_)[view].chosen_gesture = gesture->id();
|
| + pointer->GestureChosen(gesture, view);
|
| + } else {
|
| + gesture->set_state(Gesture::STATE_CHOSEN);
|
| + for (auto& pointer_and_view : gesture->pointers_and_views()) {
|
| + DCHECK((*current_change_)[pointer_and_view.view].chosen_gesture ==
|
| + kInvalidGestureId ||
|
| + (*current_change_)[pointer_and_view.view].chosen_gesture ==
|
| + gesture->id());
|
| + (*current_change_)[pointer_and_view.view].chosen_gesture = gesture->id();
|
| + pointer_and_view.pointer->GestureChosen(gesture, view);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void GestureManager::ScheduleDelete(Pointer* pointer) {
|
| + auto iter =
|
| + std::find(active_pointers_.begin(), active_pointers_.end(), pointer);
|
| + if (iter != active_pointers_.end()) {
|
| + active_pointers_.weak_erase(iter);
|
| + pointers_to_delete_.push_back(pointer);
|
| + }
|
| +}
|
| +
|
| +} // namespace view_manager
|
|
|