Commits

Anonymous committed fa22adf Merge

merge

Comments (0)

Files changed (28)

indra/llui/llcombobox.cpp

 
 	createLineEditor(p);
 
-	setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
+	mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
 }
 
 void LLComboBox::initFromParams(const LLComboBox::Params& p)
 LLComboBox::~LLComboBox()
 {
 	// children automatically deleted, including mMenu, mButton
+
+	// explicitly disconect this signal, since base class destructor might fire top lost
+	mTopLostSignalConnection.disconnect();
 }
 
 
 
 	mList->setFocus(TRUE);
 
-	// register ourselves as a "top" control
-	// effectively putting us into a special draw layer
-	// and not affecting the bounding rectangle calculation
-	gFocusMgr.setTopCtrl(this);
-
 	// Show the list and push the button down
 	mButton->setToggleState(TRUE);
 	mList->setVisible(TRUE);
 	
+	LLUI::addPopup(this);
+
 	setUseBoundingRect(TRUE);
+//	updateBoundingRect();
 }
 
 void LLComboBox::hideList()
 		mList->mouseOverHighlightNthItem(-1);
 
 		setUseBoundingRect(FALSE);
-		if( gFocusMgr.getTopCtrl() == this )
-		{
-			gFocusMgr.setTopCtrl(NULL);
-		}
+		LLUI::removePopup(this);
+//		updateBoundingRect();
 	}
 }
 

indra/llui/llcombobox.h

 	commit_callback_t	mPrearrangeCallback;
 	commit_callback_t	mTextEntryCallback;
 	commit_callback_t	mSelectionCallback;
+        boost::signals2::connection mTopLostSignalConnection;
 };
 
 // A combo box with icons for the list of items.

indra/llui/llfloater.cpp

 
 	if( !visible )
 	{
-		if( gFocusMgr.childIsTopCtrl( this ) )
-		{
-			gFocusMgr.setTopCtrl(NULL);
-		}
+		LLUI::removePopup(this);
 
 		if( gFocusMgr.childHasMouseCapture( this ) )
 		{
 
 void LLFloater::releaseFocus()
 {
-	if( gFocusMgr.childIsTopCtrl( this ) )
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	LLUI::removePopup(this);
 
 	setFocus(FALSE);
 
 // virtual
 void LLFloater::setVisibleAndFrontmost(BOOL take_focus)
 {
-	gFocusMgr.setTopCtrl(NULL);
+	LLUI::clearPopups();
 	setVisible(TRUE);
 	setFrontmost(take_focus);
 }
 	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 ) )
 		{

indra/llui/llfocusmgr.cpp

 
 const F32 FOCUS_FADE_TIME = 0.3f;
 
-// NOTE: the LLFocusableElement implementation has been moved here from lluictrl.cpp.
-
 LLFocusableElement::LLFocusableElement()
 :	mFocusLostCallback(NULL),
 	mFocusReceivedCallback(NULL),
 LLFocusMgr gFocusMgr;
 
 LLFocusMgr::LLFocusMgr()
-	:
-	mLockedView( NULL ),
+:	mLockedView( NULL ),
 	mMouseCaptor( NULL ),
 	mKeyboardFocus( NULL ),
 	mLastKeyboardFocus( NULL ),
 	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 ) )
 	{
 		}
 	}
 
-	if( childIsTopCtrl( view ) )
-	{
-		setTopCtrl( NULL );
-	}
+	LLUI::removePopup(view);
 }
 
 
 			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)
 	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;
 			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
 	}
 }
 
 	{
 		mTopCtrl = new_top;
 
-		#ifdef _DEBUG
-			mTopCtrlName = new_top ? new_top->getName() : std::string("none");
-		#endif
-
 		if (old_top)
 		{
 			old_top->onTopLost();
 	if( mTopCtrl == top_view )
 	{
 		mTopCtrl = NULL;
-		#ifdef _DEBUG
-			mTopCtrlName = std::string("none");
-		#endif
 	}
 }
 
 	}
 	
 	// release focus from "top ctrl"s, which generally hides them
