diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index c9031dd26a088ecabaf7fc004064e4bc9742d8fa..21367c224d34b5efec67de1fa4d1631b9fe5e220 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -529,23 +529,6 @@ namespace action_give_inventory
 		return acceptable;
 	}
 
-	static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
-	{
-		llassert(avatar_names.size() > 0);
-
-		const std::string& separator = LLTrans::getString("words_separator");
-		for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
-		{
-			LLAvatarName av_name = *it;
-			residents_string.append(av_name.mDisplayName);
-			if	(++it == avatar_names.end())
-			{
-				break;
-			}
-			residents_string.append(separator);
-		}
-	}
-
 	static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
 	{
 		llassert(inventory_selected_uuids.size() > 0);
@@ -675,7 +658,7 @@ namespace action_give_inventory
 		}
 
 		std::string residents;
-		build_residents_string(avatar_names, residents);
+		LLAvatarActions::buildResidentsString(avatar_names, residents);
 
 		std::string items;
 		build_items_string(inventory_selected_uuids, items);
@@ -706,7 +689,23 @@ namespace action_give_inventory
 	}
 }
 
+// static
+void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
+{
+	llassert(avatar_names.size() > 0);
 
+	const std::string& separator = LLTrans::getString("words_separator");
+	for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
+	{
+		LLAvatarName av_name = *it;
+		residents_string.append(av_name.mDisplayName);
+		if	(++it == avatar_names.end())
+		{
+			break;
+		}
+		residents_string.append(separator);
+	}
+}
 
 //static
 std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs()
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 0a69ad86a356f4bc443a7cef45576d9ab00517c2..46830eb22c59f15cc3aee49d61a451d81a980f74 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -34,6 +34,7 @@
 #include <string>
 #include <vector>
 
+class LLAvatarName;
 class LLInventoryPanel;
 class LLFloater;
 
@@ -208,6 +209,14 @@ class LLAvatarActions
 	 */
 	static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL);
 
+	/**
+	 * Builds a string of residents' display names separated by "words_separator" string.
+	 *
+	 * @param avatar_names - a vector of given avatar names from which resulting string is built
+	 * @param residents_string - the resulting string
+	 */
+	static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string);
+
 	static std::set<LLUUID> getInventorySelectedUUIDs();
 
 private:
diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp
index d3f3e41a29b9fdc0f98b10f8b54038c7f9250d3c..c734c3edd246a44e0a72177664628922023147b9 100644
--- a/indra/newview/llimconversation.cpp
+++ b/indra/newview/llimconversation.cpp
@@ -42,7 +42,6 @@ const F32 REFRESH_INTERVAL = 0.2f;
 
 LLIMConversation::LLIMConversation(const LLUUID& session_id)
   : LLTransientDockableFloater(NULL, true, session_id)
-  ,	LLEventTimer(REFRESH_INTERVAL)
   ,  mIsP2PChat(false)
   ,  mExpandCollapseBtn(NULL)
   ,  mTearOffBtn(NULL)
@@ -52,6 +51,7 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id)
   , mChatHistory(NULL)
   , mInputEditor(NULL)
   , mInputEditorTopPad(0)
+  , mRefreshTimer(new LLTimer())
 {
 	mCommitCallbackRegistrar.add("IMSession.Menu.Action",
 			boost::bind(&LLIMConversation::onIMSessionMenuItemClicked,  this, _2));
@@ -67,6 +67,10 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id)
 			boost::bind(&LLIMConversation::onIMShowModesMenuItemCheck,   this, _2));
 	mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.Enable",
 			boost::bind(&LLIMConversation::onIMShowModesMenuItemEnable,  this, _2));
+
+	// Zero expiry time is set only once to allow initial update.
+	mRefreshTimer->setTimerExpirySec(0);
+	mRefreshTimer->start();
 }
 
 LLIMConversation::~LLIMConversation()
@@ -76,6 +80,8 @@ LLIMConversation::~LLIMConversation()
 		delete mParticipantList;
 		mParticipantList = NULL;
 	}
+
+	delete mRefreshTimer;
 }
 
 BOOL LLIMConversation::postBuild()
@@ -120,19 +126,22 @@ BOOL LLIMConversation::postBuild()
 
 }
 
