summaryrefslogtreecommitdiffstats
path: root/ui/base/events/event_dispatcher.h
blob: 8e475be8bc389d79e36d7651e0c8fe3de0e4e82d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_BASE_EVENTS_EVENT_DISPATCHER_H_
#define UI_BASE_EVENTS_EVENT_DISPATCHER_H_

#include "ui/base/events/event.h"
#include "ui/base/events/event_constants.h"
#include "ui/base/events/event_target.h"
#include "ui/base/ui_export.h"

namespace ui {

// Dispatches events to appropriate targets.
class UI_EXPORT EventDispatcher {
 public:
  EventDispatcher() {}
  virtual ~EventDispatcher() {}

  // Returns whether an event can still be dispatched to a target. (e.g. during
  // event dispatch, one of the handlers may have destroyed the target, in which
  // case the event can no longer be dispatched to the target).
  virtual bool CanDispatchToTarget(EventTarget* target) = 0;

  // Allows the subclass to add additional event handlers to the dispatch
  // sequence.
  virtual void ProcessPreTargetList(EventHandlerList* list) = 0;
  virtual void ProcessPostTargetList(EventHandlerList* list) = 0;

  template<class T>
  int ProcessEvent(EventTarget* target, T* event) {
    if (!target || !target->CanAcceptEvents())
      return ER_UNHANDLED;

    Event::DispatcherApi dispatcher(event);
    dispatcher.set_target(target);

    EventHandlerList list;
    target->GetPreTargetHandlers(&list);
    ProcessPreTargetList(&list);
    int result = DispatchEventToEventHandlers(list, event);
    if (result & ER_CONSUMED)
      return result;

    // If the event hasn't been consumed, trigger the default handler. Note that
    // even if the event has already been handled (i.e. return result has
    // ER_HANDLED set), that means that the event should still be processed at
    // this layer, however it should not be processed in the next layer of
    // abstraction.
    if (CanDispatchToTarget(target)) {
      result |= DispatchEventToSingleHandler(target, event);
      if (result & ER_CONSUMED)
        return result;
    }

    if (!CanDispatchToTarget(target))
      return result;

    list.clear();
    target->GetPostTargetHandlers(&list);
    ProcessPostTargetList(&list);
    result |= DispatchEventToEventHandlers(list, event);
    return result;
  }

 private:
  template<class T>
  int DispatchEventToEventHandlers(EventHandlerList& list, T* event) {
    int result = ER_UNHANDLED;
    for (EventHandlerList::const_iterator it = list.begin(),
            end = list.end(); it != end; ++it) {
      result |= DispatchEventToSingleHandler((*it), event);
      if (result & ER_CONSUMED)
        return result;
    }
    return result;
  }

  EventResult DispatchEventToSingleHandler(EventHandler* handler,
                                           ui::KeyEvent* event) {
    return handler->OnKeyEvent(event);
  }

  EventResult DispatchEventToSingleHandler(EventHandler* handler,
                                           ui::MouseEvent* event) {
    return handler->OnMouseEvent(event);
  }

  EventResult DispatchEventToSingleHandler(EventHandler* handler,
                                           ui::ScrollEvent* event) {
    return handler->OnScrollEvent(event);
  }

  EventResult DispatchEventToSingleHandler(EventHandler* handler,
                                           ui::TouchEvent* event) {
    // TODO(sad): This needs fixing (especially for the QUEUED_ status).
    TouchStatus status = handler->OnTouchEvent(event);
    return status == ui::TOUCH_STATUS_UNKNOWN ? ER_UNHANDLED :
           status == ui::TOUCH_STATUS_QUEUED_END ? ER_CONSUMED :
                                                   ER_HANDLED;
  }

  EventResult DispatchEventToSingleHandler(EventHandler* handler,
                                           ui::GestureEvent* event) {
    return handler->OnGestureEvent(event);
  }

  DISALLOW_COPY_AND_ASSIGN(EventDispatcher);
};

}  // namespace ui

#endif  // UI_BASE_EVENTS_EVENT_DISPATCHER_H_