event_dispatcher.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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() && 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 69EventDispatchDetails EventDispatcherDelegate::PreDispatchEvent( 70 EventTarget* target, Event* event) { 71 return EventDispatchDetails(); 72} 73 74EventDispatchDetails EventDispatcherDelegate::PostDispatchEvent( 75 EventTarget* target, const Event& event) { 76 return EventDispatchDetails(); 77} 78 79EventDispatchDetails 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 101EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate) 102 : delegate_(delegate), 103 current_event_(NULL) { 104} 105 106EventDispatcher::~EventDispatcher() { 107} 108 109void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) { 110 handler_list_.erase(std::find(handler_list_.begin(), 111 handler_list_.end(), 112 handler)); 113} 114 115void 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 151void EventDispatcher::OnDispatcherDelegateDestroyed() { 152 delegate_ = NULL; 153} 154 155//////////////////////////////////////////////////////////////////////////////// 156// EventDispatcher, private: 157 158void 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 180void 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