From 7836f0fff3bd8a8098a1c920439c0c6ef131d26c Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Wed, 11 Aug 2010 12:34:27 -0400
Subject: EXT-8650 Can wear mutliple copies of a no-copy item via object links
 - EXT-8660 Cleanup ambiguous llviewerobject::set/getItemID code

Lots of files changed, but this is mostly just a trivial function call rename.  This change is very low risk.
---
 indra/newview/llagentwearables.cpp        |  2 +-
 indra/newview/llagentwearablesfetch.cpp   |  2 +-
 indra/newview/llsidepanelappearance.cpp   |  2 +-
 indra/newview/llviewerjointattachment.cpp | 20 ++++----------------
 indra/newview/llviewermenu.cpp            |  8 ++++----
 indra/newview/llviewerobject.cpp          | 25 +++++++++++++++++++++++++
 indra/newview/llviewerobject.h            | 10 +++++++---
 indra/newview/llvoavatar.cpp              |  1 +
 indra/newview/llvoavatarself.cpp          |  4 ++--
 9 files changed, 46 insertions(+), 28 deletions(-)

diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 6ee5a8b279..25456f7e26 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1756,7 +1756,7 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj
 			LLViewerObject *objectp = (*attachment_iter);
 			if (objectp)
 			{
-				LLUUID object_item_id = objectp->getItemID();
+				LLUUID object_item_id = objectp->getAttachmentItemID();
 				if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
 				{
 					// Object currently worn, was requested.
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
index d911d123f4..f6bb1b9bc9 100644
--- a/indra/newview/llagentwearablesfetch.cpp
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -215,7 +215,7 @@ void LLInitialWearablesFetch::processWearablesMessage()
 				{
 					LLViewerObject* attached_object = (*attachment_iter);
 					if (!attached_object) continue;
-					const LLUUID& item_id = attached_object->getItemID();
+					const LLUUID& item_id = attached_object->getAttachmentItemID();
 					if (item_id.isNull()) continue;
 					ids.push_back(item_id);
 				}
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 98cd0b88eb..83329ebccf 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -473,7 +473,7 @@ void LLSidepanelAppearance::fetchInventory()
 			{
 				LLViewerObject* attached_object = (*attachment_iter);
 				if (!attached_object) continue;
-				const LLUUID& item_id = attached_object->getItemID();
+				const LLUUID& item_id = attached_object->getAttachmentItemID();
 				if (item_id.isNull()) continue;
 				ids.push_back(item_id);
 			}
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 2b4b78d82d..da4960b69d 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -172,19 +172,7 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 		// re-connect object to the joint correctly
 	}
 
-	// Find the inventory item ID of the attached object
-	LLNameValue* item_id_nv = object->getNVPair("AttachItemID");
-	if( item_id_nv )
-	{
-		const char* s = item_id_nv->getString();
-		if( s )
-		{
-			LLUUID item_id;
-			item_id.set(s);
-			object->setItemID(item_id);
-			lldebugs << "getNVPair( AttachItemID ) = " << item_id << llendl;
-		}
-	}
+	object->extractAttachmentItemID();
 	mAttachedObjects.push_back(object);
 	setupDrawable(object);
 	
@@ -303,7 +291,7 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 	{
 		mUpdateXform = FALSE;
 	}
-	object->setItemID(LLUUID::null);
+	object->setAttachmentItemID(LLUUID::null);
 }
 
 //-----------------------------------------------------------------------------
@@ -429,7 +417,7 @@ const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &o
 		 ++iter)
 	{
 		const LLViewerObject* attached_object = (*iter);
-		if (attached_object->getItemID() == object_id)
+		if (attached_object->getAttachmentItemID() == object_id)
 		{
 			return attached_object;
 		}
@@ -444,7 +432,7 @@ LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_
 		 ++iter)
 	{
 		LLViewerObject* attached_object = (*iter);
-		if (attached_object->getItemID() == object_id)
+		if (attached_object->getAttachmentItemID() == object_id)
 		{
 			return attached_object;
 		}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 23e502c76f..e58f0c9aec 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -6050,7 +6050,7 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 				const LLViewerObject* attached_object = (*attachment_iter);
 				if (attached_object)
 				{
-					LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getItemID());
+					LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
 					if (itemp)
 					{
 						label += std::string(" (") + itemp->getName() + std::string(")");
@@ -6169,14 +6169,14 @@ class LLAttachmentEnableDrop : public view_listener_t
 				{
 					// make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
 					// so check to see if the item is in the inventory already
-					item = gInventory.getItem((*attachment_iter)->getItemID());
+					item = gInventory.getItem((*attachment_iter)->getAttachmentItemID());
 					if (!item)
 					{
 						// Item does not exist, make an observer to enable the pie menu 
 						// when the item finishes fetching worst case scenario 
 						// if a fetch is already out there (being sent from a slow sim)
 						// we refetch and there are 2 fetches
-						LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getItemID());		
+						LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID());		
 						worn_item_fetched->startFetch();
 						gInventory.addObserver(worn_item_fetched);
 					}
@@ -6523,7 +6523,7 @@ void handle_dump_attachments(void*)
 							!attached_object->mDrawable->isRenderType(0));
 			LLVector3 pos;
 			if (visible) pos = attached_object->mDrawable->getPosition();
