diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index eccce83c747f815221198eb71841090b45b713f2..d0f4dc88e79d83dc98e23a78d11e01fc338f6a25 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -240,6 +240,7 @@ set(viewer_SOURCE_FILES
     llimpanel.cpp
     llimview.cpp
     llimcontrolpanel.cpp
+    llinspect.cpp
     llinspectavatar.cpp
     llinspectgroup.cpp
     llinspectobject.cpp
@@ -706,6 +707,7 @@ set(viewer_HEADER_FILES
     llimview.h
     llimcontrolpanel.h
     llinspectavatar.h
+    llinspect.h
     llinspectgroup.h
     llinspectobject.h
     llinventorybridge.h
diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa299014ee681f8618d8797630627e98744190bc
--- /dev/null
+++ b/indra/newview/llinspect.cpp
@@ -0,0 +1,97 @@
+/** 
+ * @file llinspect.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "llviewerprecompiledheaders.h"
+
+#include "llinspect.h"
+
+#include "llcontrol.h"	// LLCachedControl
+#include "llui.h"		// LLUI::sSettingsGroups
+
+LLInspect::LLInspect(const LLSD& key)
+:	LLFloater(key),
+	mCloseTimer(),
+	mOpenTimer()
+{
+}
+
+LLInspect::~LLInspect()
+{
+}
+
+// virtual
+void LLInspect::draw()
+{
+	static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
+	if (mOpenTimer.getStarted())
+	{
+		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 0.f, 1.f);
+		LLViewDrawContext context(alpha);
+		LLFloater::draw();
+		if (alpha == 1.f)
+		{
+			mOpenTimer.stop();
+		}
+		
+	}
+	else if (mCloseTimer.getStarted())
+	{
+		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
+		LLViewDrawContext context(alpha);
+		LLFloater::draw();
+		if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
+		{
+			closeFloater(false);
+		}
+	}
+	else
+	{
+		LLFloater::draw();
+	}
+}
+
+// virtual
+void LLInspect::onOpen(const LLSD& data)
+{
+	LLFloater::onOpen(data);
+	
+	mCloseTimer.stop();
+	mOpenTimer.start();
+}
+
+// virtual
+void LLInspect::onFocusLost()
+{
+	LLFloater::onFocusLost();
+	
+	// Start closing when we lose focus
+	mCloseTimer.start();
+	mOpenTimer.stop();
+}
diff --git a/indra/newview/llinspect.h b/indra/newview/llinspect.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bdb7c1f2ccbca2eeb95affd70207e1ef29b66a4
--- /dev/null
+++ b/indra/newview/llinspect.h
@@ -0,0 +1,60 @@
+/** 
+ * @file llinspect.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLINSPECT_H
+#define LLINSPECT_H
+
+#include "llfloater.h"
+#include "llframetimer.h"
+
+/// Base class for all inspectors (super-tooltips showing a miniature
+/// properties view).
+class LLInspect : public LLFloater
+{
+public:
+	LLInspect(const LLSD& key);
+	virtual ~LLInspect();
+	
+	/// Inspectors have a custom fade-in/fade-out animation
+	/*virtual*/ void draw();
+	
+	/// Start open animation
+	/*virtual*/ void onOpen(const LLSD& avatar_id);
+	
+	/// Inspectors close themselves when they lose focus
+	/*virtual*/ void onFocusLost();
+	
+private:
+	LLFrameTimer		mCloseTimer;
+	LLFrameTimer		mOpenTimer;
+};
+
+#endif
\ No newline at end of file
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 14dd0cdbce41926d86685fb54ae0b9edf714772c..081e55971d4da34edb48aa31b3ef13d1e2bd6e3b 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -41,13 +41,13 @@
 #include "llcallingcard.h"
 #include "llfloaterreporter.h"
 #include "llfloaterworldmap.h"
+#include "llinspect.h"
 #include "llmutelist.h"
 #include "llpanelblockedlist.h"
 #include "llviewermenu.h"
 #include "llvoiceclient.h"
 
 // Linden libraries
-#include "llcontrol.h"	// LLCachedControl
 #include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llmenubutton.h"
@@ -66,7 +66,7 @@ class LLFetchAvatarData;
 // Avatar Inspector, a small information window used when clicking
 // on avatar names in the 2D UI and in the ambient inspector widget for
 // the 3D world.
-class LLInspectAvatar : public LLFloater
+class LLInspectAvatar : public LLInspect
 {
 	friend class LLFloaterReg;
 	
@@ -77,7 +77,6 @@ class LLInspectAvatar : public LLFloater
 	virtual ~LLInspectAvatar();
 	
 	/*virtual*/ BOOL postBuild(void);
-	/*virtual*/ void draw();
 	
 	// Because floater is single instance, need to re-parse data on each spawn
 	// (for example, inspector about same avatar but in different position)
@@ -86,9 +85,6 @@ class LLInspectAvatar : public LLFloater
 	// When closing they should close their gear menu 
 	/*virtual*/ void onClose(bool app_quitting);
 	
-	// Inspectors close themselves when they lose focus
-	/*virtual*/ void onFocusLost();
-	
 	// Update view based on information from avatar properties processor
 	void processAvatarData(LLAvatarData* data);
 	
@@ -132,8 +128,6 @@ class LLInspectAvatar : public LLFloater
 	// an in-flight request for avatar properties from LLAvatarPropertiesProcessor
 	// is represented by this object
 	LLFetchAvatarData*	mPropertiesRequest;
-	LLFrameTimer		mCloseTimer;
-	LLFrameTimer		mOpenTimer;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -183,12 +177,11 @@ class LLFetchAvatarData : public LLAvatarPropertiesObserver
 };
 
 LLInspectAvatar::LLInspectAvatar(const LLSD& sd)
-:	LLFloater( LLSD() ),	// single_instance, doesn't really need key
+:	LLInspect( LLSD() ),	// single_instance, doesn't really need key
 	mAvatarID(),			// set in onOpen()
 	mPartnerID(),
 	mAvatarName(),
-	mPropertiesRequest(NULL),
-	mCloseTimer()
+	mPropertiesRequest(NULL)
 {
 	mCommitCallbackRegistrar.add("InspectAvatar.ViewProfile",	boost::bind(&LLInspectAvatar::onClickViewProfile, this));	
 	mCommitCallbackRegistrar.add("InspectAvatar.AddFriend",	boost::bind(&LLInspectAvatar::onClickAddFriend, this));	
@@ -234,35 +227,7 @@ BOOL LLInspectAvatar::postBuild(void)
 	return TRUE;
 }
 
-void LLInspectAvatar::draw()
-{
-	static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
-	if (mOpenTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 0.f, 1.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-		if (alpha == 1.f)
-		{
-			mOpenTimer.stop();
-		}
 
-	}
-	else if (mCloseTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-		if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
-		{
-			closeFloater(false);
-		}
-	}
-	else
-	{
-		LLFloater::draw();
-	}
-}
 
 
 // Multiple calls to showInstance("inspect_avatar", foo) will provide different
@@ -270,8 +235,8 @@ void LLInspectAvatar::draw()
 //virtual
 void LLInspectAvatar::onOpen(const LLSD& data)
 {
-	mCloseTimer.stop();
-	mOpenTimer.start();
+	// Start open animation
+	LLInspect::onOpen(data);
 
 	// Extract appropriate avatar id
 	mAvatarID = data["avatar_id"];
@@ -306,14 +271,6 @@ void LLInspectAvatar::onClose(bool app_quitting)
   getChild<LLMenuButton>("gear_btn")->hideMenu();
 }	
 
-//virtual
-void LLInspectAvatar::onFocusLost()
-{
-	// Start closing when we lose focus
-	mCloseTimer.start();
-	mOpenTimer.stop();
-}
-
 void LLInspectAvatar::requestUpdate()
 {
 	// Don't make network requests when spawning from the debug menu at the
diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp
index 184d413743cb40ee5bf7e0dd0ebf5d270161ba9e..e079e27e564f12e0fb4ebb9430fd5c53d55cec96 100644
--- a/indra/newview/llinspectgroup.cpp
+++ b/indra/newview/llinspectgroup.cpp
@@ -36,6 +36,7 @@
 // viewer files
 #include "llgroupactions.h"
 #include "llgroupmgr.h"
+#include "llinspect.h"
 
 // Linden libraries
 #include "llcontrol.h"	// LLCachedControl
@@ -55,7 +56,7 @@ class LLFetchGroupData;
 
 /// Group Inspector, a small information window used when clicking
 /// on group names in the 2D UI
-class LLInspectGroup : public LLFloater
+class LLInspectGroup : public LLInspect
 {
 	friend class LLFloaterReg;
 	
@@ -65,8 +66,6 @@ class LLInspectGroup : public LLFloater
 	LLInspectGroup(const LLSD& key);
 	virtual ~LLInspectGroup();
 	
-	/*virtual*/ void draw();
-	
 	// Because floater is single instance, need to re-parse data on each spawn
 	// (for example, inspector about same group but in different position)
 	/*virtual*/ void onOpen(const LLSD& group_id);
@@ -74,9 +73,6 @@ class LLInspectGroup : public LLFloater
 	// When closing they should close their gear menu 
 	/*virtual*/ void onClose(bool app_quitting);
 	
-	// Inspectors close themselves when they lose focus
-	/*virtual*/ void onFocusLost();
-	
 	// Update view based on information from group manager
 	void processGroupData();
 	
@@ -101,8 +97,6 @@ class LLInspectGroup : public LLFloater
 	// an in-flight network request for group properties 
 	// is represented by this object
 	LLFetchGroupData*	mPropertiesRequest;
-	LLFrameTimer		mCloseTimer;
-	LLFrameTimer		mOpenTimer;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -144,10 +138,9 @@ class LLFetchGroupData : public LLGroupMgrObserver
 };
 
 LLInspectGroup::LLInspectGroup(const LLSD& sd)
-:	LLFloater( LLSD() ),	// single_instance, doesn't really need key
+:	LLInspect( LLSD() ),	// single_instance, doesn't really need key
 	mGroupID(),			// set in onOpen()
-	mPropertiesRequest(NULL),
-	mCloseTimer()
+	mPropertiesRequest(NULL)
 {
 	mCommitCallbackRegistrar.add("InspectGroup.ViewProfile",
 		boost::bind(&LLInspectGroup::onClickViewProfile, this));
@@ -168,44 +161,14 @@ LLInspectGroup::~LLInspectGroup()
 	mPropertiesRequest = NULL;
 }
 
-void LLInspectGroup::draw()
-{
-	static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
-	if (mOpenTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 0.f, 1.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-		if (alpha == 1.f)
-		{
-			mOpenTimer.stop();
-		}
-
-	}
-	else if (mCloseTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-		if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
-		{
-			closeFloater(false);
-		}
-	}
-	else
-	{
-		LLFloater::draw();
-	}
-}
-
 
 // Multiple calls to showInstance("inspect_avatar", foo) will provide different
 // LLSD for foo, which we will catch here.
 //virtual
 void LLInspectGroup::onOpen(const LLSD& data)
 {
-	mCloseTimer.stop();
-	mOpenTimer.start();
+	// start fade animation
+	LLInspect::onOpen(data);
 
 	mGroupID = data["group_id"];
 
@@ -227,16 +190,9 @@ void LLInspectGroup::onOpen(const LLSD& data)
 
 // virtual
 void LLInspectGroup::onClose(bool app_quitting)
-{  
-}	
-
-//virtual
-void LLInspectGroup::onFocusLost()
 {
-	// Start closing when we lose focus
-	mCloseTimer.start();
-	mOpenTimer.stop();
-}
+	// *TODO: If we add a gear menu, close it here
+}	
 
 void LLInspectGroup::requestUpdate()
 {
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index cdb3a10dfc3cffba5bab568f983829c57d70132d..29cca14a7bbb3b74087efdd01a93ce8bbf345ca5 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -34,6 +34,7 @@
 #include "llinspectobject.h"
 
 // Viewer
+#include "llinspect.h"
 #include "llnotifications.h"	// *TODO: Eliminate, add LLNotificationsUtil wrapper
 #include "llselectmgr.h"
 #include "llslurl.h"
@@ -43,8 +44,6 @@
 // Linden libraries
 #include "llbutton.h"			// setLabel(), not virtual!
 #include "llclickaction.h"
-#include "llcontrol.h"			// LLCachedControl
-#include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llmenubutton.h"
 #include "llresmgr.h"			// getMonetaryString
@@ -56,15 +55,13 @@
 
 class LLViewerObject;
 
-// *TODO: Abstract out base class for LLInspectObject and LLInspectObject
-
 //////////////////////////////////////////////////////////////////////////////
 // LLInspectObject
 //////////////////////////////////////////////////////////////////////////////
 
 // Object Inspector, a small information window used when clicking
 // in the ambient inspector widget for objects in the 3D world.
-class LLInspectObject : public LLFloater
+class LLInspectObject : public LLInspect
 {
 	friend class LLFloaterReg;
 	
@@ -75,7 +72,6 @@ class LLInspectObject : public LLFloater
 	virtual ~LLInspectObject();
 	
 	/*virtual*/ BOOL postBuild(void);
-	/*virtual*/ void draw();
 	
 	// Because floater is single instance, need to re-parse data on each spawn
 	// (for example, inspector about same avatar but in different position)
@@ -84,9 +80,6 @@ class LLInspectObject : public LLFloater
 	// Release the selection and do other cleanup
 	/*virtual*/ void onClose(bool app_quitting);
 	
-	// Inspectors close themselves when they lose focus
-	/*virtual*/ void onFocusLost();
-	
 private:
 	// Refresh displayed data with information from selection manager
 	void update();
@@ -113,16 +106,13 @@ class LLInspectObject : public LLFloater
 	
 private:
 	LLUUID				mObjectID;
-	LLFrameTimer		mOpenTimer;
-	LLFrameTimer		mCloseTimer;
 	LLSafeHandle<LLObjectSelection> mObjectSelection;
 };
 
 LLInspectObject::LLInspectObject(const LLSD& sd)
-:	LLFloater( LLSD() ),	// single_instance, doesn't really need key
+:	LLInspect( LLSD() ),	// single_instance, doesn't really need key
 	mObjectID(),			// set in onOpen()
-	mCloseTimer(),
-	mOpenTimer()
+	mObjectSelection()
 {
 	// can't make the properties request until the widgets are constructed
 	// as it might return immediately, so do it in postBuild.
@@ -181,39 +171,14 @@ BOOL LLInspectObject::postBuild(void)
 	return TRUE;
 }
 
-void LLInspectObject::draw()
-{
-	static LLCachedControl<F32> FADE_OUT_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
-	if (mOpenTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_OUT_TIME, 0.f, 1.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-	}
-	else if (mCloseTimer.getStarted())
-	{
-		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_OUT_TIME, 1.f, 0.f);
-		LLViewDrawContext context(alpha);
-		LLFloater::draw();
-		if (mCloseTimer.getElapsedTimeF32() > FADE_OUT_TIME)
-		{
-			closeFloater(false);
-		}
-	}
-	else
-	{
-		LLFloater::draw();
-	}
-}
-
 
 // Multiple calls to showInstance("inspect_avatar", foo) will provide different
 // LLSD for foo, which we will catch here.
 //virtual
 void LLInspectObject::onOpen(const LLSD& data)
 {
-	mCloseTimer.stop();
-	mOpenTimer.start();
+	// Start animation
+	LLInspect::onOpen(data);
 
 	// Extract appropriate avatar id
 	mObjectID = data["object_id"];
@@ -260,14 +225,6 @@ void LLInspectObject::onClose(bool app_quitting)
 	getChild<LLMenuButton>("gear_btn")->hideMenu();
 }
 
-//virtual
-void LLInspectObject::onFocusLost()
-{
-	// Start closing when we lose focus
-	mCloseTimer.start();
-	mOpenTimer.stop();
-}
-
 
 void LLInspectObject::update()
 {