event_dispatcher.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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  Event::DispatcherApi dispatch_helper(event);
50  dispatch_helper.set_phase(EP_PREDISPATCH);
51  dispatch_helper.set_result(ER_UNHANDLED);
52
53  EventDispatchDetails details = PreDispatchEvent(target, event);
54  if (!event->handled() && !details.dispatcher_destroyed)
55    details = DispatchEventToTarget(target, event);
56  if (!details.dispatcher_destroyed)
57    details = PostDispatchEvent(target, *event);
58
59  return details;
60}
61
62EventDispatchDetails EventDispatcherDelegate::PreDispatchEvent(
63    EventTarget* target, Event* event) {
64  return EventDispatchDetails();
65}
66
67EventDispatchDetails EventDispatcherDelegate::PostDispatchEvent(
68    EventTarget* target, const Event& event) {
69  return EventDispatchDetails();
70}
71
72EventDispatchDetails EventDispatcherDelegate::DispatchEventToTarget(
73    EventTarget* target,
74    Event* event) {
75  EventDispatcher* old_dispatcher = dispatcher_;
76  EventDispatcher dispatcher(this);
77  dispatcher_ = &dispatcher;
78  dispatcher.ProcessEvent(target, event);
79  if (!dispatcher.delegate_destroyed())
80    dispatcher_ = old_dispatcher;
81  else if (old_dispatcher)
82    old_dispatcher->OnDispatcherDelegateDestroyed();
83
84  return dispatcher.details();
85}
86
87////////////////////////////////////////////////////////////////////////////////
88// EventDispatcher:
89
90EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
91    : delegate_(delegate),
92      current_event_(NULL) {
93}
94
95EventDispatcher::~EventDispatcher() {
96}
97
98void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
99  handler_list_.erase(std::find(handler_list_.begin(),
100                                handler_list_.end(),
101                                handler));
102}
103
104void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
105  if (!target || !target->CanAcceptEvent(*event))
106    return;
107
108  ScopedDispatchHelper dispatch_helper(event);
109  dispatch_helper.set_target(target);
110
111  handler_list_.clear();
112  target->GetPreTargetHandlers(&handler_list_);
113
114  dispatch_helper.set_phase(EP_PRETARGET);
115  DispatchEventToEventHandlers(&handler_list_, event);
116  if (event->handled())
117    return;
118
119  // If the event hasn't been consumed, trigger the default handler. Note that
120  // even if the event has already been handled (i.e. return result has
121  // ER_HANDLED set), that means that the event should still be processed at
122  // this layer, however it should not be processed in the next layer of
123  // abstraction.
124  if (delegate_ && delegate_->CanDispatchToTarget(target)) {
125    dispatch_helper.set_phase(EP_TARGET);
126    DispatchEvent(target, event);
127    if (event->handled())
128      return;
129  }
130
131  if (!delegate_)
132    return;
133
134  if (!delegate_->CanDispatchToTarget(target)) {
135    details_.target_destroyed = true;
136    return;
137  }
138
139  handler_list_.clear();
140  target->GetPostTargetHandlers(&handler_list_);
141  dispatch_helper.set_phase(EP_POSTTARGET);
142  DispatchEventToEventHandlers(&handler_list_, event);
143}
144
145void EventDispatcher::OnDispatcherDelegateDestroyed() {
146  details_.dispatcher_destroyed = true;
147  delegate_ = NULL;
148}
149
150////////////////////////////////////////////////////////////////////////////////
151// EventDispatcher, private:
152
153void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
154                                                   Event* event) {
155  for (EventHandlerList::const_iterator it = list->begin(),
156           end = list->end(); it != end; ++it) {
157    (*it)->dispatchers_.push(this);
158  }
159
160  while (!list->empty()) {
161    EventHandler* handler = (*list->begin());
162    if (delegate_ && !event->stopped_propagation())
163      DispatchEvent(handler, event);
164
165    if (!list->empty() && *list->begin() == handler) {
166      // The handler has not been destroyed (because if it were, then it would
167      // have been removed from the list).
168      CHECK(handler->dispatchers_.top() == this);
169      handler->dispatchers_.pop();
170      list->erase(list->begin());
171    }
172  }
173}
174
175void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
176  // If the target has been invalidated or deleted, don't dispatch the event.
177  if (!delegate_->CanDispatchToTarget(event->target())) {
178    details_.target_destroyed = true;
179    if (event->cancelable())
180      event->StopPropagation();
181    return;
182  }
183
184  base::AutoReset<Event*> event_reset(&current_event_, event);
185  handler->OnEvent(event);
186  if (!delegate_ && event->cancelable())
187    event->StopPropagation();
188}
189
190}  // namespace ui
191