-			llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getItemID()
+			llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID()
 					<< (attached_object ? " present " : " absent ")
 					<< (visible ? "visible " : "invisible ")
 					<<  " at " << pos
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 15bdf126c5..d3e6f01bc8 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5233,3 +5233,28 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif
 	return ;
 }
 
+const LLUUID &LLViewerObject::getAttachmentItemID() const
+{
+	return mAttachmentItemID;
+}
+
+void LLViewerObject::setAttachmentItemID(const LLUUID &id)
+{
+	mAttachmentItemID = id;
+}
+
+const LLUUID &LLViewerObject::extractAttachmentItemID()
+{
+	LLUUID item_id = LLUUID::null;
+	LLNameValue* item_id_nv = getNVPair("AttachItemID");
+	if( item_id_nv )
+	{
+		const char* s = item_id_nv->getString();
+		if( s )
+		{
+			item_id.set(s);
+		}
+	}
+	setAttachmentItemID(item_id);
+	return getAttachmentItemID();
+}
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index be83fb7ef8..33fda9fa2d 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -678,11 +678,15 @@ protected:
 private:	
 	static S32 sNumObjects;
 
+	//--------------------------------------------------------------------
+	// For objects that are attachments
+	//--------------------------------------------------------------------
 public:
-	const LLUUID &getItemID() const { return mAttachmentItemID; }
-	void setItemID(const LLUUID &id) { mAttachmentItemID = id; }
+	const LLUUID &getAttachmentItemID() const;
+	void setAttachmentItemID(const LLUUID &id);
+	const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
 private:
