diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index aa626a9a30073ee8c5eaee083ef4423dad93f13e..53b87faf66dff72fe3093311bf2ed7735bfcfaae 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -285,7 +285,7 @@ bool LLAvatarActions::canCall()
 }
 
 // static
-void LLAvatarActions::startConference(const uuid_vec_t& ids)
+void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& floater_id)
 {
 	// *HACK: Copy into dynamic array
 	LLDynamicArray<LLUUID> id_array;
@@ -294,7 +294,7 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids)
 		id_array.push_back(*it);
 	}
 	const std::string title = LLTrans::getString("conference-title");
-	LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array);
+	LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array, false, floater_id);
 	if (session_id != LLUUID::null)
 	{
 		LLIMFloater::show(session_id);
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index e5dad74fc8128fb124c602f9b4c13ee73198fc3b..0a69ad86a356f4bc443a7cef45576d9ab00517c2 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -86,9 +86,9 @@ class LLAvatarActions
 	static void startAdhocCall(const uuid_vec_t& ids);
 
 	/**
-	 * Start conference chat with the given avatars.
+	 * Start conference chat with the given avatars in a specific IM floater.
 	 */
-	static void startConference(const uuid_vec_t& ids);
+	static void startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
 
 	/**
 	 * Show avatar profile.
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index f1bc51fbe757a060b656dd36b94d8630da3bf65f..8701b602ce8fa6770a664b54a057939c58ca4ed2 100644
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -125,10 +125,12 @@ void LLChicletBar::sessionRemoved(const LLUUID& session_id)
 	if(getChicletPanel())
 	{
 		// IM floater should be closed when session removed and associated chiclet closed
-		LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
-		if (iMfloater != NULL)
+		LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
+		if (im_floater != NULL && !im_floater->getStartConferenceInSameFloater())
 		{
-			iMfloater->closeFloater();
+			// Close the IM floater only if we are not planning to close the P2P chat
+			// and start a new conference in the same floater.
+			im_floater->closeFloater();
 		}
 
 		getChicletPanel()->removeChiclet(session_id);
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index c99da9e9c19074af9a6a550f3699498cdc636bb8..f04fecca26e6d66ae95649e2bbcb2697704e056c 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -71,18 +71,12 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)
 	mTypingTimer(),
 	mTypingTimeoutTimer(),
 	mPositioned(false),
-	mSessionInitialized(false)
+	mSessionInitialized(false),
+	mStartConferenceInSameFloater(false)
 {
 	mIsNearbyChat = false;
+	initIMSession(session_id);
 
-	mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
-
-	if (mSession)
-	{
-		mIsP2PChat = mSession->isP2PSessionType();
-		mSessionInitialized = mSession->mSessionInitialized;
-		mDialog = mSession->mType;
-	}
 	setOverlapsScreenChannel(true);
 
 	LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this);
@@ -112,6 +106,29 @@ void LLIMFloater::onFocusReceived()
 // virtual
 void LLIMFloater::onClose(bool app_quitting)
 {
+	LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
+				mSessionID);
+
+	if (session == NULL)
+	{
+		llwarns << "Empty session." << llendl;
+		return;
+	}
+
+	bool is_call_with_chat = session->isGroupSessionType()
+			|| session->isAdHocSessionType() || session->isP2PSessionType();
+
+	LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
+
+	if (is_call_with_chat && voice_channel != NULL
+			&& voice_channel->isActive())
+	{
+		LLSD payload;
+		payload["session_id"] = mSessionID;
+		LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
+		return;
+	}
+
 	setTyping(false);
 
 	// The source of much argument and design thrashing
@@ -211,8 +228,24 @@ LLIMFloater::~LLIMFloater()
 	LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this);
 }
 
-//virtual
-BOOL LLIMFloater::postBuild()
+void LLIMFloater::initIMSession(const LLUUID& session_id)
+{
+	// Change the floater key to bind it to a new session.
+	setKey(session_id);
+
+	mSessionID = session_id;
+	mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
+
+	if (mSession)
+	{
+		mIsP2PChat = mSession->isP2PSessionType();
+		mSessionInitialized = mSession->mSessionInitialized;
+
+		mDialog = mSession->mType;
+	}
+}
+
+void LLIMFloater::initIMFloater()
 {
 	const LLUUID& other_party_id =
 			LLIMModel::getInstance()->getOtherParticipantID(mSessionID);
@@ -223,6 +256,34 @@ BOOL LLIMFloater::postBuild()
 
 	boundVoiceChannel();
 
+	// Show control panel in torn off floaters only.
+	mParticipantListPanel->setVisible(!getHost() && gSavedSettings.getBOOL("IMShowControlPanel"));
+
+	// Disable input editor if session cannot accept text
+	if ( mSession && !mSession->mTextIMPossible )
+	{
+		mInputEditor->setEnabled(FALSE);
+		mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label"));
+	}
+
+	if (mIsP2PChat)
+	{
+		// look up display name for window title
+		LLAvatarNameCache::get(mSession->mOtherParticipantID,
+							   boost::bind(&LLIMFloater::onAvatarNameCache,
+										   this, _1, _2));
+	}
+	else
+	{
+		std::string session_name(LLIMModel::instance().getName(mSessionID));
+		updateSessionName(session_name, session_name);
+	}
+}
+
+//virtual
+BOOL LLIMFloater::postBuild()
+{
+	LLIMConversation::postBuild();
 
 	mInputEditor = getChild<LLLineEditor>("chat_editor");
 	mInputEditor->setMaxTextLength(1023);
@@ -248,26 +309,6 @@ BOOL LLIMFloater::postBuild()
 
 	mTypingStart = LLTrans::getString("IM_typing_start_string");
 
-	// Disable input editor if session cannot accept text
-	if ( mSession && !mSession->mTextIMPossible )
-	{
-		mInputEditor->setEnabled(FALSE);
-		mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label"));
-	}
-
-	if (mIsP2PChat)
-	{
-		// look up display name for window title
-		LLAvatarNameCache::get(mSession->mOtherParticipantID,
-							   boost::bind(&LLIMFloater::onAvatarNameCache,
-										   this, _1, _2));
-	}
-	else
-	{
-		std::string session_name(LLIMModel::instance().getName(mSessionID));
-		updateSessionName(session_name, session_name);
-	}
-	
 	childSetAction("voice_call_btn", boost::bind(&LLIMFloater::onCallButtonClicked, this));
 
 	LLVoiceClient::getInstance()->addObserver(this);
@@ -275,7 +316,9 @@ BOOL LLIMFloater::postBuild()
 	//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"
 	//see LLFloaterIMPanel for how it is done (IB)
 
-	return LLIMConversation::postBuild();
+	initIMFloater();
+
+	return TRUE;
 }
 
 void LLIMFloater::boundVoiceChannel()
@@ -603,17 +646,15 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
 	//will be different only for an ad-hoc im session
 	if (mSessionID != im_session_id)
 	{
-		mSessionID = im_session_id;
-		setKey(im_session_id);
+		initIMSession(im_session_id);
 
 		boundVoiceChannel();
 
-		mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
-		mIsP2PChat = mSession && mSession->isP2PSessionType();
-
 		buildParticipantList();
 	}
-	
+
+	initIMFloater();
+
 	//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB)
 
 	//need to send delayed messaged collected while waiting for session initialization
@@ -965,7 +1006,8 @@ BOOL LLIMFloater::dropCategory(LLInventoryCategory* category, BOOL drop)
 BOOL LLIMFloater::isInviteAllowed() const
 {
 	return ((IM_SESSION_CONFERENCE_START == mDialog)
-			|| (IM_SESSION_INVITE == mDialog));
+			 || (IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID))
+			 || mIsP2PChat);
 }
 
 class LLSessionInviteResponder: public LLHTTPClient::Responder
@@ -1107,14 +1149,6 @@ void LLIMFloater::confirmLeaveCallCallback(const LLSD& notification, const LLSD&
 }
 
 // static
-void LLIMFloater::initIMFloater()
-{
-	// This is called on viewer start up
-	// init chat window type before user changed it in preferences
-	isChatMultiTab();
-}
-
-//static
 void LLIMFloater::sRemoveTypingIndicator(const LLSD& data)
 {
 	LLUUID session_id = data["session_id"];
@@ -1139,7 +1173,6 @@ void LLIMFloater::onIMChicletCreated( const LLUUID& session_id )
 {
 	LLIMFloater::addToHost(session_id);
 }
-
 void LLIMFloater::addToHost(const LLUUID& session_id)
 {
 	if (LLIMConversation::isChatMultiTab())
@@ -1157,32 +1190,3 @@ void LLIMFloater::addToHost(const LLUUID& session_id)
 		}
 	}
 }
-
-void	LLIMFloater::onClickCloseBtn()
-{
-
-	LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
-			mSessionID);
-
-	if (session == NULL)
-	{
-		llwarns << "Empty session." << llendl;
-		return;
-	}
-
-	bool is_call_with_chat = session->isGroupSessionType()
-			|| session->isAdHocSessionType() || session->isP2PSessionType();
-
-	LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
-
-	if (is_call_with_chat && voice_channel != NULL
-			&& voice_channel->isActive())
-	{
-		LLSD payload;
-		payload["session_id"] = mSessionID;
-		LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
-		return;
-	}
-
-	LLFloater::onClickCloseBtn();
-}
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 24f28c8aee247787a6a8018196d6cd2ffdd953f1..b97d4ab90c21e0b8423d9647e8459bb5e4cc482d 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -56,6 +56,9 @@ class LLIMFloater
 
 	virtual ~LLIMFloater();
 
+	void initIMSession(const LLUUID& session_id);
+	void initIMFloater();
+
 	// LLView overrides
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void setVisible(BOOL visible);
@@ -117,14 +120,11 @@ class LLIMFloater
 			std::string& tooltip_msg);
 
 
-	static void initIMFloater();
-
 	//used as a callback on receiving new IM message
 	static void sRemoveTypingIndicator(const LLSD& data);
 	static void onIMChicletCreated(const LLUUID& session_id);
 
-protected:
-	/* virtual */ void onClickCloseBtn();
+	bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; }
 
 private:
 	// process focus events to set a currently active session
