From 41a30a59fb1b6dea2d531333d0429632f1fef2fe Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Tue, 2 Mar 2010 14:21:58 -0800
Subject: [PATCH] initial work changing topctrl to popup layer

---
 indra/llui/llcombobox.cpp                     |  7 +-
 indra/llui/llfloater.cpp                      | 15 +---
 indra/llui/llfocusmgr.cpp                     | 47 +----------
 indra/llui/llfocusmgr.h                       |  8 +-
 indra/llui/llhandle.h                         |  7 ++
 indra/llui/llmodaldialog.cpp                  |  6 +-
 indra/llui/llui.cpp                           | 29 +++++++
 indra/llui/llui.h                             | 10 +++
 indra/llui/llview.cpp                         |  5 --
 indra/newview/CMakeLists.txt                  |  2 +
 indra/newview/llappviewer.cpp                 |  6 +-
 indra/newview/llexpandabletextbox.cpp         | 15 +---
 indra/newview/llexpandabletextbox.h           |  5 --
 indra/newview/llfolderview.cpp                | 13 ++--
 indra/newview/llpanelnearbymedia.cpp          | 22 ------
 indra/newview/llpanelnearbymedia.h            |  1 -
 indra/newview/llprogressview.cpp              |  5 +-
 indra/newview/llsplitbutton.cpp               |  7 +-
 indra/newview/lluploaddialog.cpp              |  2 +-
 indra/newview/llviewerwindow.cpp              | 77 +++++++++++++------
 indra/newview/llviewerwindow.h                |  9 ++-
 .../skins/default/xui/en/main_view.xml        | 13 ++--
 22 files changed, 146 insertions(+), 165 deletions(-)

diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 9d23daf56d9..de3bf719ee2 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -615,7 +615,7 @@ void LLComboBox::showList()
 	// register ourselves as a "top" control
 	// effectively putting us into a special draw layer
 	// and not affecting the bounding rectangle calculation
-	gFocusMgr.setTopCtrl(this);
+	LLUI::addPopup(this);
 
 	// Show the list and push the button down
 	mButton->setToggleState(TRUE);
@@ -644,10 +644,7 @@ void LLComboBox::hideList()
 		mList->mouseOverHighlightNthItem(-1);
 
 		setUseBoundingRect(FALSE);
-		if( gFocusMgr.getTopCtrl() == this )
-		{
-			gFocusMgr.setTopCtrl(NULL);
-		}
+		LLUI::removePopup(this);
 	}
 }
 
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index b6d73cda3cf..b93b72abf65 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -527,10 +527,7 @@ void LLFloater::setVisible( BOOL visible )
 
 	if( !visible )
 	{
-		if( gFocusMgr.childIsTopCtrl( this ) )
-		{
-			gFocusMgr.setTopCtrl(NULL);
-		}
+		LLUI::removePopup(this);
 
 		if( gFocusMgr.childHasMouseCapture( this ) )
 		{
@@ -704,10 +701,7 @@ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
 
 void LLFloater::releaseFocus()
 {
-	if( gFocusMgr.childIsTopCtrl( this ) )
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	LLUI::removePopup(this);
 
 	setFocus(FALSE);
 
@@ -2503,10 +2497,7 @@ void LLFloaterView::syncFloaterTabOrder()
 	if (modal_dialog)
 	{
 		// If we have a visible modal dialog, make sure that it has focus
-		if( gFocusMgr.getTopCtrl() != modal_dialog )
-		{
-			gFocusMgr.setTopCtrl( modal_dialog );
-		}
+		LLUI::addPopup(modal_dialog);
 		
 		if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) )
 		{
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 35fbc7b0a88..ad2940e685b 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -38,8 +38,6 @@
 
 const F32 FOCUS_FADE_TIME = 0.3f;
 
-// NOTE: the LLFocusableElement implementation has been moved here from lluictrl.cpp.
-
 LLFocusableElement::LLFocusableElement()
 :	mFocusLostCallback(NULL),
 	mFocusReceivedCallback(NULL),
@@ -124,8 +122,7 @@ boost::signals2::connection	LLFocusableElement::setTopLostCallback(const focus_s
 LLFocusMgr gFocusMgr;
 
 LLFocusMgr::LLFocusMgr()
-	:
-	mLockedView( NULL ),
+:	mLockedView( NULL ),
 	mMouseCaptor( NULL ),
 	mKeyboardFocus( NULL ),
 	mLastKeyboardFocus( NULL ),
@@ -133,16 +130,11 @@ LLFocusMgr::LLFocusMgr()
 	mKeystrokesOnly(FALSE),
 	mTopCtrl( NULL ),
 	mAppHasFocus(TRUE)   // Macs don't seem to notify us that we've gotten focus, so default to true
-	#ifdef _DEBUG
-		, mMouseCaptorName("none")
-		, mKeyboardFocusName("none")
-		, mTopCtrlName("none")
-	#endif
 {
 }
 
 
-void LLFocusMgr::releaseFocusIfNeeded( const LLView* view )
+void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
 {
 	if( childHasMouseCapture( view ) )
 	{
@@ -162,10 +154,7 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view )
 		}
 	}
 
-	if( childIsTopCtrl( view ) )
-	{
-		setTopCtrl( NULL );
-	}
+	LLUI::removePopup(view);
 }
 
 
@@ -248,11 +237,6 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
 			return;
 		}
 
-		#ifdef _DEBUG
-			LLUICtrl* focus_ctrl = dynamic_cast<LLUICtrl*>(new_focus);
-			mKeyboardFocusName = focus_ctrl ? focus_ctrl->getName() : std::string("none");
-		#endif
-
 		// If we've got a default keyboard focus, and the caller is
 		// releasing keyboard focus, move to the default.
 		if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL)
