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