-BOOL LLIMConversation::tick()
+void LLIMConversation::draw()
 {
-	// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
-	// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
-	if (isDead()) return false;
+	LLTransientDockableFloater::draw();
 
-	// Need to resort the participant list if it's in sort by recent speaker order.
-	if (mParticipantList)
+	if (mRefreshTimer->hasExpired())
 	{
-		mParticipantList->update();
-	}
+		if (mParticipantList)
+		{
+			mParticipantList->update();
+		}
 
-	return false;
+		refresh();
+
+		// Restart the refresh timer
+		mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL);
+	}
 }
 
 void LLIMConversation::buildParticipantList()
@@ -144,10 +153,11 @@ void LLIMConversation::buildParticipantList()
 	}
 	else
 	{
+		LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
 		// for group and ad-hoc chat we need to include agent into list
-		if(!mIsP2PChat && !mParticipantList && mSessionID.notNull())
+		if(!mIsP2PChat && mSessionID.notNull() && speaker_manager)
 		{
-			LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+			delete mParticipantList; // remove the old list and create a new one if the session id has changed
 			mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false);
 		}
 	}
diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h
index 47c98d6f8b7530a3d35c0f043197df6303fa4dda..50663137ac7f0e7a17cdb53d937b3ae005c6a129 100644
--- a/indra/newview/llimconversation.h
+++ b/indra/newview/llimconversation.h
@@ -40,7 +40,6 @@ class LLChatHistory;
 
 class LLIMConversation
 	: public LLTransientDockableFloater
-	, public LLEventTimer
 {
 
 public:
@@ -65,6 +64,7 @@ class LLIMConversation
 	/*virtual*/ void onOpen(const LLSD& key);
 	/*virtual*/ void onClose(bool app_quitting);
 	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void draw();
 
 protected:
 
@@ -89,8 +89,6 @@ class LLIMConversation
 	void buildParticipantList();
 	void onSortMenuItemClicked(const LLSD& userdata);
 
-	/*virtual*/ BOOL tick();
-
 	bool mIsNearbyChat;
 	bool mIsP2PChat;
 
@@ -103,6 +101,9 @@ class LLIMConversation
 	LLButton* mCloseBtn;
 
 private:
+	/// Refreshes the floater at a constant rate.
+	virtual void refresh() = 0;
+
 	/// Update floater header and toolbar buttons when hosted/torn off state is toggled.
 	void updateHeaderAndToolbar();
 
@@ -113,10 +114,11 @@ class LLIMConversation
 	 */
 	void reshapeChatHistory();
 
-
 	LLChatHistory* mChatHistory;
 	LLChatEntry* mInputEditor;
 	int mInputEditorTopPad; // padding between input field and chat history
+
+	LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
 };
 
 
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 9ea4bec0692c285dfafee58c4ee53916850df8c7..6a5bf153d42038963e8ee64594b5f1ad13b911c8 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -105,6 +105,18 @@ void LLIMFloater::onFocusReceived()
 	}
 }
 
+// virtual
+void LLIMFloater::refresh()
+{
+	if (mMeTyping)
+	{
+		// Time out if user hasn't typed for a while.
+		if (mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS)
+		{
+			setTyping(false);
+		}
+	}
+}
 
 /* static */
 void LLIMFloater::newIMCallback(const LLSD& data)
@@ -188,6 +200,7 @@ void LLIMFloater::sendMsg()
 
 LLIMFloater::~LLIMFloater()
 {
+	mParticipantsListRefreshConnection.disconnect();
 	mVoiceChannelStateChangeConnection.disconnect();
 	if(LLVoiceClient::instanceExists())
 	{
@@ -225,6 +238,8 @@ void LLIMFloater::initIMFloater()
 
 	boundVoiceChannel();
 
+	mTypingStart = LLTrans::getString("IM_typing_start_string");
+
 	// Show control panel in torn off floaters only.
 	mParticipantListPanel->setVisible(!getHost() && gSavedSettings.getBOOL("IMShowControlPanel"));
 
@@ -246,6 +261,20 @@ void LLIMFloater::initIMFloater()
 	{
 		std::string session_name(LLIMModel::instance().getName(mSessionID));
 		updateSessionName(session_name, session_name);
+
+		// For ad hoc conferences we should update the title with participants names.
+		if ((IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID))
+						|| mDialog == IM_SESSION_CONFERENCE_START)
+		{
+			if (mParticipantsListRefreshConnection.connected())
+			{
+				mParticipantsListRefreshConnection.disconnect();
+			}
+
+			LLAvatarList* avatar_list = getChild<LLAvatarList>("speakers_list");
+			mParticipantsListRefreshConnection = avatar_list->setRefreshCompleteCallback(
+					boost::bind(&LLIMFloater::onParticipantsListChanged, this, _1));
+		}
 	}
 }
 
