13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be
306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file.
406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#ifndef CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_
606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#define CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once
806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <map>
1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/basictypes.h"
1206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/logging.h"
1306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/message_loop.h"
1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/port.h"
153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/condition_variable.h"
163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/lock.h"
1706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/deprecated/event_sys.h"
1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// How to use Channels:
2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 0. Assume Bob is the name of the class from which you want to broadcast
2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    events.
2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 1. Choose an EventType. This could be an Enum or something more complicated.
2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 2. Create an EventTraits class for your EventType. It must have
2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    two members:
2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//      typedef x EventType;
2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//      static bool IsChannelShutdownEvent(const EventType& event);
2906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
3006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 3. Add an EventChannel<MyEventTraits>* instance and event_channel() const;
3106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    accessor to Bob.
3206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    Delete the channel ordinarily in Bob's destructor, or whenever you want.
3306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 4. To broadcast events, call bob->event_channel()->NotifyListeners(event).
3406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 5. Only call NotifyListeners from a single thread at a time.
3506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// How to use Listeners/Hookups:
3706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 0. Assume you want a class called Lisa to listen to events from Bob.
3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 1. Create an event handler method in Lisa. Its single argument should be of
4006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    your event type.
4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 2. Add a EventListenerHookup* hookup_ member to Lisa.
4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 3. Initialize the hookup by calling:
4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//      hookup_ = NewEventListenerHookup(bob->event_channel(),
4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//                                       this,
4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//                                       &Lisa::HandleEvent);
4706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// 4. Delete hookup_ in Lisa's destructor, or anytime sooner to stop receiving
4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//    events.
5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// An Event Channel is a source, or broadcaster of events. Listeners subscribe
5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// by calling the AddListener() method. The owner of the channel calls the
5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// NotifyListeners() method.
5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Don't inherit from this class. Just make an event_channel member and an
5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// event_channel() accessor.
5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// No reason why CallbackWaiters has to be templatized.
5906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass CallbackWaiters {
6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackWaiters() : waiter_count_(0),
6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                      callback_done_(false),
6306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                      condvar_(&mutex_) {
6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~CallbackWaiters() {
6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    DCHECK_EQ(0, waiter_count_);
6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  void WaitForCallbackToComplete(base::Lock* listeners_mutex) {
6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    {
703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      base::AutoLock lock(mutex_);
7106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      waiter_count_ += 1;
7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      listeners_mutex->Release();
7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      while (!callback_done_)
7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        condvar_.Wait();
7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      waiter_count_ -= 1;
7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      if (0 != waiter_count_)
7706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        return;
7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    delete this;
8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void Signal() {
833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock lock(mutex_);
8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    callback_done_ = true;
8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    condvar_.Broadcast();
8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch protected:
8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int waiter_count_;
9006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  bool callback_done_;
913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::Lock mutex_;
923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::ConditionVariable condvar_;
9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventTraitsType, typename NotifyLock,
9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename ScopedNotifyLocker>
9706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass EventChannel {
9806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef EventTraitsType EventTraits;
10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef typename EventTraits::EventType EventType;
10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef EventListener<EventType> Listener;
10206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
10306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch protected:
10406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef std::map<Listener*, bool> Listeners;
10506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
10606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
10706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // The shutdown event gets send in the EventChannel's destructor.
10806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  explicit EventChannel(const EventType& shutdown_event)
10906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : current_listener_callback_(NULL),
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      current_listener_callback_message_loop_(NULL),
11106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      callback_waiters_(NULL),
11206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      shutdown_event_(shutdown_event) {
11306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
11406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~EventChannel() {
11606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Tell all the listeners that the channel is being deleted.
11706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    NotifyListeners(shutdown_event_);
11806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Make sure all the listeners have been disconnected. Otherwise, they
12006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // will try to call RemoveListener() at a later date.
12106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#if defined(DEBUG)
1223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock lock(listeners_mutex_);
12306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (typename Listeners::iterator i = listeners_.begin();
12406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch         i != listeners_.end(); ++i) {
12506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      DCHECK(i->second) << "Listener not disconnected";
12606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
12706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#endif
12806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
12906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
13006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Never call this twice for the same listener.
13106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  //
13206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Thread safe.
13306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void AddListener(Listener* listener) {
1343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock lock(listeners_mutex_);
13506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typename Listeners::iterator found = listeners_.find(listener);
13606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (found == listeners_.end()) {
13706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      listeners_.insert(std::make_pair(listener,
13806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                       false));  // Not dead yet.
13906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else {
14006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      DCHECK(found->second) << "Attempted to add the same listener twice.";
14106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      found->second = false;  // Not dead yet.
14206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
14306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
14406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
14506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // If listener's callback is currently executing, this method waits until the
14606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // callback completes before returning.
14706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  //
14806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Thread safe.
14906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void RemoveListener(Listener* listener) {
15006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    bool wait = false;
15106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    listeners_mutex_.Acquire();
15206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typename Listeners::iterator found = listeners_.find(listener);
15306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (found != listeners_.end()) {
15406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      found->second = true;  // Mark as dead.
15506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      wait = (found->first == current_listener_callback_ &&
15606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          (MessageLoop::current() != current_listener_callback_message_loop_));
15706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
15806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (!wait) {
15906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      listeners_mutex_.Release();
16006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      return;
16106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
16206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (NULL == callback_waiters_)
16306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      callback_waiters_ = new CallbackWaiters;
16406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    callback_waiters_->WaitForCallbackToComplete(&listeners_mutex_);
16506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
16606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
16706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Blocks until all listeners have been notified.
16806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  //
16906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // NOT thread safe.  Must only be called by one thread at a time.
17006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void NotifyListeners(const EventType& event) {
17106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ScopedNotifyLocker lock_notify(notify_lock_);
17206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    listeners_mutex_.Acquire();
17306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    DCHECK(NULL == current_listener_callback_);
17406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    current_listener_callback_message_loop_ = MessageLoop::current();
17506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typename Listeners::iterator i = listeners_.begin();
17606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    while (i != listeners_.end()) {
17706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      if (i->second) {  // Clean out dead listeners
17806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        listeners_.erase(i++);
17906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        continue;
18006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
18106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      current_listener_callback_ = i->first;
18206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      listeners_mutex_.Release();
18306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      i->first->HandleEvent(event);
18506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      listeners_mutex_.Acquire();
18706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      current_listener_callback_ = NULL;
18806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      if (NULL != callback_waiters_) {
18906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        callback_waiters_->Signal();
19006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        callback_waiters_ = NULL;
19106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
19206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
19306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      ++i;
19406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
19506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    listeners_mutex_.Release();
19606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
19706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
19806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // A map iterator remains valid until the element it points to gets removed
19906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // from the map, so a map is perfect for our needs.
20006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  //
20106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Map value is a bool, true means the Listener is dead.
20206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Listeners listeners_;
20306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // NULL means no callback is currently being called.
20406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Listener* current_listener_callback_;
20506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Only valid when current_listener is not NULL.
20606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // The thread on which the callback is executing.
20706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  MessageLoop* current_listener_callback_message_loop_;
20806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Win32 Event that is usually NULL. Only created when another thread calls
20906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Remove while in callback. Owned and closed by the thread calling Remove().
21006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackWaiters* callback_waiters_;
21106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::Lock listeners_mutex_;  // Protects all members above.
21306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const EventType shutdown_event_;
21406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  NotifyLock notify_lock_;
21506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
21606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DISALLOW_COPY_AND_ASSIGN(EventChannel);
21706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
21806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
21906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// An EventListenerHookup hooks up a method in your class to an EventChannel.
22006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Deleting the hookup disconnects from the EventChannel.
22106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
22206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Contains complexity of inheriting from Listener class and managing lifetimes.
22306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch//
22406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Create using NewEventListenerHookup() to avoid explicit template arguments.
22506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass EventListenerHookup {
22606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
22706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  virtual ~EventListenerHookup() { }
22806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
22906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
23006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventChannel, typename EventTraits,
23106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          class Derived>
23206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass EventListenerHookupImpl : public EventListenerHookup,
23306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochpublic EventListener<typename EventTraits::EventType> {
23406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
23506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  explicit EventListenerHookupImpl(EventChannel* channel)
23606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : channel_(channel), deleted_(NULL) {
23706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    channel->AddListener(this);
23806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    connected_ = true;
23906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
24006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
24106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ~EventListenerHookupImpl() {
24206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (NULL != deleted_)
24306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      *deleted_ = true;
24406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (connected_)
24506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      channel_->RemoveListener(this);
24606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
24706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
24806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef typename EventTraits::EventType EventType;
24906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  virtual void HandleEvent(const EventType& event) {
25006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    DCHECK(connected_);
25106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    bool deleted = false;
25206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    deleted_ = &deleted;
25306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    static_cast<Derived*>(this)->Callback(event);
25406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (deleted)  // The callback (legally) deleted this.
25506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      return;  // The only safe thing to do.
25606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    deleted_ = NULL;
25706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (EventTraits::IsChannelShutdownEvent(event)) {
25806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      channel_->RemoveListener(this);
25906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      connected_ = false;
26006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
26106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
26206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch protected:
26406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  EventChannel* const channel_;
26506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  bool connected_;
26606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  bool* deleted_;  // Allows the handler to delete the hookup.
26706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
26806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// SimpleHookup just passes the event to the callback message.
27006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventChannel, typename EventTraits,
27106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename CallbackObject, typename CallbackMethod>
27206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass SimpleHookup
27306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : public EventListenerHookupImpl<EventChannel, EventTraits,
27406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     SimpleHookup<EventChannel,
27506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                  EventTraits,
27606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                  CallbackObject,
27706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                  CallbackMethod> > {
27806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
27906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  SimpleHookup(EventChannel* channel, CallbackObject* cbobject,
28006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch               CallbackMethod cbmethod)
28106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : EventListenerHookupImpl<EventChannel, EventTraits,
28206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              SimpleHookup>(channel), cbobject_(cbobject),
28306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    cbmethod_(cbmethod) { }
28406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
28506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef typename EventTraits::EventType EventType;
28606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void Callback(const EventType& event) {
28706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    (cbobject_->*cbmethod_)(event);
28806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
28906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackObject* const cbobject_;
29006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackMethod const cbmethod_;
29106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
29206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
29306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// ArgHookup also passes an additional arg to the callback method.
29406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventChannel, typename EventTraits,
29506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename CallbackObject, typename CallbackMethod,
29606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename CallbackArg0>
29706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass ArgHookup
29806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : public EventListenerHookupImpl<EventChannel, EventTraits,
29906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     ArgHookup<EventChannel, EventTraits,
30006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                               CallbackObject,
30106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                               CallbackMethod,
30206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                               CallbackArg0> > {
30306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
30406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ArgHookup(EventChannel* channel, CallbackObject* cbobject,
30506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch            CallbackMethod cbmethod, CallbackArg0 arg0)
30606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : EventListenerHookupImpl<EventChannel, EventTraits,
30706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              ArgHookup>(channel), cbobject_(cbobject),
30806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      cbmethod_(cbmethod), arg0_(arg0) { }
30906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
31006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  typedef typename EventTraits::EventType EventType;
31106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  void Callback(const EventType& event) {
31206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    (cbobject_->*cbmethod_)(arg0_, event);
31306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
31406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackObject* const cbobject_;
31506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackMethod const cbmethod_;
31606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  CallbackArg0 const arg0_;
31706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
31806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
31906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
32006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventChannel, typename CallbackObject,
32106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename CallbackMethod>
32206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochEventListenerHookup* NewEventListenerHookup(EventChannel* channel,
32306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            CallbackObject* cbobject,
32406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            CallbackMethod cbmethod) {
32506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return new SimpleHookup<EventChannel,
32606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typename EventChannel::EventTraits,
32706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    CallbackObject, CallbackMethod>(channel, cbobject, cbmethod);
32806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
32906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
33006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochtemplate <typename EventChannel, typename CallbackObject,
33106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          typename CallbackMethod, typename CallbackArg0>
33206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochEventListenerHookup* NewEventListenerHookup(EventChannel* channel,
33306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            CallbackObject* cbobject,
33406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            CallbackMethod cbmethod,
33506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            CallbackArg0 arg0) {
33606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return new ArgHookup<EventChannel,
33706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typename EventChannel::EventTraits,
33806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    CallbackObject, CallbackMethod, CallbackArg0>(channel, cbobject,
33906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                  cbmethod, arg0);
34006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
34106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
34206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#endif  // CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_
343