From afe61eb994377e25d60d0a0893510a693149c6be Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Tue, 23 Sep 2008 01:53:11 +0000
Subject: [PATCH] QAR-849 merge maint-viewer-10-merge 96838-97237 -> release

---
 doc/contributions.txt                         |   6 +-
 indra/cmake/CMakeLists.txt                    |   1 +
 indra/cmake/DBusGlib.cmake                    |  29 +++
 indra/llcharacter/llbvhloader.cpp             |  45 +++-
 indra/llcharacter/llmotioncontroller.cpp      |   5 +
 indra/llcommon/llstring.h                     |  30 +--
 indra/llimagej2coj/llimagej2coj.cpp           |  19 +-
 indra/llmessage/llmessagetemplate.cpp         |   2 +-
 indra/llui/lllineeditor.cpp                   |  25 ++-
 indra/llui/lllineeditor.h                     |   1 -
 indra/llui/lltexteditor.h                     |   4 +-
 indra/llwindow/llwindow.cpp                   |   6 +
 indra/llwindow/llwindow.h                     |   1 +
 indra/llwindow/llwindowsdl.cpp                |  62 +++---
 indra/llwindow/llwindowsdl.h                  |  25 +--
 indra/newview/CMakeLists.txt                  |   3 +
 indra/newview/app_settings/keywords.ini       |  10 +-
 indra/newview/llagent.cpp                     |   5 +-
 indra/newview/llappviewer.cpp                 |  62 +++---
 indra/newview/llappviewer.h                   |   7 +-
 indra/newview/llappviewerlinux.cpp            | 195 +++++++++++++++++-
 indra/newview/llappviewerlinux.h              |  29 +++
 indra/newview/llappviewerlinux_api.h          | 148 +++++++++++++
 indra/newview/llappviewerlinux_api.xml        |  14 ++
 indra/newview/llappviewerlinux_api_dbus.cpp   | 131 ++++++++++++
 indra/newview/llappviewerlinux_api_dbus.h     |  49 +++++
 .../llappviewerlinux_api_dbus_syms_raw.inc    |   9 +
 indra/newview/llappviewerwin32.cpp            |  31 ++-
 indra/newview/llappviewerwin32.h              |   4 +
 indra/newview/llaudiosourcevo.cpp             |   2 +-
 indra/newview/llcommandlineparser.cpp         |  12 +-
 indra/newview/llfilepicker.cpp                |   4 +-
 indra/newview/llfloaterimagepreview.cpp       |  91 ++++----
 indra/newview/llfloaterimagepreview.h         |   2 +
 indra/newview/llgroupmgr.cpp                  |  17 ++
 indra/newview/llmutelist.cpp                  |  20 ++
 indra/newview/llmutelist.h                    |   3 +-
 indra/newview/llnetmap.cpp                    |   6 +-
 indra/newview/llpreviewsound.cpp              |   3 +-
 indra/newview/llstartup.cpp                   |   6 +
 indra/newview/lltoolplacer.cpp                |   4 +-
 indra/newview/llvieweraudio.cpp               |   8 +
 indra/newview/llviewermenu.cpp                |  87 +++-----
 indra/newview/llviewermessage.cpp             |   6 +-
 indra/newview/llviewerobject.cpp              |  12 +-
 indra/newview/llviewertexteditor.cpp          |   3 +-
 indra/newview/llviewerwindow.cpp              |   1 +
 indra/newview/llvoavatar.cpp                  |  13 +-
 indra/newview/pipeline.cpp                    |  12 ++
 install.xml                                   |  24 +++
 50 files changed, 1018 insertions(+), 276 deletions(-)
 create mode 100644 indra/cmake/DBusGlib.cmake
 create mode 100644 indra/newview/llappviewerlinux_api.h
 create mode 100644 indra/newview/llappviewerlinux_api.xml
 create mode 100644 indra/newview/llappviewerlinux_api_dbus.cpp
 create mode 100644 indra/newview/llappviewerlinux_api_dbus.h
 create mode 100644 indra/newview/llappviewerlinux_api_dbus_syms_raw.inc

diff --git a/doc/contributions.txt b/doc/contributions.txt
index b6575ad2f35..df8d8a979ad 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -10,7 +10,7 @@ Able Whitman
 	VWR-1691
 	VWR-1735
 Adam Marker
-    VWR-2755
+	VWR-2755
 Aimee Trescothick
 	VWR-3903
 	VWR-4083
@@ -79,6 +79,7 @@ bushing Spatula
 	VWR-424
 Carjay McGinnis
 	VWR-3737
+	VWR-4070
 	VWR-6154
 Catherine Pfeffer
 	VWR-1282
@@ -184,6 +185,7 @@ Jacek Antonelli
 	VWR-188
 	VWR-427
 	VWR-597
+	VWR-2054
 	VWR-2448
 	VWR-3605
 JB Kraft
@@ -214,6 +216,8 @@ Michelle2 Zenovka
 	VWR-4506
 	VWR-7831
 	VWR-8889
+	VWR-8310
+	VWR-4022
 Mm Alder
 	VWR-3777
 	VWR-4794
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 27ba04558e3..1b9bcffd168 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -18,6 +18,7 @@ set(cmake_SOURCE_FILES
     CMakeCopyIfDifferent.cmake
     CopyWinLibs.cmake
     CSharpMacros.cmake
+    DBusGlib.cmake
     DirectX.cmake
     ELFIO.cmake
     EXPAT.cmake
diff --git a/indra/cmake/DBusGlib.cmake b/indra/cmake/DBusGlib.cmake
new file mode 100644
index 00000000000..cfc4ccd404f
--- /dev/null
+++ b/indra/cmake/DBusGlib.cmake
@@ -0,0 +1,29 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+if (STANDALONE)
+  include(FindPkgConfig)
+
+  pkg_check_modules(DBUSGLIB REQUIRED dbus-glib-1)
+
+elseif (LINUX)
+  use_prebuilt_binary(dbusglib)
+  set(DBUSGLIB_FOUND ON FORCE BOOL)
+  set(DBUSGLIB_INCLUDE_DIRS
+      ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0
+      )
+  # We don't need to explicitly link against dbus-glib itself, because
+  # the viewer probes for the system's copy at runtime.
+  set(DBUSGLIB_LIBRARIES
+      gobject-2.0
+      glib-2.0
+      )
+endif (STANDALONE)
+
+if (DBUSGLIB_FOUND)
+  set(DBUSGLIB ON CACHE BOOL "Build with dbus-glib message bus support.")
+endif (DBUSGLIB_FOUND)
+
+if (DBUSGLIB)
+  add_definitions(-DLL_DBUS_ENABLED=1)
+endif (DBUSGLIB)
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index 54b3ec98eb5..b34328ce25a 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -1133,6 +1133,8 @@ void LLBVHLoader::optimize()
 
 			F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f);
 
+			double diff_max = 0;
+			KeyVector::iterator ki_max = ki;
 			for (; ki != joint->mKeys.end(); ++ki)
 			{
 				if (ki_prev == ki_last_good_pos)
@@ -1193,30 +1195,55 @@ void LLBVHLoader::optimize()
 					F32 x_delta;
 					F32 y_delta;
 					F32 rot_test;
-
+					
+					// Test if the rotation has changed significantly since the very first frame.  If false
+					// for all frames, then we'll just throw out this joint's rotation entirely.
 					x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
 					y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
 					rot_test = x_delta + y_delta;
-
 					if (rot_test > ROTATION_MOTION_THRESHOLD)
 					{
 						rot_changed = TRUE;
 					}
-
 					x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot);
 					y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot);
 					rot_test = x_delta + y_delta;
 
-					if (rot_test < rot_threshold)
-					{
-						ki_prev->mIgnoreRot = TRUE;
-						numRotFramesConsidered++;
-					}
-					else
+					// Draw a line between the last good keyframe and current.  Test the distance between the last frame (current-1, i.e. ki_prev)
+					// and the line.  If it's greater than some threshold, then it represents a significant frame and we want to include it.
+					if (rot_test >= rot_threshold ||
+						(ki+1 == joint->mKeys.end() && numRotFramesConsidered > 2))
 					{
+						// Add the current test keyframe (which is technically the previous key, i.e. ki_prev).
 						numRotFramesConsidered = 2;
 						ki_last_good_rot = ki_prev;
 						joint->mNumRotKeys++;
+
+						// Add another keyframe between the last good keyframe and current, at whatever point was the most "significant" (i.e.
+						// had the largest deviation from the earlier tests).  Note that a more robust approach would be test all intermediate
+						// keyframes against the line between the last good keyframe and current, but we're settling for this other method
+						// because it's significantly faster.
+						if (diff_max > 0)
+						{
+							if (ki_max->mIgnoreRot == TRUE)
+							{
+								ki_max->mIgnoreRot = FALSE;
+								joint->mNumRotKeys++;
+							}
+							diff_max = 0;
+						}
+					}
+					else
+					{
+						// This keyframe isn't significant enough, throw it away.
+						ki_prev->mIgnoreRot = TRUE;
+						numRotFramesConsidered++;
+						// Store away the keyframe that has the largest deviation from the interpolated line, for insertion later.
+						if (rot_test > diff_max)
+						{
+							diff_max = rot_test;
+							ki_max = ki;
+						}
 					}
 				}
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index 3cb4da4e3ae..051f2d625c4 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -783,6 +783,11 @@ void LLMotionController::updateLoadingMotions()
 			llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
 			sRegistry.markBad(motionp->getID());
 			mLoadingMotions.erase(curiter);