@@ -334,20 +318,12 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f
 	if( mKeyboardFocus == focus )
 	{
 		mKeyboardFocus = NULL;
-		#ifdef _DEBUG
-			mKeyboardFocusName = std::string("none");
-		#endif
 	}
 }
 
 
 void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
 {
-	//if (mFocusLocked)
-	//{
-	//	return;
-	//}
-
 	if( new_captor != mMouseCaptor )
 	{
 		LLMouseHandler* old_captor = mMouseCaptor;
@@ -370,24 +346,14 @@ void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
 			old_captor->onMouseCaptureLost();
 		}
 
-		#ifdef _DEBUG
-			mMouseCaptorName = new_captor ? new_captor->getName() : std::string("none");
-		#endif
 	}
 }
 
 void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor )
 {
-	//if (mFocusLocked)
-	//{
-	//	return;
-	//}
 	if( mMouseCaptor == captor )
 	{
 		mMouseCaptor = NULL;
-		#ifdef _DEBUG
-			mMouseCaptorName = std::string("none");
-		#endif
 	}
 }
 
@@ -416,10 +382,6 @@ void LLFocusMgr::setTopCtrl( LLUICtrl* new_top  )
 	{
 		mTopCtrl = new_top;
 
-		#ifdef _DEBUG
-			mTopCtrlName = new_top ? new_top->getName() : std::string("none");
-		#endif
-
 		if (old_top)
 		{
 			old_top->onTopLost();
@@ -432,9 +394,6 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view )
 	if( mTopCtrl == top_view )
 	{
 		mTopCtrl = NULL;
-		#ifdef _DEBUG
-			mTopCtrlName = std::string("none");
-		#endif
 	}
 }
 
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 83ecd1d301f..5b08c628d40 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -119,7 +119,7 @@ class LLFocusMgr
 	BOOL			childIsTopCtrl( const LLView* parent ) const;
 
 	// All Three
-	void			releaseFocusIfNeeded( const LLView* top_view );
+	void			releaseFocusIfNeeded( LLView* top_view );
 	void			lockFocus();
 	void			unlockFocus();
 	BOOL			focusLocked() const { return mLockedView != NULL; }
@@ -149,12 +149,6 @@ class LLFocusMgr
 
 	typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
 	focus_history_map_t mFocusHistory;