-	LLUUID mAttachmentItemID; // ItemID when item is in user inventory.
+	LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
 };
 
 ///////////////////
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 1ca10219ce..4e00355bbe 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -5710,6 +5710,7 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent)
 
 void LLVOAvatar::addChild(LLViewerObject *childp)
 {
+	childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
 	LLViewerObject::addChild(childp);
 	if (childp->mDrawable)
 	{
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 3a283e7aa6..73ea629bc3 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1067,7 +1067,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 	// Should just be the last object added
 	if (attachment->isObjectAttached(viewer_object))
 	{
-		const LLUUID& attachment_id = viewer_object->getItemID();
+		const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
 		LLAppearanceMgr::instance().registerAttachment(attachment_id);
 	}
 
@@ -1077,7 +1077,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 //virtual
 BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 {
-	const LLUUID attachment_id = viewer_object->getItemID();
+	const LLUUID attachment_id = viewer_object->getAttachmentItemID();
 	if (LLVOAvatar::detachObject(viewer_object))
 	{
 		// the simulator should automatically handle permission revocation
-- 
cgit v1.2.3


From 5be5c3f0daf25d2b190a8a563ea9efa278a8e716 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 11 Aug 2010 19:31:20 -0600
Subject: fix for EXT-7399: 2.0.2 with http textures loads textures slower than
 1.23.5 and EXT-7397: decoding textures get stuck in REQ status

---
 indra/newview/lltexturefetch.cpp | 129 +++++++++++----------------------------
 indra/newview/lltexturefetch.h   |  14 +----
 2 files changed, 36 insertions(+), 107 deletions(-)

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 846cba4a3b..f4899d0d5d 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -54,6 +54,7 @@
 #include "llviewertexturelist.h"
 #include "llviewertexture.h"
 #include "llviewerregion.h"
+#include "llviewerstats.h"
 #include "llworld.h"
 
 //////////////////////////////////////////////////////////////////////////////
@@ -150,7 +151,7 @@ public:
 	~LLTextureFetchWorker();
 	void relese() { --mActiveCount; }
 
-	void callbackHttpGet(const LLChannelDescriptors& channels,
+	S32 callbackHttpGet(const LLChannelDescriptors& channels,
 						 const LLIOPipe::buffer_ptr_t& buffer,
 						 bool partial, bool success);
 	void callbackCacheRead(bool success, LLImageFormatted* image,
@@ -335,8 +336,9 @@ public:
 				worker->setGetStatus(status, reason);
 // 				llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
 			}
-			mFetcher->removeFromHTTPQueue(mID);
-			worker->callbackHttpGet(channels, buffer, partial, success);
+			
+			S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
+			mFetcher->removeFromHTTPQueue(mID, data_size);
 		}
 		else
 		{
@@ -850,19 +852,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	{
 		if(mCanUseHTTP)
 		{
-			// *TODO: Integrate this with llviewerthrottle
-			// Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP,
-			// but probably not for Textures.
-			// Set the throttle to the entire bandwidth, assuming UDP packets will get priority
-			// when they are needed
-			//F32 max_bandwidth = mFetcher->mMaxBandwidth;
-			if (mFetcher->isHTTPThrottled(mDesiredSize))// ||
-				//mFetcher->getTextureBandwidth() > max_bandwidth)
-			{
-				// Make normal priority and return (i.e. wait until there is room in the queue)
-				setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
-				return false;
-			}
+			//NOTE:
+			//it seems ok to let sim control the UDP traffic
+			//so there is no throttle for http here.
+			//
 			
 			mFetcher->removeFromNetworkQueue(this, false);
 			
@@ -979,6 +972,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					else
 					{
 						resetFormattedData();
+						mState = DONE;
 						return true; // failed
 					}
 				}
@@ -1271,8 +1265,7 @@ bool LLTextureFetchWorker::deleteOK()
 
 	if ((haveWork() &&
 		 // not ok to delete from these states
-		 ((mState == WAIT_HTTP_REQ) ||
-		  (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
+		 ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
 	{
 		delete_ok = false;
 	}
@@ -1351,29 +1344,29 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 
 //////////////////////////////////////////////////////////////////////////////
 
-void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
+S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 										   const LLIOPipe::buffer_ptr_t& buffer,
 										   bool partial, bool success)
 {
+	S32 data_size = 0 ;
+
 	LLMutexLock lock(&mWorkMutex);
 
 	if (mState != WAIT_HTTP_REQ)
 	{
 		llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
 				<< " req=" << mSentRequest << " state= " << mState << llendl;
-		return;
+		return data_size;
 	}
 	if (mLoaded)
 	{
 		llwarns << "Duplicate callback for " << mID.asString() << llendl;
-		return; // ignore duplicate callback
+		return data_size ; // ignore duplicate callback
 	}
 	if (success)
 	{
 		// get length of stream:
-		S32 data_size = buffer->countAfter(channels.in(), NULL);
-
-		gTextureList.sTextureBits += data_size * 8; // Approximate - does not include header bits
+		data_size = buffer->countAfter(channels.in(), NULL);		
 	
 		LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
 		if (data_size > 0)
@@ -1410,6 +1403,8 @@ void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 	}
 	mLoaded = TRUE;
 	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+
+	return data_size ;
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1528,15 +1523,11 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mTextureCache(cache),
 	  mImageDecodeThread(imagedecodethread),
 	  mTextureBandwidth(0),
+	  mHTTPTextureBits(0),
 	  mCurlGetRequest(NULL)
 {
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
 	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
-	
-	for(S32 i = 0 ; i < TOTAL_TEXTURE_TYPES; i++)
-	{
-		mHTTPThrottleFlag[i] = FALSE ;
-	}
 }
 
 LLTextureFetch::~LLTextureFetch()
@@ -1678,69 +1669,11 @@ void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
 	mHTTPTextureQueue.insert(id);
 }
 
-void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
+void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
 {
 	LLMutexLock lock(&mNetworkQueueMutex);
 	mHTTPTextureQueue.erase(id);
-}
-
-void LLTextureFetch::clearHTTPThrottleFlag()
-{
-	static const F32 WAIT_TIME = 0.3f ; //seconds.
-	static LLFrameTimer timer ;
-
-	if(timer.getElapsedTimeF32() < WAIT_TIME) //wait for WAIT_TIME
-	{
-		return ;
-	}
-	timer.reset() ;
-
-	LLMutexLock lock(&mNetworkQueueMutex);
-	for(S32 i = 0 ; i < TOTAL_TEXTURE_TYPES; i++)//reset the http throttle flags.
-	{
-		mHTTPThrottleFlag[i] = FALSE ;
-	}
-}
-
-//check if need to throttle this fetching request.
-//rule: if a request can not be inserted into the http queue due to a full queue,
-//      block all future insertions of requests with larger fetching size requirement.
-//because:
-//      later insertions are usually at lower priorities; and
-//      small textures need chance to be fetched.
-bool LLTextureFetch::isHTTPThrottled(S32 requested_size)
-{
-	static const S32 SMALL_TEXTURE_MAX_SIZE = 64 * 64 * 4 ;
-	static const S32 MEDIUM_TEXTURE_MAX_SIZE = 256 * 256 * 4 ;
-	static const U32 MAX_HTTP_QUEUE_SIZE = 8 ;
-
-	//determine the class of the texture: SMALL, MEDIUM, or LARGE.
-	S32 type = LARGE_TEXTURE ;
-	if(requested_size <= SMALL_TEXTURE_MAX_SIZE)
-	{
-		type = SMALL_TEXTURE ;
-	}
-	else if(requested_size <= MEDIUM_TEXTURE_MAX_SIZE)
-	{
-		type = MEDIUM_TEXTURE ;
-	}
-
-	LLMutexLock lock(&mNetworkQueueMutex);
-
-	if(mHTTPTextureQueue.size() >= MAX_HTTP_QUEUE_SIZE)//if the http queue is full.
-	{
-		if(!mHTTPThrottleFlag[type + 1])
-		{
-			for(S32 i = type + 1 ; i < TOTAL_TEXTURE_TYPES; i++) //block all requests with fetching size larger than this request.		
-			{
-				mHTTPThrottleFlag[i] = TRUE ;			
-			}
-		}
-		
-		return true ;
-	}
-
-	return mHTTPThrottleFlag[type] ; //true if this request can not be inserted to the http queue.
+	mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits	
 }
 
 void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
@@ -1888,12 +1821,19 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
 //virtual
 S32 LLTextureFetch::update(U32 max_time_ms)
 {
-	S32 res;
-	
 	static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS");
-	mMaxBandwidth = band_width ;
-	
-	res = LLWorkerThread::update(max_time_ms);
+
+	{
+		mNetworkQueueMutex.lock() ;
+		mMaxBandwidth = band_width ;
+
+		gTextureList.sTextureBits += mHTTPTextureBits ;
+		mHTTPTextureBits = 0 ;
+
+		mNetworkQueueMutex.unlock() ;
+	}
+
+	S32 res = LLWorkerThread::update(max_time_ms);
 	
 	if (!mDebugPause)
 	{
@@ -1909,7 +1849,6 @@ S32 LLTextureFetch::update(U32 max_time_ms)
 			lldebugs << "processed: " << processed << " messages." << llendl;
 		}
 	}
-	clearHTTPThrottleFlag();
 
 	return res;
 }
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index c31c38b04a..2024165e7e 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -94,9 +94,7 @@ protected:
 	void addToNetworkQueue(LLTextureFetchWorker* worker);
 	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
 	void addToHTTPQueue(const LLUUID& id);
-	void removeFromHTTPQueue(const LLUUID& id);
-	bool isHTTPThrottled(S32 requested_size);
-	void clearHTTPThrottleFlag();
+	void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
 	// Called from worker thread (during doWork)
 	void processCurlRequests();	
@@ -136,15 +134,7 @@ private:
 	F32 mMaxBandwidth;
 	LLTextureInfo mTextureInfo;
 
-	enum
-	{
-		SMALL_TEXTURE = 0 , //size <= 64 * 64
-		MEDIUM_TEXTURE,     //size <= 256 * 256
-		LARGE_TEXTURE,      //size > 256 * 256
-		DUMMY,
-		TOTAL_TEXTURE_TYPES
-	};
-	BOOL mHTTPThrottleFlag[TOTAL_TEXTURE_TYPES];
+	U32 mHTTPTextureBits;
 };
 
 #endif // LL_LLTEXTUREFETCH_H
-- 
cgit v1.2.3


From 4281e2bd01c64acd2c5b0ae106f890be7d2fc443 Mon Sep 17 00:00:00 2001
From: Tofu Linden <tofu.linden@lindenlab.com>
Date: Thu, 12 Aug 2010 14:12:54 +0100
Subject: EXT-8589 FIXED Nothing happens if choose 'Invite to Group' from
 avatar's 3D context menu

The groups-chooser was auto-closing when the IW selection was lost, which in the case of right-clicking on (other) avatars is immediately.  The 'hg blame' is lost in merge-fubarism so I can't track why this behaviour was ever introduced, but I can think or (or find) no reason to autoclose in this case - the groups picker dialog doesn't even use the current selection, let alone care if it's lost.
---
 indra/newview/llfloatergroups.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp
index 3952c54670..307c937f6e 100644
--- a/indra/newview/llfloatergroups.cpp
+++ b/indra/newview/llfloatergroups.cpp
@@ -47,7 +47,6 @@
 #include "llbutton.h"
 #include "llgroupactions.h"
 #include "llscrolllistctrl.h"
-#include "llselectmgr.h"
 #include "lltextbox.h"
 #include "lluictrlfactory.h"
 #include "lltrans.h"
@@ -90,8 +89,6 @@ BOOL LLFloaterGroupPicker::postBuild()
 		list_ctrl->setContextMenu(LLScrollListCtrl::MENU_GROUP);
 	}
 	
-	LLSelectMgr::getInstance()->mUpdateSignal.connect(boost::bind(&LLFloaterGroupPicker::onBtnCancel, this));
-
 	childSetAction("OK", onBtnOK, this);
 
 	childSetAction("Cancel", onBtnCancel, this);
-- 
cgit v1.2.3


From 6c1796c105054bf52f879ab7060a2f53f896d44d Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Thu, 12 Aug 2010 11:00:39 -0400
Subject: DEV-52580 WIP: disallow multiple links to the same attachment in
 updateAppearanceFromCOF()

---
 indra/newview/llappearancemgr.cpp | 80 ++++++++++++++++++++++-----------------
 indra/newview/llappearancemgr.h   |  6 ++-
 2 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 2729053390..5a076845da 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1608,46 +1608,56 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,
 	}
 }
 
-void LLAppearanceMgr::enforceItemCountLimits()
+S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
+												 LLAssetType::EType type,
+												 S32 max_items,
+												 LLInventoryModel::item_array_t& items_to_kill)
 {
-	S32 purge_count = 0;
-	
-	LLInventoryModel::item_array_t body_items;
-	getDescendentsOfAssetType(getCOF(), body_items, LLAssetType::AT_BODYPART, false);
-	LLInventoryModel::item_array_t curr_body_items = body_items;
-	removeDuplicateItems(body_items);
-	filterWearableItems(body_items, 1);
-	LLInventoryModel::item_array_t kill_body_items;
-	item_array_diff(curr_body_items,body_items,kill_body_items);
-	for (LLInventoryModel::item_array_t::iterator it = kill_body_items.begin();
-		 it != kill_body_items.end();
-		 ++it)
+	S32 to_kill_count = 0;
+
+	LLInventoryModel::item_array_t items;
+	getDescendentsOfAssetType(cat_id, items, type, false);
+	LLInventoryModel::item_array_t curr_items = items;
+	removeDuplicateItems(items);
+	if (max_items > 0)
 	{
-		LLViewerInventoryItem *item = *it;
-		llinfos << "purging dup body part " << item->getName() << llendl;
-		gInventory.purgeObject(item->getUUID());
-		purge_count++;
+		filterWearableItems(items, max_items);
 	}
-	
-	LLInventoryModel::item_array_t wear_items;
-	getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false);
-	LLInventoryModel::item_array_t curr_wear_items = wear_items;
-	removeDuplicateItems(wear_items);
-	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
-	LLInventoryModel::item_array_t kill_wear_items;
-	item_array_diff(curr_wear_items,wear_items,kill_wear_items);
-	for (LLInventoryModel::item_array_t::iterator it = kill_wear_items.begin();
-		 it != kill_wear_items.end();
+	LLInventoryModel::item_array_t kill_items;
+	item_array_diff(curr_items,items,kill_items);
+	for (LLInventoryModel::item_array_t::iterator it = kill_items.begin();
+		 it != kill_items.end();
 		 ++it)
 	{
-		LLViewerInventoryItem *item = *it;
-		llinfos << "purging excess clothing item " << item->getName() << llendl;
-		gInventory.purgeObject(item->getUUID());
-		purge_count++;
+		items_to_kill.push_back(*it);
+		to_kill_count++;
 	}
+	return to_kill_count;
+}
+	
+												 
+void LLAppearanceMgr::enforceItemRestrictions()
+{
+	S32 purge_count = 0;
+	LLInventoryModel::item_array_t items_to_kill;
 
-	if (purge_count>0)
+	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART,
+											  1, items_to_kill);
+	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING,
+											  LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT,
+											  -1, items_to_kill);
+
+	if (items_to_kill.size()>0)
 	{
+		for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin();
+			 it != items_to_kill.end();
+			 ++it)
+		{
+			LLViewerInventoryItem *item = *it;
+			llinfos << "purging duplicate or excess item " << item->getName() << llendl;
+			gInventory.purgeObject(item->getUUID());
+		}
 		gInventory.notifyObservers();
 	}
 }