+			motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
+			if (found_it != mDeprecatedMotions.end())
+			{
+				mDeprecatedMotions.erase(found_it);
+			}
 			mAllMotions.erase(motionp->getID());
 			delete motionp;
 		}
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 475531a2adf..1a60a35c2cc 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -133,26 +133,32 @@ struct char_traits<U16>
 class LLStringOps
 {
 public:
-	static char toUpper(char elem) { return toupper(elem); }
+	static char toUpper(char elem) { return toupper((unsigned char)elem); }
 	static llwchar toUpper(llwchar elem) { return towupper(elem); }
 	
-	static char toLower(char elem) { return tolower(elem); }
+	static char toLower(char elem) { return tolower((unsigned char)elem); }
 	static llwchar toLower(llwchar elem) { return towlower(elem); }
 
-	static BOOL isSpace(char elem) { return isspace(elem) != 0; }
-	static BOOL isSpace(llwchar elem) { return iswspace(elem) != 0; }
+	static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
+	static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
 
-	static BOOL isUpper(char elem) { return isupper(elem) != 0; }
-	static BOOL isUpper(llwchar elem) { return iswupper(elem) != 0; }
+	static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
+	static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
 
-	static BOOL isLower(char elem) { return islower(elem) != 0; }
-	static BOOL isLower(llwchar elem) { return iswlower(elem) != 0; }
+	static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
+	static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
+
+	static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
+	static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
+
+	static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
+	static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
+
+	static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
+	static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
 
 	static S32	collate(const char* a, const char* b) { return strcoll(a, b); }
 	static S32	collate(const llwchar* a, const llwchar* b);
-
-	static BOOL isDigit(char a) { return isdigit(a) != 0; }
-	static BOOL isDigit(llwchar a) { return iswdigit(a) != 0; }
 };
 
 // Allowing assignments from non-strings into format_map_t is apparently
@@ -180,7 +186,7 @@ class LLStringUtilBase
 	typedef std::map<FormatMapString, FormatMapString> format_map_t;
 	static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
 	
-	static BOOL	isValidIndex(const std::basic_string<T>& string, size_type i)
+	static bool isValidIndex(const std::basic_string<T>& string, size_type i)
 	{
 		return !string.empty() && (0 <= i) && (i <= string.size());
 	}
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 2818859d93b..fc3b89d7461 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -151,9 +151,11 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 	// dereference the array.
 	if(!image || !image->numcomps)
 	{
-		fprintf(stderr, "ERROR -> decodeImpl: failed to decode image!\n");
+		llwarns << "ERROR -> decodeImpl: failed to decode image!" << llendl;
 		if (image)
+		{
 			opj_image_destroy(image);
+		}
 
 		return TRUE; // done
 	}
@@ -170,6 +172,17 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 		}
 	}
 	
+	if(image->numcomps <= first_channel)
+	{
+		llwarns << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << llendl;
+		if (image)
+		{
+			opj_image_destroy(image);
+		}
+			
+		return TRUE;
+	}
+
 	// Copy image data into our raw image format (instead of the separate channel format
 
 	S32 img_components = image->numcomps;
@@ -211,7 +224,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
 		}
 		else // Some rare OpenJPEG versions have this bug.
 		{
-			fprintf(stderr, "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)\n");
+			llwarns << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << llendl;
 			opj_image_destroy(image);
 
 			return TRUE; // done
@@ -430,7 +443,7 @@ BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
 
 	if(!image)
 	{
-		fprintf(stderr, "ERROR -> getMetadata: failed to decode image!\n");
+		llwarns << "ERROR -> getMetadata: failed to decode image!" << llendl;
 		return FALSE;
 	}
 
diff --git a/indra/llmessage/llmessagetemplate.cpp b/indra/llmessage/llmessagetemplate.cpp
index b6c5304f09a..c09f3e9c490 100644
--- a/indra/llmessage/llmessagetemplate.cpp
+++ b/indra/llmessage/llmessagetemplate.cpp
@@ -50,7 +50,7 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S3
 	}
 	if(size)
 	{
-		delete mData; // Delete it if it already exists
+		delete[] mData; // Delete it if it already exists
 		mData = new U8[size];
 		htonmemcpy(mData, data, mType, size);
 	}
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index a41b2af2b43..a8ed555a450 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -35,6 +35,7 @@
  
 #include "lllineeditor.h"
 
+#include "lltexteditor.h"
 #include "audioengine.h"
 #include "llmath.h"
 #include "llfontgl.h"
@@ -450,19 +451,19 @@ BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 		BOOL doSelectAll = TRUE;
 
 		// Select the word we're on
-		if( isPartOfWord( wtext[mCursorPos] ) )
+		if( LLTextEditor::isPartOfWord( wtext[mCursorPos] ) )
 		{
 			S32 old_selection_start = mLastSelectionStart;
 			S32 old_selection_end = mLastSelectionEnd;
 
 			// Select word the cursor is over
-			while ((mCursorPos > 0) && isPartOfWord( wtext[mCursorPos-1] ))
+			while ((mCursorPos > 0) && LLTextEditor::isPartOfWord( wtext[mCursorPos-1] ))
 			{	// Find the start of the word
 				mCursorPos--;
 			}
 			startSelection();	
 
-			while ((mCursorPos < (S32)wtext.length()) && isPartOfWord( wtext[mCursorPos] ) )
+			while ((mCursorPos < (S32)wtext.length()) && LLTextEditor::isPartOfWord( wtext[mCursorPos] ) )
 			{	// Find the end of the word
 				mCursorPos++;
 			}
@@ -764,7 +765,7 @@ S32 LLLineEditor::prevWordPos(S32 cursorPos) const
 	{
 		cursorPos--;
 	}
-	while( (cursorPos > 0) && isPartOfWord( wtext[cursorPos-1] ) )
+	while( (cursorPos > 0) && LLTextEditor::isPartOfWord( wtext[cursorPos-1] ) )
 	{
 		cursorPos--;
 	}
@@ -774,7 +775,7 @@ S32 LLLineEditor::prevWordPos(S32 cursorPos) const
 S32 LLLineEditor::nextWordPos(S32 cursorPos) const
 {
 	const LLWString& wtext = mText.getWString();
-	while( (cursorPos < getLength()) && isPartOfWord( wtext[cursorPos] ) )
+	while( (cursorPos < getLength()) && LLTextEditor::isPartOfWord( wtext[cursorPos] ) )
 	{
 		cursorPos++;
 	} 
@@ -1817,9 +1818,6 @@ BOOL LLLineEditor::prevalidateFloat(const LLWString &str)
 	return success;
 }
 
-//static
-BOOL LLLineEditor::isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); }
-
 // static
 BOOL LLLineEditor::postvalidateFloat(const std::string &str)
 {
@@ -1993,7 +1991,7 @@ BOOL LLLineEditor::prevalidateAlphaNum(const LLWString &str)
 	if(len == 0) return rv;
 	while(len--)
 	{
-		if( !isalnum(str[len]) )
+		if( !LLStringOps::isAlnum((char)str[len]) )
 		{
 			rv = FALSE;
 			break;
@@ -2012,7 +2010,7 @@ BOOL LLLineEditor::prevalidateAlphaNumSpace(const LLWString &str)
 	if(len == 0) return rv;
 	while(len--)
 	{
-		if(!(isalnum(str[len]) || (' ' == str[len])))
+		if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len])))
 		{
 			rv = FALSE;
 			break;
@@ -2034,7 +2032,7 @@ BOOL LLLineEditor::prevalidatePrintableNotPipe(const LLWString &str)
 			rv = FALSE;
 			break;
 		}
-		if(!((' ' == str[len]) || isalnum(str[len]) || ispunct(str[len])))
+		if(!((' ' == str[len]) || LLStringOps::isAlnum((char)str[len]) || LLStringOps::isPunct((char)str[len])))
 		{
 			rv = FALSE;
 			break;
@@ -2052,12 +2050,13 @@ BOOL LLLineEditor::prevalidatePrintableNoSpace(const LLWString &str)
 	if(len == 0) return rv;
 	while(len--)
 	{
-		if(iswspace(str[len]))
+		if(LLStringOps::isSpace(str[len]))
 		{
 			rv = FALSE;
 			break;
 		}
-		if( !(isalnum(str[len]) || ispunct(str[len]) ) )
+		if( !(LLStringOps::isAlnum((char)str[len]) ||
+		      LLStringOps::isPunct((char)str[len]) ) )
 		{
 			rv = FALSE;
 			break;
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 98242a493de..9e8212cfbb9 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -194,7 +194,6 @@ class LLLineEditor
 	void			setMaxTextLength(S32 max_text_length);
 	void			setTextPadding(S32 left, S32 right); // Used to specify room for children before or after text.
 
-	static BOOL		isPartOfWord(llwchar c);
 	// Prevalidation controls which keystrokes can affect the editor
 	void			setPrevalidate( BOOL (*func)(const LLWString &) );
 	static BOOL		prevalidateFloat(const LLWString &str );
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index ff93d087ea6..af9908a5405 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -249,6 +249,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 	const LLTextSegment*	getPreviousSegment();
 	void getSelectedSegments(std::vector<const LLTextSegment*>& segments);
 
+	static bool		isPartOfWord(llwchar c) { return (c == '_') || LLStringOps::isAlnum((char)c); }
+
 protected:
 	//
 	// Methods
@@ -266,8 +268,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 	void 			assignEmbedded(const std::string &s);
 	BOOL 			truncate();				// Returns true if truncation occurs
 	
-	static BOOL		isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); }
-
 	void			removeCharOrTab();
 	void			setCursorAtLocalPos(S32 x, S32 y, BOOL round);
 	S32				getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 4f467be02d9..03c36e95fcf 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -310,6 +310,12 @@ std::string LLWindow::getFontListSans()
 #endif
 }
 