-
-	#ifdef _DEBUG
-		std::string		mMouseCaptorName;
-		std::string		mKeyboardFocusName;
-		std::string		mTopCtrlName;
-	#endif
 };
 
 extern LLFocusMgr gFocusMgr;
diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h
index 899f6b9326f..8ade327044d 100644
--- a/indra/llui/llhandle.h
+++ b/indra/llui/llhandle.h
@@ -67,6 +67,13 @@ class LLHandle
 		return *this; 
 	}
 
+	template<typename Subclass>
+	LLHandle<T>& operator =(const LLHandle<Subclass>& other)  
+	{ 
+		mTombStone = other.mTombStone;
+		return *this; 
+	}
+
 	bool isDead() const 
 	{ 
 		return mTombStone->getTarget() == NULL; 
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 387af059357..6cff68c20b7 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -111,7 +111,7 @@ void LLModalDialog::onOpen(const LLSD& key)
 	
 		// This is a modal dialog.  It sucks up all mouse and keyboard operations.
 		gFocusMgr.setMouseCapture( this );
-		gFocusMgr.setTopCtrl( this );
+		LLUI::addPopup(this);
 		setFocus(TRUE);
 
 		sModalStack.push_front( this );
@@ -153,7 +153,7 @@ void LLModalDialog::setVisible( BOOL visible )
 			gFocusMgr.setMouseCapture( this );
 
 			// The dialog view is a root view
-			gFocusMgr.setTopCtrl( this );
+			LLUI::addPopup(this);
 			setFocus( TRUE );
 		}
 		else
@@ -291,7 +291,7 @@ void LLModalDialog::onAppFocusGained()
 		// This is a modal dialog.  It sucks up all mouse and keyboard operations.
 		gFocusMgr.setMouseCapture( instance );
 		instance->setFocus(TRUE);
-		gFocusMgr.setTopCtrl( instance );
+		LLUI::addPopup(instance);
 
 		instance->centerOnScreen();
 	}
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index b348ec2d293..64df1dbc7a4 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -86,6 +86,9 @@ std::list<std::string> gUntranslated;
 /*static*/ LLHelp*			LLUI::sHelpImpl = NULL;
 /*static*/ std::vector<std::string> LLUI::sXUIPaths;
 /*static*/ LLFrameTimer		LLUI::sMouseIdleTimer;
+/*static*/ LLUI::add_popup_t	LLUI::sAddPopupFunc;
+/*static*/ LLUI::remove_popup_t	LLUI::sRemovePopupFunc;
+/*static*/ LLUI::clear_popups_t	LLUI::sClearPopupsFunc;
 
 // register filtereditor here
 static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
@@ -1607,6 +1610,13 @@ void LLUI::cleanupClass()
 	sImageProvider->cleanUp();
 }
 
+void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup,  const clear_popups_t& clear_popups)
+{
+	sAddPopupFunc = add_popup;
+	sRemovePopupFunc = remove_popup;
+	sClearPopupsFunc = clear_popups;
+}
+
 //static
 void LLUI::dirtyRect(LLRect rect)
 {
@@ -1877,6 +1887,25 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
 	return *sSettingGroups["config"]; // default group
 }
 
+//static 
+void LLUI::addPopup(LLView* viewp)
+{
+	if (sAddPopupFunc)
+	{
+		sAddPopupFunc(viewp);
+	}
+}
+
+//static 
+void LLUI::removePopup(LLView* viewp)
+{
+	if (sRemovePopupFunc)
+	{
+		sRemovePopupFunc(viewp);
+	}
+}
+
+
 //static
 // spawn_x and spawn_y are top left corner of view in screen GL coordinates
 void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index af8d4ea03b3..824d76f5267 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -160,12 +160,17 @@ class LLUI
 	// Methods
 	//
 	typedef std::map<std::string, LLControlGroup*> settings_map_t;