@@ -1670,7 +1680,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
 
 	// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
 	// this should catch anything that gets through.
-	enforceItemCountLimits();
+	enforceItemRestrictions();
 	
 	// update dirty flag to see if the state of the COF matches
 	// the saved outfit stored as a folder link
@@ -2741,8 +2751,8 @@ bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
 	 LLInventoryModel::item_array_t items;
 	 LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id));
 	 gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(),
-	 cats,
-	 items,
+									 cats,
+									 items,
 	 LLInventoryModel::EXCLUDE_TRASH,
 	 find_links);
 
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index eb495bd274..796ac5c572 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -66,7 +66,11 @@ public:
 	void renameOutfit(const LLUUID& outfit_id);
 	void takeOffOutfit(const LLUUID& cat_id);
 	void addCategoryToCurrentOutfit(const LLUUID& cat_id);
-	void enforceItemCountLimits();
+	S32 findExcessOrDuplicateItems(const LLUUID& cat_id,
+								   LLAssetType::EType type,
+								   S32 max_items,
+								   LLInventoryModel::item_array_t& items_to_kill);
+	void enforceItemRestrictions();
 
 	// Copy all items and the src category itself.
 	void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
-- 
cgit v1.2.3


From 4627c4b698cf75abd8bd59b6a05ea923c57f7574 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 12 Aug 2010 21:52:22 -0600
Subject: Fix for EXT-8578: Blurry image in profile never resolves - texture
 queue problem?

