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