+	typedef boost::function<void(LLView*)> add_popup_t;
+	typedef boost::function<void(LLView*)> remove_popup_t;
+	typedef boost::function<void(void)> clear_popups_t;
+
 	static void initClass(const settings_map_t& settings,
 						  LLImageProviderInterface* image_provider,
 						  LLUIAudioCallback audio_callback = NULL,
 						  const LLVector2 *scale_factor = NULL,
 						  const std::string& language = LLStringUtil::null);
 	static void cleanupClass();
+	static void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& );
 
 	static void pushMatrix();
 	static void popMatrix();
@@ -207,6 +212,8 @@ class LLUI
 	static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); }
 	static void resetMouseIdleTimer() { sMouseIdleTimer.reset(); }
 	static LLWindow* getWindow() { return sWindow; }
+	static void addPopup(LLView*);
+	static void removePopup(LLView*);
 
 	// Ensures view does not overlap mouse cursor, but is inside
 	// the view's parent rectangle.  Used for tooltips, inspectors.
@@ -227,6 +234,9 @@ class LLUI
 	static LLImageProviderInterface* sImageProvider;
 	static std::vector<std::string> sXUIPaths;
 	static LLFrameTimer		sMouseIdleTimer;
+	static add_popup_t		sAddPopupFunc;
+	static remove_popup_t	sRemovePopupFunc;
+	static clear_popups_t	sClearPopupsFunc;
 };
 
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 63e627ceb5a..db2c460eec8 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -592,11 +592,6 @@ void LLView::setVisible(BOOL visible)
 {
 	if ( mVisible != visible )
 	{
-		if( !visible && (gFocusMgr.getTopCtrl() == this) )
-		{
-			gFocusMgr.setTopCtrl( NULL );
-		}
-
 		mVisible = visible;
 
 		// notify children of visibility change if root, or part of visible hierarchy
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 14eb75e4575..8ad3b2085d4 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -347,6 +347,7 @@ set(viewer_SOURCE_FILES
     llpatchvertexarray.cpp
     llplacesinventorybridge.cpp
     llplacesinventorypanel.cpp
+    llpopupview.cpp
     llpolymesh.cpp
     llpolymorph.cpp
     llpreview.cpp
@@ -844,6 +845,7 @@ set(viewer_HEADER_FILES
     llplacesinventorypanel.h
     llpolymesh.h
     llpolymorph.h
+    llpopupview.h
     llpreview.h
     llpreviewanim.h
     llpreviewgesture.h
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 948d38befb7..a06e54e208c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -702,9 +702,9 @@ bool LLAppViewer::init()
 	settings_map["account"] = &gSavedPerAccountSettings;
 
 	LLUI::initClass(settings_map,
-					LLUIImageList::getInstance(),
-					ui_audio_callback,
-					&LLUI::sGLScaleFactor);
+		LLUIImageList::getInstance(),
+		ui_audio_callback,
+		&LLUI::sGLScaleFactor);
 	
 	// Setup paths and LLTrans after LLUI::initClass has been called
 	LLUI::setupPaths();
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 3818ee6f786..9a906d8323b 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -35,6 +35,7 @@
 
 #include "llscrollcontainer.h"
 #include "llwindow.h"
+#include "llviewerwindow.h"
 
 static LLDefaultChildRegistry::Register<LLExpandableTextBox> t1("expandable_text");
 
@@ -382,7 +383,7 @@ void LLExpandableTextBox::expandTextBox()
 	setFocus(TRUE);
 	// this lets us receive top_lost event(needed to collapse text box)
 	// it also draws text box above all other ui elements
-	gFocusMgr.setTopCtrl(this);
+	gViewerWindow->addPopup(this);
 
 	mExpanded = true;
 }
@@ -401,10 +402,7 @@ void LLExpandableTextBox::collapseTextBox()
 
 	updateTextBoxRect();
 
-	if(gFocusMgr.getTopCtrl() == this)
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(this);
 }
 
 void LLExpandableTextBox::onFocusLost()
@@ -414,13 +412,6 @@ void LLExpandableTextBox::onFocusLost()
 	LLUICtrl::onFocusLost();
 }
 
