From c1920e3c1c60fb792cf091750b05de618b355878 Mon Sep 17 00:00:00 2001
From: Don Kjer <don@lindenlab.com>
Date: Fri, 9 Nov 2007 01:56:15 +0000
Subject: [PATCH] EFFECTIVE MERGE: svn merge -r 70833:71458
 svn+ssh://svn/svn/linden/branches/maintenance-2 into release ACTUAL MERGE:
 svn merge -r 73210:73222
 svn+ssh://svn/svn/linden/qa/maintenance-2-merge-73206 into release

---
 indra/llcommon/llapp.cpp           |  34 +++++
 indra/llcommon/llkeythrottle.h     | 205 +++++++++++++++++++++++++++++
 indra/llcommon/llsd.h              |   1 +
 indra/llcommon/llsdserialize.cpp   |   5 +
 indra/llui/llfloater.cpp           |   6 +-
 indra/llui/lllineeditor.cpp        |  10 +-
 indra/llui/lllineeditor.h          |   2 -
 indra/llui/llscrolllistctrl.cpp    |  19 ++-
 indra/llui/llscrolllistctrl.h      |   1 +
 indra/llui/lltexteditor.cpp        |  10 +-
 indra/llui/lltexteditor.h          |   2 -
 indra/llwindow/llwindowwin32.cpp   |  27 +++-
 indra/llwindow/llwindowwin32.h     |   1 +
 indra/newview/llagent.cpp          |  15 +++
 indra/newview/llagent.h            |   2 +
 indra/newview/llfloaterfriends.cpp |  34 ++++-
 indra/newview/llstartup.cpp        |   6 +-
 indra/newview/lltexturefetch.cpp   |  16 ++-
 indra/newview/lltoolmgr.cpp        |   5 +
 indra/newview/lltoolmgr.h          |   2 +
 indra/newview/llviewermenufile.cpp |  11 ++
 indra/newview/llviewerwindow.cpp   |   2 +
 indra/newview/pipeline.cpp         |  36 -----
 23 files changed, 373 insertions(+), 79 deletions(-)
 create mode 100644 indra/llcommon/llkeythrottle.h

diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index b0751b80e98..2347ac9cd9a 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -47,6 +47,7 @@
 //
 #if LL_WINDOWS
 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
+BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
 #else
 #include <unistd.h> // for fork()
 void setup_signals();
@@ -219,6 +220,11 @@ void LLApp::setupErrorHandling()
 	// Disable this until the viewer gets ported so server crashes can be JIT debugged.
 	//LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
 	//prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
+
+	// This sets a callback to handle w32 signals to the console window.
+	// The viewer shouldn't be affected, sicne its a windowed app.
+	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
+
 #else
 	//
 	// Start up signal handling.
@@ -399,6 +405,34 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except
 	return retval;
 }
 
