From dd012cc375680c1907e16baa675d29d40ad4f43c Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Thu, 12 Apr 2012 23:09:47 +0300
Subject: [PATCH] CHUI-87 FIXED crash in handling notifications after viewer
 disconnect. Notification handlers now use LLHandles to screen channels.

---
 indra/newview/llimhandler.cpp                 | 12 +++++------
 indra/newview/llnearbychathandler.cpp         | 11 ++++++----
 indra/newview/llnotificationalerthandler.cpp  | 18 ++++++++---------
 indra/newview/llnotificationgrouphandler.cpp  | 16 ++++++++-------
 indra/newview/llnotificationhandler.h         |  4 ++--
 indra/newview/llnotificationhandlerutil.cpp   |  2 +-
 indra/newview/llnotificationofferhandler.cpp  | 19 +++++++++---------
 indra/newview/llnotificationscripthandler.cpp | 20 +++++++++----------
 indra/newview/llnotificationtiphandler.cpp    | 17 ++++++++--------
 indra/newview/llscreenchannel.h               |  3 +--
 10 files changed, 64 insertions(+), 58 deletions(-)

diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp
index cd71da73935..07d73c8c66f 100644
--- a/indra/newview/llimhandler.cpp
+++ b/indra/newview/llimhandler.cpp
@@ -42,7 +42,7 @@ LLIMHandler::LLIMHandler(e_notification_type type, const LLSD& id)
 	mType = type;
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
+	mChannel = LLChannelManager::getInstance()->createNotificationChannel()->getHandle();
 }
 
 //--------------------------------------------------------------------------
@@ -55,13 +55,13 @@ void LLIMHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
-	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
+	mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLIMHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -72,7 +72,7 @@ bool LLIMHandler::processNotification(const LLSD& notify)
 		return false;
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -104,7 +104,7 @@ bool LLIMHandler::processNotification(const LLSD& notify)
 		p.panel = im_box;
 		p.can_be_stored = false;
 		p.on_delete_toast = boost::bind(&LLIMHandler::onDeleteToast, this, _1);
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->addToast(p);
 
@@ -113,7 +113,7 @@ bool LLIMHandler::processNotification(const LLSD& notify)
 	}
 	else if (notify["sigtype"].asString() == "delete")
 	{
-		mChannel->killToastByNotificationID(notification->getID());
+		mChannel.get()->killToastByNotificationID(notification->getID());
 	}
 	return false;
 }
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index 240a7c7a35c..600fd395fb0 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -458,7 +458,9 @@ LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& i
 
 	channel->setCreatePanelCallback(callback);
 
-	mChannel = LLChannelManager::getInstance()->addChannel(channel);
+	LLChannelManager::getInstance()->addChannel(channel);
+
+	mChannel = channel->getHandle();
 }
 
 LLNearbyChatHandler::~LLNearbyChatHandler()
@@ -558,11 +560,12 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg,
 		&& nearby_chat->isInVisibleChain() 
 		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
 			&& gSavedSettings.getBOOL("UseChatBubbles") )
-		|| !mChannel->getShowToasts() ) // to prevent toasts in Busy mode
+		|| mChannel.isDead()
+		|| !mChannel.get()->getShowToasts() ) // to prevent toasts in Busy mode
 		return;//no need in toast if chat is visible or if bubble chat is enabled
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -579,7 +582,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg,
 	}
 	*/
 
-	LLNearbyChatScreenChannel* channel = dynamic_cast<LLNearbyChatScreenChannel*>(mChannel);
+	LLNearbyChatScreenChannel* channel = dynamic_cast<LLNearbyChatScreenChannel*>(mChannel.get());
 
 	if(channel)
 	{
diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp
index cae7d02fedd..89fe7bb3c22 100644
--- a/indra/newview/llnotificationalerthandler.cpp
+++ b/indra/newview/llnotificationalerthandler.cpp
@@ -51,8 +51,8 @@ LLAlertHandler::LLAlertHandler(e_notification_type type, const LLSD& id) : mIsMo
 	p.channel_align = CA_CENTRE;
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->getChannel(p);
-	mChannel->setCanStoreToasts(false);
+	mChannel = LLChannelManager::getInstance()->getChannel(p)->getHandle();
+	mChannel.get()->setCanStoreToasts(false);
 }
 
 //--------------------------------------------------------------------------