-void LLExpandableTextBox::onTopLost()
-{
-	collapseTextBox();
-
-	LLUICtrl::onTopLost();
-}
-
 void LLExpandableTextBox::setValue(const LLSD& value)
 {
 	collapseTextBox();
diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h
index 58316ddb984..690c500e849 100644
--- a/indra/newview/llexpandabletextbox.h
+++ b/indra/newview/llexpandabletextbox.h
@@ -139,11 +139,6 @@ class LLExpandableTextBox : public LLUICtrl
 	 */
 	/*virtual*/ void onFocusLost();
 
-	/**
-	 * Collapses text box on top_lost event
-	 */
-	/*virtual*/ void onTopLost();
-
 	/**
 	 * Draws text box, collapses text box if its expanded and its parent's position changed
 	 */
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index 23f19a38a6d..ff19a974bb7 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -284,10 +284,7 @@ LLFolderView::~LLFolderView( void )
 
 	LLView::deleteViewByHandle(mPopupMenuHandle);
 
-	if(mRenamer == gFocusMgr.getTopCtrl())
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(mRenamer);
 
 	mAutoOpenItems.removeAllNodes();
 	clearSelection();
@@ -971,7 +968,7 @@ void LLFolderView::finishRenamingItem( void )
 		mRenameItem->rename( mRenamer->getText() );
 	}
 
-	gFocusMgr.setTopCtrl( NULL );	
+	gViewerWindow->removePopup(mRenamer);
 
 	if( mRenameItem )
 	{
@@ -988,7 +985,7 @@ void LLFolderView::closeRenamer( void )
 	// will commit current name (which could be same as original name)
 	mRenamer->setFocus( FALSE );
 	mRenamer->setVisible( FALSE );
-	gFocusMgr.setTopCtrl( NULL );
+	gViewerWindow->removePopup(mRenamer);
 
 	if( mRenameItem )
 	{
@@ -1420,7 +1417,7 @@ void LLFolderView::startRenamingSelectedItem( void )
 		mRenamer->setFocus( TRUE );
 		mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1));
 		mRenamer->setFocusLostCallback(boost::bind(onRenamerLost, _1));
-		gFocusMgr.setTopCtrl( mRenamer );
+		gViewerWindow->addPopup(mRenamer);
 	}
 }
 
@@ -1901,7 +1898,7 @@ void LLFolderView::deleteAllChildren()
 {
 	if(mRenamer == gFocusMgr.getTopCtrl())
 	{
-		gFocusMgr.setTopCtrl(NULL);
+		gViewerWindow->removePopup(mRenamer);
 	}
 	LLView::deleteViewByHandle(mPopupMenuHandle);
 	mPopupMenuHandle = LLHandle<LLView>();
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index c02f154dc86..41e37a9b1b5 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -193,28 +193,13 @@ void LLPanelNearByMedia::handleVisibilityChange ( BOOL new_visibility )
 	if (new_visibility)	
 	{
 		mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
-		//gFocusMgr.setTopCtrl(this);
 	}
 	else
 	{
 		mHoverTimer.stop();
-		//if (gFocusMgr.getTopCtrl() == this)
-		//{
-		//	gFocusMgr.setTopCtrl(NULL);
-		//}
 	}
 }
 
-/*virtual*/ 
-void LLPanelNearByMedia::onTopLost ()
-{
-	//LLUICtrl* new_top = gFocusMgr.getTopCtrl();
-	//if (!new_top || !new_top->hasAncestor(this))
-	//{
-	//	setVisible(FALSE);
-	//}
-}
-
 /*virtual*/
 void LLPanelNearByMedia::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