+//virtual
+void LLWindow::processMiscNativeEvents()
+{
+	// do nothing unless subclassed
+}
+
 #define UTF16_IS_HIGH_SURROGATE(U) ((U16)((U) - 0xD800) < 0x0400)
 #define UTF16_IS_LOW_SURROGATE(U)  ((U16)((U) - 0xDC00) < 0x0400)
 #define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000)
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 9b1f0059207..9c3dfd319c0 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -190,6 +190,7 @@ class LLWindow
 	virtual U32	 getFSAASamples() = 0;
 	virtual BOOL restoreGamma() = 0;			// Restore original gamma table (before updating gamma)
 	virtual ESwapMethod getSwapMethod() { return mSwapMethod; }
+	virtual void processMiscNativeEvents();
 	virtual void gatherInput() = 0;
 	virtual void delayInputProcessing() = 0;
 	virtual void swapBuffers() = 0;
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index e2d114245d8..96a8fae5928 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -104,7 +104,8 @@ void maybe_unlock_display(void)
 
 #if LL_GTK
 // Lazily initialize and check the runtime GTK version for goodness.
-BOOL ll_try_gtk_init(void)
+// static
+bool LLWindowSDL::ll_try_gtk_init(void)
 {
 	static BOOL done_gtk_diag = FALSE;
 	static BOOL gtk_is_good = FALSE;
@@ -166,7 +167,8 @@ BOOL ll_try_gtk_init(void)
 
 
 #if LL_X11
-Window get_SDL_XWindowID(void)
+// static
+Window LLWindowSDL::get_SDL_XWindowID(void)
 {
 	if (gWindowImplementation) {
 		return gWindowImplementation->mSDL_XWindowID;
@@ -174,7 +176,8 @@ Window get_SDL_XWindowID(void)
 	return None;
 }
 
-Display* get_SDL_Display(void)
+//static
+Display* LLWindowSDL::get_SDL_Display(void)
 {
 	if (gWindowImplementation) {
 		return gWindowImplementation->mSDL_Display;
@@ -1235,7 +1238,7 @@ typedef Atom x11clipboard_type;
  */
 static x11clipboard_type get_x11_readwrite_clipboard_type(void)
 {
-	return XInternAtom(get_SDL_Display(), "CLIPBOARD", False);
+	return XInternAtom(LLWindowSDL::get_SDL_Display(), "CLIPBOARD", False);
 }
 
 static x11clipboard_type get_x11_write_clipboard_type(void)
@@ -1248,18 +1251,18 @@ static x11clipboard_type get_x11_write_clipboard_type(void)
    storage because their use isn't really defined for holding UTF8. */
 static x11clipboard_type get_x11_cutbuffer_clipboard_type(void)
 {
-	return XInternAtom(get_SDL_Display(), "SECONDLIFE_CUTBUFFER", False);
+	return XInternAtom(LLWindowSDL::get_SDL_Display(), "SECONDLIFE_CUTBUFFER", False);
 }
 
 /* Some X11 atom-generators */
 static Atom get_x11_targets_atom(void)
 {
-	return XInternAtom(get_SDL_Display(), "TARGETS", False);
+	return XInternAtom(LLWindowSDL::get_SDL_Display(), "TARGETS", False);
 }
 
 static Atom get_x11_text_atom(void)
 {
-	return XInternAtom(get_SDL_Display(), "TEXT", False);
+	return XInternAtom(LLWindowSDL::get_SDL_Display(), "TEXT", False);
 }
 
 /* These defines, and convert_data/convert_x11clipboard,
@@ -1544,7 +1547,7 @@ int clipboard_filter_callback(const SDL_Event *event)
 		sevent.xselection.property = None;
 		sevent.xselection.requestor = req->requestor;
 		sevent.xselection.time = req->time;
-		if ( XGetWindowProperty(get_SDL_Display(), DefaultRootWindow(get_SDL_Display()),
+		if ( XGetWindowProperty(LLWindowSDL::get_SDL_Display(), DefaultRootWindow(LLWindowSDL::get_SDL_Display()),
 					get_x11_cutbuffer_clipboard_type(), 0, INT_MAX/4, False, req->target,
 					&sevent.xselection.target, &seln_format,
 					&nbytes, &overflow, &seln_data) == Success )
@@ -1558,7 +1561,7 @@ int clipboard_filter_callback(const SDL_Event *event)
 					if ( seln_data[nbytes-1] == '\0' )
 						--nbytes;
 				}
-				XChangeProperty(get_SDL_Display(), req->requestor, req->property,
+				XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor, req->property,
 						req->target, seln_format, PropModeReplace,
 						seln_data, nbytes);
 				sevent.xselection.property = req->property;
@@ -1571,7 +1574,7 @@ int clipboard_filter_callback(const SDL_Event *event)
 					get_x11_targets_atom()
 				};
 				supported[0] = sevent.xselection.target;
-				XChangeProperty(get_SDL_Display(), req->requestor,
+				XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor,
 						req->property, XA_ATOM, 32, PropModeReplace,
 						(unsigned char*)supported,
 						num_supported);
@@ -1584,10 +1587,10 @@ int clipboard_filter_callback(const SDL_Event *event)
 			XFree(seln_data);
 		}
 		int sendret =
-			XSendEvent(get_SDL_Display(),req->requestor,False,0,&sevent);
+			XSendEvent(LLWindowSDL::get_SDL_Display(),req->requestor,False,0,&sevent);
 		if ((sendret==BadValue) || (sendret==BadWindow))
 			llwarns << "Clipboard SendEvent failed" << llendl;
-		XSync(get_SDL_Display(), False);
+		XSync(LLWindowSDL::get_SDL_Display(), False);
 	}
 		break;
 	}
@@ -1959,17 +1962,14 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain)
 	return mGrabbyKeyFlags;
 }
 
-void LLWindowSDL::gatherInput()
+// virtual
+void LLWindowSDL::processMiscNativeEvents()
 {
-    const Uint32 CLICK_THRESHOLD = 300;  // milliseconds
-    static int leftClick = 0;
-    static int rightClick = 0;
-    static Uint32 lastLeftDown = 0;
-    static Uint32 lastRightDown = 0;
-    SDL_Event event;
-
-#if LL_GTK && LL_LLMOZLIB_ENABLED
-    // Pump GTK events so embedded Gecko doesn't starve.
+#if LL_GTK && (LL_LLMOZLIB_ENABLED || LL_DBUS_ENABLED)
+	// Pump GTK events to avoid starvation for:
+	// * Embedded Gecko
+	// * DBUS servicing
+	// * Anything else which quietly hooks into the default glib/GTK loop
     if (ll_try_gtk_init())
     {
 	    // Yuck, Mozilla's GTK callbacks play with the locale - push/pop
@@ -1992,7 +1992,17 @@ void LLWindowSDL::gatherInput()
 
 	    setlocale(LC_ALL, saved_locale.c_str() );
     }
-#endif // LL_GTK && LL_LLMOZLIB_ENABLED
+#endif // LL_GTK && (LL_LLMOZLIB_ENABLED || LL_DBUS_ENABLED)
+}
+
+void LLWindowSDL::gatherInput()
+{
+    const Uint32 CLICK_THRESHOLD = 300;  // milliseconds
+    static int leftClick = 0;
+    static int rightClick = 0;
+    static Uint32 lastLeftDown = 0;
+    static Uint32 lastRightDown = 0;
+    SDL_Event event;
 
     // Handle all outstanding SDL events
     while (SDL_PollEvent(&event))
@@ -2497,12 +2507,10 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ
 {
 	S32 rtn = OSBTN_CANCEL;
 
-	ll_try_gtk_init();
-
 	if(gWindowImplementation != NULL)
 		gWindowImplementation->beforeDialog();
 
-	if (ll_try_gtk_init()
+	if (LLWindowSDL::ll_try_gtk_init()
 	    // We can NOT expect to combine GTK and SDL's aggressive fullscreen
 	    && ((NULL==gWindowImplementation) || (!was_fullscreen))
 	    )
@@ -2754,7 +2762,7 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url)
 void *LLWindowSDL::getPlatformWindow()
 {
 #if LL_GTK && LL_LLMOZLIB_ENABLED
-	if (ll_try_gtk_init())
+	if (LLWindowSDL::ll_try_gtk_init())
 	{
 		maybe_lock_display();
 
diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h
index 6ac2a789ac4..091b0de1e0a 100644
--- a/indra/llwindow/llwindowsdl.h
+++ b/indra/llwindow/llwindowsdl.h
@@ -89,6 +89,7 @@ class LLWindowSDL : public LLWindow
 	/*virtual*/ void setFSAASamples(const U32 samples);
 	/*virtual*/ BOOL restoreGamma();			// Restore original gamma table (before updating gamma)
 	/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
+	/*virtual*/ void processMiscNativeEvents();
 	/*virtual*/ void gatherInput();
 	/*virtual*/ void swapBuffers();
 
@@ -129,6 +130,16 @@ class LLWindowSDL : public LLWindow
 	void (*Lock_Display)(void);
 	void (*Unlock_Display)(void);
 
+#if LL_GTK
+	// Lazily initialize and check the runtime GTK version for goodness.
+	static bool ll_try_gtk_init(void);
+#endif // LL_GTK
+
+#if LL_X11
+	static Window get_SDL_XWindowID(void);
+	static Display* get_SDL_Display(void);
+#endif // LL_X11	
+
 protected:
 	LLWindowSDL(
 		const std::string& title, int x, int y, int width, int height, U32 flags,
@@ -205,8 +216,6 @@ class LLWindowSDL : public LLWindow
 	BOOL mFlashing;
 	LLTimer mFlashTimer;
 #endif //LL_X11
-
-	
 };
 
 
@@ -223,16 +232,4 @@ class LLSplashScreenSDL : public LLSplashScreen
 
 S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type);
 
-void load_url_external(const char* url);
-
-#if LL_GTK
-// Lazily initialize and check the runtime GTK version for goodness.
-BOOL ll_try_gtk_init(void);
-#endif // LL_GTK
-
-#if LL_X11
-Window get_SDL_XWindowID(void);
-Display* get_SDL_Display(void);
-#endif // LL_X11
-
 #endif //LL_LLWINDOWSDL_H
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 8b97ef7da9b..78c4a71d3e7 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -5,6 +5,7 @@ project(viewer)
 include(00-Common)
 include(Boost)
 include(BuildVersion)
+include(DBusGlib)
 include(DirectX)
 include(ELFIO)
 include(FMOD)
@@ -874,6 +875,7 @@ endif (DARWIN)
 
 if (LINUX)
     LIST(APPEND viewer_SOURCE_FILES llappviewerlinux.cpp)
+    LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp)
     LIST(APPEND CMAKE_EXE_LINKER_FLAGS -Wl,--as-needed)
 
     set(viewer_LIBRARIES
@@ -1392,6 +1394,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${viewer_LIBRARIES}
     ${BOOST_PROGRAM_OPTIONS_LIBRARY}
     ${BOOST_REGEX_LIBRARY}
+    ${DBUSGLIB_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${FMODWRAPPER_LIBRARY}
     ${OPENGL_LIBRARIES}
diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini
index 3679c3882c2..0ab977d8e9b 100644
--- a/indra/newview/app_settings/keywords.ini
+++ b/indra/newview/app_settings/keywords.ini
@@ -332,11 +332,11 @@ REMOTE_DATA_REQUEST	Value of event_type in remote_event if XML-RPC request is re
 REMOTE_DATA_REPLY	Value of event_type in remote_event if XML-RPC reply is received
 
 
-PRIM_TYPE			Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE,:PRIM_TYPE_TORUS, or PRIM_TYPE_TUBE and their arguments
-PRIM_MATERIAL		Sets material to PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS,:PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC,:PRIM_MATERIAL_RUBBER, or PRIM_MATERIAL_LIGHT
+PRIM_TYPE			Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, or PRIM_TYPE_SCULPT and their arguments
+PRIM_MATERIAL		Followed by PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS, PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC, or PRIM_MATERIAL_RUBBER
 PRIM_PHYSICS		Sets physics to TRUE or FALSE
-PRIM_FLEXIBLE		Sets primitive flexibility to TRUE or FALSE
-PRIM_POINT_LIGHT	Sets light emission to TRUE or FALSE
+PRIM_FLEXIBLE		Followed by TRUE or FALSE, integer softness, float gravity, float friction, float wind, float tension, and vector force
+PRIM_POINT_LIGHT	Followed by TRUE or FALSE, vector color, float intensity, float radius, float falloff
 PRIM_TEMP_ON_REZ	Sets temporay on rez to TRUE or FALSE
 PRIM_PHANTOM		Sets phantom to TRUE or FALSE
 PRIM_CAST_SHADOWS	DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams.
@@ -357,7 +357,7 @@ PRIM_TYPE_SPHERE	Followed by integer hole shape, vector cut, float hollow, vecto
 PRIM_TYPE_TORUS		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
 PRIM_TYPE_TUBE		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
 PRIM_TYPE_RING		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
-PRIM_TYPE_SCULPT	Followed by a key or string texture uuid.
+PRIM_TYPE_SCULPT	Followed by a key/string texture uuid, and one of PRIM_SCULPT_TYPE_SPHERE, PRIM_SCULPT_TYPE_TORUS, PRIM_SCULPT_TYPE_PLANE, or PRIM_SCULPT_TYPE_CYLINDER
 
 PRIM_HOLE_DEFAULT	Sets hole type to match the prim type.
 PRIM_HOLE_SQUARE	Sets hole type to square.
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 19a06763744..36e4182e375 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4103,7 +4103,10 @@ void LLAgent::changeCameraToThirdPerson(BOOL animate)
 
 	if (mAvatarObject)
 	{
-		mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
+		if (!mAvatarObject->mIsSitting)
+		{
+			mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
+		}
 		mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
 		mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
 	}
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8ee21b61158..87467e6afa5 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -307,9 +307,6 @@ const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
 
 static std::string gSecondLife;
 static std::string gWindowTitle;
-#ifdef LL_WINDOWS
-	static char sWindowClass[] = "Second Life";
-#endif
 
 std::string gLoginPage;
 std::vector<std::string> gLoginURIs;
@@ -329,8 +326,7 @@ static void ui_audio_callback(const LLUUID& uuid)
 {
 	if (gAudiop)
 	{
-		F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
-		gAudiop->triggerSound(uuid, gAgent.getID(), volume);
+		gAudiop->triggerSound(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
 	}
 }
 
@@ -496,30 +492,17 @@ void LLAppViewer::initGridChoice()
 	}
 }
 
-bool send_url_to_other_instance(const std::string& url)
+//virtual
+bool LLAppViewer::initSLURLHandler()
 {
-#if LL_WINDOWS
-	wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
-	mbstowcs(window_class, sWindowClass, 255);
-	window_class[255] = 0;
-	// Use the class instead of the window name.
-	HWND other_window = FindWindow(window_class, NULL);
-
-	if (other_window != NULL)
-	{
-		lldebugs << "Found other window with the name '" << gWindowTitle << "'" << llendl;
-		COPYDATASTRUCT cds;
-		const S32 SLURL_MESSAGE_TYPE = 0;
-		cds.dwData = SLURL_MESSAGE_TYPE;
-		cds.cbData = url.length() + 1;
-		cds.lpData = (void*)url.c_str();
-
-		LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
-		lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
-				 << gWindowTitle << "' returned " << msg_result << llendl;
-		return true;
-	}
-#endif
+	// does nothing unless subclassed
+	return false;
+}
+
+//virtual
+bool LLAppViewer::sendURLToOtherInstance(const std::string& url)
+{
+	// does nothing unless subclassed
 	return false;
 }
 
@@ -715,6 +698,9 @@ bool LLAppViewer::init()
 	// Find partition serial number (Windows) or hardware serial (Mac)
 	mSerialNumber = generateSerialNumber();
 
+	// do any necessary set-up for accepting incoming SLURLs from apps
+	initSLURLHandler();
+
 	if(false == initHardwareTest())
 	{
 		// Early out from user choice.
@@ -888,6 +874,13 @@ bool LLAppViewer::mainLoop()
 		{
 			LLFastTimer t(LLFastTimer::FTM_FRAME);
 			
+			pingMainloopTimeout("Main:MiscNativeWindowEvents");
+			
+			{
+				LLFastTimer t2(LLFastTimer::FTM_MESSAGES);
+				gViewerWindow->mWindow->processMiscNativeEvents();
+			}
+			
 			pingMainloopTimeout("Main:GatherInput");
 			
 			{
@@ -1915,7 +1908,7 @@ bool LLAppViewer::initConfiguration()
 #endif
 	LLStringUtil::truncate(gWindowTitle, 255);
 
-	//RN: if we received a URL, hand it off to the existing instance
+	//RN: if we received a URL, hand it off to the existing instance.
 	// don't call anotherInstanceRunning() when doing URL handoff, as
 	// it relies on checking a marker file which will not work when running
 	// out of different directories
@@ -1930,7 +1923,7 @@ bool LLAppViewer::initConfiguration()
 	}
 	if (!slurl.empty())
 	{
-		if (send_url_to_other_instance(slurl))
+		if (sendURLToOtherInstance(slurl))
 		{
 			// successfully handed off URL to existing instance, exit
 			return false;
@@ -2419,24 +2412,23 @@ bool LLAppViewer::anotherInstanceRunning()
 		{
 			// Another instance is running. Skip the rest of these operations.
 			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
-			return TRUE;
+			return true;
 		}
 		if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
 		{
 			apr_file_close(fMarker);
 			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
-			return TRUE;
+			return true;
 		}
 		// No other instances; we'll lock this file now & delete on quit.
 		apr_file_close(fMarker);
 	}
 	LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
-	return FALSE;
+	return false;
 }
 
 void LLAppViewer::initMarkerFile()
 {
-
 	//First, check for the existence of other files.
 	//There are marker files for two different types of crashes
 	
@@ -2691,7 +2683,7 @@ bool LLAppViewer::initCache()
 	
 	// Init the texture cache
 	// Allocate 80% of the cache size for textures
-	BOOL read_only = mSecondInstance ? true : false;
+	BOOL read_only = mSecondInstance ? TRUE : FALSE;
 	const S32 MB = 1024*1024;
 	S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
 	const S64 MAX_CACHE_SIZE = 1024*MB;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 24157909731..a43fc56e51f 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -135,15 +135,18 @@ class LLAppViewer : public LLApp
 	void resumeMainloopTimeout(const std::string& state = "", F32 secs = -1.0f);
 	void pingMainloopTimeout(const std::string& state, F32 secs = -1.0f);
 
+
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
 	virtual bool initLogging(); // Initialize log files, logging system, return false on failure.
 	virtual void initConsole() {}; // Initialize OS level debugging console.
 	virtual bool initHardwareTest() { return true; } // A false result indicates the app should quit.
+	virtual bool initSLURLHandler();
+	virtual bool sendURLToOtherInstance(const std::string& url);
 
-    virtual bool initParseCommandLine(LLCommandLineParser& clp) 
+	virtual bool initParseCommandLine(LLCommandLineParser& clp) 
         { return true; } // Allow platforms to specify the command line args.
-	
+
 	virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this.
 
 
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index a40ee702c6e..3f6a30cf329 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -1,6 +1,6 @@
 /**
  * @file llappviewerlinux.cpp
- * @brief The LLAppViewerWin32 class definitions
+ * @brief The LLAppViewerLinux class definitions
  *
  * $LicenseInfo:firstyear=2007&license=viewergpl$
  * 
@@ -36,8 +36,10 @@
 #include "llcommandlineparser.h"
 
 #include "llmemtype.h"
+#include "llurldispatcher.h"		// SLURL from other app instance
 #include "llviewernetwork.h"
 #include "llviewercontrol.h"
+#include "llwindowsdl.h"
 #include "llmd5.h"
 #include "llfindlocale.h"
 
@@ -60,6 +62,17 @@
 # include "ELFIO/ELFIO.h"		// for better backtraces
 #endif
 
+#if LL_DBUS_ENABLED
+# include "llappviewerlinux_api_dbus.h"
+
+// regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h:
+#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
+#undef g_return_if_fail
+#define g_return_if_fail(COND) llg_return_if_fail(COND)
+// The generated API
+# include "llappviewerlinux_api.h"
+#endif
+
 namespace
 {
 	int gArgC = 0;
@@ -321,6 +334,186 @@ bool LLAppViewerLinux::init()
 	return LLAppViewer::init();
 }
 
+/////////////////////////////////////////
+#if LL_DBUS_ENABLED
+
+typedef struct
+{
+        GObjectClass parent_class;
+} ViewerAppAPIClass;
+
+static void viewerappapi_init(ViewerAppAPI *server);
+static void viewerappapi_class_init(ViewerAppAPIClass *klass);
+
+///
+
+// regrettable hacks to give us better runtime compatibility with older systems in general
+static GType llg_type_register_static_simple_ONCE(GType parent_type,
+						  const gchar *type_name,
+						  guint class_size,
+						  GClassInitFunc class_init,
+						  guint instance_size,
+						  GInstanceInitFunc instance_init,
+						  GTypeFlags flags)
+{
+	static GTypeInfo type_info;
+	memset(&type_info, 0, sizeof(type_info));
+
+	type_info.class_size = class_size;
+	type_info.class_init = class_init;
+	type_info.instance_size = instance_size;
+	type_info.instance_init = instance_init;
+
+	return g_type_register_static(parent_type, type_name, &type_info, flags);
+}
+#define llg_intern_static_string(S) (S)
+#define g_intern_static_string(S) llg_intern_static_string(S)
+#define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags)
+
+G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT);
+
+void viewerappapi_class_init(ViewerAppAPIClass *klass)
+{
+}
+
+static bool dbus_server_init = false;
+
+void viewerappapi_init(ViewerAppAPI *server)
+{
+	// Connect to the default DBUS, register our service/API.
+
+	if (!dbus_server_init)
+	{
+		GError *error = NULL;
+		
+		server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
+		if (server->connection)
+		{
+			lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info);
+			
+			lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server));
+			
+			DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+
+			guint request_name_ret_unused;
+			// akin to org_freedesktop_DBus_request_name
+			if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID))
+			{
+				// total success.
+				dbus_server_init = true;
+			}
+			else 
+			{
+				llwarns << "Unable to register service name: " << error->message << llendl;
+			}
+	
+			g_object_unref(serverproxy);
+		}
+		else
+		{
+			g_warning("Unable to connect to dbus: %s", error->message);
+		}
+
+		if (error)
+			g_error_free(error);
+	}
+}
+
+gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error)
+{
+	bool success = false;
+
+	llinfos << "Was asked to go to slurl: " << slurl << llendl;
+
+	const bool from_external_browser = true;
+	if (LLURLDispatcher::dispatch(slurl, from_external_browser))
+	{
+		// bring window to foreground, as it has just been "launched" from a URL
+		// todo: hmm, how to get there from here?
+		//xxx->mWindow->bringToFront();
+		success = true;
+	}		
+
+	*success_rtn = g_new (gboolean, 1);
+	(*success_rtn)[0] = (gboolean)success;
+
+	return TRUE; // the invokation succeeded, even if the actual dispatch didn't.
+}
+
+///
+
+//virtual
+bool LLAppViewerLinux::initSLURLHandler()
+{
+	if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
+	{
+		return false; // failed
+	}
+
+	g_type_init();
+
+	//ViewerAppAPI *api_server = (ViewerAppAPI*)
+	g_object_new(viewerappapi_get_type(), NULL);
+
+	return true;
+}
+
+//virtual
+bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
+{
+	if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
+	{
+		return false; // failed
+	}
+
+	bool success = false;
+	DBusGConnection *bus;
+	GError *error = NULL;
+
+	g_type_init();
+	
+	bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (bus)
+	{
+		gboolean rtn = FALSE;
+		DBusGProxy *remote_object =
+			lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE);
+
+		if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error,
+					G_TYPE_STRING, url.c_str(), G_TYPE_INVALID,
+				       G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID))
+		{
+			success = rtn;
+		}
+		else
+		{
+			llinfos << "Call-out to other instance failed (perhaps not running): " << error->message << llendl;
+		}
+
+		g_object_unref(G_OBJECT(remote_object));
+	}
+	else
+	{
+		llwarns << "Couldn't connect to session bus: " << error->message << llendl;
+	}
+
+	if (error)
+		g_error_free(error);
+	
+	return success;
+}
+
+#else // LL_DBUS_ENABLED
+bool LLAppViewerLinux::initSLURLHandler()
+{
+	return false; // not implemented without dbus
+}
+bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
+{
+	return false; // not implemented without dbus
+}
+#endif // LL_DBUS_ENABLED
+
 void LLAppViewerLinux::handleSyncCrashTrace()
 {
 	// This backtrace writes into stack_trace.log
diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h
index 300cb10e2d2..a0e48ea388b 100644
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -32,6 +32,14 @@
 #ifndef LL_LLAPPVIEWERLINUX_H
 #define LL_LLAPPVIEWERLINUX_H
 
+#if LL_DBUS_ENABLED
+extern "C" {
+# include <glib.h>
+# include <glib-object.h>
+# include <dbus/dbus-glib.h>
+}
+#endif
+
 #ifndef LL_LLAPPVIEWER_H
 #include "llappviewer.h"
 #endif
@@ -49,6 +57,7 @@ class LLAppViewerLinux : public LLAppViewer
 	//
 	virtual bool init();			// Override to do application initialization
 	std::string generateSerialNumber();
+	bool setupSLURLHandler();
 
 protected:
 	virtual bool beingDebugged();
@@ -58,6 +67,26 @@ class LLAppViewerLinux : public LLAppViewer
 
 	virtual bool initLogging();
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
+
+	virtual bool initSLURLHandler();
+	virtual bool sendURLToOtherInstance(const std::string& url);
 };
 
+#if LL_DBUS_ENABLED
+typedef struct
+{
+        GObject parent;
+        DBusGConnection *connection;
+} ViewerAppAPI;
+
+extern "C" {
+	gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error);
+}
+
+#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService"
+#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI"
+#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI"
+
+#endif // LL_DBUS_ENABLED
+
 #endif // LL_LLAPPVIEWERLINUX_H
diff --git a/indra/newview/llappviewerlinux_api.h b/indra/newview/llappviewerlinux_api.h
new file mode 100644
index 00000000000..f9c7c6df35f
--- /dev/null
+++ b/indra/newview/llappviewerlinux_api.h
@@ -0,0 +1,148 @@
+/* Generated by dbus-binding-tool; do not edit! */
+/**
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */ 
+
+#ifndef __dbus_glib_marshal_viewerapp_MARSHAL_H__
+#define __dbus_glib_marshal_viewerapp_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.5XXD8T:1) */
+extern void dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure     *closure,
+                                                                         GValue       *return_value,
+                                                                         guint         n_param_values,
+                                                                         const GValue *param_values,
+                                                                         gpointer      invocation_hint,
+                                                                         gpointer      marshal_data);
+void
+dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure     *closure,
+                                                             GValue       *return_value,
+                                                             guint         n_param_values,
+                                                             const GValue *param_values,
+                                                             gpointer      invocation_hint,
+                                                             gpointer      marshal_data)
+{
+  typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer     data1,
+                                                                    gpointer     arg_1,
+                                                                    gpointer     arg_2,
+                                                                    gpointer     arg_3,
+                                                                    gpointer     data2);
+  register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gboolean v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       g_marshal_value_peek_string (param_values + 1),
+                       g_marshal_value_peek_pointer (param_values + 2),
+                       g_marshal_value_peek_pointer (param_values + 3),
+                       data2);
+
+  g_value_set_boolean (return_value, v_return);
+}
+
+G_END_DECLS
+
+#endif /* __dbus_glib_marshal_viewerapp_MARSHAL_H__ */
+
+#include <dbus/dbus-glib.h>
+static const DBusGMethodInfo dbus_glib_viewerapp_methods[] = {
+  { (GCallback) viewer_app_api_GoSLURL, dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER, 0 },
+};
+
+const DBusGObjectInfo dbus_glib_viewerapp_object_info = {
+  0,
+  dbus_glib_viewerapp_methods,
+  1,
+"com.secondlife.ViewerAppAPI\0GoSLURL\0S\0slurl\0I\0s\0success_ret\0O\0F\0N\0b\0\0\0",
+"\0",
+"\0"
+};
+
diff --git a/indra/newview/llappviewerlinux_api.xml b/indra/newview/llappviewerlinux_api.xml
new file mode 100644
index 00000000000..fac35b7adc8
--- /dev/null
+++ b/indra/newview/llappviewerlinux_api.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- dbus-binding-tool -mode=glib-server llappviewerlinux_api.xml -prefix=viewerapp -output=llappviewerlinux_api.h -->
+
+<node name="/com/secondlife/ViewerAppAPI">
+  <interface name="com.secondlife.ViewerAppAPI">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api"/>
+    <method name="GoSLURL">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api_GoSLURL"/>
+      <arg type="s" name="slurl" direction="in" />
+      <arg type="b" name="success_ret" direction="out" />
+    </method>
+  </interface>
+</node>
diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp
new file mode 100644
index 00000000000..24dfea1c6a3
--- /dev/null
+++ b/indra/newview/llappviewerlinux_api_dbus.cpp
@@ -0,0 +1,131 @@
+/** 
+ * @file llappviewerlinux_api_dbus.cpp
+ * @brief dynamic DBus symbol-grabbing code
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#if LL_DBUS_ENABLED
+
+#include "linden_common.h"
+
+extern "C" {
+#include <dbus/dbus-glib.h>
+
+#include "apr_pools.h"
+#include "apr_dso.h"
+}
+
+#define DEBUGMSG(...) lldebugs << llformat(__VA_ARGS__) << llendl
+#define INFOMSG(...) llinfos << llformat(__VA_ARGS__) << llendl
+#define WARNMSG(...) llwarns << llformat(__VA_ARGS__) << llendl
+
+#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) RTN (*ll##DBUSSYM)(__VA_ARGS__) = NULL
+#include "llappviewerlinux_api_dbus_syms_raw.inc"
+#undef LL_DBUS_SYM
+
+static bool sSymsGrabbed = false;
+static apr_pool_t *sSymDBUSDSOMemoryPool = NULL;
+static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL;
+
+bool grab_dbus_syms(std::string dbus_dso_name)
+{
+	if (sSymsGrabbed)
+	{
+		// already have grabbed good syms
+		return TRUE;
+	}
+
+	bool sym_error = false;
+	bool rtn = false;
+	apr_status_t rv;
+	apr_dso_handle_t *sSymDBUSDSOHandle = NULL;
+
+#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0)
+
+	//attempt to load the shared library
+	apr_pool_create(&sSymDBUSDSOMemoryPool, NULL);
+  
+	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,
+					       dbus_dso_name.c_str(),
+					       sSymDBUSDSOMemoryPool) ))
+	{
+		INFOMSG("Found DSO: %s", dbus_dso_name.c_str());
+
+#include "llappviewerlinux_api_dbus_syms_raw.inc"
+      
+		if ( sSymDBUSDSOHandle )
+		{
+			sSymDBUSDSOHandleG = sSymDBUSDSOHandle;
+			sSymDBUSDSOHandle = NULL;
+		}
+      
+		rtn = !sym_error;
+	}
+	else
+	{
+		INFOMSG("Couldn't load DSO: %s", dbus_dso_name.c_str());
+		rtn = false; // failure
+	}
+
+	if (sym_error)
+	{
+		WARNMSG("Failed to find necessary symbols in DBUS-GLIB libraries.");
+	}
+#undef LL_DBUS_SYM
+
+	sSymsGrabbed = rtn;
+	return rtn;
+}
+
+
+void ungrab_dbus_syms()
+{ 
+	// should be safe to call regardless of whether we've
+	// actually grabbed syms.
+
+	if ( sSymDBUSDSOHandleG )
+	{
+		apr_dso_unload(sSymDBUSDSOHandleG);
+		sSymDBUSDSOHandleG = NULL;
+	}
+	
+	if ( sSymDBUSDSOMemoryPool )
+	{
+		apr_pool_destroy(sSymDBUSDSOMemoryPool);
+		sSymDBUSDSOMemoryPool = NULL;
+	}
+	
+	// NULL-out all of the symbols we'd grabbed
+#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0)
+#include "llappviewerlinux_api_dbus_syms_raw.inc"
+#undef LL_DBUS_SYM
+
+	sSymsGrabbed = false;
+}
+
+#endif // LL_DBUS_ENABLED
diff --git a/indra/newview/llappviewerlinux_api_dbus.h b/indra/newview/llappviewerlinux_api_dbus.h
new file mode 100644
index 00000000000..7afdb270b84
--- /dev/null
+++ b/indra/newview/llappviewerlinux_api_dbus.h
@@ -0,0 +1,49 @@
+/** 
+ * @file llappviewerlinux_api_dbus.h
+ * @brief DBus-glib symbol handling
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#if LL_DBUS_ENABLED
+
+extern "C" {
+#include <dbus/dbus-glib.h>
+}
+
+#define DBUSGLIB_DYLIB_DEFAULT_NAME "libdbus-glib-1.so.2"
+
+bool grab_dbus_syms(std::string dbus_dso_name);
+void ungrab_dbus_syms();
+
+#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) extern RTN (*ll##DBUSSYM)(__VA_ARGS__)
+#include "llappviewerlinux_api_dbus_syms_raw.inc"
+#undef LL_DBUS_SYM
+
+#endif // LL_DBUS_ENABLED
diff --git a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc b/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc
new file mode 100644
index 00000000000..c0548e2fba2
--- /dev/null
+++ b/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc
@@ -0,0 +1,9 @@
+
+// required symbols to grab
+LL_DBUS_SYM(true, dbus_g_bus_get, DBusGConnection*, DBusBusType, GError**);
+LL_DBUS_SYM(true, dbus_g_proxy_new_for_name, DBusGProxy*, DBusGConnection*, const char *, const char*, const char*);
+LL_DBUS_SYM(true, dbus_g_proxy_call, gboolean, DBusGProxy*, const char*, GError**, GType, ...);
+LL_DBUS_SYM(true, dbus_g_object_type_install_info, void, GType, const DBusGObjectInfo*);
+LL_DBUS_SYM(true, dbus_g_connection_register_g_object, void, DBusGConnection*, const char*, GObject*);
+
+// optional symbols to grab
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index bdffaeafb3b..06b2a467de8 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -64,7 +64,7 @@
 
 #include "llcommandlineparser.h"
 
-//*FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
+// *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
 // The lib was compiled under VS2005 - in VS2003 we need to remap assert
 #ifdef LL_DEBUG
 #ifdef LL_MSVC7 
@@ -77,6 +77,8 @@ extern "C" {
 #endif
 #endif
 
+const std::string LLAppViewerWin32::sWindowClass = "Second Life";
+
 LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
 {
     // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
@@ -478,6 +480,33 @@ void LLAppViewerWin32::handleCrashReporting()
 	}
 }
 
+//virtual
+bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
+{
+	wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
+	mbstowcs(window_class, sWindowClass.c_str(), 255);
+	window_class[255] = 0;
+	// Use the class instead of the window name.
+	HWND other_window = FindWindow(window_class, NULL);
+
+	if (other_window != NULL)
+	{
+		lldebugs << "Found other window with the name '" << getWindowTitle() << "'" << llendl;
+		COPYDATASTRUCT cds;
+		const S32 SLURL_MESSAGE_TYPE = 0;
+		cds.dwData = SLURL_MESSAGE_TYPE;
+		cds.cbData = url.length() + 1;
+		cds.lpData = (void*)url.c_str();
+
+		LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
+		lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
+				 << getWindowTitle() << "' returned " << msg_result << llendl;
+		return true;
+	}
+	return false;
+}
+
+
 std::string LLAppViewerWin32::generateSerialNumber()
 {
 	char serial_md5[MD5HEX_STR_SIZE];		// Flawfinder: ignore
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index d8a79a8b7a3..5f26a182630 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -56,8 +56,12 @@ class LLAppViewerWin32 : public LLAppViewer
 	virtual void handleCrashReporting(); 
 	virtual void handleSyncCrashTrace();
 
+	virtual bool sendURLToOtherInstance(const std::string& url);
+
 	std::string generateSerialNumber();
 
+	static const std::string sWindowClass;
+
 private:
 	void disableWinErrorReporting();
 
diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp
index b7f4820a594..3b340739d7d 100644
--- a/indra/newview/llaudiosourcevo.cpp
+++ b/indra/newview/llaudiosourcevo.cpp
@@ -39,7 +39,7 @@
 #include "llviewerparcelmgr.h"
 
 LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp)
-:	LLAudioSource(sound_id, owner_id, gain), 
+	:	LLAudioSource(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX), 
 	mObjectp(objectp), 
 	mActualGain(gain)
 {
diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp
index f9c8100cf58..ac07622e8f3 100644
--- a/indra/newview/llcommandlineparser.cpp
+++ b/indra/newview/llcommandlineparser.cpp
@@ -416,11 +416,6 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value,
                        const std::string& opt_name, 
                        LLControlGroup* ctrlGroup)
 {
-    if(value.size() > 1)
-    {
-        llwarns << "Ignoring extra tokens mapped to the setting: " << opt_name << "." << llendl; 
-    }
-    
     // *FIX: Do sematic conversion here.
     // LLSD (ImplString) Is no good for doing string to type conversion for...
     // booleans
@@ -457,7 +452,7 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value,
         default:
             {
                 // For the default types, let llsd do the conversion.
-                if(value.size() > 1)
+                if(value.size() > 1 && ctrl->isType(TYPE_LLSD))
                 {
                     // Assume its an array...
                     LLSD llsdArray;
@@ -472,6 +467,11 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value,
                 }
                 else if(value.size() > 0)
                 {
+					if(value.size() > 1)
+					{
+						llwarns << "Ignoring extra tokens mapped to the setting: " << opt_name << "." << llendl; 
+					}
+
                     LLSD llsdValue;
                     llsdValue.assign(LLSD::String(value[0]));
                     ctrl->setValue(llsdValue, false);
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 0f180472fd7..7ac50d76100 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -933,7 +933,7 @@ void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer
 
 GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context)
 {
-	if (ll_try_gtk_init() &&
+	if (LLWindowSDL::ll_try_gtk_init() &&
 	    ! gViewerWindow->getWindow()->getFullscreen())
 	{
 		GtkWidget *win = NULL;
@@ -974,7 +974,7 @@ GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::stri
 		// Make GTK tell the window manager to associate this
 		// dialog with our non-GTK raw X11 window, which should try
 		// to keep it on top etc.
-		Window XWindowID = get_SDL_XWindowID();
+		Window XWindowID = LLWindowSDL::get_SDL_XWindowID();
 		if (None != XWindowID)
 		{
 			gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 3d29bb32866..4b0afd6db32 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -774,7 +774,9 @@ LLImagePreviewSculpted::LLImagePreviewSculpted(S32 width, S32 height) : LLDynami
 	LLVolumeParams volume_params;
 	volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE);
 	volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_SPHERE);
-	mVolume = new LLVolume(volume_params, (F32) MAX_LOD);
+	
+	F32 const HIGHEST_LOD = 4.0f;
+	mVolume = new LLVolume(volume_params,  HIGHEST_LOD);
 
 	/*
 	mDummyAvatar = new LLVOAvatar(LLUUID::null, LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
@@ -811,7 +813,36 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
 	{
 		mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0);
 	}
-	
+
+	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
+	U32 num_indices = vf.mIndices.size();
+	U32 num_vertices = vf.mVertices.size();
+
+	mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0);
+	mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE);
+
+	LLStrider<LLVector3> vertex_strider;
+	LLStrider<LLVector3> normal_strider;
+	LLStrider<U16> index_strider;
+
+	mVertexBuffer->getVertexStrider(vertex_strider);
+	mVertexBuffer->getNormalStrider(normal_strider);
+	mVertexBuffer->getIndexStrider(index_strider);
+
+	// build vertices and normals
+	for (U32 i = 0; (S32)i < num_vertices; i++)
+	{
+		*(vertex_strider++) = vf.mVertices[i].mPosition;
+		LLVector3 normal = vf.mVertices[i].mNormal;
+		normal.normalize();
+		*(normal_strider++) = normal;
+	}
+
+	// build indices
+	for (U16 i = 0; i < num_indices; i++)
+	{
+		*(index_strider++) = vf.mIndices[i];
+	}
 }
 
 
@@ -846,7 +877,7 @@ BOOL LLImagePreviewSculpted::render()
 	glMatrixMode(GL_MODELVIEW);
 	gGL.popMatrix();
 
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glClear(GL_DEPTH_BUFFER_BIT);
 	
 	LLVector3 target_pos(0, 0, 0);
 
@@ -865,55 +896,21 @@ BOOL LLImagePreviewSculpted::render()
 	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
 	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE);
 
-	gPipeline.enableLightsAvatar();
-		
-	gGL.pushMatrix();
-	glScalef(0.5, 0.5, 0.5);
-	
 	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
 	U32 num_indices = vf.mIndices.size();
-	U32 num_vertices = vf.mVertices.size();
-
-	if (num_vertices > 0 && num_indices > 0)
-	{
-		glEnableClientState(GL_NORMAL_ARRAY);
-		// build vertices and normals
-		F32* vertices = new F32[num_vertices * 3];
-		F32* normals = new F32[num_vertices * 3];
-
-		for (U32 i = 0; (S32)i < num_vertices; i++)
-		{
-			LLVector3 position = vf.mVertices[i].mPosition;
-			vertices[i*3]   = position.mV[VX];
-			vertices[i*3+1] = position.mV[VY];
-			vertices[i*3+2] = position.mV[VZ];
-			
-			LLVector3 normal = vf.mVertices[i].mNormal;
-			normals[i*3]   = normal.mV[VX];
-			normals[i*3+1] = normal.mV[VY];
-			normals[i*3+2] = normal.mV[VZ];
-		}
+	
+	mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
 
-		// build indices
-		U16* indices = new U16[num_indices];
-		for (U16 i = 0; i < num_indices; i++)
-		{
-			indices[i] = vf.mIndices[i];
-		}
+	gPipeline.enableLightsAvatar();
+	gGL.pushMatrix();
+	const F32 SCALE = 1.25f;
+	gGL.scalef(SCALE, SCALE, SCALE);
+	const F32 BRIGHTNESS = 0.9f;
+	gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+	mVertexBuffer->draw(LLVertexBuffer::TRIANGLES, num_indices, 0);
 
-		gGL.color3f(0.4f, 0.4f, 0.4f);
-		glVertexPointer(3, GL_FLOAT, 0, (void *)vertices);
-		glNormalPointer(GL_FLOAT, 0, (void *)normals);
-		glDrawRangeElements(GL_TRIANGLES, 0, num_vertices-1, num_indices, GL_UNSIGNED_SHORT, (void *)indices);
+	gGL.popMatrix();
 		
-		gGL.popMatrix();
-		glDisableClientState(GL_NORMAL_ARRAY);
-
-		delete [] indices;
-		delete [] vertices;
-		delete [] normals;
-	}
-
 	return TRUE;
 }
 
diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h
index 0376ec2bcb2..045c8b98673 100644
--- a/indra/newview/llfloaterimagepreview.h
+++ b/indra/newview/llfloaterimagepreview.h
@@ -41,6 +41,7 @@ class LLJoint;
 class LLViewerJointMesh;
 class LLVOAvatar;
 class LLTextBox;
+class LLVertexBuffer;
 
 class LLImagePreviewSculpted : public LLDynamicTexture
 {
@@ -67,6 +68,7 @@ class LLImagePreviewSculpted : public LLDynamicTexture
 	F32			mCameraZoom;
 	LLVector3	mCameraOffset;
 	LLPointer<LLVolume> mVolume;
+	LLPointer<LLVertexBuffer> mVertexBuffer;
 };
 
 
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 32ccc761f8d..631b2caa91b 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -52,6 +52,7 @@
 #include "llfloaterdirectory.h"
 #include "llfloatergroupinfo.h"
 #include "lluictrlfactory.h"
+#include <boost/regex.hpp>
 
 
 const U32 MAX_CACHED_GROUPS = 10;
@@ -791,6 +792,20 @@ LLGroupMgrGroupData* LLGroupMgr::getGroupData(const LLUUID& id)
 	return NULL;
 }
 
+// Helper function for LLGroupMgr::processGroupMembersReply
+// This reformats date strings from MM/DD/YYYY to YYYY/MM/DD ( e.g. 1/27/2008 -> 2008/1/27 )
+// so that the sorter can sort by year before month before day.
+static void formatDateString(std::string &date_string)
+{
+	using namespace boost;
+	cmatch result;
+	const regex expression("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})");
+	if (regex_match(date_string.c_str(), result, expression))
+	{
+		date_string = result[3]+"/"+result[1]+"/"+result[2];
+	}
+}
+
 // static
 void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 {
@@ -840,6 +855,8 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 
 			if (member_id.notNull())
 			{
+				formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25
+				
 				//llinfos << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << llendl;
 				LLGroupMemberData* newdata = new LLGroupMemberData(member_id, 
 																	contribution, 
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 5311a594fbc..ccf63b32852 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -97,6 +97,26 @@ const char AGENT_SUFFIX[] = " (resident)";
 const char OBJECT_SUFFIX[] = " (object)";
 const char GROUP_SUFFIX[] = " (group)";
 
+
+LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)
+  : mID(id),
+	mName(name),
+	mType(type),
+	mFlags(flags)
+{
+	// muting is done by root objects only - try to find this objects root
+	LLViewerObject *objectp = gObjectList.findObject(mID);
+	if ((objectp) && (!objectp->isAvatar()))
+	{
+		LLViewerObject *parentp = (LLViewerObject *)objectp->getParent();
+		if (parentp)
+		{
+			mID = parentp->getID();
+		}
+	}
+}
+
+
 std::string LLMute::getDisplayName() const
 {
 	std::string name_with_suffix = mName;
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index c1b887b8773..5db5c41c4bc 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -60,8 +60,7 @@ class LLMute
 		flagAll				= 0x0000000F		// Mask of all currently defined flags
 	};
 	
-	LLMute(const LLUUID& id, const std::string& name = std::string(), EType type = BY_NAME, U32 flags = 0) 
-	: mID(id), mName(name), mType(type),mFlags(flags) { }
+	LLMute(const LLUUID& id, const std::string& name = std::string(), EType type = BY_NAME, U32 flags = 0);
 
 	// Returns name + suffix based on type
 	// For example:  "James Tester (resident)"
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 47948281ab2..4f559105f6d 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -642,7 +642,11 @@ void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &
 	LLVector3 local_pos;
 	local_pos.setVec( pos - mObjectImageCenterGlobal );
 
-	S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
+	// DEV-17370 - megaprims of size > 4096 cause lag.  (go figger.)
+	const F32 MAX_RADIUS = 256.0f;
+	F32 radius_clamped = llmin(radius_meters, MAX_RADIUS);
+	
+	S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM);
 	renderPoint( local_pos, color, diameter_pixels );
 }
 
diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp
index 3c23bf15aee..a9140e23e0e 100644
--- a/indra/newview/llpreviewsound.cpp
+++ b/indra/newview/llpreviewsound.cpp
@@ -106,7 +106,6 @@ void LLPreviewSound::auditionSound( void *userdata )
 	if(item && gAudiop)
 	{
 		LLVector3d lpos_global = gAgent.getPositionGlobal();
-		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX");
-		gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), volume, lpos_global);
+		gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
 	}
 }
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index eaf1b90be38..500dcfecbfb 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -743,6 +743,12 @@ bool idle_startup()
 		gLoginMenuBarView->setVisible( TRUE );
 		gLoginMenuBarView->setEnabled( TRUE );
 
+		// DEV-16927.  The following code removes errant keystrokes that happen while the window is being 
+		// first made visible.
+#ifdef _WIN32
+		MSG msg;
+		while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
+#endif
 		timeout.reset();
 		return FALSE;
 	}
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index 8806d1465aa..fa9c9063ff3 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -224,8 +224,8 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
 	// Play creation sound
 	if (gAudiop)
 	{
-		F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
-		gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), volume);
+		gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")),
+							   gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
 	}
 
 	gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index cefbed1353d..0d250d97f61 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -139,6 +139,14 @@ void audio_update_volume(bool force_update)
 		{
 			audio_update_wind(true);
 		}
+
+		// handle secondary gains
+		gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX,
+								  gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX"));
+		gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI,
+								  gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI"));
+		gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT,
+								  gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient"));
 	}
 
 	// Streaming Music
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 7681e98eae9..dfe4bd58bd4 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -323,13 +323,6 @@ void handle_talk_to(void *userdata);
 // Debug menu
 void show_permissions_control(void*);
 void toggle_build_options(void* user_data);
-#if 0 // Unused
-void handle_audio_status_1(void*);
-void handle_audio_status_2(void*);
-void handle_audio_status_3(void*);
-void handle_audio_status_4(void*);
-#endif
-void manage_landmarks(void*);
 void reload_ui(void*);
 void handle_agent_stop_moving(void*);
 void print_packets_lost(void*);
@@ -1757,6 +1750,24 @@ class LLViewCheckJoystickFlycam : public view_listener_t
 	}
 };
 
+class LLViewCommunicate : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+        if (LLFloaterChatterBox::getInstance()->getFloaterCount() == 0)
+		{
+			LLFloaterMyFriends::toggleInstance();
+		}
+		else
+		{
+			LLFloaterChatterBox::toggleInstance();
+		}
+		
+		return true;
+	}
+};
+
+
 void handle_toggle_flycam()
 {
 	LLViewerJoystick::getInstance()->toggleFlycam();
@@ -2975,63 +2986,16 @@ void show_permissions_control(void*)
 	floaterp->mPermissions->addPermissionsData("foo3", LLUUID::null, 0);
 }
 
-#if 0 // Unused (these just modify AudioInfoPage which is not used anywhere in the code
-void handle_audio_status_1(void*)
-{
-	S32 page = gSavedSettings.getS32("AudioInfoPage");
-	if (1 == page)
-	{
-		page = 0;
-	}
-	else
-	{
-		page = 1;
-	}
-	gSavedSettings.setS32("AudioInfoPage", page);	
-}
 
-void handle_audio_status_2(void*)
+class LLCreateLandmarkCallback : public LLInventoryCallback
 {
-	S32 page = gSavedSettings.getS32("AudioInfoPage");
-	if (2 == page)
-	{
-		page = 0;
-	}
-	else
-	{
-		page = 2;
-	}
-	gSavedSettings.setS32("AudioInfoPage", page);	
-}
-
-void handle_audio_status_3(void*)
-{
-	S32 page = gSavedSettings.getS32("AudioInfoPage");
-	if (3 == page)
-	{
-		page = 0;
-	}
-	else
-	{
-		page = 3;
-	}
-	gSavedSettings.setS32("AudioInfoPage", page);	
-}
-
-void handle_audio_status_4(void*)
-{
-	S32 page = gSavedSettings.getS32("AudioInfoPage");
-	if (4 == page)
-	{
-		page = 0;
-	}
-	else
+public:
+	/*virtual*/ void fire(const LLUUID& inv_item)
 	{
-		page = 4;
+		llinfos << "Created landmark with inventory id " << inv_item
+			<< llendl;
 	}
-	gSavedSettings.setS32("AudioInfoPage", page);	
-}
-#endif
+};
 
 void reload_ui(void *)
 {
@@ -4948,7 +4912,7 @@ class LLWorldCreateLandmark : public view_listener_t
 							  LLAssetType::AT_LANDMARK,
 							  LLInventoryType::IT_LANDMARK,
 							  NOT_WEARABLE, PERM_ALL, 
-							  NULL);
+							  new LLCreateLandmarkCallback);
 		return true;
 	}
 };
