Home | History | Annotate | Download | only in events
      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:
     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 
     33 EventDispatcherDelegate::EventDispatcherDelegate()
     34     : dispatcher_(NULL) {
     35 }
     36 
     37 EventDispatcherDelegate::~EventDispatcherDelegate() {
     38   if (dispatcher_)
     39     dispatcher_->OnDispatcherDelegateDestroyed();
     40 }
     41 
     42 Event* EventDispatcherDelegate::current_event() {
     43   return dispatcher_ ? dispatcher_->current_event() : NULL;
     44 }
     45 
     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 
     69 EventDispatchDetails EventDispatcherDelegate::PreDispatchEvent(
     70     EventTarget* target, Event* event) {
     71   return EventDispatchDetails();
     72 }
     73 
     74 EventDispatchDetails EventDispatcherDelegate::PostDispatchEvent(
     75     EventTarget* target, const Event& event) {
     76   return EventDispatchDetails();
     77 }
     78 
     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 
    101 EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
    102     : delegate_(delegate),
    103       current_event_(NULL) {
    104 }
    105 
    106 EventDispatcher::~EventDispatcher() {
    107 }
    108 
    109 void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
    110   handler_list_.erase(std::find(handler_list_.begin(),
    111                                 handler_list_.end(),
    112                                 handler));
    113 }
    114 
    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 
    151 void EventDispatcher::OnDispatcherDelegateDestroyed() {
    152   delegate_ = NULL;
    153 }
    154 
    155 ////////////////////////////////////////////////////////////////////////////////
    156 // EventDispatcher, private:
    157 
    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 
    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(&current_event_, event);
    189   handler->OnEvent(event);
    190   if (!delegate_ && event->cancelable())
    191     event->StopPropagation();
    192 }
    193 
    194 }  // namespace ui
    195