diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 647c816fdf13bca81897bfadc43458fe126a2c28..d631a7cd652410b5d526b8f47fd4747ff97c9027 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2619,3 +2619,13 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
 	return true; // *TODO: Error checking
 }
 
+bool LLFloater::isShown() const
+{
+    return ! isMinimized() && isInVisibleChain();
+}
+
+/* static */
+bool LLFloater::isShown(const LLFloater* floater)
+{
+    return floater && floater->isShown();
+}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index cbe374252f4f25108b1a52050cc6b40949972017..6e9235eed80c9b58bb5b9a433e235f413bbea4cf 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -185,7 +185,13 @@ friend class LLMultiFloater;
 	void			addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
 	LLFloater*		getDependee() { return (LLFloater*)mDependeeHandle.get(); }
 	void		removeDependentFloater(LLFloater* dependent);
-	BOOL			isMinimized()					{ return mMinimized; }
+	BOOL			isMinimized() const				{ return mMinimized; }
+	/// isShown() differs from getVisible() in that isShown() also considers
+	/// isMinimized(). isShown() is true only if visible and not minimized.
+	bool			isShown() const;
+	/// The static isShown() can accept a NULL pointer (which of course
+	/// returns false). When non-NULL, it calls the non-static isShown().
+	static bool		isShown(const LLFloater* floater);
 	BOOL			isFrontmost();
 	BOOL			isDependent()					{ return !mDependeeHandle.isDead(); }
 	void			setCanMinimize(BOOL can_minimize);
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 8e56951dbfb177de7db9e2a3368ef59db784ff1a..3c5a8a69216cb34de310536e3be3b962475a9f31 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -252,7 +252,7 @@ bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+	if (LLFloater::isShown(instance))
 	{
 		// When toggling *visibility*, close the host instead of the floater when hosted
 		if (instance->getHost())
@@ -272,14 +272,7 @@ bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
-	{
-		return true;
-	}
-	else
-	{
-		return false;
-	}
+	return LLFloater::isShown(instance);
 }
 
 //static
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index cb8fa6dfdaefafb72044813c1b796d5ec2d6250a..57d148b5af474025a2fd9bbbc94f816c7850da2a 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -18,6 +18,8 @@
 // external library headers
 // other Linden headers
 #include "llfloaterreg.h"
+#include "llfloater.h"
+#include "llbutton.h"
 
 LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
     LLDispatchListener(pumpName, "op")
@@ -28,6 +30,10 @@ LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
     add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
     add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
     add("toggleInstance", &LLFloaterRegListener::toggleInstance, requiredName);
+    LLSD requiredNameButton;
+    requiredNameButton["name"] = LLSD();
+    requiredNameButton["button"] = LLSD();
+    add("clickButton", &LLFloaterRegListener::clickButton, requiredNameButton);
 }
 
 void LLFloaterRegListener::getBuildMap(const LLSD& event) const
@@ -64,3 +70,45 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const
 {
     LLFloaterReg::toggleInstance(event["name"], event["key"]);
 }
+
+void LLFloaterRegListener::clickButton(const LLSD& event) const
+{
+    // If the caller requests a reply, build the reply.
+    LLReqID reqID(event);
+    LLSD reply(reqID.makeResponse());
+
+    LLFloater* floater = LLFloaterReg::findInstance(event["name"], event["key"]);
+    if (! LLFloater::isShown(floater))
+    {
+        reply["type"]  = "LLFloater";
+        reply["name"]  = event["name"];
+        reply["key"]   = event["key"];
+        reply["error"] = floater? "!isShown()" : "NULL";
+    }
+    else
+    {
+        // Here 'floater' points to an LLFloater instance with the specified
+        // name and key which isShown().
+        LLButton* button = floater->findChild<LLButton>(event["button"]);
+        if (! LLButton::isAvailable(button))
+        {
+            reply["type"]  = "LLButton";
+            reply["name"]  = event["button"];
+            reply["error"] = button? "!isAvailable()" : "NULL";
+        }
+        else
+        {
+            // Here 'button' points to an isAvailable() LLButton child of
+            // 'floater' with the specified button name. Pretend to click it.
+            button->onCommit();
+            // Leave reply["error"] isUndefined(): no error, i.e. success.
+        }
+    }
+
+    // Send a reply only if caller asked for a reply.
+    LLSD replyPump(event["reply"]);
+    if (replyPump.isString())       // isUndefined() if absent
+    {
+        LLEventPumps::instance().obtain(replyPump).post(reply);
+    }
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index 58d2c0793658ffa7e81d65f2c3e0c906b5a4e291..304ecd10904aebd567289db04c69c7da45136318 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -30,6 +30,7 @@ class LLFloaterRegListener: public LLDispatchListener
     void showInstance(const LLSD& event) const;
     void hideInstance(const LLSD& event) const;
     void toggleInstance(const LLSD& event) const;
+    void clickButton(const LLSD& event) const;
 };
 
 #endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 7db6eab9ad864bd312b98edb3f242002ae224722..01561d95cf5649cfd60d8f6ddb1b0da067375b11 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -437,6 +437,18 @@ void LLView::setEnabled(BOOL enabled)
 	mEnabled = enabled;
 }
 