@@ -7682,6 +7646,7 @@ void initialize_menus()
 	addMenu(new LLViewMouselook(), "View.Mouselook");
 	addMenu(new LLViewBuildMode(), "View.BuildMode");
 	addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam");
+	addMenu(new LLViewCommunicate(), "View.Communicate");
 	addMenu(new LLViewResetView(), "View.ResetView");
 	addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter");
 	addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ce91678a361..e47ffe2d7f4 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -861,7 +861,8 @@ void open_offer(const std::vector<LLUUID>& items, const std::string& from_name)
 		}
 
 		if(gSavedSettings.getBOOL("ShowInInventory") &&
-			asset_type != LLAssetType::AT_CALLINGCARD)
+		   asset_type != LLAssetType::AT_CALLINGCARD &&
+		   item->getInventoryType() != LLInventoryType::IT_ATTACHMENT)
 		{
 			LLInventoryView::showAgentInventory(TRUE);
 		}
@@ -3306,8 +3307,7 @@ void process_sound_trigger(LLMessageSystem *msg, void **)
 		return;
 	}
 
-	F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (gain * gSavedSettings.getF32("AudioLevelSFX"));
-	gAudiop->triggerSound(sound_id, owner_id, volume, pos_global);
+	gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global);
 }
 
 void process_preload_sound(LLMessageSystem *msg, void **user_data)
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 461a21d51a4..cc031b43680 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2763,12 +2763,6 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent)
 
 BOOL LLViewerObject::updateLOD()
 {
-	// Update volume of looping sounds
-	if (mAudioSourcep && mAudioSourcep->isLoop())
-	{
-		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (mAudioGain * gSavedSettings.getF32("AudioLevelSFX"));
-		mAudioSourcep->setGain(volume);
-	}
 	return FALSE;
 }
 