@@ -64,13 +64,13 @@ LLAlertHandler::~LLAlertHandler()
 void LLAlertHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().getWidth() / 2;
-	mChannel->init(channel_right_bound, channel_right_bound);
+	mChannel.get()->init(channel_right_bound, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLAlertHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -81,7 +81,7 @@ bool LLAlertHandler::processNotification(const LLSD& notify)
 		return false;
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -114,22 +114,22 @@ bool LLAlertHandler::processNotification(const LLSD& notify)
 		// Show alert in middle of progress view (during teleport) (EXT-1093)
 		LLProgressView* progress = gViewerWindow->getProgressView();
 		LLRect rc = progress && progress->getVisible() ? progress->getRect() : gViewerWindow->getWorldViewRectScaled();
-		mChannel->updatePositionAndSize(rc);
+		mChannel.get()->updatePositionAndSize(rc);
 
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->addToast(p);
 	}
 	else if (notify["sigtype"].asString() == "change")
 	{
 		LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal);
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog);
 	}
 	else
 	{
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->killToastByNotificationID(notification->getID());
 	}
diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp
index 9b7fdaef82b..ad51389241c 100644
--- a/indra/newview/llnotificationgrouphandler.cpp
+++ b/indra/newview/llnotificationgrouphandler.cpp
@@ -42,10 +42,12 @@ LLGroupHandler::LLGroupHandler(e_notification_type type, const LLSD& id)
 	mType = type;
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
-	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+	LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
 	if(channel)
+	{
 		channel->setOnRejectToastCallback(boost::bind(&LLGroupHandler::onRejectToast, this, _1));
+		mChannel = channel->getHandle();
+	}
 }
 
 //--------------------------------------------------------------------------
@@ -58,13 +60,13 @@ void LLGroupHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
-	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
+	mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLGroupHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -75,7 +77,7 @@ bool LLGroupHandler::processNotification(const LLSD& notify)
 		return false;
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -91,7 +93,7 @@ bool LLGroupHandler::processNotification(const LLSD& notify)
 		p.panel = notify_box;
 		p.on_delete_toast = boost::bind(&LLGroupHandler::onDeleteToast, this, _1);
 
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->addToast(p);
 
@@ -102,7 +104,7 @@ bool LLGroupHandler::processNotification(const LLSD& notify)
 	}
 	else if (notify["sigtype"].asString() == "delete")
 	{
-		mChannel->killToastByNotificationID(notification->getID());
+		mChannel.get()->killToastByNotificationID(notification->getID());
 	}
 	return false;
 }
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 23dbb6b047c..3569ad64479 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -103,8 +103,8 @@ class LLEventHandler
 	// at the moment, when a handlers creates a channel.
 	virtual void initChannel()=0;
 
-	LLScreenChannelBase*	mChannel;
-	e_notification_type		mType;
+	LLHandle<LLScreenChannelBase>	mChannel;
+	e_notification_type				mType;
 
 };
 
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 1b767e80d42..7c6287967af 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -64,7 +64,7 @@ LLSysHandler::LLSysHandler()
 
 void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif)
 {
-	LLScreenChannel* channel = dynamic_cast<LLScreenChannel *>(mChannel);
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel *>(mChannel.get());
 	if (channel == NULL)
 	{
 		return;
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 68fd65be0f9..1552ed3346c 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -45,12 +45,13 @@ LLOfferHandler::LLOfferHandler(e_notification_type type, const LLSD& id)
 	mType = type;
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
-	mChannel->setControlHovering(true);
-
-	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+	LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
 	if(channel)
+	{
+		channel->setControlHovering(true);
 		channel->setOnRejectToastCallback(boost::bind(&LLOfferHandler::onRejectToast, this, _1));
+		mChannel = channel->getHandle();
+	}
 }
 
 //--------------------------------------------------------------------------
@@ -63,13 +64,13 @@ void LLOfferHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
-	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
+	mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLOfferHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -80,7 +81,7 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 		return false;
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -134,7 +135,7 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 				// we not save offer notifications to the syswell floater that should be added to the IM floater
 				p.can_be_stored = !add_notid_to_im;
 
-				LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+				LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 				if(channel)
 					channel->addToast(p);
 
@@ -175,7 +176,7 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 			{
 				LLHandlerUtil::decIMMesageCounter(notification);
 			}
-			mChannel->killToastByNotificationID(notification->getID());
+			mChannel.get()->killToastByNotificationID(notification->getID());
 		}
 	}
 
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index bbb4d03768b..995915206bc 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -47,13 +47,13 @@ LLScriptHandler::LLScriptHandler(e_notification_type type, const LLSD& id)
 	mType = type;
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
-	mChannel->setControlHovering(true);
-	
-	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+	LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
 	if(channel)
