Back to index

lightning-sunbird  0.9+nobinonly
nsObserverList.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #define NS_WEAK_OBSERVERS
00039 
00040 #include "pratom.h"
00041 #include "nsString.h"
00042 #include "nsAutoLock.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsIWeakReference.h"
00045 #include "nsEnumeratorUtils.h"
00046 #include "nsObserverList.h"
00047 
00048 nsObserverList::nsObserverList()
00049 {
00050     MOZ_COUNT_CTOR(nsObserverList);
00051     mLock = PR_NewLock();
00052 }
00053 
00054 nsObserverList::~nsObserverList(void)
00055 {
00056     MOZ_COUNT_DTOR(nsObserverList);
00057     PR_DestroyLock(mLock);
00058 }
00059 
00060 nsresult
00061 nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
00062 {
00063     nsresult rv;
00064     PRBool inserted;
00065     
00066     NS_ENSURE_ARG(anObserver);
00067 
00068     nsAutoLock lock(mLock);
00069 
00070     if (!mObserverList) {
00071         rv = NS_NewISupportsArray(getter_AddRefs(mObserverList));
00072         if (NS_FAILED(rv)) return rv;
00073     }
00074 
00075 #ifdef NS_WEAK_OBSERVERS
00076     nsCOMPtr<nsISupports> observerRef;
00077     if (ownsWeak) {
00078         nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver);
00079         NS_ASSERTION(weakRefFactory, "AddObserver: trying weak object that doesnt support nsIWeakReference");
00080         if ( weakRefFactory )
00081             observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory)));
00082     } else {
00083 #if DEBUG_dougt_xxx
00084         // if you are hitting this assertion, contact dougt@netscape.com.  There may be a ownership problem caused by his checkin to freeze nsIObserver
00085         nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver);
00086         NS_ASSERTION(!weakRefFactory, "Your object supports weak references, but is being added with a strong reference");
00087 #endif
00088         observerRef = anObserver;
00089     }
00090     if (!observerRef)
00091         return NS_ERROR_FAILURE;
00092 
00093     inserted = mObserverList->AppendElement(observerRef); 
00094 #else
00095     if (*anObserver)
00096         inserted = mObserverList->AppendElement(*anObserver);
00097 #endif
00098     return inserted ? NS_OK : NS_ERROR_FAILURE;
00099 }
00100 
00101 nsresult
00102 nsObserverList::RemoveObserver(nsIObserver* anObserver)
00103 {
00104     PRBool removed = PR_FALSE;
00105     
00106     NS_ENSURE_ARG(anObserver);
00107 
00108     // Prevent the observer from being destroyed while we're inside the lock.
00109     nsCOMPtr<nsIObserver> kungFuDeathGrip(anObserver);
00110 
00111 #ifdef NS_WEAK_OBSERVERS
00112     // Get the weak ref before we acquire the lock, because this QI could
00113     // run any arbitrary JS code
00114     nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver);
00115     nsCOMPtr<nsISupports> observerRef;
00116     if (weakRefFactory) {
00117         observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory)));
00118     }
00119 
00120     nsAutoLock lock(mLock);
00121 
00122     if (!mObserverList)
00123        return NS_ERROR_FAILURE;
00124     
00125     if (observerRef) {
00126         removed = mObserverList->RemoveElement(observerRef);
00127     }
00128 
00129     if (!removed && anObserver) {
00130         removed = mObserverList->RemoveElement(anObserver);
00131     }
00132 #else
00133     nsAutoLock lock(mLock);
00134 
00135     if (!mObserverList)
00136        return NS_ERROR_FAILURE;
00137     
00138     if (*anObserver)
00139         removed = mObserverList->RemoveElement(*anObserver);
00140 #endif
00141 
00142     return removed ? NS_OK : NS_ERROR_FAILURE;
00143 }
00144 
00145 nsresult
00146 nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator)
00147 {
00148     nsAutoLock lock(mLock);
00149 
00150     ObserverListEnumerator * enumerator= new ObserverListEnumerator(mObserverList);
00151     *anEnumerator = enumerator;
00152     if (!enumerator)
00153         return NS_ERROR_OUT_OF_MEMORY;
00154 
00155     NS_ADDREF(enumerator);
00156     return NS_OK;
00157 }
00158 
00159 
00160 ObserverListEnumerator::ObserverListEnumerator(nsISupportsArray* aValueArray)
00161     : mValueArray(aValueArray), mIndex(0)
00162 {
00163     if (mValueArray) {
00164         NS_ADDREF(mValueArray);
00165         PRUint32 total;
00166         mValueArray->Count(&total);
00167         mIndex = PRInt32(total);
00168     }
00169 }
00170 
00171 ObserverListEnumerator::~ObserverListEnumerator(void)
00172 {
00173     NS_IF_RELEASE(mValueArray);
00174 }
00175 
00176 NS_IMPL_ISUPPORTS1(ObserverListEnumerator, nsISimpleEnumerator)
00177 
00178 NS_IMETHODIMP
00179 ObserverListEnumerator::HasMoreElements(PRBool* aResult)
00180 {
00181     NS_PRECONDITION(aResult != 0, "null ptr");
00182     if (! aResult)
00183         return NS_ERROR_NULL_POINTER;
00184 
00185     if (!mValueArray) {
00186         *aResult = PR_FALSE;
00187         return NS_OK;
00188     }
00189 
00190     *aResult = (mIndex > 0);
00191     return NS_OK;
00192 }
00193 
00194 NS_IMETHODIMP
00195 ObserverListEnumerator::GetNext(nsISupports** aResult)
00196 {
00197     NS_PRECONDITION(aResult != 0, "null ptr");
00198     if (! aResult)
00199         return NS_ERROR_NULL_POINTER;
00200 
00201     if (!mValueArray) {
00202         *aResult = nsnull;
00203         return NS_OK;
00204     }
00205 
00206     if (mIndex <= 0 )
00207         return NS_ERROR_UNEXPECTED;
00208 
00209     mValueArray->GetElementAt(--mIndex, aResult);
00210     if (*aResult) {
00211         nsCOMPtr<nsIWeakReference> weakRefFactory = do_QueryInterface(*aResult);
00212         if ( weakRefFactory ) {
00213             nsCOMPtr<nsISupports> weakref = do_QueryReferent(weakRefFactory);
00214             NS_RELEASE(*aResult);
00215             NS_IF_ADDREF(*aResult = weakref);
00216 
00217             return NS_OK;
00218         }
00219     }
00220 
00221     return NS_OK;
00222 }