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