event_dispatcher.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/events/event_dispatcher.h"
6
7#include <algorithm>
8
9#include "ui/events/event_target.h"
10#include "ui/events/event_targeter.h"
11
12namespace ui {
13
14namespace {
15
16class ScopedDispatchHelper : public Event::DispatcherApi {
17 public:
18  explicit ScopedDispatchHelper(Event* event)
19      : Event::DispatcherApi(event) {
20    set_result(ui::ER_UNHANDLED);
21  }
22
23  virtual ~ScopedDispatchHelper() {
24    set_phase(EP_POSTDISPATCH);
25  }
26
27 private:
28  DISALLOW_COPY_AND_ASSIGN(ScopedDispatchHelper);
29};
30
31}  // namespace
32
33EventDispatcherDelegate::EventDispatcherDelegate()
34    : dispatcher_(NULL) {
35}
36
37EventDispatcherDelegate::~EventDispatcherDelegate() {
38  if (dispatcher_)
39    dispatcher_->OnDispatcherDelegateDestroyed();
40}
41
42Event* EventDispatcherDelegate::current_event() {
43  return dispatcher_ ? dispatcher_->current_event() : NULL;
44}
45
46EventDispatchDetails EventDispatcherDelegate::DispatchEvent(EventTarget* target,
47                                                            Event* event) {
48  CHECK(target);
49  EventDispatchDetails details = PreDispatchEvent(target, event);
50  if (!details.dispatcher_destroyed)
51    details = DispatchEventToTarget(target, event);
52  if (!details.dispatcher_destroyed)
53    details = PostDispatchEvent(target, *event);
54
55  return details;
56}
57
58EventDispatchDetails EventDispatcherDelegate::PreDispatchEvent(
59    EventTarget* target, Event* event) {
60  return EventDispatchDetails();
61}
62
63EventDispatchDetails EventDispatcherDelegate::PostDispatchEvent(
64    EventTarget* target, const Event& event) {
65  return EventDispatchDetails();
66}
67
68EventDispatchDetails EventDispatcherDelegate::DispatchEventToTarget(
69    EventTarget* target,
70    Event* event) {
71  EventDispatcher* old_dispatcher = dispatcher_;
72  EventDispatcher dispatcher(this);
73  dispatcher_ = &dispatcher;
74  dispatcher.ProcessEvent(target, event);
75  if (!dispatcher.delegate_destroyed())
76    dispatcher_ = old_dispatcher;
77  else if (old_dispatcher)
78    old_dispatcher->OnDispatcherDelegateDestroyed();
79
80  return dispatcher.details();
81}
82
83////////////////////////////////////////////////////////////////////////////////
84// EventDispatcher:
85
86EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
87    : delegate_(delegate),
88      current_event_(NULL) {
89}
90
91EventDispatcher::~EventDispatcher() {
92}
93
94void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
95  handler_list_.erase(std::find(handler_list_.begin(),
96                                handler_list_.end(),
97                                handler));
98}
99
100void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
101  if (!target || !target->CanAcceptEvent(*event))
102    return;
103
104  ScopedDispatchHelper dispatch_helper(event);
105  dispatch_helper.set_target(target);
106
107  handler_list_.clear();
108  target->GetPreTargetHandlers(&handler_list_);
109
110  dispatch_helper.set_phase(EP_PRETARGET);
111  DispatchEventToEventHandlers(&handler_list_, event);
112  if (event->handled())
113    return;
114
115  // If the event hasn't been consumed, trigger the default handler. Note that
116  // even if the event has already been handled (i.e. return result has
117  // ER_HANDLED set), that means that the event should still be processed at
118  // this layer, however it should not be processed in the next layer of
119  // abstraction.
120  if (delegate_ && delegate_->CanDispatchToTarget(target)) {
121    dispatch_helper.set_phase(EP_TARGET);
122    DispatchEvent(target, event);
123    if (event->handled())
124      return;
125  }
126
127  if (!delegate_)
128    return;
129
130  if (!delegate_->CanDispatchToTarget(target)) {
131    details_.target_destroyed = true;
132    return;
133  }
134
135  handler_list_.clear();
136  target->GetPostTargetHandlers(&handler_list_);
137  dispatch_helper.set_phase(EP_POSTTARGET);
138  DispatchEventToEventHandlers(&handler_list_, event);
139}
140
141void EventDispatcher::OnDispatcherDelegateDestroyed() {
142  details_.dispatcher_destroyed = true;
143  delegate_ = NULL;
144}
145
146////////////////////////////////////////////////////////////////////////////////
147// EventDispatcher, private:
148
149void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
150                                                   Event* event) {
151  for (EventHandlerList::const_iterator it = list->begin(),
152           end = list->end(); it != end; ++it) {
153    (*it)->dispatchers_.push(this);
154  }
155
156  while (!list->empty()) {
157    EventHandler* handler = (*list->begin());
158    if (delegate_ && !event->stopped_propagation())
159      DispatchEvent(handler, event);
160
161    if (!list->empty() && *list->begin() == handler) {
162      // The handler has not been destroyed (because if it were, then it would
163      // have been removed from the list).
164      CHECK(handler->dispatchers_.top() == this);
165      handler->dispatchers_.pop();
166      list->erase(list->begin());
167    }
168  }
169}
170
171void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
172  // If the target has been invalidated or deleted, don't dispatch the event.
173  if (!delegate_->CanDispatchToTarget(event->target())) {
174    details_.target_destroyed = true;
175    if (event->cancelable())
176      event->StopPropagation();
177    return;
178  }
179
180  base::AutoReset<Event*> event_reset(&current_event_, event);
181  handler->OnEvent(event);
182  if (!delegate_ && event->cancelable())
183    event->StopPropagation();
184}
185
186}  // namespace ui
187