@@ -273,8 +302,6 @@ BOOL LLIMFloater::postBuild()
 
 	setDocked(true);
 
-	mTypingStart = LLTrans::getString("IM_typing_start_string");
-
 	LLButton* add_btn = getChild<LLButton>("add_btn");
 
 	// Allow to add chat participants depending on the session type
@@ -341,7 +368,9 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids)
        for (uuid_vec_t::const_iterator id = uuids.begin();
                        id != uuids.end(); ++id)
        {
-               if (*id == mOtherParticipantUUID)
+    	   	   // Skip this check for ad hoc conferences,
+    	       // conference participants should be listed in mSession->mInitialTargetIDs.
+               if (mIsP2PChat && *id == mOtherParticipantUUID)
                {
                        return false;
                }
@@ -411,11 +440,6 @@ void LLIMFloater::onCallButtonClicked()
 	}
 }
 
-/*void LLIMFloater::onOpenVoiceControlsClicked()
-{
-	LLFloaterReg::showInstance("voice_controls");
-}*/
-
 void LLIMFloater::onChange(EStatusType status, const std::string &channelURI, bool proximal)
 {
 	if(status != STATUS_JOINING && status != STATUS_LEFT_CHANNEL)
@@ -448,28 +472,55 @@ void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id,
 	mTypingStart.setArg("[NAME]", ui_title);
 }
 
-// virtual
-BOOL LLIMFloater::tick()
+void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
 {
-	// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
-	// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
-	if (isDead())
+	LLAvatarList* avatar_list = dynamic_cast<LLAvatarList*>(ctrl);
+	if (!avatar_list)
 	{
-		return false;
+		return;
 	}
 
-	BOOL parents_retcode = LLIMConversation::tick();
+	bool all_names_resolved = true;
+	std::vector<LLSD> participants_uuids;
 
-	if ( mMeTyping )
+	avatar_list->getValues(participants_uuids);
+
+	// Check whether we have all participants names in LLAvatarNameCache
+	for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it)
 	{
-		// Time out if user hasn't typed for a while.
-		if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS )
+		const LLUUID& id = it->asUUID();
+		LLAvatarName av_name;
+		if (!LLAvatarNameCache::get(id, &av_name))
 		{
-			setTyping(false);
+			all_names_resolved = false;
+
+			// If a name is not found in cache, request it and continue the process recursively
+			// until all ids are resolved into names.
+			LLAvatarNameCache::get(id,
+					boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list));
+			break;
 		}
 	}
 
-	return parents_retcode;
+	if (all_names_resolved)
+	{
+		std::vector<LLAvatarName> avatar_names;
+		std::vector<LLSD>::const_iterator it = participants_uuids.begin();
+		for (; it != participants_uuids.end(); ++it)
+		{
+			const LLUUID& id = it->asUUID();
+			LLAvatarName av_name;
+			if (LLAvatarNameCache::get(id, &av_name))
+			{
+				avatar_names.push_back(av_name);
+			}
+		}
+
+		std::string ui_title;
+		LLAvatarActions::buildResidentsString(avatar_names, ui_title);
+
+		updateSessionName(ui_title, ui_title);
+	}
 }
 
 //static
@@ -737,8 +788,6 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
 	{
 		initIMSession(im_session_id);
 
-		boundVoiceChannel();
-
 		buildParticipantList();
 	}
 
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 6847efedf1d3b4090d3cb9e26beb003aecfe465f..23f9e75e215a58809251cb0e739afb01068510e4 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -66,7 +66,6 @@ class LLIMFloater
 	/*virtual*/ void setVisible(BOOL visible);
 	/*virtual*/ BOOL getVisible();
 	// Check typing timeout timer.