---
 indra/newview/llviewertexture.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index e38608bcfc..9b3243a1bc 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -814,7 +814,7 @@ void LLViewerTexture::generateGLTexture()
 LLImageGL* LLViewerTexture::getGLTexture() const
 {
 	llassert(mGLTexturep.notNull()) ;
-	
+
 	return mGLTexturep ;
 }
 
@@ -1489,8 +1489,13 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerFetchedTexture::processTextureStats()
 {
-	if(mFullyLoaded)
+	if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture.
 	{
+		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ;
+	}
+
+	if(mFullyLoaded)
+	{		
 		if(mDesiredDiscardLevel <= mMinDesiredDiscardLevel)//already loaded
 		{
 			return ;
-- 
cgit v1.2.3


From 5881252ab2e9ab31b05c1a54d8ce723013eee15a Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Fri, 13 Aug 2010 11:12:51 -0400
Subject: EXT-8650 Can wear multiple copies of no-copy item via object links *
 EXT-8688 Automatically detach same object is detected * EXT-8689 Cleanup
 detachAttachmentIntoInventory code

When an object arrives as an attachment, if it's already attached then it's automatically detached.
---
 indra/newview/llappearancemgr.cpp         | 32 ++++++++++---------------------
 indra/newview/llinventorybridge.cpp       | 27 ++------------------------
 indra/newview/llviewerjointattachment.cpp | 21 ++++++++++++++++----
 indra/newview/llvoavatarself.cpp          | 23 ++++++++++++++++++++++
 indra/newview/llvoavatarself.h            |  1 +
 5 files changed, 53 insertions(+), 51 deletions(-)

diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 6fdd71bfbf..21a635e738 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2496,29 +2496,17 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
 
 	switch (item_to_remove->getType())
 	{
-	case LLAssetType::AT_CLOTHING:
-		if (get_is_item_worn(id_to_remove))
-		{
-			//*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future
-			LLWearableBridge::removeItemFromAvatar(item_to_remove);
-		}
-		break;
-	case LLAssetType::AT_OBJECT:
-		gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
-		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
-		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-		gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_to_remove->getLinkedUUID());
-		gMessageSystem->sendReliable( gAgent.getRegion()->getHost());
-
-		{
-			// this object might have been selected, so let the selection manager know it's gone now
-			LLViewerObject *found_obj = gObjectList.findObject(item_to_remove->getLinkedUUID());
-			if (found_obj)
+		case LLAssetType::AT_CLOTHING:
+			if (get_is_item_worn(id_to_remove))
 			{
-				LLSelectMgr::getInstance()->remove(found_obj);
-			};
-		}
-	default: break;
+				//*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future
+				LLWearableBridge::removeItemFromAvatar(item_to_remove);
+			}
+			break;
+		case LLAssetType::AT_OBJECT:
+			LLVOAvatarSelf::detachAttachmentIntoInventory(item_to_remove->getLinkedUUID());
+		default:
+			break;
 	}
 
 	// *HACK: Force to remove garbage from COF.
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 9bbc6514b4..66bf325f04 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -3957,18 +3957,7 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
 		LLInventoryItem* item = gInventory.getItem(mUUID);
 		if(item)
 		{
-			gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
-			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
-			gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
-			gMessageSystem->sendReliable( gAgent.getRegion()->getHost());
-
-			// this object might have been selected, so let the selection manager know it's gone now
-			LLViewerObject *found_obj = gObjectList.findObject(item->getLinkedUUID());
-			if (found_obj)
-			{
-				LLSelectMgr::getInstance()->remove(found_obj);
-			}
+			LLVOAvatarSelf::detachAttachmentIntoInventory(item->getLinkedUUID());
 		}
 	}
 	else LLItemBridge::performAction(model, action);