+// Win32 doesn't support signals. This is used instead.
+BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) 
+{ 
+	switch (fdwCtrlType) 
+	{ 
+ 		case CTRL_BREAK_EVENT: 
+		case CTRL_LOGOFF_EVENT: 
+		case CTRL_SHUTDOWN_EVENT: 
+		case CTRL_CLOSE_EVENT: // From end task or the window close button.
+		case CTRL_C_EVENT:  // from CTRL-C on the keyboard
+			// Just set our state to quitting, not error
+			if (LLApp::isQuitting() || LLApp::isError())
+			{
+				// We're already trying to die, just ignore this signal
+				if (LLApp::sLogInSignal)
+				{
+					llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl;
+				}
+				return TRUE;
+			}
+			LLApp::setQuitting();
+			return TRUE; 
+	
+		default: 
+			return FALSE; 
+	} 
+} 
+
 #else //!LL_WINDOWS
 void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback)
 {
diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h
new file mode 100644
index 00000000000..708f23f3b1f
--- /dev/null
+++ b/indra/llcommon/llkeythrottle.h
@@ -0,0 +1,205 @@
+/** 
+ * @file llkeythrottle.h
+ * @brief LLKeyThrottle class definition
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLKEY_THROTTLE_H
+#define LL_LLKEY_THROTTLE_H
+
+// LLKeyThrottle keeps track of the number of action occurences with a key value
+// for a type over a given time period.  If the rate set in the constructor is
+// exceeed, the key is considered blocked.  The transition from unblocked to
+// blocked is noted so the responsible agent can be informed.  This transition
+// takes twice the look back window to clear.
+
+#include "linden_common.h"
+
+#include "llframetimer.h"
+#include <map>
+
+
+// Implementation utility class - use LLKeyThrottle, not this
+template <class T>
+class LLKeyThrottleImpl
+{
+public:
+	struct Entry {
+		U32		count;
+		BOOL	blocked;
+
+		Entry() : count(0), blocked(FALSE) { }
+	};
+
+	typedef std::map<T, Entry> EntryMap;
+
+	EntryMap * prevMap;
+	EntryMap * currMap;
+	
+	U32 countLimit;
+		// maximum number of keys allowed per interval
+		
+	U64 interval_usec;
+		// each map covers this time period
+	U64 start_usec;
+		// currMap started counting at this time
+		// prevMap covers the previous interval
+	
+	LLKeyThrottleImpl() : prevMap(0), currMap(0) { }
+
+	static U64 getTime()
+	{
+		return LLFrameTimer::getTotalTime();
+	}
+};
+
+
+template< class T >
+class LLKeyThrottle
+{
+public:
+	LLKeyThrottle(U32 limit, F32 interval)
+		: m(* new LLKeyThrottleImpl<T>)
+	{
+		// limit is the maximum number of keys
+		// allowed per interval (in seconds)
+		m.countLimit = limit;
+		m.interval_usec = (U64)(interval * USEC_PER_SEC);
+		m.start_usec = LLKeyThrottleImpl<T>::getTime();
+
+		m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+		m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+	}
+		
+	~LLKeyThrottle()
+	{
+		delete m.prevMap;
+		delete m.currMap;
+		delete &m;
+	}
+
+	enum State {
+		THROTTLE_OK,			// rate not exceeded, let pass
+		THROTTLE_NEWLY_BLOCKED,	// rate exceed for the first time
+		THROTTLE_BLOCKED,		// rate exceed, block key
+	};
+
+	// call each time the key wants use
+	State noteAction(const T& id, S32 weight = 1)
+	{
+		U64 now = LLKeyThrottleImpl<T>::getTime();
+
+		if (now >= (m.start_usec + m.interval_usec))
+		{
+			if (now < (m.start_usec + 2 * m.interval_usec))
+			{
+				// prune old data
+				delete m.prevMap;
+				m.prevMap = m.currMap;
+				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+
+				m.start_usec += m.interval_usec;
+			}
+			else
+			{
+				// lots of time has passed, all data is stale
+				delete m.prevMap;
+				delete m.currMap;
+				m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+
+				m.start_usec = now;
+			}
+		}
+
+		U32 prevCount = 0;
+		BOOL prevBlocked = FALSE;
+
+		typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
+		if (prev != m.prevMap->end())
+		{
+			prevCount = prev->second.count;
+			prevBlocked = prev->second.blocked;
+		}
+
+		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
+
+		bool wereBlocked = curr.blocked || prevBlocked;
+
+		curr.count += weight;
+
+		// curr.count is the number of keys in
+		// this current 'time slice' from the beginning of it until now
+		// prevCount is the number of keys in the previous
+		// time slice scaled to be one full time slice back from the current 
+		// (now) time.
+
+		// compute current, windowed rate
+		F64 timeInCurrent = ((F64)(now - m.start_usec) / m.interval_usec);
+		F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
+		
+		curr.blocked |= averageCount > m.countLimit;
+
+		bool nowBlocked = curr.blocked || prevBlocked;
+
+		if (!nowBlocked)
+		{
+			return THROTTLE_OK;
+		}
+		else if (!wereBlocked)
+		{
+			return THROTTLE_NEWLY_BLOCKED;
+		}
+		else
+		{
+			return THROTTLE_BLOCKED;
+		}
+	}
+
+	// call to force throttle conditions for id
+	void throttleAction(const T& id)
+	{
+		noteAction(id);
+		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
+		if (curr.count < m.countLimit)
+		{
+			curr.count = m.countLimit;
+		}
+		curr.blocked = TRUE;
+	}
+
+	// returns TRUE if key is blocked
+	BOOL isThrottled(const T& id) const
+	{
+		if (m.currMap->empty()
+			&& m.prevMap->empty())
+		{
+			// most of the time we'll fall in here
+			return FALSE;
+		}
+
+		// NOTE, we ignore the case where id is in the map but the map is stale.  
+		// You might think that we'd stop throttling things in such a case, 
+		// however it may be that a god has disabled scripts in the region or 
+		// estate --> we probably want to report the state of the id when the 
+		// scripting engine was paused.
+		typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id);
+		if (entry != m.currMap->end())
+		{
+			return entry->second.blocked;
+		}
+		entry = m.prevMap->find(id);
+		if (entry != m.prevMap->end())
+		{
+			return entry->second.blocked;
+		}
+		return FALSE;
+	}
+
+protected:
+	LLKeyThrottleImpl<T>& m;
+};
+
+#endif
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 1fb917f0f9d..65ba7ddc4f7 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -376,6 +376,7 @@ struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
 	}
 };
 
+std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
 
 /** QUESTIONS & TO DOS
 	- Would Binary be more convenient as usigned char* buffer semantics?
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index a7470bec8be..5ab94715c53 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -1641,4 +1641,9 @@ void serialize_string(const std::string& value, std::ostream& str)
 	}
 }
 
+std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
+{
+	s << LLSDNotationStreamer(llsd);
+	return s;
+}
 
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 41a67f22fca..6f1c281eb24 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2220,7 +2220,6 @@ BOOL LLFloaterView::allChildrenClosed()
 {
 	// see if there are any visible floaters (some floaters "close"
 	// by setting themselves invisible)
-	S32 visible_count = 0;
 	for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
 	{
 		LLView* viewp = *it;
@@ -2228,11 +2227,10 @@ BOOL LLFloaterView::allChildrenClosed()
 
 		if (floaterp->getVisible() && floaterp->canClose())
 		{
-			visible_count++;
+			return false;
 		}
 	}
-
-	return (visible_count == 0);
+	return true;
 }
 
 
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index ecdcbc370d0..0a63ebbe74f 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -158,8 +158,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
 		mHandleEditKeysDirectly( FALSE ),
 		mSelectAllonFocusReceived( FALSE ),
 		mPassDelete(FALSE),
-		mReadOnly(FALSE),
-		mLastIMEPosition( -1, -1 )
+		mReadOnly(FALSE)
 {
 	llassert( max_length_bytes > 0 );
 
@@ -1638,12 +1637,7 @@ void LLLineEditor::draw()
 				S32 pixels_after_scroll = findPixelNearestPos();	// RCalculcate for IME position
 				LLRect screen_pos = getScreenRect();
 				LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - UI_LINEEDITOR_V_PAD );
-				if ( ime_pos.mX != mLastIMEPosition.mX || ime_pos.mY != mLastIMEPosition.mY )
-				{
-					mLastIMEPosition.mX = ime_pos.mX;
-					mLastIMEPosition.mY = ime_pos.mY;
-					getWindow()->setLanguageTextInput( ime_pos );
-				}
+				getWindow()->setLanguageTextInput( ime_pos );
 			}
 		}
 
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 2cd2ebf9fe7..f1b9fbe33ee 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -279,8 +279,6 @@ class LLLineEditor
 
 	S32			mBorderThickness;
 
-	LLCoordGL	mLastIMEPosition;		// Last screen position used for the IME editor
-
 	BOOL		mIgnoreArrowKeys;
 	BOOL		mIgnoreTab;
 	BOOL		mDrawAsterixes;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index f5eef29dcb2..96a739418f9 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -701,7 +701,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
 			break;
 		}
 	
-		updateLineHeight();
+		updateLineHeightInsert(item);
 		mPageLines = mLineHeight ? mItemListRect.getHeight() / mLineHeight : 0;
 		BOOL scrollbar_visible = mPageLines < getItemCount();
 		
@@ -753,12 +753,11 @@ void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
 	}
 }
 
+const S32 SCROLL_LIST_ROW_PAD = 2;
 
 // Line height is the max height of all the cells in all the items.
 void LLScrollListCtrl::updateLineHeight()
 {
-	const S32 ROW_PAD = 2;
-
 	mLineHeight = 0;
 	item_list::iterator iter;
 	for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
@@ -768,11 +767,23 @@ void LLScrollListCtrl::updateLineHeight()
 		S32 i = 0;
 		for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
 		{
-			mLineHeight = llmax( mLineHeight, cell->getHeight() + ROW_PAD );
+			mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD );
 		}
 	}
 }
 
+// when the only change to line height is from an insert, we needn't scan the entire list
+void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp)
+{
+	S32 num_cols = itemp->getNumColumns();
+	S32 i = 0;
+	for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
+	{
+		mLineHeight = llmax( mLineHeight, cell->getHeight() + SCROLL_LIST_ROW_PAD );
+	}
+}
+
+
 void LLScrollListCtrl::updateColumns()
 {
 	mColumnsIndexed.resize(mColumns.size());
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 5ceee2e1f65..a98a411efa8 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -589,6 +589,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	void			selectNextItem(BOOL extend_selection);
 	void			drawItems();
 	void			updateLineHeight();
+	void            updateLineHeightInsert(LLScrollListItem* item);
 	void			reportInvalidInput();
 	BOOL			isRepeatedChars(const LLWString& string) const;
 	void			selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 0184878e457..af1813a429a 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -310,8 +310,7 @@ LLTextEditor::LLTextEditor(
 	mMouseDownX(0),
 	mMouseDownY(0),
 	mLastSelectionX(-1),
-	mLastSelectionY(-1),
-	mLastIMEPosition(-1,-1)
+	mLastSelectionY(-1)
 {
 	mSourceID.generate();
 
@@ -2817,12 +2816,7 @@ void LLTextEditor::drawCursor()
 				// Make sure the IME is in the right place
 				LLRect screen_pos = getScreenRect();
 				LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_left), screen_pos.mBottom + llfloor(cursor_top) );
-				if ( ime_pos.mX != mLastIMEPosition.mX || ime_pos.mY != mLastIMEPosition.mY )
-				{
-					mLastIMEPosition.mX = ime_pos.mX;
-					mLastIMEPosition.mY = ime_pos.mY;
-					getWindow()->setLanguageTextInput( ime_pos );
-				}
+				getWindow()->setLanguageTextInput( ime_pos );
 			}
 		}
 	}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 55aba575517..d38accca8f9 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -439,8 +439,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 
 	BOOL			mParseHTML;
 	LLString		mHTML;
-
-	LLCoordGL		mLastIMEPosition;		// Last position of the IME editor
 };
 
 class LLTextSegment
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index bb99d4c7b55..0286623662e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -92,6 +92,7 @@ BOOL	LLWindowWin32::sLanguageTextInputAllowed = TRUE;
 HKL		LLWindowWin32::sWinInputLocale = 0;
 DWORD	LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE;
 DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
+LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 
 // The following class LLWinImm delegates Windows IMM APIs.
 // We need this because some language versions of Windows,
@@ -3372,14 +3373,15 @@ void LLWindowWin32::allowLanguageTextInput(BOOL b)
 // Put the IME window at the right place (near current text input).   Point coordinates should be the top of the current text line.
 void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
 {
-	if (sLanguageTextInputAllowed && LLWinImm::isAvailable())
-	{
+	if ( LLWinImm::isAvailable() )
+	{		
 		HIMC himc = LLWinImm::getContext(mWindowHandle);
 
 		LLCoordWindow win_pos;
 		convertCoords( position, &win_pos );
 
-		if ( win_pos.mX >= 0 && win_pos.mY >= 0 )
+		if ( win_pos.mX >= 0 && win_pos.mY >= 0 && 
+			(win_pos.mX >= 0 != sWinIMEWindowPosition.mX ) || (win_pos.mY >= 0 != sWinIMEWindowPosition.mY ) )
 		{
 			COMPOSITIONFORM ime_form;
 			memset( &ime_form, 0, sizeof(ime_form) );
@@ -3388,10 +3390,27 @@ void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
 			ime_form.ptCurrentPos.y = win_pos.mY;
 
 			LLWinImm::setCompositionWindow( himc, &ime_form );
+
+			sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY );
 		}
 
-		LLWinImm::releaseContext(mWindowHandle, himc);
+		// Input not allowed, make sure it's set to alpha numeric mode
+		if ( !sLanguageTextInputAllowed )
 
+		{
+			if ( LLWinImm::getOpenStatus(himc) )
+			{
+				DWORD conversion_mode = 0;
+				DWORD sentence_mode = 0;
+				LLWinImm::getConversionStatus(himc, &conversion_mode, &sentence_mode);
+				if ( conversion_mode != IME_CMODE_ALPHANUMERIC )
+				{	// Set to no-conversion mode instead of turning it off
+					LLWinImm::setConversionStatus(himc, IME_CMODE_ALPHANUMERIC, IME_SMODE_NONE );
+				}
+			}
+		}
+
+		LLWinImm::releaseContext(mWindowHandle, himc);
 	}
 }
 
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 938ece912c4..62b1f73cede 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -187,6 +187,7 @@ class LLWindowWin32 : public LLWindow
 	static HKL		sWinInputLocale;
 	static DWORD	sWinIMEConversionMode;
 	static DWORD	sWinIMESentenceMode;
+	static LLCoordWindow sWinIMEWindowPosition;
 
 	friend class LLWindowManager;
 };
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 54f6741fee6..d7e316438c9 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -527,6 +527,21 @@ void LLAgent::resetView(BOOL reset_camera)
 	}
 }
 
+// Handle any actions that need to be performed when the main app gains focus
+// (such as through alt-tab).
+//-----------------------------------------------------------------------------
+// onAppFocusGained()
+//-----------------------------------------------------------------------------
+void LLAgent::onAppFocusGained()
+{
+	if (CAMERA_MODE_MOUSELOOK == mCameraMode)
+	{
+		changeCameraToDefault();
+		gToolMgr->clearSavedTool();
+	}
+}
+
+
 void LLAgent::ageChat()
 {
 	if (mAvatarObject)
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index ad0606aea23..c6de97fede4 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -141,6 +141,8 @@ class LLAgent : public LLObservable
 	// default position behind the avatar.
 	void			unlockView();
 
+	void            onAppFocusGained();
+
 	void			sendMessage();						// Send message to this agent's region.
 	void			sendReliableMessage();
 
diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp
index 6f792e062f4..6f4945e54b0 100644
--- a/indra/newview/llfloaterfriends.cpp
+++ b/indra/newview/llfloaterfriends.cpp
@@ -61,19 +61,43 @@
 //Maximum number of people you can select to do an operation on at once.
 #define MAX_FRIEND_SELECT 20
 #define RIGHTS_CHANGE_TIMEOUT 5.0
+#define OBSERVER_TIMEOUT 0.5
 
 // simple class to observe the calling cards.
-class LLLocalFriendsObserver : public LLFriendObserver
+class LLLocalFriendsObserver : public LLFriendObserver, public LLEventTimer
 {
-public:
-	LLLocalFriendsObserver(LLPanelFriends* floater) : mFloater(floater) {}
-	virtual ~LLLocalFriendsObserver() { mFloater = NULL; }
+public: 
+	LLLocalFriendsObserver(LLPanelFriends* floater) : mFloater(floater), LLEventTimer(OBSERVER_TIMEOUT)
+	{
+		mEventTimer.stop();
+	}
+	virtual ~LLLocalFriendsObserver()
+	{
+		mFloater = NULL;
+	}
 	virtual void changed(U32 mask)
 	{
-		mFloater->updateFriends(mask);
+		// events can arrive quickly in bulk - we need not process EVERY one of them -
+		// so we wait a short while to let others pile-in, and process them in aggregate.
+		mEventTimer.start();
+		mEventTimer.reset();
+
+		// save-up all the mask-bits which have come-in
+		mMask |= mask;
+	}
+	virtual BOOL tick()
+	{
+		mFloater->updateFriends(mMask);
+
+		mEventTimer.stop();
+		mMask = 0;
+
+		return FALSE;
 	}
+	
 protected:
 	LLPanelFriends* mFloater;
+	U32 mMask;
 };
 
 LLPanelFriends::LLPanelFriends() :
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 0111676a97e..d5af7243a07 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2162,17 +2162,17 @@ BOOL idle_startup()
 				if (url_ok)
 				{
 					args["[TYPE]"] = "desired";
-					args["[HELP]"] = " ";
+					args["[HELP]"] = "";
 				}
 				else if (gSavedSettings.getBOOL("LoginLastLocation"))
 				{
 					args["[TYPE]"] = "last";
-					args["[HELP]"] = " \n ";
+					args["[HELP]"] = "";
 				}
 				else
 				{
 					args["[TYPE]"] = "home";
-					args["[HELP]"] = " \nYou may want to set a new home location.\n ";
+					args["[HELP]"] = "\nYou may want to set a new home location.";
 				}
 				gViewerWindow->alertXml("AvatarMoved", args);
 			}
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index ae42ec60d36..94641467422 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1294,11 +1294,21 @@ bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 pri
 			return false;
 		}
 	}
-	// If the requester knows the dimentions of the image,
-	// this will calculate how much data we need without having to parse the header
+
 	S32 desired_size;
-	if (w*h*c > 0)
+	if ((discard == 0) && worker && worker->mFileSize)
+	{
+		// if we want the entire image, and we know its size, then get it all
+		// (calcDataSizeJ2C() below makes assumptions about how the image
+		// was compressed - this code ensures that when we request the entire image,
+		// we really do get it.)
+		desired_size = worker->mFileSize;
+	}
+	else if (w*h*c > 0)
 	{
+		// If the requester knows the dimentions of the image,
+		// this will calculate how much data we need without having to parse the header
+
 		desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, discard);
 	}
 	else
diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp
index ae74eba026e..0e46ece7946 100644
--- a/indra/newview/lltoolmgr.cpp
+++ b/indra/newview/lltoolmgr.cpp
@@ -428,6 +428,11 @@ void LLToolMgr::onAppFocusGained()
 	updateToolStatus();
 }
 
+void LLToolMgr::clearSavedTool()
+{
+	mSavedTool = NULL;
+}
+
 /////////////////////////////////////////////////////
 // LLToolset
 
diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h
index e0f554d5b6b..557208be7ba 100644
--- a/indra/newview/lltoolmgr.h
+++ b/indra/newview/lltoolmgr.h
@@ -70,6 +70,8 @@ class LLToolMgr
 	void			onAppFocusGained();
 	void			onAppFocusLost();
 
+	void            clearSavedTool();
+
 protected:
 	friend class LLToolset;  // to allow access to setCurrentTool();
 	void			setCurrentTool(LLTool* tool);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index ac4ac77f0c4..13ff55ce1c1 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -348,6 +348,16 @@ class LLFileCloseWindow : public view_listener_t
 	}
 };
 
+class LLFileEnableCloseAllWindows : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		bool open_children = gFloaterView->allChildrenClosed();
+		gMenuHolder->findControl(userdata["control"].asString())->setValue(!open_children);
+		return true;
+	}
+};
+
 class LLFileCloseAllWindows : public view_listener_t
 {
 	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -1036,6 +1046,7 @@ void init_menu_file()
 	(new LLFileCloseWindow())->registerListener(gMenuHolder, "File.CloseWindow");
 	(new LLFileCloseAllWindows())->registerListener(gMenuHolder, "File.CloseAllWindows");
 	(new LLFileEnableCloseWindow())->registerListener(gMenuHolder, "File.EnableCloseWindow");
+	(new LLFileEnableCloseAllWindows())->registerListener(gMenuHolder, "File.EnableCloseAllWindows");
 	(new LLFileSaveTexture())->registerListener(gMenuHolder, "File.SaveTexture");
 	(new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot");
 	(new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk");
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e7e2151353f..74788f6f26d 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1221,6 +1221,8 @@ void LLViewerWindow::handleFocus(LLWindow *window)
 {
 	gFocusMgr.setAppHasFocus(TRUE);
 	LLModalDialog::onAppFocusGained();
+
+	gAgent.onAppFocusGained();
 	if (gToolMgr)
 	{
 		gToolMgr->onAppFocusGained();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 559db5fc892..e9faccb4da6 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -385,22 +385,14 @@ void LLPipeline::releaseGLBuffers()
 
 	if (mCubeFrameBuffer)
 	{
-#if !defined(__sparc)
 		glDeleteFramebuffersEXT(1, &mCubeFrameBuffer);
 		glDeleteRenderbuffersEXT(1, &mCubeDepth);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 		mCubeDepth = mCubeFrameBuffer = 0;
 	}
 
 	if (mFramebuffer[0])
 	{
-#if !defined(__sparc)
 		glDeleteFramebuffersEXT(2, mFramebuffer);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 		mFramebuffer[0] = mFramebuffer[1] = 0;
 	}
 }
@@ -3778,12 +3770,8 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 	BOOL reattach = FALSE;
 	if (mCubeFrameBuffer == 0)
 	{
-#if !defined(__sparc)
 		glGenFramebuffersEXT(1, &mCubeFrameBuffer);
 		glGenRenderbuffersEXT(1, &mCubeDepth);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 		reattach = TRUE;
 	}
 
@@ -3854,7 +3842,6 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 
 	if (reattach)
 	{
-#if !defined(__sparc)
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mCubeDepth);
 		GLint res_x, res_y;
 		glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_WIDTH_EXT, &res_x);
@@ -3866,22 +3853,15 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 		}
 		
 		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 	}
 
 	for (S32 i = 0; i < 6; i++)
 	{
-#if !defined(__sparc)
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubeFrameBuffer);
 		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
 									cube_face[i], cube_map->getGLName(), 0);
 		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
 										GL_RENDERBUFFER_EXT, mCubeDepth);		
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 		glMatrixMode(GL_PROJECTION);
 		glLoadIdentity();
 		gluPerspective(90.f, 1.f, 0.1f, 1024.f);
@@ -3901,11 +3881,7 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 		gPipeline.renderGeom(cube_cam);
 	}
 
-#if !defined(__sparc)
 	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 
 	cube_cam.setOrigin(origin);
 	gPipeline.resetDrawOrders();
@@ -4114,14 +4090,10 @@ void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res,
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable cull(GL_CULL_FACE);
 
-#if !defined(__sparc)
 	if (mFramebuffer[0] == 0)
 	{
 		glGenFramebuffersEXT(2, mFramebuffer);
 	}
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 
 	GLint viewport[4];
 	glGetIntegerv(GL_VIEWPORT, viewport);
@@ -4144,15 +4116,11 @@ void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res,
 
 	for (S32 i = 0; i < kernel; i++)
 	{
-#if !defined(__sparc)
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebuffer[i%2]);
 		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 
 								GL_COLOR_ATTACHMENT0_EXT,
 								GL_TEXTURE_2D, 
 								i%2 == 0 ? buffer : dest, 0);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 		
 		glBindTexture(GL_TEXTURE_2D, i == 0 ? source : 
 									i%2==0 ? dest :
@@ -4179,11 +4147,7 @@ void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res,
 		
 	}
 
-#if !defined(__sparc)
 	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-#else
-#error Can we generalize this without a CPU architecture test?
-#endif
 	gGlowProgram.unbind();
 
 	glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
-- 
GitLab