diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 0d5c431d752da09717cd5edc447e90765cdbb066..a163b6fd625b2d9e320026e090bdbf8107bdfb53 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -122,9 +122,17 @@ class LLEventHandler
 class LLSysHandler : public LLEventHandler
 {
 public:
+	LLSysHandler();
 	virtual ~LLSysHandler() {};
 
 	virtual bool processNotification(const LLSD& notify)=0;
+
+protected :
+	static void init();
+	void removeExclusiveNotifications(const LLNotificationPtr& notif);
+
+	typedef std::list< std::set<std::string> > exclusive_notif_sets;
+	static exclusive_notif_sets sExclusiveNotificationGroups;
 };
 
 /**
@@ -171,6 +179,7 @@ class LLTipHandler : public LLSysHandler
 
 protected:
 	virtual void onDeleteToast(LLToast* toast);
+	virtual void onRejectToast(const LLUUID& id);
 	virtual void initChannel();
 };
 
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 9de9998cbdd5d7ff7c542f1a3399fbb7e7da818f..546017f0286dc0bc3527abf495e28fc70c66868c 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -43,6 +43,75 @@
 
 using namespace LLNotificationsUI;
 
+// static
+std::list< std::set<std::string> > LLSysHandler::sExclusiveNotificationGroups;
+
+// static
+void LLSysHandler::init()
+{
+	std::set<std::string> online_offline_group;
+	online_offline_group.insert("FriendOnline");
+	online_offline_group.insert("FriendOffline");
+
+	sExclusiveNotificationGroups.push_back(online_offline_group);
+}
+
+LLSysHandler::LLSysHandler()
+{
+	if(sExclusiveNotificationGroups.empty())
+	{
+		init();
+	}
+}
+
+void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif)
+{
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel *>(mChannel);
+	if (channel == NULL)
+	{
+		return;
+	}
+
+	class ExclusiveMatcher: public LLScreenChannel::Matcher
+	{
+	public:
+		ExclusiveMatcher(const std::set<std::string>& excl_group,
+				const std::string& from_name) :
+			mExclGroup(excl_group), mFromName(from_name)
+		{
+		}
+		bool matches(const LLNotificationPtr notification) const
+		{
+			for (std::set<std::string>::iterator it = mExclGroup.begin(); it
+					!= mExclGroup.end(); it++)
+			{
+				std::string from_name = LLHandlerUtil::getSubstitutionName(notification);
+				if (notification->getName() == *it && from_name == mFromName)
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+	private:
+		const std::set<std::string>& mExclGroup;
+		const std::string& mFromName;
+	};
+
+
+	for (exclusive_notif_sets::iterator it = sExclusiveNotificationGroups.begin(); it
+			!= sExclusiveNotificationGroups.end(); it++)
+	{
+		std::set<std::string> group = *it;
+		std::set<std::string>::iterator g_it = group.find(notif->getName());
+		if (g_it != group.end())
+		{
+			channel->killMatchedToasts(ExclusiveMatcher(group,
+					LLHandlerUtil::getSubstitutionName(notif)));
+		}
+	}
+}
+
 const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"),
 		REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM(
 				"ObjectGiveItem"), OBJECT_GIVE_ITEM_UNKNOWN_USER(
@@ -249,9 +318,15 @@ LLUUID LLHandlerUtil::spawnIMSession(const std::string& name, const LLUUID& from
 // static
 std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notification)
 {
-	return notification->getSubstitutions().has("NAME")
+	std::string res = notification->getSubstitutions().has("NAME")
 		? notification->getSubstitutions()["NAME"]
 		: notification->getSubstitutions()["[NAME]"];
+	if (res.empty())
+	{
+		LLUUID from_id = notification->getPayload()["FROM_ID"];
+		gCacheName->getFullName(from_id, res);
+	}
+	return res;
 }
 
 // static
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index be76959d07e88fde12aeefdae9b7ae3145cd0271..4e2c5085ed34df509983a5b2000e2dff133e3c6a 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -40,6 +40,7 @@
 #include "lltoastnotifypanel.h"
 #include "llviewercontrol.h"
 #include "llviewerwindow.h"
+#include "llnotificationmanager.h"
 
 using namespace LLNotificationsUI;
 
@@ -82,6 +83,10 @@ LLTipHandler::LLTipHandler(e_notification_type type, const LLSD& id)
 
 	// Getting a Channel for our notifications
 	mChannel = LLChannelManager::getInstance()->createNotificationChannel();
+
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+	if(channel)
+		channel->setOnRejectToastCallback(boost::bind(&LLTipHandler::onRejectToast, this, _1));
 }
 
 //--------------------------------------------------------------------------
@@ -167,6 +172,8 @@ bool LLTipHandler::processNotification(const LLSD& notify)
 		p.is_tip = true;
 		p.can_be_stored = false;
 		
+		removeExclusiveNotifications(notification);
+
 		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
 		if(channel)
 			channel->addToast(p);
@@ -185,4 +192,14 @@ void LLTipHandler::onDeleteToast(LLToast* toast)
 
 //--------------------------------------------------------------------------
 
+void LLTipHandler::onRejectToast(const LLUUID& id)
+{
+	LLNotificationPtr notification = LLNotifications::instance().find(id);
 
+	if (notification
+			&& LLNotificationManager::getInstance()->getHandlerForNotification(
+					notification->getType()) == this)
+	{
+		LLNotifications::instance().cancel(notification);
+	}
+}
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index c75d90be6f34b472fbc46cb4c0cd68e77a68adbb..a4426b370e16ad427a96261199624e80677a5c57 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -687,7 +687,10 @@ void LLNotificationsUI::LLScreenChannel::startFadingToasts()
 	while (it != mToastList.end())
 	{
 		ToastElem& elem = *it;
-		elem.toast->startFading();
+		if (elem.toast->getVisible())
+		{
+			elem.toast->startFading();
+		}
 		++it;
 	}
 }