mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			450 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			450 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2013
 | |
| // Google Inc. All rights reserved.
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //    * Redistributions of source code must retain the above copyright
 | |
| // notice, this list of conditions and the following disclaimer.
 | |
| //    * Redistributions in binary form must reproduce the above
 | |
| // copyright notice, this list of conditions and the following disclaimer
 | |
| // in the documentation and/or other materials provided with the
 | |
| // distribution.
 | |
| //    * Neither the name of Google Inc. nor the name Chromium Embedded
 | |
| // Framework nor the names of its contributors may be used to endorse
 | |
| // or promote products derived from this software without specific prior
 | |
| // written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| #ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
 | |
| #define CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
 | |
| #pragma once
 | |
| 
 | |
| #if defined(BASE_CALLBACK_LIST_H_)
 | |
| // Do nothing if the Chromium header has already been included.
 | |
| // This can happen in cases where Chromium code is used directly by the
 | |
| // client application. When using Chromium code directly always include
 | |
| // the Chromium header first to avoid type conflicts.
 | |
| #elif defined(USING_CHROMIUM_INCLUDES)
 | |
| // When building CEF include the Chromium header directly.
 | |
| #include "base/callback_list.h"
 | |
| #else  // !USING_CHROMIUM_INCLUDES
 | |
| // The following is substantially similar to the Chromium implementation.
 | |
| // If the Chromium implementation diverges the below implementation should be
 | |
| // updated to match.
 | |
| 
 | |
| #include <list>
 | |
| 
 | |
| #include "include/base/cef_basictypes.h"
 | |
| #include "include/base/cef_build.h"
 | |
| #include "include/base/cef_callback.h"
 | |
| #include "include/base/cef_logging.h"
 | |
| #include "include/base/cef_macros.h"
 | |
| #include "include/base/cef_scoped_ptr.h"
 | |
| #include "include/base/internal/cef_callback_internal.h"
 | |
| 
 | |
| // OVERVIEW:
 | |
| //
 | |
| // A container for a list of callbacks.  Unlike a normal STL vector or list,
 | |
| // this container can be modified during iteration without invalidating the
 | |
| // iterator. It safely handles the case of a callback removing itself
 | |
| // or another callback from the list while callbacks are being run.
 | |
| //
 | |
| // TYPICAL USAGE:
 | |
| //
 | |
| // class MyWidget {
 | |
| //  public:
 | |
| //   ...
 | |
| //
 | |
| //   typedef base::Callback<void(const Foo&)> OnFooCallback;
 | |
| //
 | |
| //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
 | |
| //   RegisterCallback(const OnFooCallback& cb) {
 | |
| //     return callback_list_.Add(cb);
 | |
| //   }
 | |
| //
 | |
| //  private:
 | |
| //   void NotifyFoo(const Foo& foo) {
 | |
| //      callback_list_.Notify(foo);
 | |
| //   }
 | |
| //
 | |
| //   base::CallbackList<void(const Foo&)> callback_list_;
 | |
| //
 | |
| //   DISALLOW_COPY_AND_ASSIGN(MyWidget);
 | |
| // };
 | |
| //
 | |
| //
 | |
| // class MyWidgetListener {
 | |
| //  public:
 | |
| //   MyWidgetListener::MyWidgetListener() {
 | |
| //     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
 | |
| //             base::Bind(&MyWidgetListener::OnFoo, this)));
 | |
| //   }
 | |
| //
 | |
| //   MyWidgetListener::~MyWidgetListener() {
 | |
| //      // Subscription gets deleted automatically and will deregister
 | |
| //      // the callback in the process.
 | |
| //   }
 | |
| //
 | |
| //  private:
 | |
| //   void OnFoo(const Foo& foo) {
 | |
| //     // Do something.
 | |
| //   }
 | |
| //
 | |
| //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
 | |
| //       foo_subscription_;
 | |
| //
 | |
| //   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
 | |
| // };
 | |
| 
 | |
