From 40b6cb754122f613c1f3018786f095691ec382ff Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Wed, 20 Jan 2010 15:14:38 -0500
Subject: For EXT-4222: Switching outfits sometimes causes me to wear both, and
 show previous outfit as worn.  Postpone appearance change until wearables
 have resolved.

---
 indra/llcommon/llfasttimer.h      |  30 +++---
 indra/newview/llappearancemgr.cpp | 200 ++++++++++++++++++++++----------------
 indra/newview/llappearancemgr.h   |  38 +++++++-
 3 files changed, 168 insertions(+), 100 deletions(-)

diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index cd76bfe709..4874ece958 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -99,21 +99,21 @@ inline U64 get_cpu_clock_count_64()
 #else
 #define LL_INLINE
 #endif
-
-#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
-inline U32 get_cpu_clock_count_32()
-{																	
-	U64 x;															
-	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					
-	return (U32)x >> 8;													
-}
-
-inline U32 get_cpu_clock_count_64()
-{																	
-	U64 x;
-	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
-	return x >> 8;
-}
+
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+inline U32 get_cpu_clock_count_32()
+{																	
+	U64 x;															
+	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					
+	return (U32)x >> 8;													
+}
+
+inline U32 get_cpu_clock_count_64()
+{																	
+	U64 x;
+	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+	return x >> 8;
+}
 #endif
 
 #if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__))
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 748d8bdfbf..0d4e048dde 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -274,6 +274,7 @@ private:
 
 struct LLFoundData
 {
+	LLFoundData() {}
 	LLFoundData(const LLUUID& item_id,
 				const LLUUID& asset_id,
 				const std::string& name,
@@ -292,20 +293,81 @@ struct LLFoundData
 };
 
 	
-struct LLWearableHoldingPattern
+class LLWearableHoldingPattern
 {
-	LLWearableHoldingPattern() : mResolved(0) {}
-	~LLWearableHoldingPattern()
-	{
-		for_each(mFoundList.begin(), mFoundList.end(), DeletePointer());
-		mFoundList.clear();
-	}
-	typedef std::list<LLFoundData*> found_list_t;
+public:
+	LLWearableHoldingPattern();
+	~LLWearableHoldingPattern();
+
+	bool pollCompletion();
+	bool isDone();
+	
+	typedef std::list<LLFoundData> found_list_t;
 	found_list_t mFoundList;
+	LLInventoryModel::item_array_t mObjItems;
+	LLInventoryModel::item_array_t mGestItems;
 	S32 mResolved;
-	bool append;
+	LLTimer mWaitTime;
 };
 
+LLWearableHoldingPattern::LLWearableHoldingPattern():
+	mResolved(0)
+{
+	llwarns << "constructor" << llendl;
+}
+
+LLWearableHoldingPattern::~LLWearableHoldingPattern()
+{
+	llwarns << "destructor" << llendl;
+}
+
+bool LLWearableHoldingPattern::isDone()
+{
+	return (mResolved >= (S32)mFoundList.size());
+}
+
+bool LLWearableHoldingPattern::pollCompletion()
+{
+	bool done = isDone();
+	llwarns << "polling, done status: " << done << llendl;
+	if (done)
+	{
+		// Activate all gestures in this folder
+		if (mGestItems.count() > 0)
+		{
+			llinfos << "Activating " << mGestItems.count() << " gestures" << llendl;
+			
+			LLGestureManager::instance().activateGestures(mGestItems);
+			
+			// Update the inventory item labels to reflect the fact
+			// they are active.
+			LLViewerInventoryCategory* catp =
+				gInventory.getCategory(LLAppearanceManager::instance().getCOF());
+
+			if (catp)
+			{
+				gInventory.updateCategory(catp);
+				gInventory.notifyObservers();
+			}
+		}
+		
+		// Update attachments to match those requested.
+		LLVOAvatar* avatar = gAgent.getAvatarObject();
+		if( avatar )
+		{
+			llinfos << "Updating " << mObjItems.count() << " attachments" << llendl;
+			LLAgentWearables::userUpdateAttachments(mObjItems);
+		}
+
+		// Update wearables.
+		llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl;
+		LLAppearanceManager::instance().updateAgentWearables(this, false);
+
+		delete this;
+	}
+	return done;
+}
+
 static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
 {
 	LLInventoryModel::item_array_t new_items;
@@ -336,26 +398,21 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
 static void onWearableAssetFetch(LLWearable* wearable, void* data)
 {
 	LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
-	bool append = holder->append;
 	
 	if(wearable)
 	{
 		for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
 			 iter != holder->mFoundList.end(); ++iter)
 		{
-			LLFoundData* data = *iter;
-			if(wearable->getAssetID() == data->mAssetID)
+			LLFoundData& data = *iter;
+			if(wearable->getAssetID() == data.mAssetID)
 			{
-				data->mWearable = wearable;
+				data.mWearable = wearable;
 				break;
 			}
 		}
 	}
 	holder->mResolved += 1;
-	if(holder->mResolved >= (S32)holder->mFoundList.size())
-	{
-		LLAppearanceManager::instance().updateAgentWearables(holder, append);
-	}
 }
 
 LLUUID LLAppearanceManager::getCOF()
@@ -662,12 +719,12 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
 		for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
 			 iter != holder->mFoundList.end(); ++iter)
 		{
-			LLFoundData* data = *iter;
-			LLWearable* wearable = data->mWearable;
+			LLFoundData& data = *iter;
+			LLWearable* wearable = data.mWearable;
 			if( wearable && ((S32)wearable->getType() == i) )
 			{
 				LLViewerInventoryItem* item;
-				item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
+				item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
 				if( item && (item->getAssetUUID() == wearable->getAssetID()) )
 				{
 					items.put(item);
@@ -683,8 +740,6 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
 		gAgentWearables.setWearableOutfit(items, wearables, !append);
 	}
 
-	delete holder;
-
 //	dec_busy_count();
 }
 
@@ -706,86 +761,63 @@ void LLAppearanceManager::updateAppearanceFromCOF()
 	LLInventoryModel::item_array_t gest_items;
 	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links);
 	