@@ -186,6 +186,8 @@ class LLIMFloater
 	bool mSessionInitialized;
 	LLSD mQueuedMsgsForInit;
 
+	bool mStartConferenceInSameFloater;
+
 	// connection to voice channel state change signal
 	boost::signals2::connection mVoiceChannelStateChangeConnection;
 };
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 46b1cb5f189b5b1f78fe2cb8f66df20c6093c838..0d2b1f06b58e298beb73adc9ddbbd4eba6d261e0 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -2591,7 +2591,8 @@ LLUUID LLIMMgr::addSession(
 	const std::string& name,
 	EInstantMessage dialog,
 	const LLUUID& other_participant_id,
-	const LLDynamicArray<LLUUID>& ids, bool voice)
+	const LLDynamicArray<LLUUID>& ids, bool voice,
+	const LLUUID& floater_id)
 {
 	if (0 == ids.getLength())
 	{
@@ -2606,6 +2607,18 @@ LLUUID LLIMMgr::addSession(
 
 	LLUUID session_id = computeSessionID(dialog,other_participant_id);
 
+	if (floater_id.notNull())
+	{
+		LLIMFloater* im_floater = LLIMFloater::findInstance(floater_id);
+		if (im_floater && im_floater->getStartConferenceInSameFloater())
+		{
+			// The IM floater should be initialized with a new session_id
+			// so that it is found by that id when creating a chiclet in LLIMFloater::onIMChicletCreated,
+			// and a new floater is not created.
+			im_floater->initIMSession(session_id);
+		}
+	}
+
 	bool new_session = !LLIMModel::getInstance()->findIMSession(session_id);
 
 	//works only for outgoing ad-hoc sessions
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 9d19af4b62ec2177f9c03d002a743d02bb3d2954..58a2ac516250a104fbc93df78e0ea69fe4b4c615 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -347,10 +347,12 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
 
 	// Adds a session using a specific group of starting agents
 	// the dialog type is assumed correct. Returns the uuid of the session.
+	// A session can be added to a floater specified by floater_id.
 	LLUUID addSession(const std::string& name,
 					  EInstantMessage dialog,
 					  const LLUUID& other_participant_id,
-					  const LLDynamicArray<LLUUID>& ids, bool voice = false);
+					  const LLDynamicArray<LLUUID>& ids, bool voice = false,
+					  const LLUUID& floater_id = LLUUID::null);
 
 	/**
 	 * Creates a P2P session with the requisite handle for responding to voice calls.
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 8b54c6ce53b550a271c57fd703313d8b9e370a12..e35dbf21d4fc0e31a7d0724f49462d9a903766f8 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -130,6 +130,7 @@ LLNearbyChat::LLNearbyChat(const LLSD& key)
 	mSpeakerMgr(NULL),
 	mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT)
 {
+	mIsNearbyChat = true;
 	mSpeakerMgr = LLLocalSpeakerMgr::getInstance();
 }
 
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index c84790d83904646e0126bb03f9af3d49813b13b1..ac2109dda488a43246fdc9b3cc2cbc1c907e95f2 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -81,7 +81,7 @@ LLContextMenu* NearbyMenu::createMenu()
 		// Set up for multi-selected People
 
 		// registrar.add("Avatar.AddFriend",	boost::bind(&LLAvatarActions::requestFriendshipDialog,	mUUIDs)); // *TODO: unimplemented
-		registrar.add("Avatar.IM",			boost::bind(&LLAvatarActions::startConference,			mUUIDs));
+		registrar.add("Avatar.IM",			boost::bind(&LLAvatarActions::startConference,			mUUIDs, LLUUID::null));
 		registrar.add("Avatar.Call",		boost::bind(&LLAvatarActions::startAdhocCall,			mUUIDs));
 		registrar.add("Avatar.OfferTeleport",	boost::bind(&NearbyMenu::offerTeleport,					this));
 		registrar.add("Avatar.RemoveFriend",boost::bind(&LLAvatarActions::removeFriendsDialog,		mUUIDs));
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 2f13ba5ab1896648bdfa283ac72131482620a176..320a602916b7c13ae00459626fa7239b2f066b9c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2153,7 +2153,6 @@ bool idle_startup()
 
 		LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
 
-		LLIMFloater::initIMFloater();
 		display_startup();
 
 		return TRUE;
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index beeb4eea9bfd654fe3401569a45a5faa9ef9ffe7..fc5b6b10af1eaa5d3a09f0a1d105905897fd323d 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -69,8 +69,7 @@
                  top="5"
                  left_pad="4"
                  name="add_btn"
-                 width="31">
-             </button>   
+                 width="31"/>
              <button
                  follows="top|left"
                  height="25"
@@ -82,8 +81,7 @@
                  top="5"
                  left_pad="4"
                  name="voice_call_btn"
-                 width="31">
-             </button>
+                 width="31"/>
              <button
                  follows="right|top"
                  height="25"