@@ -234,13 +219,6 @@ const F32 AUTO_CLOSE_FADE_TIME_END = 5.0f;
 /*virtual*/
 void LLPanelNearByMedia::draw()
 {
-	//LLUICtrl* new_top = gFocusMgr.getTopCtrl();
-	//if (new_top != this)
-	//{
-	//	// reassert top ctrl
-	//	gFocusMgr.setTopCtrl(this);
-	//}
-
 	// keep bottom of panel on screen
 	LLRect screen_rect = calcScreenRect();
 	if (screen_rect.mBottom < 0)
diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h
index 4f864519f59..809a8d81a15 100644
--- a/indra/newview/llpanelnearbymedia.h
+++ b/indra/newview/llpanelnearbymedia.h
@@ -54,7 +54,6 @@ class LLPanelNearByMedia : public LLPanel
 	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
 	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
 	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
-	/*virtual*/ void onTopLost ();
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
 
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index 0476e785a5c..15831d85a00 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -128,11 +128,14 @@ void LLProgressView::setVisible(BOOL visible)
 {
 	if (getVisible() && !visible)
 	{
+		gViewerWindow->removePopup(this);
+
 		mFadeTimer.start();
 	}
 	else if (!getVisible() && visible)
 	{
-		gFocusMgr.setTopCtrl(this);
+		gViewerWindow->addPopup(this);
+
 		setFocus(TRUE);
 		mFadeTimer.stop();
 		mProgressTimer.start();
diff --git a/indra/newview/llsplitbutton.cpp b/indra/newview/llsplitbutton.cpp
index ffd9bc76248..e5323db4666 100644
--- a/indra/newview/llsplitbutton.cpp
+++ b/indra/newview/llsplitbutton.cpp
@@ -165,7 +165,7 @@ void LLSplitButton::showButtons()
 
 	// register ourselves as a "top" control
 	// effectively putting us into a special draw layer
-	gFocusMgr.setTopCtrl(this);
+	gViewerWindow->addPopup(this);
 
 	mItemsPanel->setFocus(TRUE);
 
@@ -182,10 +182,7 @@ void LLSplitButton::hideButtons()
 	mArrowBtn->setToggleState(FALSE);
 
 	setUseBoundingRect(FALSE);
-	if(gFocusMgr.getTopCtrl() == this)
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(this);
 }
 
 
diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp
index 577b5952e5c..22c7d670f80 100644
--- a/indra/newview/lluploaddialog.cpp
+++ b/indra/newview/lluploaddialog.cpp
@@ -91,7 +91,7 @@ LLUploadDialog::LLUploadDialog( const std::string& msg)
 	setMessage(msg);
 
 	// The dialog view is a root view
-	gFocusMgr.setTopCtrl( this );
+	gViewerWindow->addPopup(this);
 }
 
 void LLUploadDialog::setMessage( const std::string& msg)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index f1ec489a206..5bd79c67c32 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -131,6 +131,7 @@
 #include "llmorphview.h"
 #include "llmoveview.h"
 #include "llnavigationbar.h"
+#include "llpopupview.h"
 #include "llpreviewtexture.h"
 #include "llprogressview.h"
 #include "llresmgr.h"
@@ -690,30 +691,30 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK
 	}
 
 	// Topmost view gets a chance before the hierarchy
-	LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-	if (top_ctrl)
-	{
-		S32 local_x, local_y;
-		top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
-		if (down)
-		{
-			if (top_ctrl->pointInView(local_x, local_y))
-			{
-				return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down)	;
-			}
-			else
-			{
-				gFocusMgr.setTopCtrl(NULL);
-			}
-		}
-		else
-		{
-			if (top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask))
-			{
-				return TRUE;
-			}
-		}
-	}
+	//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+	//if (top_ctrl)
+	//{
+	//	S32 local_x, local_y;
+	//	top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+	//	if (down)
+	//	{
+	//		if (top_ctrl->pointInView(local_x, local_y))
+	//		{
+	//			return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down)	;
+	//		}
+	//		else
+	//		{
+	//			gFocusMgr.setTopCtrl(NULL);
+	//		}
+	//	}
+	//	else
+	//	{
+	//		if (top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask))
+	//		{
+	//			return TRUE;
+	//		}
+	//	}
+	//}
 
 	// Give the UI views a chance to process the click
 	if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