@@ -4331,8 +4325,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow
 	{
 		BOOL queue = flags & LL_SOUND_FLAG_QUEUE;
 		mAudioGain = gain;
-		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : gain * gSavedSettings.getF32("AudioLevelSFX");
-		mAudioSourcep->setGain(volume);
+		mAudioSourcep->setGain(gain);
 		mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP);
 		mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER);
 		mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE);
@@ -4370,8 +4363,7 @@ void LLViewerObject::adjustAudioGain(const F32 gain)
 	if (mAudioSourcep)
 	{
 		mAudioGain = gain;
-		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : mAudioGain * gSavedSettings.getF32("AudioLevelSFX");
-		mAudioSourcep->setGain(volume);
+		mAudioSourcep->setGain(mAudioGain);
 	}
 }
 
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 0a11f79fd1f..aa5f5e0ae08 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -1402,8 +1402,7 @@ void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item )
 	const F32 SOUND_GAIN = 1.0f;
 	if(gAudiop)
 	{
-		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX"));
-		gAudiop->triggerSound(item->getAssetUUID(), gAgentID, volume, lpos_global);
+		gAudiop->triggerSound(item->getAssetUUID(), gAgentID, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
 	}
 	showCopyToInvDialog( item );
 }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1363a536cb1..8ff257ee778 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1260,6 +1260,7 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
 
 BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
 {
+	if (!activating) gAgent.changeCameraToDefault();
 	LLViewerJoystick::getInstance()->setNeedsReset(true);
 	return FALSE;
 }
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 0ccba521fa3..e67bdfe01fa 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3775,10 +3775,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 //							AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED,
 //							AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN );
 
