From 936a1e36de45cc1f8a56cdd84dd05ed4382aea83 Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Wed, 5 Aug 2009 01:13:57 +0000
Subject: [PATCH] merge -r 129526 skinning-19 -> viewer-2.0.0-3 Cherry pick a
 fix to enable IM windows.

---
 indra/llui/llfocusmgr.cpp | 44 ++++++++++++++++++++++++++++++++-------
 indra/llui/llfocusmgr.h   |  4 ++++
 2 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index a66f147dcc7..7e452a25a38 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -98,8 +98,6 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke
 		return;
 	}
 
-	//llinfos << "Keyboard focus handled by " << (new_focus ? new_focus->getName() : "nothing") << llendl;
-
 	mKeystrokesOnly = keystrokes_only;
 
 	if( new_focus != mKeyboardFocus )
@@ -107,17 +105,47 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke
 		mLastKeyboardFocus = mKeyboardFocus;
 		mKeyboardFocus = new_focus;
 
-		if( mLastKeyboardFocus )
+		view_handle_list_t new_focus_list;
+
+		// walk up the tree to root and add all views to the new_focus_list
+		for (LLView* ctrl = mKeyboardFocus; ctrl && ctrl != LLUI::getRootView(); ctrl = ctrl->getParent())
 		{
-			mLastKeyboardFocus->onFocusLost();
+			if (ctrl) 
+			{
+				new_focus_list.push_front(ctrl->getHandle());
+			}
 		}
 
-		// clear out any existing flash
-		if (new_focus)
+		view_handle_list_t::iterator new_focus_iter = new_focus_list.begin();
+		view_handle_list_t::iterator old_focus_iter = mCachedKeyboardFocusList.begin();
+
+		// compare the new focus sub-tree to the old focus sub-tree
+		// iterate through the lists in lockstep until we get to a non-common ancestor
+		while ((new_focus_iter != new_focus_list.end()) && 
+			   (old_focus_iter != mCachedKeyboardFocusList.end()) && 
+			   ((*new_focus_iter) == (*old_focus_iter)))
 		{
-			mFocusWeight = 0.f;
-			new_focus->onFocusReceived();
+			new_focus_iter++;
+			old_focus_iter++;
 		}
+		
+		// call onFocusLost on all remaining in the old focus list
+		while (old_focus_iter != mCachedKeyboardFocusList.end())
+		{
+			old_focus_iter->get()->onFocusLost();
+			old_focus_iter++;
+		}
+
+		// call onFocusReceived on all remaining in the new focus list
+		while (new_focus_iter != new_focus_list.end())
+		{
+			new_focus_iter->get()->onFocusReceived();
+			new_focus_iter++;
+		}
+
+		// cache the new focus list for next time
+		swap(mCachedKeyboardFocusList, new_focus_list);
+
 		mFocusTimer.reset();
 
 		#ifdef _DEBUG
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index aaeb25a8706..165a114f3d8 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -102,6 +102,10 @@ class LLFocusMgr
 	LLUICtrl*			mLastKeyboardFocus;			// who last had focus
 	LLUICtrl*			mDefaultKeyboardFocus;
 	BOOL				mKeystrokesOnly;
+	
+	// caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
+	typedef std::list<LLHandle<LLView> > view_handle_list_t;
+	view_handle_list_t mCachedKeyboardFocusList;
 
 	// Top View
 	LLUICtrl*			mTopCtrl;
-- 
GitLab