+	{
+		channel->setControlHovering(true);
 		channel->setOnRejectToastCallback(boost::bind(&LLScriptHandler::onRejectToast, this, _1));
-
+		mChannel = channel->getHandle();
+	}
 }
 
 //--------------------------------------------------------------------------
@@ -66,13 +66,13 @@ void LLScriptHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
-	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
+	mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLScriptHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -83,7 +83,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
 		return false;
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -109,7 +109,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
 			p.panel = notify_box;	
 			p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1);
 
-			LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+			LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 			if(channel)
 			{
 				channel->addToast(p);
@@ -127,7 +127,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
 		}
 		else
 		{
-			mChannel->killToastByNotificationID(notification->getID());
+			mChannel.get()->killToastByNotificationID(notification->getID());
 		}
 	}
 	return false;
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index fb0891c4c5a..e397cfa046d 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -46,11 +46,12 @@ LLTipHandler::LLTipHandler(e_notification_type type, const LLSD& id)
 	mType = type;	
 
 	// Getting a Channel for our notifications
-	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
-
-	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+	LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
 	if(channel)
+	{
 		channel->setOnRejectToastCallback(boost::bind(&LLTipHandler::onRejectToast, this, _1));
+		mChannel = channel->getHandle();
+	}
 }
 
 //--------------------------------------------------------------------------
@@ -63,13 +64,13 @@ void LLTipHandler::initChannel()
 {
 	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
-	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
+	mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
 }
 
 //--------------------------------------------------------------------------
 bool LLTipHandler::processNotification(const LLSD& notify)
 {
-	if(!mChannel)
+	if(mChannel.isDead())
 	{
 		return false;
 	}
@@ -80,7 +81,7 @@ bool LLTipHandler::processNotification(const LLSD& notify)
 		return false;	
 
 	// arrange a channel on a screen
-	if(!mChannel->getVisible())
+	if(!mChannel.get()->getVisible())
 	{
 		initChannel();
 	}
@@ -137,13 +138,13 @@ bool LLTipHandler::processNotification(const LLSD& notify)
 		
 		removeExclusiveNotifications(notification);
 
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
 		if(channel)
 			channel->addToast(p);
 	}
 	else if (notify["sigtype"].asString() == "delete")
 	{
-		mChannel->killToastByNotificationID(notification->getID());
+		mChannel.get()->killToastByNotificationID(notification->getID());
 	}
 	return false;
 }
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index 695b6cd44d5..56a9cf8b4ba 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -117,7 +117,7 @@ class LLScreenChannelBase : public LLUICtrl
 	
 	// get ID of a channel
 	LLUUID	getChannelID() { return mID; }
-	LLHandle<LLScreenChannelBase> getHandle() { mRootHandle.bind(this); return mRootHandle; }
+	LLHandle<LLScreenChannelBase> getHandle() { return getDerivedHandle<LLScreenChannelBase>(); }
 
 protected:
 	void	updateRect();
@@ -130,7 +130,6 @@ class LLScreenChannelBase : public LLUICtrl
 	bool		mDisplayToastsAlways;
 	// controls whether a channel shows toasts or not
 	bool		mShowToasts;
-	LLRootHandle<LLScreenChannelBase> mRootHandle;
 	// 
 	EToastAlignment		mToastAlignment;
 	EChannelAlignment	mChannelAlignment;
-- 
GitLab