summaryrefslogtreecommitdiff
path: root/indra/llui/llfocusmgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llfocusmgr.cpp')
-rw-r--r--indra/llui/llfocusmgr.cpp71
1 files changed, 46 insertions, 25 deletions
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 3899897c5f..b8142216fc 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -88,6 +88,12 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view )
void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystrokes_only)
{
+ // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived)
+ // making the rest of our processing unnecessary since it will already be
+ // handled by the recursive call
+ static bool focus_dirty;
+ focus_dirty = false;
+
if (mLockedView &&
(new_focus == NULL ||
(new_focus != mLockedView && !new_focus->hasAncestor(mLockedView))))
@@ -104,6 +110,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke
mLastKeyboardFocus = mKeyboardFocus;
mKeyboardFocus = new_focus;
+ // list of the focus and it's ancestors
+ view_handle_list_t old_focus_list = mCachedKeyboardFocusList;
view_handle_list_t new_focus_list;
// walk up the tree to root and add all views to the new_focus_list
@@ -111,42 +119,53 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke
{
if (ctrl)
{
- new_focus_list.push_front(ctrl->getHandle());
+ new_focus_list.push_back(ctrl->getHandle());
}
}
- 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)))
+ // remove all common ancestors since their focus is unchanged
+ while (!new_focus_list.empty() &&
+ !old_focus_list.empty() &&
+ new_focus_list.back() == old_focus_list.back())
{
- new_focus_iter++;
- old_focus_iter++;
+ new_focus_list.pop_back();
+ old_focus_list.pop_back();
}
-
- // call onFocusLost on all remaining in the old focus list
- while (old_focus_iter != mCachedKeyboardFocusList.end())
- {
- if (old_focus_iter->get() != NULL) {
- old_focus_iter->get()->onFocusLost();
+
+ // walk up the old focus branch calling onFocusLost
+ // we bubble up the tree to release focus, and back down to add
+ for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin();
+ old_focus_iter != old_focus_list.end() && !focus_dirty;
+ old_focus_iter++)
+ {
+ LLView* old_focus_view = old_focus_iter->get();
+ if (old_focus_view)
+ {
+ mCachedKeyboardFocusList.pop_front();
+ old_focus_view->onFocusLost();
}
- old_focus_iter++;
}
- // call onFocusReceived on all remaining in the new focus list
- while (new_focus_iter != new_focus_list.end())
+ // walk down the new focus branch calling onFocusReceived
+ for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin();
+ new_focus_riter != new_focus_list.rend() && !focus_dirty;
+ new_focus_riter++)
+ {
+ LLView* new_focus_view = new_focus_riter->get();
+ if (new_focus_view)
+ {
+ mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
+ new_focus_view->onFocusReceived();
+ }
+ }
+
+ // if focus was changed as part of an onFocusLost or onFocusReceived call
+ // stop iterating on current list since it is now invalid
+ if (focus_dirty)
{
- new_focus_iter->get()->onFocusReceived();
- new_focus_iter++;
+ return;
}
- // cache the new focus list for next time
- swap(mCachedKeyboardFocusList, new_focus_list);
-
#ifdef _DEBUG
mKeyboardFocusName = new_focus ? new_focus->getName() : std::string("none");
#endif
@@ -181,6 +200,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke
{
lockFocus();
}
+
+ focus_dirty = true;
}