-	if( !wear_items.count() && !obj_items.count() && !gest_items.count())
+	if(!wear_items.count())
 	{
 		LLNotificationsUtil::add("CouldNotPutOnOutfit");
 		return;
 	}
-		
-	// Processes that take time should show the busy cursor
-	//inc_busy_count(); // BAP this is currently a no-op in llinventorybridge.cpp - do we need it?
-		
-	// Activate all gestures in this folder
-	if (gest_items.count() > 0)
-	{
-		llinfos << "Activating " << gest_items.count() << " gestures" << llendl;
 
-		LLGestureManager::instance().activateGestures(gest_items);
+	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
 
-		// Update the inventory item labels to reflect the fact
-		// they are active.
-		LLViewerInventoryCategory* catp = gInventory.getCategory(current_outfit_id);
-		if (catp)
+	holder->mObjItems = obj_items;
+	holder->mGestItems = gest_items;
+		
+	// Note: can't do normal iteration, because if all the
+	// wearables can be resolved immediately, then the
+	// callback will be called (and this object deleted)
+	// before the final getNextData().
+	LLDynamicArray<LLFoundData> found_container;
+	for(S32 i = 0; i  < wear_items.count(); ++i)
+	{
+		LLViewerInventoryItem *item = wear_items.get(i);
+		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
+		if (item && linked_item)
 		{
-			gInventory.updateCategory(catp);
-			gInventory.notifyObservers();
+			LLFoundData found(linked_item->getUUID(),
+							  linked_item->getAssetUUID(),
+							  linked_item->getName(),
+							  linked_item->getType());
+			holder->mFoundList.push_front(found);
+			found_container.put(found);
 		}
-	}
-
-	if(wear_items.count() > 0)
-	{
-		// Note: can't do normal iteration, because if all the
-		// wearables can be resolved immediately, then the
-		// callback will be called (and this object deleted)
-		// before the final getNextData().
-		LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
-		LLFoundData* found;
-		LLDynamicArray<LLFoundData*> found_container;
-		for(S32 i = 0; i  < wear_items.count(); ++i)
+		else
 		{
-			LLViewerInventoryItem *item = wear_items.get(i);
-			LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
-			if (item && linked_item)
+			if (!item)
 			{
-				found = new LLFoundData(linked_item->getUUID(),
-										linked_item->getAssetUUID(),
-										linked_item->getName(),
-										linked_item->getType());
-				holder->mFoundList.push_front(found);
-				found_container.put(found);
+				llwarns << "attempt to wear a null item " << llendl;
 			}
-			else
+			else if (!linked_item)
 			{
-				if (!item)
-				{
-					llwarns << "attempt to wear a null item " << llendl;
-				}
-				else if (!linked_item)
-				{
-					llwarns << "attempt to wear a broken link " << item->getName() << llendl;
-				}
+				llwarns << "attempt to wear a broken link " << item->getName() << llendl;
 			}
 		}
-		for(S32 i = 0; i < found_container.count(); ++i)
-		{
-			holder->append = false;
-			found = found_container.get(i);
-				
-			// Fetch the wearables about to be worn.
-			LLWearableList::instance().getAsset(found->mAssetID,
-												found->mName,
-												found->mAssetType,
-												onWearableAssetFetch,
-												(void*)holder);
-		}
 	}
 
-	// Update attachments to match those requested.
-	LLVOAvatar* avatar = gAgent.getAvatarObject();
-	if( avatar )
+	for(S32 i = 0; i < found_container.count(); ++i)
 	{
-		LLAgentWearables::userUpdateAttachments(obj_items);
+		LLFoundData& found = found_container.get(i);
+				
+		// Fetch the wearables about to be worn.
+		LLWearableList::instance().getAsset(found.mAssetID,
+											found.mName,
+											found.mAssetType,
+											onWearableAssetFetch,
+											(void*)holder);
+
 	}
+
+	doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollCompletion,holder));
+
 }
 
 void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category,
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 20745b70e4..517face777 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -39,7 +39,7 @@
 #include "llcallbacklist.h"
 
 class LLWearable;