-	if (!focus && mTopCtrl)
+	if (!focus)
 	{
-		setTopCtrl(NULL);
+		LLUI::clearPopups();
 	}
 	mAppHasFocus = focus; 
 }

indra/llui/llfocusmgr.h

 	virtual BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
+	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
 protected:	
 	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
-	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
 	focus_signal_t*  mFocusLostCallback;
 	focus_signal_t*  mFocusReceivedCallback;
 	focus_signal_t*  mFocusChangedCallback;
 	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; }
 
 	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;

indra/llui/llhandle.h

 		return *this; 
 	}
 
+	template<typename Subclass>
+	LLHandle<T>& operator =(const LLHandle<Subclass>& other)  
+	{ 
+		mTombStone = other.mTombStone;
+		return *this; 
+	}
+
 	bool isDead() const 
 	{ 
 		return mTombStone->getTarget() == NULL; 

indra/llui/llmodaldialog.cpp

 	
 		// 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 );
 			gFocusMgr.setMouseCapture( this );
 
 			// The dialog view is a root view
-			gFocusMgr.setTopCtrl( this );
+			LLUI::addPopup(this);
 			setFocus( TRUE );
 		}
 		else
 		// 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();
 	}

indra/llui/llui.cpp

 /*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");
 	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)
 {
 	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
+void LLUI::clearPopups()
+{
+	if (sClearPopupsFunc)
+	{
+		sClearPopupsFunc();
+	}
+}
+
+
 //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)

indra/llui/llui.h

 	// 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();
 	static void resetMouseIdleTimer() { sMouseIdleTimer.reset(); }
 	static LLWindow* getWindow() { return sWindow; }
 
+	static void addPopup(LLView*);
+	static void removePopup(LLView*);
+	static void clearPopups();
+
 	// Ensures view does not overlap mouse cursor, but is inside
 	// the view's parent rectangle.  Used for tooltips, inspectors.
 	// Optionally override the view's default X/Y, which are relative to the
 	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;
 };
 
 

indra/llui/llview.cpp

 {
 	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

indra/newview/CMakeLists.txt

     llpatchvertexarray.cpp
     llplacesinventorybridge.cpp
     llplacesinventorypanel.cpp
+    llpopupview.cpp
     llpolymesh.cpp
     llpolymorph.cpp
     llpreview.cpp
     llplacesinventorypanel.h
     llpolymesh.h
     llpolymorph.h
+    llpopupview.h
     llpreview.h
     llpreviewanim.h
     llpreviewgesture.h

indra/newview/llappviewer.cpp

 	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();

indra/newview/llexpandabletextbox.cpp

 
 #include "llscrollcontainer.h"
 #include "llwindow.h"
+#include "llviewerwindow.h"
 
 static LLDefaultChildRegistry::Register<LLExpandableTextBox> t1("expandable_text");
 
 	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;
 }
 
 	updateTextBoxRect();
 
-	if(gFocusMgr.getTopCtrl() == this)
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(this);
 }
 
 void LLExpandableTextBox::onFocusLost()

indra/newview/llexpandabletextbox.h

 	 */
 	/*virtual*/ void onTopLost();
 
+
 	/**
 	 * Draws text box, collapses text box if its expanded and its parent's position changed
 	 */

indra/newview/llfolderview.cpp

 
 	LLView::deleteViewByHandle(mPopupMenuHandle);
 
-	if(mRenamer == gFocusMgr.getTopCtrl())
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(mRenamer);
 
 	mAutoOpenItems.removeAllNodes();
 	clearSelection();
 		mRenameItem->rename( mRenamer->getText() );
 	}
 
-	gFocusMgr.setTopCtrl( NULL );	
+	gViewerWindow->removePopup(mRenamer);
 
 	if( mRenameItem )
 	{
 	// 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 )
 	{
 		mRenamer->setFocus( TRUE );
 		mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1));
 		mRenamer->setFocusLostCallback(boost::bind(onRenamerLost, _1));
