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(¤t_event_, event); 145 handler->OnEvent(event); 146 if (!delegate_ && event->cancelable()) 147 event->StopPropagation(); 148} 149 150} // namespace ui 151