30 #include <sbIMediaItem.h>
31 #include <sbIMediaList.h>
32 #include <sbIMediaListListener.h>
34 #include <nsIWeakReference.h>
35 #include <nsIWeakReferenceUtils.h>
37 #include <nsAutoLock.h>
38 #include <nsHashKeys.h>
39 #include <nsThreadUtils.h>
40 #include <nsServiceManagerUtils.h>
45 #include <nsIXPConnect.h>
51 #define SB_ENSURE_TRUE_VOID(_arg) \
52 NS_ENSURE_TRUE((_arg), )
60 static PRLogModuleInfo* gMediaListListenerLog = nsnull;
61 #define TRACE(args) if (gMediaListListenerLog) PR_LOG(gMediaListListenerLog, PR_LOG_DEBUG, args)
62 #define LOG(args) if (gMediaListListenerLog) PR_LOG(gMediaListListenerLog, PR_LOG_WARN, args)
72 : mListenerArrayLock(nsnull),
77 if (!gMediaListListenerLog) {
78 gMediaListListenerLog = PR_NewLogModule(
"sbLocalDatabaseMediaListListener");
81 TRACE((
"LocalDatabaseMediaListListener[0x%.8x] - Constructed",
this));
86 if (mListenerArrayLock) {
87 nsAutoLock::DestroyLock(mListenerArrayLock);
89 TRACE((
"LocalDatabaseMediaListListener[0x%.8x] - Destructed",
this));
96 NS_WARN_IF_FALSE(!mListenerArrayLock,
"You're calling Init more than once!");
99 if (!mListenerArrayLock) {
101 nsAutoLock::NewLock(
"sbLocalDatabaseMediaListListener::"
102 "mListenerArrayLock");
103 NS_ENSURE_TRUE(mListenerArrayLock, NS_ERROR_OUT_OF_MEMORY);
117 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
119 nsCAutoString objtype;
120 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aListener);
122 objtype.AssignLiteral(
"wrapped");
125 objtype.AssignLiteral(
"native");
129 stack.AssignLiteral(
"no js stack");
131 nsCOMPtr<nsIStackFrame> current;
132 xpc->GetCurrentJSStack(getter_AddRefs(current));
134 current->ToString(getter_Copies(stack));
136 TRACE((
"LocalDatabaseMediaListListener[0x%.8x] - "
137 "AddListener 0x%.8x %d %s %s",
138 this, aListener, aOwnsWeak, objtype.get(), stack.get()));
142 NS_ASSERTION(mListenerArrayLock,
"You haven't called Init yet!");
143 NS_ENSURE_ARG_POINTER(aListener);
155 nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
157 NS_ENSURE_SUCCESS(rv, rv);
159 nsAutoLock lock(mListenerArrayLock);
162 PRUint32 length = mListenerArray.Length();
163 nsCOMPtr<nsISupports> ref = do_QueryInterface(aListener, &rv);
164 NS_ENSURE_SUCCESS(rv, rv);
167 nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aListener, &rv);
168 NS_ENSURE_SUCCESS(rv, rv);
169 for (PRUint32
i = 0;
i < length;
i++) {
170 if(mListenerArray[
i]->mRef == weak) {
171 NS_WARNING(
"Attempted to add a weak listener twice!");
177 for (PRUint32
i = 0;
i < length;
i++) {
178 if(mListenerArray[
i]->mRef == ref) {
179 NS_WARNING(
"Attempted to add a strong listener twice!");
186 NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
189 nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aListener, &rv);
190 NS_ENSURE_SUCCESS(rv, rv);
191 rv = info->Init(proxyObjMgr, weak, mBatchDepth, aFlags, aPropertyFilter);
192 NS_ENSURE_SUCCESS(rv, rv);
195 rv = info->Init(proxyObjMgr, aListener, mBatchDepth, aFlags, aPropertyFilter);
196 NS_ENSURE_SUCCESS(rv, rv);
199 sbListenerInfoAutoPtr* added = mListenerArray.AppendElement(info.forget());
200 NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
204 if (mBatchDepth > 0) {
205 nsCOMPtr<sbIMediaList> list =
206 do_QueryInterface(NS_ISUPPORTS_CAST(
sbIMediaList*, aList), &rv);
207 NS_ENSURE_SUCCESS(rv, rv);
209 for (PRUint32
i = 0;
i < mBatchDepth;
i++) {
210 (*added)->BeginBatch();
211 rv = aListener->OnBatchBegin(aList);
212 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"OnBatchBegin returned a failure code");
223 TRACE((
"LocalDatabaseMediaListListener[0x%.8x] - RemoveListener 0x%.8x",
225 NS_ASSERTION(mListenerArrayLock,
"You haven't called Init yet!");
226 NS_ENSURE_ARG_POINTER(aListener);
229 PRUint32 batchDepth = 0;
231 nsAutoLock lock(mListenerArrayLock);
233 PRUint32 length = mListenerArray.Length();
235 nsCOMPtr<nsISupports> ref = do_QueryInterface(aListener, &rv);
236 for (PRUint32
i = 0;
i < length;
i++) {
237 if(mListenerArray[
i]->mRef == ref) {
238 for (PRUint32 j = 0; j < mBatchDepth; j++) {
239 mListenerArray[
i]->EndBatch();
241 mListenerArray.RemoveElementAt(
i);
246 nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aListener, &rv);
247 if (NS_SUCCEEDED(rv)) {
248 for (PRUint32
i = 0;
i < length;
i++) {
249 if(mListenerArray[
i]->mRef == weak) {
250 mListenerArray.RemoveElementAt(
i);
254 NS_WARNING(
"Attempted to remove a weak listener that was never added!");
257 NS_WARNING(
"Attempted to remove a strong listener that was never added!");
261 batchDepth = mBatchDepth;
281 if (batchDepth > 0) {
282 nsCOMPtr<sbIMediaList> list =
283 do_QueryInterface(NS_ISUPPORTS_CAST(
sbIMediaList*, aList), &rv);
284 NS_ENSURE_SUCCESS(rv, rv);
286 for (PRUint32
i = 0;
i < batchDepth;
i++) {
287 rv = aListener->OnBatchEnd(aList);
288 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"OnBatchEnd returned a failure code");
298 NS_ASSERTION(mListenerArrayLock,
"You haven't called Init yet!");
300 nsAutoLock lock(mListenerArrayLock);
301 return mListenerArray.Length();
305 sbLocalDatabaseMediaListListener::SnapshotListenerArray(sbMediaListListenersArray& aArray,
309 nsAutoLock lock(mListenerArrayLock);
311 PRUint32 length = mListenerArray.Length();
312 for (PRUint32
i = 0;
i < length;
i++) {
313 if (mListenerArray[
i]->ShouldNotify(aFlags, aProperties)) {
314 nsString debugAddress;
315 mListenerArray[
i]->GetDebugAddress(debugAddress);
316 ListenerAndDebugAddress* added =
317 aArray.AppendElement(ListenerAndDebugAddress(mListenerArray[
i]->mProxy,
319 NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
327 sbLocalDatabaseMediaListListener::SweepListenerArray(sbStopNotifyArray& aStopNotifying)
329 nsAutoLock lock(mListenerArrayLock);
331 PRUint32 numStopNotifying = aStopNotifying.Length();
338 for (PRInt32
i = numStopNotifying - 1;
i >= 0;
i--) {
339 const StopNotifyFlags&
stop = aStopNotifying[
i];
342 for (PRInt32 j = mListenerArray.Length() - 1; j >= 0; j--) {
343 if (stop.listener == mListenerArray[j]->mProxy) {
345 mListenerArray.RemoveElementAt(j);
348 if (stop.listenerFlags > 0) {
349 mListenerArray[j]->SetShouldStopNotifying(stop.listenerFlags);
360 #define SB_NOTIFY_LOG_COUNT(method) \
361 nsString __notifiedList; \
362 TRACE(("LocalDatabaseMediaListListener[0x%.8x] - " #method " %d of %d", \
363 this, snapshot.Length(), mListenerArray.Length()));
365 #define SB_NOTIFY_LOG_REMEMBER_NOTIFIED \
367 __notifiedList.AppendLiteral(" "); \
368 __notifiedList.Append(snapshot[i].debugAddress); \
369 __notifiedList.AppendLiteral(" ("); \
370 __notifiedList.AppendInt(__delta); \
371 __notifiedList.AppendLiteral(")"); \
374 #define SB_NOTIFY_LOG_NOTIFIED \
375 TRACE(("LocalDatabaseMediaListListener[0x%.8x] - Notified%s", \
376 this, NS_LossyConvertUTF16toASCII(__notifiedList).get()));
378 #define SB_NOTIFY_LOG_START_TIMER \
379 PRTime __now = PR_Now();
381 #define SB_NOTIFY_LOG_STOP_TIMER \
382 PRUint32 __delta = (PRUint32)(PR_Now() - __now);
385 #define SB_NOTIFY_LOG_COUNT(method)
386 #define SB_NOTIFY_LOG_REMEMBER_NOTIFIED
387 #define SB_NOTIFY_LOG_NOTIFIED
388 #define SB_NOTIFY_LOG_START_TIMER
389 #define SB_NOTIFY_LOG_STOP_TIMER
393 #define SB_NOTIFY_LISTENERS_HEAD \
394 NS_ASSERTION(mListenerArrayLock, "You haven't called Init yet!"); \
396 sbMediaListListenersArray snapshot;
398 #define SB_NOTIFY_LISTENERS_TAIL(method, call, flag) \
399 SB_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); \
401 PRUint32 length = snapshot.Length(); \
402 sbStopNotifyArray stopNotifying(length); \
404 SB_NOTIFY_LOG_COUNT(method) \
406 for (PRUint32 i = 0; i < length; i++) { \
407 PRBool noMoreForBatch = PR_FALSE; \
408 SB_NOTIFY_LOG_START_TIMER \
409 rv = snapshot[i].listener->call; \
410 SB_NOTIFY_LOG_STOP_TIMER \
411 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), #call " returned a failure code"); \
412 PRBool isGone = rv == NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; \
413 PRUint32 listenerFlags = 0; \
414 if (noMoreForBatch) { \
415 listenerFlags = sbIMediaList::flag; \
417 StopNotifyFlags* added = \
418 stopNotifying.AppendElement(StopNotifyFlags(snapshot[i].listener, \
421 SB_ENSURE_TRUE_VOID(added); \
422 SB_NOTIFY_LOG_REMEMBER_NOTIFIED; \
425 SB_NOTIFY_LOG_NOTIFIED \
426 SweepListenerArray(stopNotifying);
428 #define SB_NOTIFY_LISTENERS(method, call, flag) \
429 SB_NOTIFY_LISTENERS_HEAD \
430 nsresult rv = SnapshotListenerArray(snapshot, sbIMediaList::flag); \
431 SB_NOTIFY_LISTENERS_TAIL(method, call, flag)
433 #define SB_NOTIFY_LISTENERS_PROPERTIES(method, call, flag) \
434 SB_NOTIFY_LISTENERS_HEAD \
435 nsresult rv = SnapshotListenerArray(snapshot, \
436 sbIMediaList::flag, \
438 SB_NOTIFY_LISTENERS_TAIL(method, call, flag)
452 OnItemAdded(aList, aItem, aIndex, &noMoreForBatch),
453 LISTENER_FLAGS_ITEMADDED);
469 OnBeforeItemRemoved(aList,
473 LISTENER_FLAGS_BEFOREITEMREMOVED);
488 OnAfterItemRemoved(aList,
492 LISTENER_FLAGS_AFTERITEMREMOVED);
509 aList->ToString(list);
511 aItem->ToString(item);
513 aProperties->ToString(props);
514 TRACE((
"LocalDatabaseMediaListListener[0x%.8x] - "
515 "NotifyListenersItemUpdated %s %s %d %s",
this,
516 NS_LossyConvertUTF16toASCII(list).
get(),
517 NS_LossyConvertUTF16toASCII(item).
get(),
519 NS_LossyConvertUTF16toASCII(props).
get()));
527 LISTENER_FLAGS_ITEMUPDATED);
545 LISTENER_FLAGS_ITEMMOVED);
554 PRBool aExcludeLists)
559 OnBeforeListCleared(aList, aExcludeLists, &noMoreForBatch),
560 LISTENER_FLAGS_BEFORELISTCLEARED);
569 PRBool aExcludeLists)
574 OnListCleared(aList, aExcludeLists, &noMoreForBatch),
575 LISTENER_FLAGS_LISTCLEARED);
588 nsAutoLock lock(mListenerArrayLock);
590 PRUint32 length = mListenerArray.Length();
591 for (PRUint32
i = 0;
i < length;
i++) {
592 mListenerArray[
i]->BeginBatch();
598 LISTENER_FLAGS_BATCHBEGIN);
611 nsAutoLock lock(mListenerArrayLock);
613 if (mBatchDepth == 0) {
614 NS_ERROR(
"Batch begin/end imbalance");
619 PRUint32 length = mListenerArray.Length();
620 for (PRUint32
i = 0;
i < length;
i++) {
621 mListenerArray[
i]->EndBatch();
627 LISTENER_FLAGS_BATCHEND);
644 PRUint32 aCurrentBatchDepth,
648 NS_ENSURE_ARG_POINTER(aProxyObjMgr);
649 NS_ASSERTION(aListener,
"aListener is null");
650 NS_ASSERTION(!mProxy,
"Init called twice");
653 mRef = do_QueryInterface(aListener, &rv);
654 NS_ENSURE_SUCCESS(rv, rv);
658 PRBool success = mStopNotifiyingStack.SetLength(aCurrentBatchDepth);
659 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
660 for (PRUint32
i = 0;
i < aCurrentBatchDepth;
i++) {
661 mStopNotifiyingStack[
i] = 0;
664 InitPropertyFilter(aPropertyFilter);
669 NS_PROXY_TO_CURRENT_THREAD,
672 NS_PROXY_SYNC | NS_PROXY_ALWAYS,
673 getter_AddRefs(mProxy));
674 NS_ENSURE_SUCCESS(rv, rv);
678 PRUint32 len = PR_snprintf(buf,
sizeof(buf),
"0x%.8x", aListener);
679 mDebugAddress.Assign(NS_ConvertASCIItoUTF16(buf, len));
686 nsIWeakReference* aWeakListener,
687 PRUint32 aCurrentBatchDepth,
691 NS_ENSURE_ARG_POINTER(aProxyObjMgr);
692 NS_ASSERTION(aWeakListener,
"aWeakListener is null");
693 NS_ASSERTION(!mProxy,
"Init called twice");
696 mRef = do_QueryInterface(aWeakListener, &rv);
697 NS_ENSURE_SUCCESS(rv, rv);
699 mWeak = aWeakListener;
702 PRBool success = mStopNotifiyingStack.SetLength(aCurrentBatchDepth);
703 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
704 for (PRUint32
i = 0;
i < aCurrentBatchDepth;
i++) {
705 mStopNotifiyingStack[
i] = 0;
708 InitPropertyFilter(aPropertyFilter);
710 nsCOMPtr<sbIMediaListListener> wrapped =
712 NS_ENSURE_TRUE(wrapped, NS_ERROR_OUT_OF_MEMORY);
718 NS_PROXY_TO_CURRENT_THREAD,
721 NS_PROXY_SYNC | NS_PROXY_ALWAYS,
722 getter_AddRefs(mProxy));
723 NS_ENSURE_SUCCESS(rv, rv);
726 nsCOMPtr<sbIMediaListListener>
listener = do_QueryReferent(aWeakListener);
728 PRUint32 len = PR_snprintf(buf,
sizeof(buf),
"0x%.8x",
729 listener ? listener.get() : 0);
730 mDebugAddress.Assign(NS_ConvertASCIItoUTF16(buf, len));
739 aDebugAddress = mDebugAddress;
746 if ((mFlags & aFlag) == 0) {
751 if (mStopNotifiyingStack.Length() > 0 && mStopNotifiyingStack[0] & aFlag) {
756 if (mHasPropertyFilter && aProperties) {
760 rv = aProperties->GetLength(&length);
761 NS_ENSURE_SUCCESS(rv, PR_FALSE);
763 for (PRUint32
i = 0;
i < length;
i++) {
764 nsCOMPtr<sbIProperty> property;
765 rv = aProperties->GetPropertyAt(
i, getter_AddRefs(property));
766 NS_ENSURE_SUCCESS(rv, PR_FALSE);
769 rv =
property->GetId(
id);
770 NS_ENSURE_SUCCESS(rv, PR_FALSE);
772 if (mPropertyFilter.GetEntry(
id)) {
789 PRUint32* success = mStopNotifiyingStack.InsertElementAt(0, 0);
796 if (mStopNotifiyingStack.Length() == 0) {
797 NS_ERROR(
"BeginBatch/EndBatch out of balance");
801 mStopNotifiyingStack.RemoveElementAt(0);
808 if (mStopNotifiyingStack.Length() == 0) {
812 mStopNotifiyingStack[0] |= aFlag;
820 if (aPropertyFilter) {
821 mHasPropertyFilter = PR_TRUE;
824 rv = aPropertyFilter->GetLength(&length);
825 NS_ENSURE_SUCCESS(rv, rv);
827 PRBool success = mPropertyFilter.Init(length);
828 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
830 for (PRUint32
i = 0;
i < length;
i++) {
831 nsCOMPtr<sbIProperty> property;
832 rv = aPropertyFilter->GetPropertyAt(
i, getter_AddRefs(property));
833 NS_ENSURE_SUCCESS(rv, rv);
836 rv =
property->GetId(
id);
837 NS_ENSURE_SUCCESS(rv, rv);
839 nsStringHashKey* added = mPropertyFilter.PutEntry(
id);
840 NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
844 mHasPropertyFilter = PR_FALSE;
854 mWrappedWeak(aWeakListener)
856 NS_ASSERTION(mWrappedWeak,
"aWeakListener is null");
865 already_AddRefed<sbIMediaListListener>
866 sbWeakMediaListListenerWrapper::GetListener()
868 nsCOMPtr<sbIMediaListListener> strongListener = do_QueryReferent(mWrappedWeak);
869 if (!strongListener) {
870 LOG((
"sbWeakMediaListListenerWrapper[0x%.8x] - Weak listener is gone",
876 NS_ADDREF(listenerPtr);
883 #define SB_TRY_NOTIFY(call) \
884 nsCOMPtr<sbIMediaListListener> listener = GetListener(); \
886 return listener->call; \
888 return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
891 sbWeakMediaListListenerWrapper::OnItemAdded(
sbIMediaList* aMediaList,
894 PRBool* aNoMoreForBatch)
896 SB_TRY_NOTIFY(OnItemAdded(aMediaList, aMediaItem, aIndex, aNoMoreForBatch))
900 sbWeakMediaListListenerWrapper::OnBeforeItemRemoved(
sbIMediaList* aMediaList,
903 PRBool* aNoMoreForBatch)
912 sbWeakMediaListListenerWrapper::OnAfterItemRemoved(
sbIMediaList* aMediaList,
915 PRBool* aNoMoreForBatch)
924 sbWeakMediaListListenerWrapper::OnItemUpdated(
sbIMediaList* aMediaList,
927 PRBool* aNoMoreForBatch)
936 sbWeakMediaListListenerWrapper::OnItemMoved(
sbIMediaList* aMediaList,
939 PRBool* aNoMoreForBatch)
948 sbWeakMediaListListenerWrapper::OnBeforeListCleared(
sbIMediaList* aMediaList,
949 PRBool aExcludeLists,
950 PRBool* aNoMoreForBatch)
952 SB_TRY_NOTIFY(OnBeforeListCleared(aMediaList, aExcludeLists, aNoMoreForBatch))
956 sbWeakMediaListListenerWrapper::OnListCleared(
sbIMediaList* aMediaList,
957 PRBool aExcludeLists,
958 PRBool* aNoMoreForBatch)
960 SB_TRY_NOTIFY(OnListCleared(aMediaList, aExcludeLists, aNoMoreForBatch))
964 sbWeakMediaListListenerWrapper::OnBatchBegin(
sbIMediaList* aMediaList)
970 sbWeakMediaListListenerWrapper::OnBatchEnd(
sbIMediaList* aMediaList)
function stop(ch, cx, status, data)
void GetDebugAddress(nsAString &mDebugAddress)
void SetShouldStopNotifying(PRUint32 aFlag)
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
PRBool ShouldNotify(PRUint32 aFlag, sbIPropertyArray *aProperties=nsnull)
nsresult do_GetProxyForObjectWithManager(nsIProxyObjectManager *aProxyObjMgr, nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
_getSelectedPageStyle s i
nsresult Init(nsIProxyObjectManager *aProxyObjMgr, sbIMediaListListener *aListener, PRUint32 aCurrentBatchDepth, PRUint32 aFlags, sbIPropertyArray *aPropertyFilter)