| namespace base {
 | |
| 
 | |
| namespace cef_internal {
 | |
| 
 | |
| template <typename CallbackType>
 | |
| class CallbackListBase {
 | |
|  public:
 | |
|   class Subscription {
 | |
|    public:
 | |
|     Subscription(CallbackListBase<CallbackType>* list,
 | |
|                  typename std::list<CallbackType>::iterator iter)
 | |
|         : list_(list), iter_(iter) {}
 | |
| 
 | |
|     ~Subscription() {
 | |
|       if (list_->active_iterator_count_) {
 | |
|         iter_->Reset();
 | |
|       } else {
 | |
|         list_->callbacks_.erase(iter_);
 | |
|         if (!list_->removal_callback_.is_null())
 | |
|           list_->removal_callback_.Run();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|    private:
 | |
|     CallbackListBase<CallbackType>* list_;
 | |
|     typename std::list<CallbackType>::iterator iter_;
 | |
| 
 | |
|     DISALLOW_COPY_AND_ASSIGN(Subscription);
 | |
|   };
 | |
| 
 | |
|   // Add a callback to the list. The callback will remain registered until the
 | |
|   // returned Subscription is destroyed, which must occur before the
 | |
|   // CallbackList is destroyed.
 | |
|   scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
 | |
|     DCHECK(!cb.is_null());
 | |
|     return scoped_ptr<Subscription>(
 | |
|         new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
 | |
|   }
 | |
| 
 | |
|   // Sets a callback which will be run when a subscription list is changed.
 | |
|   void set_removal_callback(const Closure& callback) {
 | |
|     removal_callback_ = callback;
 | |
|   }
 | |
| 
 | |
|   // Returns true if there are no subscriptions. This is only valid to call when
 | |
|   // not looping through the list.
 | |
|   bool empty() {
 | |
|     DCHECK_EQ(0, active_iterator_count_);
 | |
|     return callbacks_.empty();
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   // An iterator class that can be used to access the list of callbacks.
 | |
|   class Iterator {
 | |
|    public:
 | |
|     explicit Iterator(CallbackListBase<CallbackType>* list)
 | |
|         : list_(list), list_iter_(list_->callbacks_.begin()) {
 | |
|       ++list_->active_iterator_count_;
 | |
|     }
 | |
| 
 | |
|     Iterator(const Iterator& iter)
 | |
|         : list_(iter.list_), list_iter_(iter.list_iter_) {
 | |
|       ++list_->active_iterator_count_;
 | |
|     }
 | |
| 
 | |
|     ~Iterator() {
 | |
|       if (list_ && --list_->active_iterator_count_ == 0) {
 | |
|         list_->Compact();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     CallbackType* GetNext() {
 | |
|       while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
 | |
|         ++list_iter_;
 | |
| 
 | |
|       CallbackType* cb = NULL;
 | |
|       if (list_iter_ != list_->callbacks_.end()) {
 | |
|         cb = &(*list_iter_);
 | |
|         ++list_iter_;
 | |
|       }
 | |
|       return cb;
 | |
|     }
 | |
| 
 | |
|    private:
 | |
|     CallbackListBase<CallbackType>* list_;
 | |
|     typename std::list<CallbackType>::iterator list_iter_;
 | |
|   };
 | |
| 
 | |
|   CallbackListBase() : active_iterator_count_(0) {}
 | |
| 
 | |
|   ~CallbackListBase() {
 | |
|     DCHECK_EQ(0, active_iterator_count_);
 | |
|     DCHECK_EQ(0U, callbacks_.size());
 | |
|   }
 | |
| 
 | |
|   // Returns an instance of a CallbackListBase::Iterator which can be used
 | |
|   // to run callbacks.
 | |
|   Iterator GetIterator() { return Iterator(this); }
 | |
| 
 | |
|   // Compact the list: remove any entries which were NULLed out during
 | |
|   // iteration.
 | |
|   void Compact() {
 | |
|     typename std::list<CallbackType>::iterator it = callbacks_.begin();
 | |
|     bool updated = false;
 | |
|     while (it != callbacks_.end()) {
 | |
|       if ((*it).is_null()) {
 | |
|         updated = true;
 | |
|         it = callbacks_.erase(it);
 | |
|       } else {
 | |
|         ++it;
 | |
|       }
 | |
| 
 | |
|       if (updated && !removal_callback_.is_null())
 | |
|         removal_callback_.Run();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   std::list<CallbackType> callbacks_;
 | |
|   int active_iterator_count_;
 | |
|   Closure removal_callback_;
 | |
| 
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
 | |
| };
 | |
| 
 | |
| }  // namespace cef_internal
 | |
| 
 | |
| template <typename Sig>
 | |
| class CallbackList;
 | |
| 
 | |
| template <>
 | |
| class CallbackList<void(void)>
 | |
|     : public cef_internal::CallbackListBase<Callback<void(void)>> {
 | |
|  public:
 | |
|   typedef Callback<void(void)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify() {
 | |
|     cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1>
 | |
| class CallbackList<void(A1)>
 | |
|     : public cef_internal::CallbackListBase<Callback<void(A1)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1, typename A2>
 | |
| class CallbackList<void(A1, A2)>
 | |
|     : public cef_internal::CallbackListBase<Callback<void(A1, A2)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1, typename A2, typename A3>
 | |
| class CallbackList<void(A1, A2, A3)>
 | |
|     : public cef_internal::CallbackListBase<Callback<void(A1, A2, A3)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2, A3)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2,
 | |
|               typename cef_internal::CallbackParamTraits<A3>::ForwardType a3) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2, a3);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1, typename A2, typename A3, typename A4>
 | |
| class CallbackList<void(A1, A2, A3, A4)>
 | |
|     : public cef_internal::CallbackListBase<Callback<void(A1, A2, A3, A4)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2, A3, A4)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2,
 | |
|               typename cef_internal::CallbackParamTraits<A3>::ForwardType a3,
 | |
|               typename cef_internal::CallbackParamTraits<A4>::ForwardType a4) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2, a3, a4);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1, typename A2, typename A3, typename A4, typename A5>
 | |
| class CallbackList<void(A1, A2, A3, A4, A5)>
 | |
|     : public cef_internal::CallbackListBase<
 | |
|           Callback<void(A1, A2, A3, A4, A5)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2, A3, A4, A5)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2,
 | |
|               typename cef_internal::CallbackParamTraits<A3>::ForwardType a3,
 | |
|               typename cef_internal::CallbackParamTraits<A4>::ForwardType a4,
 | |
|               typename cef_internal::CallbackParamTraits<A5>::ForwardType a5) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2, a3, a4, a5);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1,
 | |
|           typename A2,
 | |
|           typename A3,
 | |
|           typename A4,
 | |
|           typename A5,
 | |
|           typename A6>
 | |
| class CallbackList<void(A1, A2, A3, A4, A5, A6)>
 | |
|     : public cef_internal::CallbackListBase<
 | |
|           Callback<void(A1, A2, A3, A4, A5, A6)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2, A3, A4, A5, A6)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2,
 | |
