michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsObserverList.h" michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "xpcpublic.h" michael@0: michael@0: nsresult michael@0: nsObserverList::AddObserver(nsIObserver* anObserver, bool ownsWeak) michael@0: { michael@0: NS_ASSERTION(anObserver, "Null input"); michael@0: michael@0: if (!ownsWeak) { michael@0: ObserverRef* o = mObservers.AppendElement(anObserver); michael@0: if (!o) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr weak = do_GetWeakReference(anObserver); michael@0: if (!weak) michael@0: return NS_NOINTERFACE; michael@0: michael@0: ObserverRef *o = mObservers.AppendElement(weak); michael@0: if (!o) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsObserverList::RemoveObserver(nsIObserver* anObserver) michael@0: { michael@0: NS_ASSERTION(anObserver, "Null input"); michael@0: michael@0: if (mObservers.RemoveElement(static_cast(anObserver))) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr observerRef = do_GetWeakReference(anObserver); michael@0: if (!observerRef) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!mObservers.RemoveElement(observerRef)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) michael@0: { michael@0: nsRefPtr e(new nsObserverEnumerator(this)); michael@0: e.forget(anEnumerator); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsObserverList::FillObserverArray(nsCOMArray &aArray) michael@0: { michael@0: aArray.SetCapacity(mObservers.Length()); michael@0: michael@0: nsTArray observers(mObservers); michael@0: michael@0: for (int32_t i = observers.Length() - 1; i >= 0; --i) { michael@0: if (observers[i].isWeakRef) { michael@0: nsCOMPtr o(do_QueryReferent(observers[i].asWeak())); michael@0: if (o) { michael@0: aArray.AppendObject(o); michael@0: } michael@0: else { michael@0: // the object has gone away, remove the weakref michael@0: mObservers.RemoveElement(observers[i].asWeak()); michael@0: } michael@0: } michael@0: else { michael@0: aArray.AppendObject(observers[i].asObserver()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsObserverList::NotifyObservers(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t *someData) michael@0: { michael@0: nsCOMArray observers; michael@0: FillObserverArray(observers); michael@0: michael@0: for (int32_t i = 0; i < observers.Count(); ++i) { michael@0: observers[i]->Observe(aSubject, aTopic, someData); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsObserverList::UnmarkGrayStrongObservers() michael@0: { michael@0: for (uint32_t i = 0; i < mObservers.Length(); ++i) { michael@0: if (!mObservers[i].isWeakRef) { michael@0: xpc_TryUnmarkWrappedGrayObject(mObservers[i].asObserver()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsObserverEnumerator, nsISimpleEnumerator) michael@0: michael@0: nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList) michael@0: : mIndex(0) michael@0: { michael@0: aObserverList->FillObserverArray(mObservers); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsObserverEnumerator::HasMoreElements(bool *aResult) michael@0: { michael@0: *aResult = (mIndex < mObservers.Count()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsObserverEnumerator::GetNext(nsISupports* *aResult) michael@0: { michael@0: if (mIndex == mObservers.Count()) { michael@0: NS_ERROR("Enumerating after HasMoreElements returned false."); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: NS_ADDREF(*aResult = mObservers[mIndex]); michael@0: ++mIndex; michael@0: return NS_OK; michael@0: }