-struct LLWearableHoldingPattern;
+class LLWearableHoldingPattern;
 
 class LLAppearanceManager: public LLSingleton<LLAppearanceManager>
 {
@@ -168,4 +168,40 @@ void doOnIdle(T callable)
 	gIdleCallbacks.addFunction(&OnIdleCallback<T>::onIdle,cb_functor);
 }
 
+// Shim class and template function to allow arbitrary boost::bind
+// expressions to be run as recurring idle callbacks.
+template <typename T>
+class OnIdleCallbackRepeating
+{
+public:
+	OnIdleCallbackRepeating(T callable):
+		mCallable(callable)
+	{
+	}
+	// Will keep getting called until the callable returns false.
+	static void onIdle(void *data)
+	{
+		OnIdleCallbackRepeating<T>* self = reinterpret_cast<OnIdleCallbackRepeating<T>*>(data);
+		bool done = self->call();
+		if (done)
+		{
+			gIdleCallbacks.deleteFunction(onIdle, data);
+			delete self;
+		}
+	}
+	bool call()
+	{
+		return mCallable();
+	}
+private:
+	T mCallable;
+};
+
+template <typename T>
+void doOnIdleRepeating(T callable)
+{
+	OnIdleCallbackRepeating<T>* cb_functor = new OnIdleCallbackRepeating<T>(callable);
+	gIdleCallbacks.addFunction(&OnIdleCallbackRepeating<T>::onIdle,cb_functor);
+}
+
 #endif
-- 
cgit v1.2.3