-			F32 ambient_volume = gSavedSettings.getF32("AudioLevelAmbient");
-			F32 gain = gSavedSettings.getBOOL("MuteAmbient") 
-				? 0.f 
-				: (.50f * ambient_volume * ambient_volume);
+			const F32 STEP_VOLUME = 0.5f;
 			LLUUID& step_sound_id = getStepSound();
 
 			LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
@@ -3786,7 +3783,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 			if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
 				&& !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
 			{
-				gAudiop->triggerSound(step_sound_id, getID(), gain, foot_pos_global);
+				gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
 			}
 		}
 	}
@@ -4760,14 +4757,12 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL
 					// to support both spatialized and non-spatialized instances of the same sound
 					//if (mIsSelf)
 					//{
-					//  F32 volume = gain * gSavedSettings.getF32("AudioLevelUI")
-					//	gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), volume);
+					//	gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
 					//}
 					//else
 					{
 						LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping"));
-						F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX");
-						gAudiop->triggerSound(sound_id, getID(), volume, char_pos_global);
+						gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global);
 					}
 				}
 			}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 7dd9ab5e1e4..2bd18319469 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2665,6 +2665,18 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects, BOOL render
 	LLGLState::checkClientArrays();
 	U32 last_type = 0;
 	
+	// If we don't do this, we crash something on changing graphics settings
+	// from Medium -> Low, because we unload all the shaders and the 
+	// draw pools aren't aware.  I don't know if this has to be a separate
+	// loop before actual rendering. JC
+	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+	{
+		LLDrawPool *poolp = *iter;
+		if (poolp->isFacePool() && hasRenderType(poolp->getType()))
+		{
+			poolp->prerender();
+		}
+	}
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 	{
 		LLDrawPool *poolp = *iter;
diff --git a/install.xml b/install.xml
index c96474eb60f..bda2ff4afd9 100644
--- a/install.xml
+++ b/install.xml
@@ -206,6 +206,25 @@
           </map>
         </map>
       </map>
+      <key>dbusglib</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.</string>
+        <key>description</key>
+        <string>dbus/dbus-glib: headers only</string>
+        <key>license</key>
+        <string>AFL2.1</string>
+        <key>packages</key>
+        <map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>eb25444142d4102b0ce1b7ffaadb071e</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbusglib-linux-20080707.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>elfio</key>
       <map>
         <key>license</key>
@@ -1109,6 +1128,11 @@ anguage Infrstructure (CLI) international standard</string>
     </map>
     <key>licenses</key>
     <map>
+      <key>AFL2.1</key>
+      <map>
+        <key>url</key>
+        <string>http://opensource-definition.org/licenses/afl-2.1.html</string>
+      </map>
       <key>GL</key>
       <map>
         <key>url</key>
-- 
GitLab