|               typename cef_internal::CallbackParamTraits<A3>::ForwardType a3,
 | |
|               typename cef_internal::CallbackParamTraits<A4>::ForwardType a4,
 | |
|               typename cef_internal::CallbackParamTraits<A5>::ForwardType a5,
 | |
|               typename cef_internal::CallbackParamTraits<A6>::ForwardType a6) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2, a3, a4, a5, a6);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| template <typename A1,
 | |
|           typename A2,
 | |
|           typename A3,
 | |
|           typename A4,
 | |
|           typename A5,
 | |
|           typename A6,
 | |
|           typename A7>
 | |
| class CallbackList<void(A1, A2, A3, A4, A5, A6, A7)>
 | |
|     : public cef_internal::CallbackListBase<
 | |
|           Callback<void(A1, A2, A3, A4, A5, A6, A7)>> {
 | |
|  public:
 | |
|   typedef Callback<void(A1, A2, A3, A4, A5, A6, A7)> CallbackType;
 | |
| 
 | |
|   CallbackList() {}
 | |
| 
 | |
|   void Notify(typename cef_internal::CallbackParamTraits<A1>::ForwardType a1,
 | |
|               typename cef_internal::CallbackParamTraits<A2>::ForwardType a2,
 | |
|               typename cef_internal::CallbackParamTraits<A3>::ForwardType a3,
 | |
|               typename cef_internal::CallbackParamTraits<A4>::ForwardType a4,
 | |
|               typename cef_internal::CallbackParamTraits<A5>::ForwardType a5,
 | |
|               typename cef_internal::CallbackParamTraits<A6>::ForwardType a6,
 | |
|               typename cef_internal::CallbackParamTraits<A7>::ForwardType a7) {
 | |
|     typename cef_internal::CallbackListBase<CallbackType>::Iterator it =
 | |
|         this->GetIterator();
 | |
|     CallbackType* cb;
 | |
|     while ((cb = it.GetNext()) != NULL) {
 | |
|       cb->Run(a1, a2, a3, a4, a5, a6, a7);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   DISALLOW_COPY_AND_ASSIGN(CallbackList);
 | |
| };
 | |
| 
 | |
| }  // namespace base
 | |
| 
 | |
| #endif  // !USING_CHROMIUM_INCLUDES
 | |
| 
 | |
| #endif  // CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
 |