Commits

leslie_linden committed 6a219ee

EXP-1398 FIX -- Viewer Crash when moving Speak button from bottom toolbar to side toolbar with call request dialog active on Mac

* Added "on button removed" callback for toolbars.
* Changed docking on incoming and outgoing call floaters to be undocked when "speak" button removed.

Reviewed by Leyla.

  • Participants
  • Parent commits f8b7711

Comments (0)

Files changed (6)

indra/llui/lltoolbar.cpp

 	mHandleDropCallback(NULL),
 	mButtonAddSignal(NULL),
 	mButtonEnterSignal(NULL),
+	mButtonLeaveSignal(NULL),
+	mButtonRemoveSignal(NULL),
 	mDragAndDropTarget(false)
 {
 	mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text;
 	delete mPopupMenuHandle.get();
 	delete mButtonAddSignal;
 	delete mButtonEnterSignal;
+	delete mButtonLeaveSignal;
+	delete mButtonRemoveSignal;
 }
 
 void LLToolBar::createContextMenu()
 		++rank;
 	}
 	
+	if (mButtonRemoveSignal)
+	{
+		(*mButtonRemoveSignal)(*it_button);
+	}
+	
 	// Delete the button and erase the command and button records
 	delete (*it_button);
 	mButtonCommands.erase(it_command);
 	return button;
 }
 
+boost::signals2::connection connectSignal(LLToolBar::button_signal_t*& signal, const LLToolBar::button_signal_t::slot_type& cb)
+{
+	if (!signal)
+	{
+		signal = new LLToolBar::button_signal_t();
+	}
+
+	return signal->connect(cb);
+}
+
 boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb)
 {
-	if (!mButtonAddSignal) mButtonAddSignal = new button_signal_t();
-	return mButtonAddSignal->connect(cb);
+	return connectSignal(mButtonAddSignal, cb);
 }
 
 boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb)
 {
-	if (!mButtonEnterSignal) mButtonEnterSignal = new button_signal_t();
-	return mButtonEnterSignal->connect(cb);
+	return connectSignal(mButtonEnterSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonLeaveCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonLeaveSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonRemoveCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonRemoveSignal, cb);
 }
 
 BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 	}
 }
 
+void LLToolBarButton::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	LLButton::onMouseLeave(x, y, mask);
+	
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonLeaveSignal)
+	{
+		(*(parent_toolbar->mButtonLeaveSignal))(this);
+	}	
+}
+
 void LLToolBarButton::onMouseCaptureLost()
 {
 	mIsDragged = false;

indra/llui/lltoolbar.h

 	void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; }
 
 	void onMouseEnter(S32 x, S32 y, MASK mask);
+	void onMouseLeave(S32 x, S32 y, MASK mask);
 	void onMouseCaptureLost();
 
 	void onCommit();
 	typedef boost::signals2::signal<void (LLView* button)> button_signal_t;
 	boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb);
 	boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonLeaveCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonRemoveCallback(const button_signal_t::slot_type& cb);
 
 	void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; }
 
 
 	button_signal_t*				mButtonAddSignal;
 	button_signal_t*				mButtonEnterSignal;
+	button_signal_t*				mButtonLeaveSignal;
+	button_signal_t*				mButtonRemoveSignal;
 
 	std::string						mButtonTooltipSuffix;
 };

indra/newview/llimview.cpp

 {
 	if (!LLDockableFloater::postBuild() || !gToolBarView)
 		return FALSE;
-
-	LLView *anchor_panel = gToolBarView->findChildView("speak");
-	LLDockControl::DocAt dock_pos = getDockControlPos();
-	setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos));
-
-	setUseTongue(anchor_panel);
-
+	
+	dockToToolbarButton("speak");
+	
 	return TRUE;
 }
 
+void LLCallDialog::dockToToolbarButton(const std::string& toolbarButtonName)
+{
+	LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName);
+	LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName);
+
+	setUseTongue(anchor_panel);
+
+	setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos));
+}
+
+LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarButtonName)
+{
+	LLCommandId command_id(toolbarButtonName);
+	S32 toolbar_loc = gToolBarView->hasCommand(command_id);
+	
+	LLDockControl::DocAt doc_at = LLDockControl::TOP;
+	
+	switch (toolbar_loc)
+	{
+		case LLToolBarView::TOOLBAR_LEFT:
+			doc_at = LLDockControl::RIGHT;
+			break;
+			
+		case LLToolBarView::TOOLBAR_RIGHT:
+			doc_at = LLDockControl::LEFT;
+			break;
+	}
+	
+	return doc_at;
+}
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLOutgoingCallDialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	}
 }
 
-LLDockControl::DocAt LLCallDialog::getDockControlPos()
-{
-	LLToolBar* tool_bar = NULL;
-
-	if((tool_bar = gToolBarView->getChild<LLToolBar>("toolbar_left")) && tool_bar->hasChild("speak", true))
-	{
-		return LLDockControl::RIGHT; // Speak button in the left toolbar so the call floater should be to the right of the speak button
-	}
-	else if((tool_bar = gToolBarView->getChild<LLToolBar>("toolbar_right")) && tool_bar->hasChild("speak", true))
-	{
-		return LLDockControl::LEFT; // Speak button in the right toolbar so the call floater should be to the left of the speak button
-	}
-
-	return LLDockControl::TOP;
-}
-
 bool LLCallDialog::lifetimeHasExpired()
 {
 	if (mLifetimeTimer.getStarted())

indra/newview/llimview.h

 
 	virtual BOOL postBuild();
 
+	void dockToToolbarButton(const std::string& toolbarButtonName);
+	
 	// check timer state
 	/*virtual*/ void draw();
 	/*virtual*/ void onOpen(const LLSD& key);
-
+	
 protected:
 	// lifetime timer for a notification
 	LLTimer	mLifetimeTimer;
 	LLSD mPayload;
 
 private:
-	LLDockControl::DocAt getDockControlPos();
+	LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName);
 };
 
 class LLIncomingCallDialog : public LLCallDialog