-		gFocusMgr.setTopCtrl( mRenamer );
+		gViewerWindow->addPopup(mRenamer);
 	}
 }
 
 {
 	if(mRenamer == gFocusMgr.getTopCtrl())
 	{
-		gFocusMgr.setTopCtrl(NULL);
+		gViewerWindow->removePopup(mRenamer);
 	}
 	LLView::deleteViewByHandle(mPopupMenuHandle);
 	mPopupMenuHandle = LLHandle<LLView>();

indra/newview/llpanelnearbymedia.cpp

 	  mParcelMediaItem(NULL),
 	  mParcelAudioItem(NULL)
 {
+	mHoverTimer.stop();
+
 	mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
 							gSavedSettings.getBOOL("MediaTentativeAutoPlay");
 
 }
 
 /*virtual*/ 
+void LLPanelNearByMedia::onTopLost()
+{
+	setVisible(FALSE);
+}
+
+
+/*virtual*/ 
 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)
 {
 /*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)

indra/newview/llpanelnearbymedia.h

 	/*virtual*/ void draw();
 	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
 	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onTopLost();
 	/*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);
 

indra/newview/llpanelvolumepulldown.cpp

 // Default constructor
 LLPanelVolumePulldown::LLPanelVolumePulldown()
 {
+	mHoverTimer.stop();
+
     mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2));
 	mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2));
 	LLUICtrlFactory::instance().buildPanel(this, "panel_volume_pulldown.xml");
 	LLPanel::onMouseEnter(x,y,mask);
 }
 
+/*virtual*/
+void LLPanelVolumePulldown::onTopLost()
+{
+	setVisible(FALSE);
+}
 
 /*virtual*/
 void LLPanelVolumePulldown::onMouseLeave(S32 x, S32 y, MASK mask)
 	else
 	{
 		mHoverTimer.stop();
+
 	}
 }
 