@@ -4321,19 +4310,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
 				LLViewerInventoryItem *obj_item = obj_item_array.get(i);
 				if (get_is_item_worn(obj_item->getUUID()))
 				{
-					gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
-					gMessageSystem->nextBlockFast(_PREHASH_ObjectData );
-					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
-					gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item->getLinkedUUID() );
-					
-					gMessageSystem->sendReliable( gAgent.getRegion()->getHost() );
-					
-					// this object might have been selected, so let the selection manager know it's gone now
-					LLViewerObject *found_obj = gObjectList.findObject( obj_item->getLinkedUUID());
-					if (found_obj)
-					{
-						LLSelectMgr::getInstance()->remove(found_obj);
-					}
+					LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID());
 				}
 			}
 		}
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index da4960b69d..c9335366cd 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -35,12 +35,11 @@
 #include "llviewerjointattachment.h"
 
 #include "llagentconstants.h"
-
 #include "llviewercontrol.h"
 #include "lldrawable.h"
 #include "llgl.h"
 #include "llrender.h"
-#include "llvoavatar.h"
+#include "llvoavatarself.h"
 #include "llvolume.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
@@ -164,6 +163,9 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 //-----------------------------------------------------------------------------
 BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 {
+	object->extractAttachmentItemID();
+
+	// Same object reattached
 	if (isObjectAttached(object))
 	{
 		llinfos << "(same object re-attached)" << llendl;
@@ -171,8 +173,19 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 		// Pass through anyway to let setupDrawable()
 		// re-connect object to the joint correctly
 	}
+	
+	// Two instances of the same inventory item attached --
+	// Request detach, and kill the object in the meantime.
+	if (getAttachedObject(object->getAttachmentItemID()))
+	{
+		llinfos << "(same object re-attached)" << llendl;
+		object->markDead();
+
+		// If this happens to be attached to self, then detach.
+		LLVOAvatarSelf::detachAttachmentIntoInventory(object->getAttachmentItemID());
+		return FALSE;
+	}
 
-	object->extractAttachmentItemID();
 	mAttachedObjects.push_back(object);
 	setupDrawable(object);
 	
@@ -195,7 +208,7 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 	}
 	calcLOD();
 	mUpdateXform = TRUE;
