Commits

leslie_linden committed 27f2726

EXP-1742 FIX -- Clicking IM notification or receiving multiple IM notifications in quick succession crashes to desktop

* Moved toast logic for mouse hover out of the draw call to avoid chain of callbacks that lead to reordering of the draw list while we are iterating over it.

  • Participants
  • Parent commits 3d2d5d2

Comments (0)

Files changed (3)

File indra/newview/llappviewer.cpp

 //#include "llfirstuse.h"
 #include "llrender.h"
 #include "llteleporthistory.h"
+#include "lltoast.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
 #include "llvector4a.h"
 	LLFrameTimer::updateFrameTime();
 	LLFrameTimer::updateFrameCount();
 	LLEventTimer::updateClass();
+	LLNotificationsUI::LLToast::updateClass();
 	LLCriticalDamp::updateInterpolants();
 	LLMortician::updateClass();
 	LLFilePickerThread::clearDead();  //calls LLFilePickerThread::notify()

File indra/newview/lltoast.cpp

 
 	// init callbacks if present
 	if(!p.on_delete_toast().empty())
+	{
 		mOnDeleteToastSignal.connect(p.on_delete_toast());
+	}
 }
 
 void LLToast::reshape(S32 width, S32 height, BOOL called_from_parent)
 { 
 	mCanFade = can_fade; 
 	if(!mCanFade)
+	{
 		mTimer->stop();
+	}
 }
 
 //--------------------------------------------------------------------------
 			drawChild(mHideBtn);
 		}
 	}
-
-	updateHoveredState();
-
-	LLToastLifeTimer* timer = getTimer();
-	if (!timer)
-	{
-		return;
-	}
-
-	// Started timer means the mouse had left the toast previously.
-	// If toast is hovered in the current frame we should handle
-	// a mouse enter event.
-	if(timer->getStarted() && mIsHovered)
-	{
-		mOnToastHoverSignal(this, MOUSE_ENTER);
-
-		updateTransparency();
-
-		//toasts fading is management by Screen Channel
-
-		sendChildToFront(mHideBtn);
-		if(mHideBtn && mHideBtn->getEnabled())
-		{
-			mHideBtn->setVisible(TRUE);
-		}
-		mToastMouseEnterSignal(this, getValue());
-	}
-	// Stopped timer means the mouse had entered the toast previously.
-	// If the toast is not hovered in the current frame we should handle
-	// a mouse leave event.
-	else if(!timer->getStarted() && !mIsHovered)
-	{
-		mOnToastHoverSignal(this, MOUSE_LEAVE);
-
-		updateTransparency();
-
-		//toasts fading is management by Screen Channel
-
-		if(mHideBtn && mHideBtn->getEnabled())
-		{
-			if( mHideBtnPressed )
-			{
-				mHideBtnPressed = false;
-				return;
-			}
-			mHideBtn->setVisible(FALSE);
-		}
-		mToastMouseLeaveSignal(this, getValue());
-	}
 }
 
 //--------------------------------------------------------------------------
 	{
 		// mouse is not over this toast
 		mIsHovered = false;
-		return;
+	}
+	else
+	{
+		bool is_overlapped_by_other_floater = false;
+
+		const child_list_t* child_list = gFloaterView->getChildList();
+
+		// find this toast in gFloaterView child list to check whether any floater
+		// with higher Z-order is visible under the mouse pointer overlapping this toast
+		child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this);
+		if (r_iter != child_list->rend())
+		{
+			// skip this toast and proceed to views above in Z-order
+			for (++r_iter; r_iter != child_list->rend(); ++r_iter)
+			{
+				LLView* view = *r_iter;
+				is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y);
+				if (is_overlapped_by_other_floater)
+				{
+					break;
+				}
+			}
+		}
+
+		mIsHovered = !is_overlapped_by_other_floater;
 	}
 
-	bool is_overlapped_by_other_floater = false;
-
-	const child_list_t* child_list = gFloaterView->getChildList();
-
-	// find this toast in gFloaterView child list to check whether any floater
-	// with higher Z-order is visible under the mouse pointer overlapping this toast
-	child_list_const_reverse_iter_t r_iter = std::find(child_list->rbegin(), child_list->rend(), this);
-	if (r_iter != child_list->rend())
-	{
-		// skip this toast and proceed to views above in Z-order
-		for (++r_iter; r_iter != child_list->rend(); ++r_iter)
+	LLToastLifeTimer* timer = getTimer();
+	
+	if (timer)
+	{	
+		// Started timer means the mouse had left the toast previously.
+		// If toast is hovered in the current frame we should handle
+		// a mouse enter event.
+		if(timer->getStarted() && mIsHovered)
 		{
-			LLView* view = *r_iter;
-			is_overlapped_by_other_floater = view->isInVisibleChain() && view->calcScreenRect().pointInRect(x, y);
-			if (is_overlapped_by_other_floater) break;
+			mOnToastHoverSignal(this, MOUSE_ENTER);
+			
+			updateTransparency();
+			
+			//toasts fading is management by Screen Channel
+			
+			sendChildToFront(mHideBtn);
+			if(mHideBtn && mHideBtn->getEnabled())
+			{
+				mHideBtn->setVisible(TRUE);
+			}
+			
+			mToastMouseEnterSignal(this, getValue());
+		}
+		// Stopped timer means the mouse had entered the toast previously.
+		// If the toast is not hovered in the current frame we should handle
+		// a mouse leave event.
+		else if(!timer->getStarted() && !mIsHovered)
+		{
+			mOnToastHoverSignal(this, MOUSE_LEAVE);
+			
+			updateTransparency();
+			
+			//toasts fading is management by Screen Channel
+			
+			if(mHideBtn && mHideBtn->getEnabled())
+			{
+				if( mHideBtnPressed )
+				{
+					mHideBtnPressed = false;
+					return;
+				}
+				mHideBtn->setVisible(FALSE);
+			}
+			
+			mToastMouseLeaveSignal(this, getValue());
 		}
 	}
-
-	mIsHovered = !is_overlapped_by_other_floater;
 }
 
 void LLToast::setBackgroundOpaque(BOOL b)
 
 	return LLModalDialog::notifyParent(info);
 }
+
+//static
+void LLToast::updateClass()
+{
+	for (LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); iter != LLInstanceTracker<LLToast>::endInstances(); ) 
+	{
+		LLToast& toast = *iter++;
+		
+		toast.updateHoveredState();
+	}
+}

File indra/newview/lltoast.h

 #ifndef LL_LLTOAST_H
 #define LL_LLTOAST_H
 
-
+#include "llinstancetracker.h"
 #include "llpanel.h"
 #include "llmodaldialog.h"
 #include "lleventtimer.h"
  * Represents toast pop-up.
  * This is a parent view for all toast panels.
  */
-class LLToast : public LLModalDialog
+class LLToast : public LLModalDialog, public LLInstanceTracker<LLToast>
 {
 	friend class LLToastLifeTimer;
 public:
 
 		Params();
 	};
+	
+	static void updateClass();
 
 	LLToast(const LLToast::Params& p);
 	virtual ~LLToast();
 
 	F32			mToastLifetime; // in seconds
 	F32			mToastFadingTime; // in seconds
-
+	
 	LLPanel*		mPanel;
 	LLButton*		mHideBtn;