-/*virtual*/ 
-void LLPanelVolumePulldown::onTopLost()
-{
-	setVisible(FALSE);
-}
-
 void LLPanelVolumePulldown::onAdvancedButtonClick(const LLSD& user_data)
 {
 	// close the global volume minicontrol, we're bringing up the big one

indra/newview/llpanelvolumepulldown.h

 	/*virtual*/ void draw();
 	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
 	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onTopLost();
 	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
-	/*virtual*/ void onTopLost();
 	/*virtual*/ BOOL postBuild();
 	
  private:

indra/newview/llpopupview.cpp

+/** 
+ * @file llpopupview.cpp
+ * @brief Holds transient popups
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2010, 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 "llpopupview.h"
+
+static LLRegisterPanelClassWrapper<LLPopupView> r("popup_holder");
+
+bool view_visible_and_enabled(LLView* viewp)
+{
+	return viewp->getVisible() && viewp->getEnabled();
+}
+
+bool view_visible(LLView* viewp)
+{
+	return viewp->getVisible();
+}
+
+
+LLPopupView::LLPopupView()
+{
+	// register ourself as handler of UI popups
+	LLUI::setPopupFuncs(boost::bind(&LLPopupView::addPopup, this, _1), boost::bind(&LLPopupView::removePopup, this, _1), boost::bind(&LLPopupView::clearPopups, this));
+}
+
+LLPopupView::~LLPopupView()
+{
+	// set empty callback function so we can't handle popups anymore
+	LLUI::setPopupFuncs(LLUI::add_popup_t(), LLUI::remove_popup_t(), LLUI::clear_popups_t());
+}
+
+void LLPopupView::draw()
+{
+	S32 screen_x, screen_y;
+
+	// remove dead popups
+	for (popup_list_t::iterator popup_it = mPopups.begin();
+		popup_it != mPopups.end();)
+	{
+		if (!popup_it->get())
+		{
+			mPopups.erase(popup_it++);
+		}
+		else
+		{
+			popup_it++;
+		}
+	}
+
+	// draw in reverse order (most recent is on top)
+	for (popup_list_t::reverse_iterator popup_it = mPopups.rbegin();
+		popup_it != mPopups.rend();)
+	{
+		LLView* popup = popup_it->get();
+
+		if (popup->getVisible())
+		{
+			popup->localPointToScreen(0, 0, &screen_x, &screen_y);
+
+			LLUI::pushMatrix();
+			{
+				LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
+				popup->draw();
+			}
+			LLUI::popMatrix();
+		}
+		++popup_it;
+	}
+
+	LLPanel::draw();
+}
+
+BOOL LLPopupView::handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)> func, 
+								   boost::function<bool(LLView*)> predicate, 
+								   S32 x, S32 y,
+								   bool close_popups)
+{
+	for (popup_list_t::iterator popup_it = mPopups.begin();
+		popup_it != mPopups.end();)
+	{
+		LLView* popup = popup_it->get();
+		if (!popup 
+			|| !predicate(popup))
+		{
+			++popup_it;
+			continue;
+		}
+
+		S32 popup_x, popup_y;
+		if (localPointToOtherView(x, y, &popup_x, &popup_y, popup) 
+			&& popup->pointInView(popup_x, popup_y))
+		{
+			if (func(popup, popup_x, popup_y))
+			{
+				return TRUE;
+			}
+		}
+
+		if (close_popups)
+		{
+			popup_list_t::iterator cur_popup_it = popup_it++;
+			mPopups.erase(cur_popup_it);
+			popup->onTopLost();
+		}
+		else
+		{
+			++popup_it;
+		}
+	}
+
+	return FALSE;
+}
+
+
+BOOL LLPopupView::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	{
+		return FALSE;
+	}
+	return TRUE;
+}
+
+BOOL LLPopupView::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	{
+		return FALSE;
+	}
+	return TRUE;
+}
+
+BOOL LLPopupView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	{
+		return FALSE;
+	}
+	return TRUE;
+}
+
+BOOL LLPopupView::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleDoubleClick, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleHover(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleHover, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleScrollWheel, _1, _2, _3, clicks), view_visible_and_enabled, x, y, false);
+}
+
+BOOL LLPopupView::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	return handleMouseEvent(boost::bind(&LLMouseHandler::handleToolTip, _1, _2, _3, mask), view_visible, x, y, false);
+}
+
+void LLPopupView::addPopup(LLView* popup)
+{
+	if (popup)
+	{
+		mPopups.erase(std::find(mPopups.begin(), mPopups.end(), popup->getHandle()));
+		mPopups.push_front(popup->getHandle());
+	}
+}
+
+void LLPopupView::removePopup(LLView* popup)
+{
+	if (popup)
+	{
+		if (gFocusMgr.childHasKeyboardFocus(popup))
+		{
+			gFocusMgr.setKeyboardFocus(NULL);
+		}
+		mPopups.erase(std::find(mPopups.begin(), mPopups.end(), popup->getHandle()));
+		popup->onTopLost();
+	}
+}
+
+void LLPopupView::clearPopups()
+{
+	for (popup_list_t::iterator popup_it = mPopups.begin();
+		popup_it != mPopups.end();)
+	{
+		LLView* popup = popup_it->get();
+
+		popup_list_t::iterator cur_popup_it = popup_it;
+		++popup_it;
+
+		mPopups.erase(cur_popup_it);
+		popup->onTopLost();
+	}
+}
+

indra/newview/llpopupview.h

+/** 
+ * @file llpopupview.h
+ * @brief Holds transient popups
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-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 LL_LLPOPUPVIEW_H
+#define LL_LLPOPUPVIEW_H
+
+#include "llpanel.h"
+
+class LLPopupView : public LLPanel
+{
+public:
+	LLPopupView();
+	~LLPopupView();
+
+	/*virtual*/ void draw();
+	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+
+	void addPopup(LLView* popup);
+	void removePopup(LLView* popup);
+	void clearPopups();
+
+	typedef std::list<LLHandle<LLView> > popup_list_t;
+	popup_list_t getCurrentPopups() { return mPopups; }
+
+private:
+	BOOL handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)>, boost::function<bool(LLView*)>, S32 x, S32 y, bool close_popups);
+	popup_list_t mPopups;
+};
+#endif //LL_LLROOTVIEW_H