-
+	
 	return TRUE;
 }
 
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 73ea629bc3..09e50dcb90 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1115,6 +1115,29 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 	return FALSE;
 }
 
+// static
+BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id)
+{
+	LLInventoryItem* item = gInventory.getItem(item_id);
+	if (item)
+	{
+		gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
+		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+		gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
+		gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
+		
+		// this object might have been selected, so let the selection manager know it's gone now
+		LLViewerObject *found_obj = gObjectList.findObject(item_id);
+		if (found_obj)
+		{
+			LLSelectMgr::getInstance()->remove(found_obj);
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
 U32 LLVOAvatarSelf::getNumWearables(LLVOAvatarDefines::ETextureIndex i) const
 {
 	LLWearableType::EType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i);
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 630afe7a0f..37d24d138f 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -295,6 +295,7 @@ public:
 	const std::string   getAttachedPointName(const LLUUID& inv_item_id) const;
 	/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
 	/*virtual*/ BOOL 	detachObject(LLViewerObject *viewer_object);
+	static BOOL			detachAttachmentIntoInventory(const LLUUID& item_id);
 
 	//--------------------------------------------------------------------
 	// HUDs
-- 
cgit v1.2.3


From f369ebec244f57205d0a9c835d4184c827e7b50f Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Fri, 13 Aug 2010 11:26:22 -0400
Subject: EXT-8650 Can wear multiple copies of no-copy item via object links *
 EXT-8661 Take out unused mRegisteredAttachments in LLAppearanceMgr

Removed unused mRegisteredAttachments.  Not sure what this was used for, but it's no longer used.
---
 indra/newview/llappearancemgr.cpp | 15 ---------------
 indra/newview/llappearancemgr.h   |  2 --
 2 files changed, 17 deletions(-)

diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 21a635e738..5c713e60f9 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2646,7 +2646,6 @@ void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
 	mAttachmentInvLinkEnabled = val;
 }
 
-// BAP TODO - mRegisteredAttachments is currently maintained but not used for anything.  Consider yanking.
 void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
 {
        llinfos << msg << llendl;
@@ -2666,7 +2665,6 @@ void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
 
 void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
 {
-       mRegisteredAttachments.insert(item_id);
 	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 
 	   if (mAttachmentInvLinkEnabled)
@@ -2684,7 +2682,6 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
 
 void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
 {
-       mRegisteredAttachments.erase(item_id);
 	   gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 
 	   if (mAttachmentInvLinkEnabled)
@@ -2697,18 +2694,6 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
 	   }
 }
 
-void LLAppearanceMgr::linkRegisteredAttachments()
-{
-	for (std::set<LLUUID>::iterator it = mRegisteredAttachments.begin();
-		 it != mRegisteredAttachments.end();
-		 ++it)
-	{
-		LLUUID item_id = *it;
-		addCOFItemLink(item_id, false);
-	}
-	mRegisteredAttachments.clear();
-}
-
 BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
 {
 	return gInventory.isObjectDescendentOf(obj_id, getCOF());
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index eb495bd274..73b05ff7cd 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -119,7 +119,6 @@ public:
 	void unregisterAttachment(const LLUUID& item_id);
 	void registerAttachment(const LLUUID& item_id);
 	void setAttachmentInvLinkEnable(bool val);
-	void linkRegisteredAttachments();
 
 	// utility function for bulk linking.
 	void linkAll(const LLUUID& category,
@@ -206,7 +205,6 @@ private:
 
 	void setOutfitLocked(bool locked);
 
-	std::set<LLUUID> mRegisteredAttachments;
 	bool mAttachmentInvLinkEnabled;
 	bool mOutfitIsDirty;
 	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
-- 
cgit v1.2.3


From 37a0124bfdedfd24c31f40c250e65ad42be0e6de Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Fri, 13 Aug 2010 14:33:30 -0400
Subject: DEV-52580 FIX

---
 indra/newview/llinventorybridge.cpp | 19 +++++++++++++++---
 indra/newview/llvoavatarself.cpp    | 40 +++++++++++++++++++++++++++++++++++++
 indra/newview/llvoavatarself.h      |  7 +++++++
 3 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 38f3521b2d..531d4c3ee9 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4000,8 +4000,17 @@ std::string LLObjectBridge::getLabelSuffix() const
 
 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment)
 {
-	LLSD payload;
-	payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link.
+	const LLUUID& item_id = item->getLinkedUUID();
+
+	// Check for duplicate request.
+	if (isAgentAvatarValid() &&
+		(gAgentAvatarp->attachmentWasRequested(item_id) ||
+		 gAgentAvatarp->isWearingAttachment(item_id)))
+	{
+		llwarns << "duplicate attachment request, ignoring" << llendl;
+		return;
+	}
+	gAgentAvatarp->addAttachmentRequest(item_id);
 
 	S32 attach_pt = 0;
 	if (isAgentAvatarValid() && attachment)
@@ -4017,6 +4026,8 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
 		}
 	}
 
+	LLSD payload;
+	payload["item_id"] = item_id; // Wear the base object in case this is a link.
 	payload["attachment_point"] = attach_pt;
 
 	if (!gSavedSettings.getBOOL("MultipleAttachments") &&
@@ -4043,11 +4054,13 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon
 	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 	if (option == 0/*YES*/)
 	{
-		LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID());
+		LLUUID item_id = notification["payload"]["item_id"].asUUID();
+		LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
 
 		if (itemp)
 		{
 			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
+			
 			if (gSavedSettings.getBOOL("MultipleAttachments"))
 				attachment_pt |= ATTACHMENT_ADD;
 
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 73ea629bc3..7e6591a194 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1015,6 +1015,44 @@ BOOL LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const
 	return FALSE;
 }
 
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatarSelf::attachmentWasRequested(const LLUUID& inv_item_id) const
+{
+	const F32 REQUEST_EXPIRATION_SECONDS = 5.0;  // any request older than this is ignored/removed.
+	std::map<LLUUID,LLTimer>::iterator it = mAttachmentRequests.find(inv_item_id);
+	if (it != mAttachmentRequests.end())
+	{
+		const LLTimer& request_time = it->second;
+		F32 request_time_elapsed = request_time.getElapsedTimeF32();
+		if (request_time_elapsed > REQUEST_EXPIRATION_SECONDS)
+		{
+			mAttachmentRequests.erase(it);
+			return FALSE;
+		}
+		else
+		{
+			return TRUE;
+		}
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+//-----------------------------------------------------------------------------
+void LLVOAvatarSelf::addAttachmentRequest(const LLUUID& inv_item_id)
+{
+	LLTimer current_time;
+	mAttachmentRequests[inv_item_id] = current_time;
+}
+
+//-----------------------------------------------------------------------------
+void LLVOAvatarSelf::removeAttachmentRequest(const LLUUID& inv_item_id)
+{
+	mAttachmentRequests.erase(inv_item_id);
+}
+
 //-----------------------------------------------------------------------------
 // getWornAttachment()
 //-----------------------------------------------------------------------------
@@ -1069,6 +1107,8 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 	{
 		const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
 		LLAppearanceMgr::instance().registerAttachment(attachment_id);
+		// Clear any pending requests once the attachment arrives.
+		removeAttachmentRequest(attachment_id);
 	}
 
 	return attachment;
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 630afe7a0f..b129ffd986 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -291,11 +291,18 @@ protected:
 public:
 	void 				updateAttachmentVisibility(U32 camera_mode);
 	BOOL 				isWearingAttachment(const LLUUID& inv_item_id) const;
+	BOOL				attachmentWasRequested(const LLUUID& inv_item_id) const;
+	void				addAttachmentRequest(const LLUUID& inv_item_id);
+	void				removeAttachmentRequest(const LLUUID& inv_item_id);
 	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id);
 	const std::string   getAttachedPointName(const LLUUID& inv_item_id) const;
 	/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
 	/*virtual*/ BOOL 	detachObject(LLViewerObject *viewer_object);
 
+private:
+	// Track attachments that have been requested but have not arrived yet.
+	mutable std::map<LLUUID,LLTimer> mAttachmentRequests;
+
 	//--------------------------------------------------------------------
 	// HUDs
 	//--------------------------------------------------------------------
-- 
cgit v1.2.3