indra/newview/lltoolbarview.cpp

 #include "lltoolbarview.h"
 
 #include "llappviewer.h"
+#include "llbutton.h"
+#include "llclipboard.h"
 #include "lldir.h"
+#include "lldockablefloater.h"
+#include "lldockcontrol.h"
+#include "llimview.h"
+#include "lltransientfloatermgr.h"
+#include "lltoolbar.h"
+#include "lltooldraganddrop.h"
 #include "llxmlnode.h"
-#include "lltoolbar.h"
-#include "llbutton.h"
-#include "lltooldraganddrop.h"
-#include "lltransientfloatermgr.h"
-#include "llclipboard.h"
 
 #include "llagent.h"  // HACK for destinations guide on startup
 #include "llfloaterreg.h"  // HACK for destinations guide on startup
 		mToolbars[i]->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
 		mToolbars[i]->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
 		mToolbars[i]->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded,_1));
+		mToolbars[i]->setButtonRemoveCallback(boost::bind(LLToolBarView::onToolBarButtonRemoved,_1));
 	}
 
 	LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&handleLoginToolbarSetup));
 
 void LLToolBarView::onToolBarButtonAdded(LLView* button)
 {
-	if (button && button->getName() == "speak")
+	llassert(button);
+	
+	if (button->getName() == "speak")
 	{
 		// Add the "Speak" button as a control view in LLTransientFloaterMgr
 		// to prevent hiding the transient IM floater upon pressing "Speak".
 		LLTransientFloaterMgr::getInstance()->addControlView(button);
+		
+		// Redock incoming and/or outgoing call windows, if applicable
+		
+		LLFloater* incoming_floater = LLFloaterReg::getLastFloaterInGroup("incoming_call");
+		LLFloater* outgoing_floater = LLFloaterReg::getLastFloaterInGroup("outgoing_call");
+		
+		if (incoming_floater && incoming_floater->isShown())
+		{
+			LLCallDialog* incoming = dynamic_cast<LLCallDialog *>(incoming_floater);
+			llassert(incoming);
+			
+			LLDockControl* dock_control = incoming->getDockControl();
+			if (dock_control->getDock() == NULL)
+			{
+				incoming->dockToToolbarButton("speak");
+			}
+		}
+		
+		if (outgoing_floater && outgoing_floater->isShown())
+		{
+			LLCallDialog* outgoing = dynamic_cast<LLCallDialog *>(outgoing_floater);
+			llassert(outgoing);
+			
+			LLDockControl* dock_control = outgoing->getDockControl();
+			if (dock_control->getDock() == NULL)
+			{
+				outgoing->dockToToolbarButton("speak");
+			}
+		}
 	}
-	else if (button && button->getName() == "voice")
+	else if (button->getName() == "voice")
 	{
 		// Add the "Voice controls" button as a control view in LLTransientFloaterMgr
 		// to prevent hiding the transient IM floater upon pressing "Voice controls".
 	}
 }
 
+void LLToolBarView::onToolBarButtonRemoved(LLView* button)
+{
+	llassert(button);
+
+	if (button->getName() == "speak")
+	{
+		LLTransientFloaterMgr::getInstance()->removeControlView(button);
+		
+		// Undock incoming and/or outgoing call windows
+		
+		LLFloater* incoming_floater = LLFloaterReg::getLastFloaterInGroup("incoming_call");
+		LLFloater* outgoing_floater = LLFloaterReg::getLastFloaterInGroup("outgoing_call");
+		
+		if (incoming_floater && incoming_floater->isShown())
+		{
+			LLDockableFloater* incoming = dynamic_cast<LLDockableFloater *>(incoming_floater);
+			llassert(incoming);
+
+			LLDockControl* dock_control = incoming->getDockControl();
+			dock_control->setDock(NULL);
+		}
+		
+		if (outgoing_floater && outgoing_floater->isShown())
+		{
+			LLDockableFloater* outgoing = dynamic_cast<LLDockableFloater *>(outgoing_floater);
+			llassert(outgoing);
+
+			LLDockControl* dock_control = outgoing->getDockControl();
+			dock_control->setDock(NULL);
+		}
+	}
+	else if (button->getName() == "voice")
+	{
+		LLTransientFloaterMgr::getInstance()->removeControlView(button);
+	}
+}
+
 void LLToolBarView::draw()
 {
 	LLRect toolbar_rects[TOOLBAR_COUNT];

indra/newview/lltoolbarview.h

 	void	addToToolset(command_id_list_t& command_list, Toolbar& toolbar) const;
 
 	static void	onToolBarButtonAdded(LLView* button);
+	static void onToolBarButtonRemoved(LLView* button);
 
 	// Pointers to the toolbars handled by the toolbar view
 	LLToolBar*  mToolbars[TOOLBAR_COUNT];