indra/newview/llprogressview.cpp

 {
 	if (getVisible() && !visible)
 	{
+
 		mFadeTimer.start();
 	}
 	else if (!getVisible() && visible)
 	{
-		gFocusMgr.setTopCtrl(this);
+		gViewerWindow->addPopup(this);
+
 		setFocus(TRUE);
 		mFadeTimer.stop();
 		mProgressTimer.start();
 			// Fade is complete, release focus
 			gFocusMgr.releaseFocusIfNeeded( this );
 			LLPanel::setVisible(FALSE);
+			gViewerWindow->removePopup(this);
+
 			gStartTexture = NULL;
 		}
 		return;

indra/newview/llsplitbutton.cpp

 
 	// register ourselves as a "top" control
 	// effectively putting us into a special draw layer
-	gFocusMgr.setTopCtrl(this);
+	gViewerWindow->addPopup(this);
 
 	mItemsPanel->setFocus(TRUE);
 
 	mArrowBtn->setToggleState(FALSE);
 
 	setUseBoundingRect(FALSE);
-	if(gFocusMgr.getTopCtrl() == this)
-	{
-		gFocusMgr.setTopCtrl(NULL);
-	}
+	gViewerWindow->removePopup(this);
 }
 
 

indra/newview/llstatusbar.cpp

 
 	childSetActionTextbox("stat_btn", onClickStatGraph);
 
-	LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");
-
 	mPanelVolumePulldown = new LLPanelVolumePulldown();
-	popup_holder->addChild(mPanelVolumePulldown);
+	addChild(mPanelVolumePulldown);
+	mPanelVolumePulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
+	mPanelVolumePulldown->setVisible(FALSE);
 
 	mPanelNearByMedia = new LLPanelNearByMedia();
-	popup_holder->addChild(mPanelNearByMedia);
-	gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(&LLStatusBar::onClickScreen, this, _1, _2));
+	addChild(mPanelNearByMedia);
 	mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
 	mPanelNearByMedia->setVisible(FALSE);
 
-	mPanelVolumePulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
-	mPanelVolumePulldown->setVisible(FALSE);
-
 	return TRUE;
 }
 
 void LLStatusBar::onMouseEnterVolume()
 {
 	LLButton* volbtn =  getChild<LLButton>( "volume_btn" );
-	LLRect vol_btn_screen_rect = volbtn->calcScreenRect();
+	LLRect vol_btn_rect = volbtn->getRect();
 	LLRect volume_pulldown_rect = mPanelVolumePulldown->getRect();
-	volume_pulldown_rect.setLeftTopAndSize(vol_btn_screen_rect.mLeft -
-	     (volume_pulldown_rect.getWidth() - vol_btn_screen_rect.getWidth())/2,
-			       vol_btn_screen_rect.mBottom,
+	volume_pulldown_rect.setLeftTopAndSize(vol_btn_rect.mLeft -
+	     (volume_pulldown_rect.getWidth() - vol_btn_rect.getWidth())/2,
+			       vol_btn_rect.mBottom,
 			       volume_pulldown_rect.getWidth(),
 			       volume_pulldown_rect.getHeight());
 
 
 
 	// show the master volume pull-down
+	LLUI::clearPopups();
+	LLUI::addPopup(mPanelVolumePulldown);
+	mPanelNearByMedia->setVisible(FALSE);
 	mPanelVolumePulldown->setVisible(TRUE);
-	mPanelNearByMedia->setVisible(FALSE);
 }
 
 void LLStatusBar::onMouseEnterNearbyMedia()
 	LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");
 	LLRect nearby_media_rect = mPanelNearByMedia->getRect();
 	LLButton* nearby_media_btn =  getChild<LLButton>( "media_toggle_btn" );
-	LLRect nearby_media_btn_rect = nearby_media_btn->calcScreenRect();
+	LLRect nearby_media_btn_rect = nearby_media_btn->getRect();
 	nearby_media_rect.setLeftTopAndSize(nearby_media_btn_rect.mLeft - 
 										(nearby_media_rect.getWidth() - nearby_media_btn_rect.getWidth())/2,
 										nearby_media_btn_rect.mBottom,
 	
 	// show the master volume pull-down
 	mPanelNearByMedia->setShape(nearby_media_rect);
+	LLUI::clearPopups();
+	LLUI::addPopup(mPanelNearByMedia);
+
+	mPanelVolumePulldown->setVisible(FALSE);
 	mPanelNearByMedia->setVisible(TRUE);
-	mPanelVolumePulldown->setVisible(FALSE);
 }
 
 
 	LLFloaterReg::showInstance("lagmeter");
 }
 