@@ -1367,6 +1368,8 @@ LLViewerWindow::LLViewerWindow(
 	LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications"));
 	llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl;
 
+	LLUI::setPopupFuncs(boost::bind(&LLViewerWindow::addPopup, this, _1), boost::bind(&LLViewerWindow::removePopup, this, _1), boost::bind(&LLViewerWindow::clearPopups, this));
+
 	// Default to application directory.
 	LLViewerWindow::sSnapshotBaseName = "Snapshot";
 	LLViewerWindow::sMovieBaseName = "SLmovie";
@@ -1559,11 +1562,13 @@ void LLViewerWindow::initBase()
 	mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
 	mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
 	mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
+	mPopupView = main_view->getChild<LLPopupView>("popup_holder");
 
 	// Constrain floaters to inside the menu and status bar regions.
 	gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
 	gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
 	
+
 	// Console
 	llassert( !gConsole );
 	LLConsole::Params cp;
@@ -2433,6 +2438,30 @@ void LLViewerWindow::handleScrollWheel(S32 clicks)
 	return;
 }
 
+void LLViewerWindow::addPopup(LLView* popup)
+{
+	if (mPopupView)
+	{
+		mPopupView->addPopup(popup);
+	}
+}
+
+void LLViewerWindow::removePopup(LLView* popup)
+{
+	if (mPopupView)
+	{
+		mPopupView->removePopup(popup);
+	}
+}
+
+void LLViewerWindow::clearPopups()
+{
+	if (mPopupView)
+	{
+		mPopupView->clearPopups();
+	}
+}
+
 void LLViewerWindow::moveCursorToCenter()
 {
 	if (! gSavedSettings.getBOOL("DisableMouseWarp"))
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index bfce65f2ba0..410445d97fa 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -69,6 +69,7 @@ class LLHUDIcon;
 class LLWindow;
 class LLRootView;
 class LLViewerWindowListener;
+class LLPopupView;
 
 #define PICK_HALF_WIDTH 5
 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1)
@@ -300,6 +301,11 @@ class LLViewerWindow : public LLWindowCallbacks
 	BOOL			handleKey(KEY key, MASK mask);
 	void			handleScrollWheel	(S32 clicks);
 
+	// add and remove views from "popup" layer
+	void			addPopup(LLView* popup);
+	void			removePopup(LLView* popup);
+	void			clearPopups();
+
 	// Hide normal UI when a logon fails, re-show everything when logon is attempted again
 	void			setNormalControlsVisible( BOOL visible );
 	void			setMenuBackgroundColor(bool god_mode = false, bool dev_grid = false);
@@ -458,6 +464,7 @@ class LLViewerWindow : public LLWindowCallbacks
 	LLHandle<LLView> mWorldViewPlaceholder;	// widget that spans the portion of screen dedicated to rendering the 3d world
 	LLHandle<LLView> mNonSideTrayView;		// parent of world view + bottom bar, etc...everything but the side tray
 	LLHandle<LLView> mFloaterViewHolder;	// container for floater_view
+	LLPopupView*	mPopupView;			// container for transient popups
 	
 	class LLDebugText* mDebugText; // Internal class for debug text
 	
@@ -477,7 +484,7 @@ class LLViewerWindow : public LLWindowCallbacks
 private:
 	// Object temporarily hovered over while dragging
 	LLPointer<LLViewerObject>	mDragHoveredObject;
-};	
+};
 
 void toggle_flying(void*);
 void toggle_first_person();
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 7b6081d7beb..85853f39bbb 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -156,18 +156,19 @@
                    name="notify_container"
                    tab_group="-2"
                    width="1024"/>
-  <menu_holder top="0"
-               follows="all"
-               height="768"
-               mouse_opaque="false"
-               name="Menu Holder"
-               width="1024"/>
   <panel top="0"
          follows="all"
          height="768"
          mouse_opaque="false"
          name="popup_holder"
+         class="popup_holder"
          width="1024"/>
+  <menu_holder top="0"
+               follows="all"
+               height="768"
+               mouse_opaque="false"
+               name="Menu Holder"
+               width="1024"/>
   <snapshot_floater_view enabled="false"
                          follows="all"
                          height="768"
-- 
GitLab