-	/*virtual*/ BOOL tick();
 
 	static LLIMFloater* findInstance(const LLUUID& session_id);
 	static LLIMFloater* getInstance(const LLUUID& session_id);
@@ -131,12 +130,18 @@ class LLIMFloater
 	/* virtual */ void onFocusLost();
 	/* virtual */ void onFocusReceived();
 
+	/*virtual*/ void refresh();
+
 	// Update the window title, input field help text, etc.
 	void updateSessionName(const std::string& ui_title, const std::string& ui_label);
 
 	// For display name lookups for IM window titles
 	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
 
+	/// Updates the list of ad hoc conference participants
+	/// in an IM floater title.
+	void onParticipantsListChanged(LLUICtrl* ctrl);
+
 	bool dropPerson(LLUUID* person_id, bool drop);
 
 	BOOL isInviteAllowed() const;
@@ -193,6 +198,8 @@ class LLIMFloater
 
 	// connection to voice channel state change signal
 	boost::signals2::connection mVoiceChannelStateChangeConnection;
+
+	boost::signals2::connection mParticipantsListRefreshConnection;
 };
 
 #endif  // LL_IMFLOATER_H
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 29ab4384cb44bbc5be2286c14f887ee2bdb3771a..369ca699c50f6c020d23fd6d9719e94267344b8c 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -186,6 +186,21 @@ BOOL LLNearbyChat::postBuild()
 	return LLIMConversation::postBuild();
 }
 
+// virtual
+void LLNearbyChat::refresh()
+{
+	displaySpeakingIndicator();
+	updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
+
+	// *HACK: Update transparency type depending on whether our children have focus.
+	// This is needed because this floater is chrome and thus cannot accept focus, so
+	// the transparency type setting code from LLFloater::setFocus() isn't reached.
+	if (getTransparencyType() != TT_DEFAULT)
+	{
+		setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
+	}
+}
+
 void LLNearbyChat::onNearbySpeakers()
 {
 	LLSD param;
@@ -389,27 +404,6 @@ void LLNearbyChat::showHistory()
 	storeRectControl();
 }
 
-
-BOOL LLNearbyChat::tick()
-{
-	// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
-	// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
-	if (isDead()) return false;
-
-	displaySpeakingIndicator();
-	updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
-
-	// *HACK: Update transparency type depending on whether our children have focus.
-	// This is needed because this floater is chrome and thus cannot accept focus, so
-	// the transparency type setting code from LLFloater::setFocus() isn't reached.
-	if (getTransparencyType() != TT_DEFAULT)
-	{
-		setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
-	}
-
-	return LLIMConversation::tick();
-}
-
 std::string LLNearbyChat::getCurrentChat()
 {
 	return mChatBox ? mChatBox->getText() : LLStringUtil::null;
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index c9aa69a912923388be3789a90ecc8ef59a15ce9b..db367f0b597c091c79afb8966d8a9a4b828061dd 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -73,8 +73,6 @@ class LLNearbyChat
 
 	LLChatEntry* getChatBox() { return mChatBox; }
 
-	//virtual void draw();
-
 	std::string getCurrentChat();
 
 	virtual BOOL handleKeyHere( KEY key, MASK mask );
@@ -119,8 +117,6 @@ class LLNearbyChat
 
 	S32 mExpandedHeight;
 
-	/*virtual*/ BOOL tick();
-
 private:
 
 	void	getAllowedRect		(LLRect& rect);
@@ -128,6 +124,8 @@ class LLNearbyChat
 	void appendMessage(const LLChat& chat, const LLSD &args = 0);
 	void	onNearbySpeakers	();
 
+	/*virtual*/ void refresh();
+
 	LLHandle<LLView>	mPopupMenuHandle;
 	std::vector<LLChat> mMessageArchive;
 	LLChatHistory*		mChatHistory;
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 59d26edff222be61845d340c8cb7c88bbc2c10f2..47518a365f4e9844c0aee5e5d0c97b9b6cc612a6 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -475,6 +475,7 @@ void LLParticipantList::update()
 {
 	mSpeakerMgr->update(true);
 
+	// Need to resort the participant list if it's in sort by recent speaker order.
 	if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder() && !isHovered())
 	{
 		// Resort avatar list