event_dispatcher.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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
9namespace ui {
10
11namespace {
12
13class ScopedDispatchHelper : public Event::DispatcherApi {
14 public:
15  explicit ScopedDispatchHelper(Event* event)
16      : Event::DispatcherApi(event) {
17    set_result(ui::ER_UNHANDLED);
18  }
19
20  virtual ~ScopedDispatchHelper() {
21    set_phase(EP_POSTDISPATCH);
22  }
23
24 private:
25  DISALLOW_COPY_AND_ASSIGN(ScopedDispatchHelper);
26};
27
28}  // namespace
29
30EventDispatcherDelegate::EventDispatcherDelegate()
31    : dispatcher_(NULL) {
32}
33
34EventDispatcherDelegate::~EventDispatcherDelegate() {
35  if (dispatcher_)
36    dispatcher_->OnDispatcherDelegateDestroyed();
37}
38
39Event* EventDispatcherDelegate::current_event() {
40  return dispatcher_ ? dispatcher_->current_event() : NULL;
41}
42
43bool EventDispatcherDelegate::DispatchEvent(EventTarget* target, Event* event) {
44  EventDispatcher* old_dispatcher = dispatcher_;
45  EventDispatcher dispatcher(this);
46  dispatcher_ = &dispatcher;
47  dispatcher.ProcessEvent(target, event);
48  if (!dispatcher.delegate_destroyed())
49    dispatcher_ = old_dispatcher;
50  else if (old_dispatcher)
51    old_dispatcher->OnDispatcherDelegateDestroyed();
52
53  return !dispatcher.delegate_destroyed();
54}
55
56EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
57    : delegate_(delegate),
58      current_event_(NULL) {
59}
60
61EventDispatcher::~EventDispatcher() {
62}
63
64void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
65  handler_list_.erase(std::find(handler_list_.begin(),
66                                handler_list_.end(),
67                                handler));
68}
69
70void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
71  if (!target || !target->CanAcceptEvent(*event))
72    return;
73
74  ScopedDispatchHelper dispatch_helper(event);
75  dispatch_helper.set_target(target);
76
77  handler_list_.clear();
78  target->GetPreTargetHandlers(&handler_list_);
79
80  dispatch_helper.set_phase(EP_PRETARGET);
81  DispatchEventToEventHandlers(handler_list_, event);
82  if (event->handled())
83    return;
84
85  // If the event hasn't been consumed, trigger the default handler. Note that
86  // even if the event has already been handled (i.e. return result has
87  // ER_HANDLED set), that means that the event should still be processed at
88  // this layer, however it should not be processed in the next layer of
89  // abstraction.
90  if (delegate_ && delegate_->CanDispatchToTarget(target)) {
91    dispatch_helper.set_phase(EP_TARGET);
92    DispatchEvent(target, event);
93    if (event->handled())
94      return;
95  }
96
97  if (!delegate_ || !delegate_->CanDispatchToTarget(target))
98    return;
99
100  handler_list_.clear();
101  target->GetPostTargetHandlers(&handler_list_);
102  dispatch_helper.set_phase(EP_POSTTARGET);
103  DispatchEventToEventHandlers(handler_list_, event);
104}
105
106void EventDispatcher::OnDispatcherDelegateDestroyed() {
107  delegate_ = NULL;
108}
109
110////////////////////////////////////////////////////////////////////////////////
111// EventDispatcher, private:
112
113void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList& list,
114                                                   Event* event) {
115  for (EventHandlerList::const_iterator it = list.begin(),
116           end = list.end(); it != end; ++it) {
117    (*it)->dispatchers_.push(this);
118  }
119
120  while (!list.empty()) {
121    EventHandler* handler = (*list.begin());
122    if (delegate_ && !event->stopped_propagation())
123      DispatchEvent(handler, event);
124
125    if (!list.empty() && *list.begin() == handler) {
126      // The handler has not been destroyed (because if it were, then it would
127      // have been removed from the list).
128      CHECK(handler->dispatchers_.top() == this);
129      handler->dispatchers_.pop();
130      list.erase(list.begin());
131    }
132  }
133}
134
135void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
136  // If the target has been invalidated or deleted, don't dispatch the event.
137  if (!delegate_->CanDispatchToTarget(event->target())) {
138    if (event->cancelable())
139      event->StopPropagation();
140    return;
141  }
142
143  base::AutoReset<Event*> event_reset(&current_event_, event);
144  handler->OnEvent(event);
145  if (!delegate_ && event->cancelable())
146    event->StopPropagation();
147}
148
149}  // namespace ui
150