+//virtual
+bool LLView::isAvailable() const
+{
+    return isInEnabledChain() && isInVisibleChain();
+}
+
+//static
+bool LLView::isAvailable(const LLView* view)
+{
+    return view && view->isAvailable();
+}
+
 //virtual
 BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 5e35068733336a3e0c44ff3042a5c01802772665..f63fc41794c28a6bcae3cacf0722913317aa2090 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -304,6 +304,11 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	BOOL			getVisible() const			{ return mVisible; }
 	virtual void	setEnabled(BOOL enabled);
 	BOOL			getEnabled() const			{ return mEnabled; }
+	/// 'available' in this context means 'visible and enabled': in other
+	/// words, can a user actually interact with this?
+	virtual bool	isAvailable() const;
+	/// The static isAvailable() tests an LLView* that could be NULL.
+	static bool		isAvailable(const LLView* view);
 	U8              getSoundFlags() const       { return mSoundFlags; }
 
 	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 4cb3b92476d4eef5dde109ba54498353d0ef9135..5b769dcab469d73077c11cae6a6cec85eea01777 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -205,7 +205,7 @@
 #pragma warning (disable:4702)
 #endif
 
-static LLAppViewerListener sAppViewerListener("LLAppViewer", NULL);
+static LLAppViewerListener sAppViewerListener("LLAppViewer", LLAppViewer::instance);
 
 ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
 //
diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp
index a3af251a3c33256c5062cc229c50a2f0bda8837b..3259309eee76872a69e8aa2b8cd16563c77dd10a 100644
--- a/indra/newview/llappviewerlistener.cpp
+++ b/indra/newview/llappviewerlistener.cpp
@@ -19,19 +19,22 @@
 // other Linden headers
 #include "llappviewer.h"
 
-LLAppViewerListener::LLAppViewerListener(const std::string& pumpname, LLAppViewer* llappviewer):
+LLAppViewerListener::LLAppViewerListener(const std::string& pumpname,
+                                         const LLAppViewerGetter& getter):
     LLDispatchListener(pumpname, "op"),
-    mAppViewer(llappviewer)
+    mAppViewerGetter(getter)
 {
     // add() every method we want to be able to invoke via this event API.
     add("requestQuit", &LLAppViewerListener::requestQuit);
+    add("forceQuit", &LLAppViewerListener::forceQuit);
 }
 
 void LLAppViewerListener::requestQuit(const LLSD& event)
 {
-    if(mAppViewer == NULL)
-    {
-        mAppViewer = LLAppViewer::instance();
-    }
-    mAppViewer->requestQuit();
+    mAppViewerGetter()->requestQuit();
+}
+
+void LLAppViewerListener::forceQuit(const LLSD& event)
+{
+    mAppViewerGetter()->forceQuit();
 }
diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h
index d702f605ef0e12d27fe8c9b7d6a4b981e6359075..73227cb95a771e2a74092f3cf74197ae230a2c52 100644
--- a/indra/newview/llappviewerlistener.h
+++ b/indra/newview/llappviewerlistener.h
@@ -13,6 +13,7 @@
 #define LL_LLAPPVIEWERLISTENER_H
 
 #include "lleventdispatcher.h"
+#include <boost/function.hpp>
 
 class LLAppViewer;
 class LLSD;
@@ -21,14 +22,16 @@ class LLSD;
 class LLAppViewerListener: public LLDispatchListener
 {
 public:
+    typedef boost::function<LLAppViewer*(void)> LLAppViewerGetter;
     /// Specify the pump name on which to listen, and bind the LLAppViewer
     /// instance to use (e.g. LLAppViewer::instance()).
-    LLAppViewerListener(const std::string& pumpname, LLAppViewer* llappviewer);
+    LLAppViewerListener(const std::string& pumpname, const LLAppViewerGetter& getter);
 
 private:
     void requestQuit(const LLSD& event);
+    void forceQuit(const LLSD& event);
 
-    LLAppViewer* mAppViewer;
+    LLAppViewerGetter mAppViewerGetter;
 };
 
 #endif /* ! defined(LL_LLAPPVIEWERLISTENER_H) */