-void LLStatusBar::onClickScreen(S32 x, S32 y)
-{
-	if (mPanelNearByMedia->getVisible())
-	{
-		LLRect screen_rect = mPanelNearByMedia->calcScreenRect();
-		if (!screen_rect.pointInRect(x, y))
-		{
-			mPanelNearByMedia->setVisible(FALSE);
-		}
-	}
-}
-
 BOOL can_afford_transaction(S32 cost)
 {
 	return((cost <= 0)||((gStatusBar) && (gStatusBar->getBalance() >=cost)));

indra/newview/lluploaddialog.cpp

 	setMessage(msg);
 
 	// The dialog view is a root view
-	gFocusMgr.setTopCtrl( this );
+	gViewerWindow->addPopup(this);
 }
 
 void LLUploadDialog::setMessage( const std::string& msg)

indra/newview/llviewerwindow.cpp

 #include "llmorphview.h"
 #include "llmoveview.h"
 #include "llnavigationbar.h"
+#include "llpopupview.h"
 #include "llpreviewtexture.h"
 #include "llprogressview.h"
 #include "llresmgr.h"
 	}
 
 	// 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 (top_ctrl->pointInView(local_x, local_y))
-		{
-			return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down)	;
-		}
-		else
-		{
-			if (down)
-			{
-				gFocusMgr.setTopCtrl(NULL);
-			}
-		}
-	}
+	//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+	//if (top_ctrl)
+	//{
+	//	S32 local_x, local_y;
+	//	top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+	//		if (top_ctrl->pointInView(local_x, local_y))
+	//		{
+	//			return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down)	;
+	//		}
+	//		else
+	//		{
+	//		if (down)
+	//		{
+	//			gFocusMgr.setTopCtrl(NULL);
+	//		}
+	//	}
+	//}
 
 	// Give the UI views a chance to process the click
 	if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
 	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;
 	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"))
 	}
 
 	// aggregate visible views that contain mouse cursor in display order
+	LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+
+	for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+	{
+		LLView* popup = popup_it->get();
+		if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+		{
+			// iterator over contents of top_ctrl, and throw into mouse_hover_set
+			for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+				it != popup->endTreeDFS();
+				++it)
+			{
+				LLView* viewp = *it;
+				if (viewp->getVisible()
+					&& viewp->calcScreenBoundingRect().pointInRect(x, y))
+				{
+					// we have a view that contains the mouse, add it to the set
+					mouse_hover_set.insert(viewp->getHandle());
+				}
+				else
+				{
+					// skip this view and all of its children
+					it.skipDescendants();
+				}
+			}
+		}
+	}
 
 	// while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
 	if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))

indra/newview/llviewerwindow.h

 class LLWindow;
 class LLRootView;
 class LLViewerWindowListener;
+class LLPopupView;
 
 #define PICK_HALF_WIDTH 5
 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1)
 	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);
 	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
 	
 private:
 	// Object temporarily hovered over while dragging
 	LLPointer<LLViewerObject>	mDragHoveredObject;
-};	
+};
 
 void toggle_flying(void*);
 void toggle_first_person();

indra/newview/skins/default/xui/en/main_view.xml

                    name="notify_container"
                    tab_group="-2"
                    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"/>
-  <panel top="0"
-         follows="all"
-         height="768"
-         mouse_opaque="false"
-         name="popup_holder"
-         width="1024"/>
   <snapshot_floater_view enabled="false"
                          follows="all"
                          height="768"