diff --git a/.hgtags b/.hgtags
index 0a97b4b9a55f49c09389b36970b0c4a3d301ae19..5c4559b2327e9765b699abd8cd91aad12b3b43f6 100755
--- a/.hgtags
+++ b/.hgtags
@@ -510,3 +510,4 @@ d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
 27e3cf444c4cc645884960a61325a9ee0e9a2d0f 3.8.4-release
 e821ef17c6edea4a59997719d8ba416d8c16e143 3.8.5-release
 5a5bd148943bfb46cf2ff2ccf376c42dee93d19b 3.8.6-release
+ae3297cdd03ab14f19f3811acbc4acd3eb600336 4.0.0-release
diff --git a/BuildParams b/BuildParams
index aeea3b1246868b59c1a58f3b4d3ff6b6347b79c8..15fb56ec179964c7e0725115cd5cc0dfa041f436 100755
--- a/BuildParams
+++ b/BuildParams
@@ -70,12 +70,15 @@ additional_packages = ""
 # the viewer_channel_suffix is prefixed by a blank and then appended to the viewer_channel
 # for the package in a setting that overrides the compiled-in value
 ################################################################
-additional_packages = "EDU"
+## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City
+## additional_packages = "EDU"
 
 # The EDU package allows us to create a separate release channel whose expirations
 # are synchronized as much as possible with the academic year
-EDU_sourceid = ""
-EDU_viewer_channel_suffix = "edu"
+## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City
+## EDU_sourceid = ""
+## Removed 2015-07-02 (MAINT-5360) until we fix packaging step in Team City
+## EDU_viewer_channel_suffix = "edu"
 
 # Notifications - to configure email notices, add a setting like this:
 # <username>_<reponame>.email = <email-address>
diff --git a/autobuild.xml b/autobuild.xml
index 52d750f64d66a074096d58a75d02f2c428a3ac67..824bf4b6908a55a5c856d433346a3a9af1b6c479 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1517,16 +1517,18 @@
         <key>version</key>
         <string>0.0.1</string>
       </map>
-      <key>llphysicsextensions_source</key>
+      <key>llceflib</key>
       <map>
         <key>copyright</key>
-        <string>Copyright (c) 2010, Linden Research, Inc.</string>
+        <string>Copyright (c) 2014, Linden Research, Inc.</string>
+        <key>description</key>
+        <string>LLCefLib implements a headless web browser, rendering modern web content to a memory buffer and providing an API for injecting mouse and keyboard events. It uses the Chromium Embedded Framework (https://bitbucket.org/chromiumembedded/cef)</string>
         <key>license</key>
-        <string>internal</string>
+        <string>LGPL</string>
         <key>license_file</key>
-        <string>LICENSES/llphysicsextensions.txt</string>
+        <string>LICENSES/LICENSE-source.txt</string>
         <key>name</key>
-        <string>llphysicsextensions_source</string>
+        <string>llceflib</string>
         <key>platforms</key>
         <map>
           <key>darwin</key>
@@ -1534,44 +1536,34 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>468e88a527e610804c3eecf07f4ed70b</string>
+              <string>5a0f74f8e736d91d2c2c6cbc71db90bd</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/Darwin/installer/llphysicsextensions_source-1.0.298369-darwin-298369.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/309177/arch/Darwin/installer/llceflib-1.5.1.309177-darwin-309177.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
           </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>793964e49c935b414c4bdbb8a0d14ad1</string>
-              <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/Linux/installer/llphysicsextensions_source-1.0.298369-linux-298369.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
           <key>windows</key>
           <map>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>922aad5261aac150e5ce3c094e57f373</string>
+              <string>5ed007e503cd768681ba282fd6d7aa76</string>
+              <key>hash_algorithm</key>
+              <string>md5</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/CYGWIN/installer/llphysicsextensions_source-1.0.298369-windows-298369.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/309177/arch/CYGWIN/installer/llceflib-1.5.1.309177-windows-309177.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.0.298369</string>
+        <string>1.5.1.309177</string>
       </map>
-      <key>llphysicsextensions_stub</key>
+      <key>llphysicsextensions_source</key>
       <map>
         <key>copyright</key>
         <string>Copyright (c) 2010, Linden Research, Inc.</string>
@@ -1580,7 +1572,7 @@
         <key>license_file</key>
         <string>LICENSES/llphysicsextensions.txt</string>
         <key>name</key>
-        <string>llphysicsextensions_stub</string>
+        <string>llphysicsextensions_source</string>
         <key>platforms</key>
         <map>
           <key>darwin</key>
@@ -1588,11 +1580,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>1175977a191ffc936fd0ccca433c8278</string>
+              <string>468e88a527e610804c3eecf07f4ed70b</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Darwin/installer/llphysicsextensions_stub-1.0.298370-darwin-298370.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/Darwin/installer/llphysicsextensions_source-1.0.298369-darwin-298369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1602,9 +1594,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d13d7927692eab2d6a63e36166b72a8a</string>
+              <string>793964e49c935b414c4bdbb8a0d14ad1</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Linux/installer/llphysicsextensions_stub-1.0.298370-linux-298370.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/Linux/installer/llphysicsextensions_source-1.0.298369-linux-298369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1614,29 +1606,27 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9594f6fd79ee924fe675a4a23e30516e</string>
+              <string>922aad5261aac150e5ce3c094e57f373</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/CYGWIN/installer/llphysicsextensions_stub-1.0.298370-windows-298370.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llphysicsextensions-source_llphysicsextensions-update/rev/298369/arch/CYGWIN/installer/llphysicsextensions_source-1.0.298369-windows-298369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.0.298370</string>
+        <string>1.0.298369</string>
       </map>
-      <key>llqtwebkit</key>
+      <key>llphysicsextensions_stub</key>
       <map>
         <key>copyright</key>
-        <string>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</string>
-        <key>description</key>
-        <string>QT cross-platform application and UI framework.</string>
+        <string>Copyright (c) 2010, Linden Research, Inc.</string>
         <key>license</key>
-        <string>LGPL</string>
+        <string>internal</string>
         <key>license_file</key>
-        <string>LICENSES/llqtwebkit.txt</string>
+        <string>LICENSES/llphysicsextensions.txt</string>
         <key>name</key>
-        <string>llqtwebkit</string>
+        <string>llphysicsextensions_stub</string>
         <key>platforms</key>
         <map>
           <key>darwin</key>
@@ -1644,11 +1634,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3c2b6be4c78b2479c3fae612e1053d37</string>
+              <string>1175977a191ffc936fd0ccca433c8278</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/canonical_3p-llqtwebkit2/rev/295522/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20141015.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Darwin/installer/llphysicsextensions_stub-1.0.298370-darwin-298370.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1658,11 +1648,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d31358176b9ba8c676458cc061767c0b</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
+              <string>d13d7927692eab2d6a63e36166b72a8a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/canonical_3p-llqtwebkit2/rev/295522/arch/Linux/installer/llqtwebkit-4.7.1-linux-20141015.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Linux/installer/llphysicsextensions_stub-1.0.298370-linux-298370.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1672,18 +1660,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>bb4e8c8006c8a7aef6d3e3c36a8cebbf</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
+              <string>9594f6fd79ee924fe675a4a23e30516e</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/canonical_3p-llqtwebkit2/rev/295522/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20141015.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/CYGWIN/installer/llphysicsextensions_stub-1.0.298370-windows-298370.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
           </map>
         </map>
         <key>version</key>
-        <string>4.7.1</string>
+        <string>1.0.298370</string>
       </map>
       <key>mesa</key>
       <map>
@@ -2052,9 +2038,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3f8b52280cb1eff2d1acd0214bce1b16</string>
+              <string>78650a79bda6435e623a940ad425a593</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/quicktime_3p-update-quicktime/rev/296445/arch/CYGWIN/installer/quicktime-7.3-windows-296445.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/quicktime_3p-update-quicktime/rev/300073/arch/CYGWIN/installer/quicktime-7.3-windows-300073.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2063,62 +2049,6 @@
         <key>version</key>
         <string>7.3</string>
       </map>
-      <key>slplugins</key>
-      <map>
-        <key>copyright</key>
-        <string>Second Life Viewer Source Code - Copyright (C) 2010, Linden Research, Inc.</string>
-        <key>description</key>
-        <string>Second Life Viewer Plugins and launcher</string>
-        <key>license</key>
-        <string>LGPL</string>
-        <key>license_file</key>
-        <string>LICENSES/slplugins-license.txt</string>
-        <key>name</key>
-        <string>slplugins</string>
-        <key>platforms</key>
-        <map>
-          <key>darwin</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>f6bfb026572f03a4c8ac6b2b7d7eb0ae</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/slplugins_3p-update-slplugins/rev/298079/arch/Darwin/installer/slplugins-3.7.24.297623.298079-darwin-298079.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>darwin</string>
-          </map>
-          <key>linux</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>64b8a3bac95b5888a7ede3d7661a18b8</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/slplugins_3p-update-slplugins/rev/298079/arch/Linux/installer/slplugins-3.7.24.297623.298079-linux-298079.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>linux</string>
-          </map>
-          <key>windows</key>
-          <map>
-            <key>archive</key>
-            <map>
-              <key>hash</key>
-              <string>3a1ea3385303b78b0327c8cea929ef27</string>
-              <key>hash_algorithm</key>
-              <string>md5</string>
-              <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/slplugins_3p-update-slplugins/rev/298079/arch/CYGWIN/installer/slplugins-3.7.24.297623.298079-windows-298079.tar.bz2</string>
-            </map>
-            <key>name</key>
-            <string>windows</string>
-          </map>
-        </map>
-        <key>version</key>
-        <string>3.7.24.297623.298079</string>
-      </map>
       <key>slvoice</key>
       <map>
         <key>copyright</key>
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 10692402a566ea41902e742399c34a88b499c255..133c5ee265c6855bf0281c1bb9c47961cfa46f15 100755
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -57,12 +57,6 @@ add_subdirectory(${VIEWER_PREFIX}test)
 if (ENABLE_MEDIA_PLUGINS)
 # viewer media plugins
 add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
-
-  # llplugin testbed code (is this the right way to include it?)
-  if (LL_TESTS AND NOT LINUX)
-    add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
-    add_subdirectory(${VIEWER_PREFIX}test_apps/llfbconnecttest)
-  endif (LL_TESTS AND NOT LINUX)
 endif (ENABLE_MEDIA_PLUGINS)
 
 if (LINUX)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 1a3b6c511793283ae52122d6e9f1d4d021e6ebd5..86fc2dfff5d4fc06713e945e3b4356e4be106295 100755
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -166,6 +166,9 @@ if (LINUX)
       -pthread
       )
 
+  # force this platform to accept TOS via external browser
+  add_definitions(-DEXTERNAL_TOS)
+
   add_definitions(-DAPPID=secondlife)
   add_definitions(-fvisibility=hidden)
   # don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work.  Sigh!  The viewer doesn't need to catch SIGCHLD anyway.
diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..9cfb7d14c7994d06d1e0163b15e3e1a46b7b78d6
--- /dev/null
+++ b/indra/cmake/CEFPlugin.cmake
@@ -0,0 +1,40 @@
+# -*- cmake -*-
+include(Linking)
+include(Prebuilt)
+
+if (USESYSTEMLIBS)
+    set(CEFPLUGIN OFF CACHE BOOL
+        "CEFPLUGIN support for the llplugin/llmedia test apps.")
+else (USESYSTEMLIBS)
+    use_prebuilt_binary(llceflib)
+    set(CEFPLUGIN ON CACHE BOOL
+        "CEFPLUGIN support for the llplugin/llmedia test apps.")
+        set(CEF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/cef)
+endif (USESYSTEMLIBS)
+
+if (WINDOWS)
+    set(CEF_PLUGIN_LIBRARIES
+        libcef.lib
+        libcef_dll_wrapper.lib
+        llceflib.lib
+    )
+elseif (DARWIN)
+    FIND_LIBRARY(APPKIT_LIBRARY AppKit)
+    if (NOT APPKIT_LIBRARY)
+        message(FATAL_ERROR "AppKit not found")
+    endif()
+
+    FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE})
+    if (NOT CEF_LIBRARY)
+        message(FATAL_ERROR "CEF not found")
+    endif()
+
+    set(CEF_PLUGIN_LIBRARIES
+        ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a
+        ${ARCH_PREBUILT_DIRS_RELEASE}/libLLCefLib.a
+        ${APPKIT_LIBRARY}
+        ${CEF_LIBRARY}
+       )
+
+elseif (LINUX)
+endif (WINDOWS)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index cd7da5d6c1913e82ba6f982101067adb7789c268..4dd69649d03cef36064ade3de64826174fa92989 100755
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -14,6 +14,7 @@ set(cmake_SOURCE_FILES
     Boost.cmake
     BuildVersion.cmake
     CARes.cmake
+    CEFPlugin.cmake
     CMakeCopyIfDifferent.cmake
     ConfigurePkgConfig.cmake
     CURL.cmake
@@ -82,18 +83,18 @@ set(cmake_SOURCE_FILES
     LLXML.cmake
     LScript.cmake
     Linking.cmake
-##  MediaPluginBase.cmake
+    MediaPluginBase.cmake
     NDOF.cmake
     OPENAL.cmake
     OpenGL.cmake
     OpenJPEG.cmake
     OpenSSL.cmake
     PNG.cmake
-##  PluginAPI.cmake
+    PluginAPI.cmake
     Prebuilt.cmake
     PulseAudio.cmake
     Python.cmake
-##  QuickTimePlugin.cmake
+    QuickTimePlugin.cmake
     TemplateCheck.cmake
     Tut.cmake
     UI.cmake
@@ -102,7 +103,6 @@ set(cmake_SOURCE_FILES
     Variables.cmake
     ViewerMiscLibs.cmake
     VisualLeakDetector.cmake
-##  WebKitLibPlugin.cmake
     XmlRpcEpi.cmake
     ZLIB.cmake
     )
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index c95f0c3702db180e1e0b8bcf11f17750ef0a22ab..74fe3f11377d096bc3e57fdaba85360168cb9a65 100755
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -6,7 +6,7 @@ set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
 include(Variables)
 
 set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib)
-##set(ARCH_PREBUILT_DIRS_PLUGINS ${AUTOBUILD_INSTALL_DIR}/plugins)
+set(ARCH_PREBUILT_DIRS_PLUGINS ${AUTOBUILD_INSTALL_DIR}/plugins)
 set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release)
 set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug)
 if (WINDOWS)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 2fb47c58a7519968fe0496f077d253e5c11f9299..63e296b556d243085c40d2c4ceb59522a60b1d4b 100755
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -26,7 +26,7 @@ set(VIEWER_PREFIX)
 set(INTEGRATION_TESTS_PREFIX)
 set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation")
 set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
-set(ENABLE_MEDIA_PLUGINS OFF CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
+set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
 
 if(LIBS_CLOSED_DIR)
   file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)
diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake
deleted file mode 100755
index f7c548a2fda5381b77ef026e41e5086d59b46609..0000000000000000000000000000000000000000
--- a/indra/cmake/WebKitLibPlugin.cmake
+++ /dev/null
@@ -1,93 +0,0 @@
-# -*- cmake -*-
-include(Linking)
-include(Prebuilt)
-include(OpenSSL)
-
-if (USESYSTEMLIBS)
-  # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny.
-  find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED)
-  include(${QT_USE_FILE})
-  set(QTDIR $ENV{QTDIR})
-  if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
-    message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; "
-      "Qt is found by looking for qmake in your PATH. "
-      "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, "
-      "or unset QTDIR if the found Qt is correct.")
-    endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
-  find_package(LLQtWebkit REQUIRED QUIET)
-  # Add the plugins.
-  set(QT_PLUGIN_LIBRARIES)
-  foreach(qlibname qgif qjpeg)
-    find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH)
-    if (QT_PLUGIN_${qlibname})
-      list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}})
-    else (QT_PLUGIN_${qtlibname})
-      message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!")
-    endif (QT_PLUGIN_${qlibname})
-  endforeach(qlibname)
-  # qjpeg depends on libjpeg
-  list(APPEND QT_PLUGIN_LIBRARIES jpeg)
-    set(WEBKITLIBPLUGIN OFF CACHE BOOL
-        "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
-else (USESYSTEMLIBS)
-    use_prebuilt_binary(llqtwebkit)
-    set(WEBKITLIBPLUGIN ON CACHE BOOL
-        "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
-endif (USESYSTEMLIBS)
-
-if (WINDOWS)
-    set(WEBKIT_PLUGIN_LIBRARIES 
-        debug llqtwebkitd
-        debug QtWebKitd4
-        debug QtOpenGLd4
-        debug QtNetworkd4
-        debug QtGuid4
-        debug QtCored4
-        debug qtmaind
-        optimized llqtwebkit
-        optimized QtWebKit4
-        optimized QtOpenGL4
-        optimized QtNetwork4
-        optimized QtGui4
-        optimized QtCore4
-        optimized qtmain
-    )
-elseif (DARWIN)
-    set(WEBKIT_PLUGIN_LIBRARIES
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.a
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libQtWebKit.4.dylib
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libQtOpenGL.4.dylib
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libQtNetwork.4.dylib
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libQtGui.4.dylib
-        ${ARCH_PREBUILT_DIRS_RELEASE}/libQtCore.4.dylib
-       )
-elseif (LINUX)
-    # *HUH:  What does this do?
-    set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES})
-    set(WEBKIT_PLUGIN_LIBRARIES
-        llqtwebkit
-#        qico
-#        qpng
-#        qtiff
-#        qsvg
-#        QtSvg
-        QtWebKit
-        QtOpenGL
-        QtNetwork
-        ${OPENSSL_LIBRARIES}
-        QtGui
-        QtCore
-#        jscore
-#        qgif
-#        qjpeg
-#        jpeg
-        fontconfig
-        X11
-        Xrender
-        GL
-
-#        sqlite3
-#        Xi
-#        SM
-        )
-endif (WINDOWS)
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 1d85aa297802ea473d49bca683dd805b5e6552ca..62bd09471a308a441933d168ac4140e1fcfd6cd3 100755
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -512,11 +512,7 @@ def copy_action(self, src, dst):
             # ensure that destination path exists
             self.cmakedirs(os.path.dirname(dst))
             self.created_paths.append(dst)
-            if not os.path.isdir(src):
-                self.ccopy(src,dst)
-            else:
-                # src is a dir
-                self.ccopytree(src,dst)
+            self.ccopymumble(src, dst)
         else:
             print "Doesn't exist:", src
 
@@ -595,28 +591,38 @@ def remove(self, *paths):
                 else:
                     os.remove(path)
 
-    def ccopy(self, src, dst):
-        """ Copy a single file or symlink.  Uses filecmp to skip copying for existing files."""
+    def ccopymumble(self, src, dst):
+        """Copy a single symlink, file or directory."""
         if os.path.islink(src):
             linkto = os.readlink(src)
-            if os.path.islink(dst) or os.path.exists(dst):
+            if os.path.islink(dst) or os.path.isfile(dst):
                 os.remove(dst)  # because symlinking over an existing link fails
+            elif os.path.isdir(dst):
+                shutil.rmtree(dst)
             os.symlink(linkto, dst)
+        elif os.path.isdir(src):
+            self.ccopytree(src, dst)
         else:
-            # Don't recopy file if it's up-to-date.
-            # If we seem to be not not overwriting files that have been
-            # updated, set the last arg to False, but it will take longer.
-            if os.path.exists(dst) and filecmp.cmp(src, dst, True):
-                return
-            # only copy if it's not excluded
-            if self.includes(src, dst):
-                try:
-                    os.unlink(dst)
-                except OSError, err:
-                    if err.errno != errno.ENOENT:
-                        raise
-
-                shutil.copy2(src, dst)
+            self.ccopyfile(src, dst)
+            # XXX What about devices, sockets etc.?
+            # YYY would we put such things into a viewer package?!
+
+    def ccopyfile(self, src, dst):
+        """ Copy a single file.  Uses filecmp to skip copying for existing files."""
+        # Don't recopy file if it's up-to-date.
+        # If we seem to be not not overwriting files that have been
+        # updated, set the last arg to False, but it will take longer.
+        if os.path.exists(dst) and filecmp.cmp(src, dst, True):
+            return
+        # only copy if it's not excluded
+        if self.includes(src, dst):
+            try:
+                os.unlink(dst)
+            except OSError, err:
+                if err.errno != errno.ENOENT:
+                    raise
+
+            shutil.copy2(src, dst)
 
     def ccopytree(self, src, dst):
         """Direct copy of shutil.copytree with the additional
@@ -632,11 +638,7 @@ def ccopytree(self, src, dst):
             srcname = os.path.join(src, name)
             dstname = os.path.join(dst, name)
             try:
-                if os.path.isdir(srcname):
-                    self.ccopytree(srcname, dstname)
-                else:
-                    self.ccopy(srcname, dstname)
-                    # XXX What about devices, sockets etc.?
+                self.ccopymumble(srcname, dstname)
             except (IOError, os.error), why:
                 errors.append((srcname, dstname, why))
         if errors:
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 73df47b933f91db8f06d44ad450feb59025535f1..7e9ae8d108196166b832d77619647e2df8edc694 100755
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -178,6 +178,11 @@ void LLCurl::Responder::setURL(const std::string& url)
 	mURL = url;
 }
 
+const std::string& LLCurl::Responder::getURL()
+{
+	return mURL;
+}
+
 void LLCurl::Responder::successResult(const LLSD& content)
 {
 	setResult(HTTP_OK, "", content);
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 385d9fffa8990beb1f07dad83e994eb2ccd53b7d..34758433c881ca69835deec4dc79b6bd59c88c8c 100755
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -147,6 +147,7 @@ class LLCurl
 	public:
 		void setHTTPMethod(EHTTPMethod method);
 		void setURL(const std::string& url);
+		const std::string& getURL();
 		void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
 		void setResponseHeader(const std::string& header, const std::string& value);
 
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index 05fc12e3380c2b0f63033c00b563f384595c20d3..8c4ddd524e8324aea7efb2e12fed502de0f90e4a 100755
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -20,7 +20,6 @@ include_directories(
     ${LLRENDER_INCLUDE_DIRS}
     ${LLXML_INCLUDE_DIRS}
     ${LLWINDOW_INCLUDE_DIRS}
-    ${LLQTWEBKIT_INCLUDE_DIR}
     )
 include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -68,7 +67,7 @@ list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})
 
 add_library (llplugin ${llplugin_SOURCE_FILES})
 
-##add_subdirectory(slplugin)
+add_subdirectory(slplugin)
 
 # Add tests
 if (LL_TESTS)
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 4bfd0de81ee9e9f2787166cac086e0303832f7f9..3d173d04595366dae7bf1db1479be02a23eb7a4a 100755
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,4 +1,4 @@
-/** 
+/**
  * @file llpluginclassmedia.cpp
  * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
  *
@@ -6,21 +6,21 @@
  * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  * @endcond
@@ -41,14 +41,13 @@ static int nextPowerOf2( int value )
 	{
 		next_power_of_2 <<= 1;
 	}
-	
+
 	return next_power_of_2;
 }
 
 LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
 {
 	mOwner = owner;
-	mPlugin = NULL;
 	reset();
 
 	//debug use
@@ -63,19 +62,19 @@ LLPluginClassMedia::~LLPluginClassMedia()
 }
 
 bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
-{	
+{
 	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
 	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
 	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-	
-	mPlugin = new LLPluginProcessParent(this);
+
+	mPlugin = LLPluginProcessParent::create(this);
 	mPlugin->setSleepTime(mSleepTime);
-	
+
 	// Queue up the media init message -- it will be sent after all the currently queued messages.
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
 	message.setValue("target", mTarget);
 	sendMessage(message);
-	
+
 	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
 
 	return true;
@@ -84,10 +83,10 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
 
 void LLPluginClassMedia::reset()
 {
-	if(mPlugin != NULL)
+	if(mPlugin)
 	{
-		delete mPlugin;
-		mPlugin = NULL;
+        mPlugin->requestShutdown();
+        mPlugin.reset();
 	}
 
 	mTextureParamsReceived = false;
@@ -115,7 +114,7 @@ void LLPluginClassMedia::reset()
 	mTextureHeight = 0;
 	mMediaWidth = 0;
 	mMediaHeight = 0;
-	mDirtyRect = LLRect::null;	
+	mDirtyRect = LLRect::null;
 	mAutoScaleMedia = false;
 	mRequestedVolume = 1.0f;
 	mPriority = PRIORITY_NORMAL;
@@ -132,7 +131,7 @@ void LLPluginClassMedia::reset()
 	mMediaName.clear();
 	mMediaDescription.clear();
 	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
-	
+
 	// media_browser class
 	mNavigateURI.clear();
 	mNavigateResultCode = -1;
@@ -140,7 +139,7 @@ void LLPluginClassMedia::reset()
 	mHistoryBackAvailable = false;
 	mHistoryForwardAvailable = false;
 	mStatusText.clear();
-	mProgressPercent = 0;	
+	mProgressPercent = 0;
 	mClickURL.clear();
 	mClickNavType.clear();
 	mClickTarget.clear();
@@ -148,7 +147,7 @@ void LLPluginClassMedia::reset()
 	mStatusCode = 0;
 
 	mClickEnforceTarget = false;
-	
+
 	// media_time class
 	mCurrentTime = 0.0f;
 	mDuration = 0.0f;
@@ -162,7 +161,7 @@ void LLPluginClassMedia::idle(void)
 	{
 		mPlugin->idle();
 	}
-	
+
 	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
 	{
 		// Can't process a size change at this time
@@ -179,7 +178,7 @@ void LLPluginClassMedia::idle(void)
 		else
 		{
 			mRequestedTextureWidth = mRequestedMediaWidth;
-			
+
 			if(mPadding > 1)
 			{
 				// Pad up to a multiple of the specified number of bytes per row
@@ -189,7 +188,7 @@ void LLPluginClassMedia::idle(void)
 				{
 					rowbytes += mPadding - pad;
 				}
-				
+
 				if(rowbytes % mRequestedTextureDepth == 0)
 				{
 					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
@@ -201,7 +200,7 @@ void LLPluginClassMedia::idle(void)
 			}
 		}
 
-		
+
 		// Size change has been requested but not initiated yet.
 		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
 
@@ -216,22 +215,22 @@ void LLPluginClassMedia::idle(void)
 				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
 				mTextureSharedMemoryName.clear();
 			}
-			
+
 			mTextureSharedMemorySize = newsize;
 			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
 			if(!mTextureSharedMemoryName.empty())
 			{
 				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-				
+
 				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
 				memset( addr, 0x00, newsize );
-				
+
 				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
 				// so it may not be worthwhile.
 				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
 			}
 		}
-		
+
 		// This is our local indicator that a change is in progress.
 		mTextureWidth = -1;
 		mTextureHeight = -1;
@@ -240,7 +239,7 @@ void LLPluginClassMedia::idle(void)
 
 		// This invalidates any existing dirty rect.
 		resetDirty();
-		
+
 		// Send a size change message to the plugin
 		{
 			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
@@ -254,11 +253,11 @@ void LLPluginClassMedia::idle(void)
 			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
 			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
 			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
-			
+
 			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
 		}
 	}
-	
+
 	if(mPlugin && mPlugin->isRunning())
 	{
 		// Send queued messages
@@ -324,11 +323,11 @@ void LLPluginClassMedia::setSizeInternal(void)
 		mRequestedMediaWidth = mDefaultMediaWidth;
 		mRequestedMediaHeight = mDefaultMediaHeight;
 	}
-	
+
 	// Save these for size/interest calculations
 	mFullMediaWidth = mRequestedMediaWidth;
 	mFullMediaHeight = mRequestedMediaHeight;
-	
+
 	if(mAllowDownsample)
 	{
 		switch(mPriority)
@@ -342,19 +341,19 @@ void LLPluginClassMedia::setSizeInternal(void)
 					mRequestedMediaHeight /= 2;
 				}
 			break;
-			
+
 			default:
 				// Don't adjust texture size
 			break;
 		}
 	}
-	
+
 	if(mAutoScaleMedia)
 	{
 		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
 		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
 	}
-	
+
 	if(mRequestedMediaWidth > 2048)
 		mRequestedMediaWidth = 2048;
 
@@ -382,9 +381,9 @@ bool LLPluginClassMedia::textureValid(void)
 		mRequestedMediaWidth != mMediaWidth ||
 		mRequestedMediaHeight != mMediaHeight ||
 		getBitsData() == NULL
-	)	
+	)
 		return false;
-	
+
 	return true;
 }
 
@@ -408,8 +407,8 @@ void LLPluginClassMedia::resetDirty(void)
 std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 {
 	std::string result;
-	
-	
+
+
 	if(modifiers & MASK_CONTROL)
 	{
 		result += "control|";
@@ -432,7 +431,7 @@ std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 	{
 		result += "meta|";
 	}
-*/	
+*/
 	return result;
 }
 
@@ -540,11 +539,11 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
 			// Don't spam unnecessary mouse move events.
 			return;
 		}
-		
+
 		mLastMouseX = x;
 		mLastMouseY = y;
 	}
-	
+
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
 	std::string temp;
 	switch(type)
@@ -559,7 +558,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
 	message.setValueS32("button", button);
 
 	message.setValueS32("x", x);
-	
+
 	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
 	if(!mRequestedTextureCoordsOpenGL)
 	{
@@ -569,42 +568,42 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
 	message.setValueS32("y", y);
 
 	message.setValue("modifiers", translateModifiers(modifiers));
-	
+
 	sendMessage(message);
 }
 
 bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
 {
 	bool result = true;
-	
+
 	// FIXME:
 	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
 	// For now, return false for the ones the webkit plugin won't handle properly.
-	
+
 	switch(key_code)
 	{
-		case KEY_BACKSPACE:		
-		case KEY_TAB:			
-		case KEY_RETURN:		
-		case KEY_PAD_RETURN:	
-		case KEY_SHIFT:			
-		case KEY_CONTROL:		
-		case KEY_ALT:			
-		case KEY_CAPSLOCK:		
-		case KEY_ESCAPE:		
-		case KEY_PAGE_UP:		
-		case KEY_PAGE_DOWN:		
-		case KEY_END:			
-		case KEY_HOME:			
-		case KEY_LEFT:			
-		case KEY_UP:			
-		case KEY_RIGHT:			
-		case KEY_DOWN:			
-		case KEY_INSERT:		
+		case KEY_BACKSPACE:
+		case KEY_TAB:
+		case KEY_RETURN:
+		case KEY_PAD_RETURN:
+		case KEY_SHIFT:
+		case KEY_CONTROL:
+		case KEY_ALT:
+		case KEY_CAPSLOCK:
+		case KEY_ESCAPE:
+		case KEY_PAGE_UP:
+		case KEY_PAGE_DOWN:
+		case KEY_END:
+		case KEY_HOME:
+		case KEY_LEFT:
+		case KEY_UP:
+		case KEY_RIGHT:
+		case KEY_DOWN:
+		case KEY_INSERT:
 		case KEY_DELETE:
-			// These will be handled		
+			// These will be handled
 		break;
-		
+
 		default:
 			// regular ASCII characters will also be handled
 			if(key_code >= KEY_SPECIAL)
@@ -615,7 +614,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
 		break;
 	}
 
-#if LL_DARWIN	
+#if LL_DARWIN
 	if(modifiers & MASK_ALT)
 	{
 		// Option-key modified characters should be handled by the unicode input path instead of this one.
@@ -634,15 +633,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
 			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
 		}
 		message.setValue("event", temp);
-		
+
 		message.setValueS32("key", key_code);
 
 		message.setValue("modifiers", translateModifiers(modifiers));
 		message.setValueLLSD("native_key_data", native_key_data);
-		
+
 		sendMessage(message);
 	}
-		
+
 	return result;
 }
 
@@ -653,10 +652,10 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
 	message.setValueS32("x", x);
 	message.setValueS32("y", y);
 	message.setValue("modifiers", translateModifiers(modifiers));
-	
+
 	sendMessage(message);
 }
-	
+
 bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
@@ -664,18 +663,33 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
 	message.setValue("text", text);
 	message.setValue("modifiers", translateModifiers(modifiers));
 	message.setValueLLSD("native_key_data", native_key_data);
-	
+
 	sendMessage(message);
-	
+
 	return true;
 }
 
+void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie");
+
+	message.setValue("uri", uri);
+	message.setValue("name", name);
+	message.setValue("value", value);
+	message.setValue("domain", domain);
+	message.setValue("path", path);
+	message.setValueBoolean("httponly", httponly);
+	message.setValueBoolean("secure", secure);
+
+	sendMessage(message);
+}
+
 void LLPluginClassMedia::loadURI(const std::string &uri)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
 
 	message.setValue("uri", uri);
-	
+
 	sendMessage(message);
 }
 
@@ -692,7 +706,7 @@ const char* LLPluginClassMedia::priorityToString(EPriority priority)
 		case PRIORITY_NORMAL:		result = "normal";		break;
 		case PRIORITY_HIGH:			result = "high";		break;
 	}
-	
+
 	return result;
 }
 
@@ -703,44 +717,44 @@ void LLPluginClassMedia::setPriority(EPriority priority)
 		mPriority = priority;
 
 		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
-		
+
 		std::string priority_string = priorityToString(priority);
 		switch(priority)
 		{
-			case PRIORITY_UNLOADED:	
+			case PRIORITY_UNLOADED:
 				mSleepTime = 1.0f;
 			break;
-			case PRIORITY_STOPPED:	
+			case PRIORITY_STOPPED:
 				mSleepTime = 1.0f;
 			break;
-			case PRIORITY_HIDDEN:	
+			case PRIORITY_HIDDEN:
 				mSleepTime = 1.0f;
 			break;
 			case PRIORITY_SLIDESHOW:
 				mSleepTime = 1.0f;
 			break;
-			case PRIORITY_LOW:		
+			case PRIORITY_LOW:
 				mSleepTime = 1.0f / 25.0f;
 			break;
-			case PRIORITY_NORMAL:	
+			case PRIORITY_NORMAL:
 				mSleepTime = 1.0f / 50.0f;
 			break;
-			case PRIORITY_HIGH:		
+			case PRIORITY_HIGH:
 				mSleepTime = 1.0f / 100.0f;
 			break;
 		}
-		
+
 		message.setValue("priority", priority_string);
 
 		sendMessage(message);
-		
+
 		if(mPlugin)
 		{
 			mPlugin->setSleepTime(mSleepTime);
 		}
-		
+
 		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
-		
+
 		// This may affect the calculated size, so recalculate it here.
 		setSizeInternal();
 	}
@@ -761,12 +775,12 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
 F64 LLPluginClassMedia::getCPUUsage()
 {
 	F64 result = 0.0f;
-	
+
 	if(mPlugin)
 	{
 		result = mPlugin->getCPUUsage();
 	}
-	
+
 	return result;
 }
 
@@ -814,10 +828,11 @@ void LLPluginClassMedia::paste()
 	sendMessage(message);
 }
 
-void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
-	message.setValue("path", user_data_path);
+	message.setValue("cache_path", user_data_path_cache);
+	message.setValue("cookies_path", user_data_path_cookies);
 	sendMessage(message);
 }
 
@@ -830,14 +845,14 @@ void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
 
 void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
 {
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled");
 	message.setValueBoolean("enable", enabled);
 	sendMessage(message);
 }
 
 void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
 {
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled");
 	message.setValueBoolean("enable", enabled);
 	sendMessage(message);
 }
@@ -855,11 +870,11 @@ void LLPluginClassMedia::setTarget(const std::string &target)
 	mTarget = target;
 }
 
-/* virtual */ 
+/* virtual */
 void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 {
 	std::string message_class = message.getClass();
-	
+
 	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 	{
 		std::string message_name = message.getName();
@@ -870,21 +885,21 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			mRequestedTextureFormat = message.getValueU32("format");
 			mRequestedTextureType = message.getValueU32("type");
 			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
-			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
-			
+			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
+
 			// These two are optional, and will default to 0 if they're not specified.
 			mDefaultMediaWidth = message.getValueS32("default_width");
 			mDefaultMediaHeight = message.getValueS32("default_height");
-			
+
 			mAllowDownsample = message.getValueBoolean("allow_downsample");
 			mPadding = message.getValueS32("padding");
 
 			setSizeInternal();
-			
+
 			mTextureParamsReceived = true;
 		}
 		else if(message_name == "updated")
-		{			
+		{
 			if(message.hasValue("left"))
 			{
 				LLRect newDirtyRect;
@@ -892,7 +907,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				newDirtyRect.mTop = message.getValueS32("top");
 				newDirtyRect.mRight = message.getValueS32("right");
 				newDirtyRect.mBottom = message.getValueS32("bottom");
-							
+
 				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
 				// If they're backwards, swap them.
 				if(newDirtyRect.mTop < newDirtyRect.mBottom)
@@ -901,7 +916,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 					newDirtyRect.mTop = newDirtyRect.mBottom;
 					newDirtyRect.mBottom = temp;
 				}
-				
+
 				if(mDirtyRect.isEmpty())
 				{
 					mDirtyRect = newDirtyRect;
@@ -911,7 +926,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 					mDirtyRect.unionWith(newDirtyRect);
 				}
 
-				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
+				LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("
 					<< newDirtyRect.mLeft << ", "
 					<< newDirtyRect.mTop << ", "
 					<< newDirtyRect.mRight << ", "
@@ -921,10 +936,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 					<< mDirtyRect.mRight << ", "
 					<< mDirtyRect.mBottom << ")"
 					<< LL_ENDL;
-				
+
 				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
-			}			
-			
+			}
+
 
 			bool time_duration_updated = false;
 			int previous_percent = mProgressPercent;
@@ -944,7 +959,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			{
 				mCurrentRate = message.getValueReal("current_rate");
 			}
-			
+
 			if(message.hasValue("loaded_duration"))
 			{
 				mLoadedDuration = message.getValueReal("loaded_duration");
@@ -955,7 +970,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
 				mLoadedDuration = mDuration;
 			}
-			
+
 			// Calculate a percentage based on the loaded duration and total duration.
 			if(mDuration != 0.0f)	// Don't divide by zero.
 			{
@@ -966,7 +981,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			{
 				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 			}
-			
+
 			if(previous_percent != mProgressPercent)
 			{
 				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
@@ -975,9 +990,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 		else if(message_name == "media_status")
 		{
 			std::string status = message.getValue("status");
-			
+
 			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
-			
+
 			if(status == "loading")
 			{
 				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
@@ -1017,24 +1032,24 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			// TODO: check that name matches?
 			mNaturalMediaWidth = width;
 			mNaturalMediaHeight = height;
-			
+
 			setSizeInternal();
 		}
 		else if(message_name == "size_change_response")
 		{
 			std::string name = message.getValue("name");
-			
+
 			// TODO: check that name matches?
-			
+
 			mTextureWidth = message.getValueS32("texture_width");
 			mTextureHeight = message.getValueS32("texture_height");
 			mMediaWidth = message.getValueS32("width");
 			mMediaHeight = message.getValueS32("height");
-			
+
 			// This invalidates any existing dirty rect.
 			resetDirty();
-			
-			// TODO: should we verify that the plugin sent back the right values?  
+
+			// TODO: should we verify that the plugin sent back the right values?
 			// Two size changes in a row may cause them to not match, due to queueing, etc.
 
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
@@ -1075,6 +1090,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			mAuthRealm = message.getValue("realm");
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
 		}
+		else if (message_name == "file_download")
+		{
+			mFileDownloadFilename = message.getValue("filename");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_FILE_DOWNLOAD);
+		}
 		else if(message_name == "debug_message")
 		{
 			mDebugMessageText = message.getValue("message_text");
@@ -1101,7 +1121,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			mNavigateResultString = message.getValue("result_string");
 			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
 			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
-			
+
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
 		}
 		else if(message_name == "progress")
@@ -1156,7 +1176,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			mGeometryY = message.getValueS32("y");
 			mGeometryWidth = message.getValueS32("width");
 			mGeometryHeight = message.getValueS32("height");
-				
+
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
 		}
 		else if(message_name == "link_hovered")
@@ -1165,7 +1185,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 			mHoverLink = message.getValue("link");
 			mHoverText = message.getValue("title");
 			// message.getValue("text");
-				
+
 			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
 		}
 		else
@@ -1181,7 +1201,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 //		if(message_name == "message_name")
 //		{
 //		}
-//		else 
+//		else
 		{
 			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 		}
@@ -1189,13 +1209,13 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 
 }
 
-/* virtual */ 
+/* virtual */
 void LLPluginClassMedia::pluginLaunchFailed()
 {
 	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
 }
 
-/* virtual */ 
+/* virtual */
 void LLPluginClassMedia::pluginDied()
 {
 	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
@@ -1235,7 +1255,7 @@ void LLPluginClassMedia::focus(bool focused)
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
 
 	message.setValueBoolean("focused", focused);
-	
+
 	sendMessage(message);
 }
 
@@ -1262,7 +1282,7 @@ void LLPluginClassMedia::clear_cookies()
 void LLPluginClassMedia::set_cookies(const std::string &cookies)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
-	message.setValue("cookies", cookies);	
+	message.setValue("cookies", cookies);
 	sendMessage(message);
 }
 
@@ -1295,7 +1315,7 @@ void LLPluginClassMedia::browse_reload(bool ignore_cache)
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
 
 	message.setValueBoolean("ignore_cache", ignore_cache);
-	
+
 	sendMessage(message);
 }
 
@@ -1415,7 +1435,7 @@ void LLPluginClassMedia::seek(float time)
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
 
 	message.setValueReal("time", time);
-	
+
 	sendMessage(message);
 }
 
@@ -1433,11 +1453,11 @@ void LLPluginClassMedia::setVolume(float volume)
 	if(volume != mRequestedVolume)
 	{
 		mRequestedVolume = volume;
-		
+
 		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
 
 		message.setValueReal("volume", volume);
-		
+
 		sendMessage(message);
 	}
 }
@@ -1456,4 +1476,3 @@ void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
 
 	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
 }
-
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 96d577f43c64fd35fa5816e26d8f772b875e233a..fc27b7bea368436f220273084e93ac6f5637188f 100755
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -133,6 +133,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	// Text may be unicode (utf8 encoded)
 	bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
 	
+	void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure);
+
 	void loadURI(const std::string &uri);
 	
 	// "Loading" means uninitialized or any state prior to fully running (processing commands)
@@ -191,7 +193,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	bool	canPaste() const { return mCanPaste; };
 	
 	// These can be called before init(), and they will be queued and sent before the media init message.
-	void	setUserDataPath(const std::string &user_data_path);
+	void	setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies);
 	void	setLanguageCode(const std::string &language_code);
 	void	setPluginsEnabled(const bool enabled);
 	void	setJavascriptEnabled(const bool enabled);
@@ -277,6 +279,10 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	std::string	getHoverText() const { return mHoverText; };
 	std::string	getHoverLink() const { return mHoverLink; };
 	
+	// these are valid during MEDIA_EVENT_LINK_HOVERED 
+	std::string getFileDownloadFilename() const { return mFileDownloadFilename; }
+
+
 	const std::string& getMediaName() const { return mMediaName; };
 	std::string getMediaDescription() const { return mMediaDescription; };
 
@@ -372,7 +378,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	int			mPadding;
 	
 	
-	LLPluginProcessParent *mPlugin;
+	LLPluginProcessParent::ptr_t mPlugin;
 	
 	LLRect mDirtyRect;
 	
@@ -424,6 +430,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	std::string		mAuthRealm;
 	std::string		mHoverText;
 	std::string		mHoverLink;
+	std::string     mFileDownloadFilename;
 	
 	/////////////////////////////////////////
 	// media_time class
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index 2f3edba7f368d5488ce02d892e7b45730a6ce345..391c23d883c327e0e412773f47bdb6b7e991f9e6 100755
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -64,6 +64,8 @@ class LLPluginClassMediaOwner
 
 		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog
 
+		MEDIA_EVENT_FILE_DOWNLOAD,			// the plugin wants to download a file
+
 		MEDIA_EVENT_DEBUG_MESSAGE,			// plugin sending back debug information for host to process
 
 		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin
diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp
index f8a282184ed6d99a5d3144071fbd1f0a7b7ccec9..be80d38305807f18640a8acb351df5e12fefff29 100755
--- a/indra/llplugin/llpluginprocesschild.cpp
+++ b/indra/llplugin/llpluginprocesschild.cpp
@@ -33,6 +33,7 @@
 #include "llpluginmessagepipe.h"
 #include "llpluginmessageclasses.h"
 
+static const F32 GOODBYE_SECONDS = 20.0f;
 static const F32 HEARTBEAT_SECONDS = 1.0f;
 static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f;  // Each call to idle will give the plugin this much time.
 
@@ -194,33 +195,43 @@ void LLPluginProcessChild::idle(void)
 					}
 				}
 				// receivePluginMessage will transition to STATE_UNLOADING
-			break;
+			    break;
+
+            case STATE_SHUTDOWNREQ:
+                if (mInstance != NULL)
+                {
+                    sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
+                    delete mInstance;
+                    mInstance = NULL;
+                }
+                setState(STATE_UNLOADING);
+                mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS);
+                break;
 
 			case STATE_UNLOADING:
-				if(mInstance != NULL)
-				{
-					sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
-					delete mInstance;
-					mInstance = NULL;
-				}
-				setState(STATE_UNLOADED);
-			break;
+                // waiting for goodbye from plugin.
+                if (mWaitGoodbye.hasExpired())
+                {
+                    LL_WARNS() << "Wait for goodbye expired.  Advancing to UNLOADED" << LL_ENDL;
+                    setState(STATE_UNLOADED);
+                }
+			    break;
 			
 			case STATE_UNLOADED:
 				killSockets();
 				setState(STATE_DONE);
-			break;
+			    break;
 
 			case STATE_ERROR:
 				// Close the socket to the launcher
 				killSockets();				
 				// TODO: Where do we go from here?  Just exit()?
 				setState(STATE_DONE);
-			break;
+			    break;
 			
 			case STATE_DONE:
 				// just sit here.
-			break;
+			    break;
 		}
 	
 	} while (idle_again);
@@ -350,6 +361,10 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
 				mPluginFile = parsed.getValue("file");
 				mPluginDir = parsed.getValue("dir");
 			}
+            else if (message_name == "shutdown_plugin")
+            {
+                setState(STATE_SHUTDOWNREQ);
+            }
 			else if(message_name == "shm_add")
 			{
 				std::string name = parsed.getValue("name");
@@ -495,6 +510,10 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
 				// Let the parent know it's loaded and initialized.
 				sendMessageToParent(new_message);
 			}
+            else if (message_name == "goodbye")
+            {
+                setState(STATE_UNLOADED);
+            }
 			else if(message_name == "shm_remove_response")
 			{
 				// Don't pass this message up to the parent
diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h
index 531422e792f7f840d24f718f57c5a04b08c56b01..b916cc9528fc51f5549a01035326e6af1188045e 100755
--- a/indra/llplugin/llpluginprocesschild.h
+++ b/indra/llplugin/llpluginprocesschild.h
@@ -80,6 +80,7 @@ class LLPluginProcessChild: public LLPluginMessagePipeOwner, public LLPluginInst
 		STATE_PLUGIN_LOADED,		// plugin library has been loaded
 		STATE_PLUGIN_INITIALIZING,	// plugin is processing init message
 		STATE_RUNNING,				// steady state (processing messages)
+        STATE_SHUTDOWNREQ,          // Parent has requested a shutdown.
 		STATE_UNLOADING,			// plugin has sent shutdown_response and needs to be unloaded
 		STATE_UNLOADED,				// plugin has been unloaded
 		STATE_ERROR,				// generic bailout state
@@ -101,12 +102,12 @@ class LLPluginProcessChild: public LLPluginMessagePipeOwner, public LLPluginInst
 	sharedMemoryRegionsType mSharedMemoryRegions;
 	
 	LLTimer mHeartbeat;
-	F64		mSleepTime;
-	F64		mCPUElapsed;
+    F64		mSleepTime;
+    F64		mCPUElapsed;
 	bool	mBlockingRequest;
 	bool	mBlockingResponseReceived;
 	std::queue<std::string> mMessageQueue;
-	
+    LLTimer mWaitGoodbye;
 	void deliverQueuedMessages();
 	
 };
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index b5a2588e1e70a152e1fc8fac8a1dbdc4789120c0..0a8e58ac90cf60d7fda67900b565ce0e6ec9f426 100755
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -46,7 +46,7 @@ bool LLPluginProcessParent::sUseReadThread = false;
 apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
 bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
 LLMutex *LLPluginProcessParent::sInstancesMutex;
-std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
+LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
 LLThread *LLPluginProcessParent::sReadThread = NULL;
 
 
@@ -104,27 +104,12 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
 	// Don't start the timer here -- start it when we actually launch the plugin process.
 	mHeartbeat.stop();
 	
-	// Don't add to the global list until fully constructed.
-	{
-		LLMutexLock lock(sInstancesMutex);
-		sInstances.push_back(this);
-	}
 }
 
 LLPluginProcessParent::~LLPluginProcessParent()
 {
 	LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
 
-	// Remove from the global list before beginning destruction.
-	{
-		// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
-		LLMutexLock lock(sInstancesMutex);
-		{
-			LLMutexLock lock2(&mIncomingQueueMutex);
-			sInstances.remove(this);
-		}
-	}
-
 	// Destroy any remaining shared memory regions
 	sharedMemoryRegionsType::iterator iter;
 	while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
@@ -139,9 +124,109 @@ LLPluginProcessParent::~LLPluginProcessParent()
 	}
 
 	LLProcess::kill(mProcess);
-	killSockets();
+    if (!LLApp::isQuitting())
+    {   // If we are quitting, the network sockets will already have been destroyed.
+        killSockets();
+    }
+}
+
+/*static*/
+LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParentOwner *owner)
+{
+    ptr_t that(new LLPluginProcessParent(owner));
+
+    // Don't add to the global list until fully constructed.
+    {
+        LLMutexLock lock(sInstancesMutex);
+        sInstances.insert(mapInstances_t::value_type(that.get(), that));
+    }
+
+    return that;
+}
+
+/*static*/
+void LLPluginProcessParent::shutdown()
+{
+    LLMutexLock lock(sInstancesMutex);
+
+    mapInstances_t::iterator it;
+    for (it = sInstances.begin(); it != sInstances.end(); ++it)
+    {
+        (*it).second->setState(STATE_GOODBYE);
+        (*it).second->idle();
+    }
+    sInstances.clear();
+}
+
+
+void LLPluginProcessParent::requestShutdown()
+{
+    setState(STATE_GOODBYE);
+    mOwner = NULL;
+
+    if (LLApp::isQuitting())
+    {   // if we're quitting, run the idle once more
+        idle();
+        removeFromProcessing();
+        return;
+    }
+
+    static uint32_t count = 0;
+    std::stringstream namestream;
+
+    namestream << "LLPluginProcessParentListener" << ++count;
+
+    //*HACK!*//
+    // After requestShutdown has been called our previous owner will no longer call 
+    // our idle() method.  Tie into the event loop here to do that until we are good
+    // and finished.
+    LL_DEBUGS("LLPluginProcessParent") << "listening on \"mainloop\"" << LL_ENDL;
+    mPolling = LLEventPumps::instance().obtain("mainloop")
+        .listen(namestream.str(), boost::bind(&LLPluginProcessParent::pollTick, this));
+
+}
+
+bool LLPluginProcessParent::pollTick()
+{
+    if (isDone())
+    {
+        ptr_t that;
+        {
+            // this grabs a copy of the smart pointer to ourselves to ensure that we do not
+            // get destroyed until after this method returns.
+            LLMutexLock lock(sInstancesMutex);
+            mapInstances_t::iterator it = sInstances.find(this);
+            if (it != sInstances.end())
+                that = (*it).second;
+        }
+
+        removeFromProcessing();
+        return true;
+    }
+
+    idle();
+    return false;
 }
 
+void LLPluginProcessParent::removeFromProcessing()
+{
+    // Remove from the global list before beginning destruction.
+    {
+        // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
+        LLMutexLock lock(sInstancesMutex);
+        {
+            LLMutexLock lock2(&mIncomingQueueMutex);
+            sInstances.erase(this);
+        }
+    }
+}
+
+bool LLPluginProcessParent::wantsPolling() const
+{
+    return (mPollFD.client_data && (mState != STATE_DONE));
+}
+
+
 void LLPluginProcessParent::killSockets(void)
 {
 	{
@@ -371,48 +456,48 @@ void LLPluginProcessParent::idle(void)
 			break;
 			
 			case STATE_LISTENING:
-			{
-				// Launch the plugin process.
+			    {
+				    // Launch the plugin process.
 				
-				// Only argument to the launcher is the port number we're listening on
-				mProcessParams.args.add(stringize(mBoundPort));
-				if (! (mProcess = LLProcess::create(mProcessParams)))
-				{
-					errorState();
-				}
-				else
-				{
-					if(mDebug)
-					{
-						#if LL_DARWIN
-						// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
+				    // Only argument to the launcher is the port number we're listening on
+				    mProcessParams.args.add(stringize(mBoundPort));
+				    if (! (mProcess = LLProcess::create(mProcessParams)))
+				    {
+					    errorState();
+				    }
+				    else
+				    {
+					    if(mDebug)
+					    {
+#if LL_DARWIN
+						    // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
 						
-						// The command we're constructing would look like this on the command line:
-						// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
-
-						LLProcess::Params params;
-						params.executable = "/usr/bin/osascript";
-						params.args.add("-e");
-						params.args.add("tell application \"Terminal\"");
-						params.args.add("-e");
-						params.args.add(STRINGIZE("set win to do script \"gdb -pid "
-												  << mProcess->getProcessID() << "\""));
-						params.args.add("-e");
-						params.args.add("do script \"continue\" in win");
-						params.args.add("-e");
-						params.args.add("end tell");
-						mDebugger = LLProcess::create(params);
-
-						#endif
-					}
+						    // The command we're constructing would look like this on the command line:
+						    // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
+
+						    LLProcess::Params params;
+						    params.executable = "/usr/bin/osascript";
+						    params.args.add("-e");
+						    params.args.add("tell application \"Terminal\"");
+						    params.args.add("-e");
+						    params.args.add(STRINGIZE("set win to do script \"gdb -pid "
+												      << mProcess->getProcessID() << "\""));
+						    params.args.add("-e");
+						    params.args.add("do script \"continue\" in win");
+						    params.args.add("-e");
+						    params.args.add("end tell");
+						    mDebugger = LLProcess::create(params);
+
+#endif
+					    }
 					
-					// This will allow us to time out if the process never starts.
-					mHeartbeat.start();
-					mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
-					setState(STATE_LAUNCHED);
-				}
-			}
-			break;
+					    // This will allow us to time out if the process never starts.
+					    mHeartbeat.start();
+					    mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
+					    setState(STATE_LAUNCHED);
+				    }
+			    }
+			    break;
 
 			case STATE_LAUNCHED:
 				// waiting for the plugin to connect
@@ -430,7 +515,7 @@ void LLPluginProcessParent::idle(void)
 						setState(STATE_CONNECTED);
 					}
 				}
-			break;
+			    break;
 			
 			case STATE_CONNECTED:
 				// waiting for hello message from the plugin
@@ -439,7 +524,7 @@ void LLPluginProcessParent::idle(void)
 				{
 					errorState();
 				}
-			break;
+			    break;
 
 			case STATE_HELLO:
 				LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
@@ -453,7 +538,7 @@ void LLPluginProcessParent::idle(void)
 				}
 
 				setState(STATE_LOADING);
-			break;
+			    break;
 			
 			case STATE_LOADING:
 				// The load_plugin_response message will kick us from here into STATE_RUNNING
@@ -461,15 +546,23 @@ void LLPluginProcessParent::idle(void)
 				{
 					errorState();
 				}
-			break;
+			    break;
 			
 			case STATE_RUNNING:
 				if(pluginLockedUpOrQuit())
 				{
 					errorState();
 				}
-			break;
+			    break;
 			
+            case STATE_GOODBYE:
+                {
+                    LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown_plugin");
+                    sendMessage(message);
+                }
+                setState(STATE_EXITING);
+                break;
+
 			case STATE_EXITING:
 				if (! LLProcess::isRunning(mProcess))
 				{
@@ -480,7 +573,7 @@ void LLPluginProcessParent::idle(void)
 					LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
 					errorState();
 				}
-			break;
+    			break;
 
 			case STATE_LAUNCH_FAILURE:
 				if(mOwner != NULL)
@@ -488,7 +581,7 @@ void LLPluginProcessParent::idle(void)
 					mOwner->pluginLaunchFailed();
 				}
 				setState(STATE_CLEANUP);
-			break;
+    			break;
 
 			case STATE_ERROR:
 				if(mOwner != NULL)
@@ -496,19 +589,18 @@ void LLPluginProcessParent::idle(void)
 					mOwner->pluginDied();
 				}
 				setState(STATE_CLEANUP);
-			break;
+			    break;
 			
 			case STATE_CLEANUP:
 				LLProcess::kill(mProcess);
 				killSockets();
 				setState(STATE_DONE);
-			break;
-			
+                dirtyPollSet();
+			    break;
 			
 			case STATE_DONE:
 				// just sit here.
-			break;
-			
+    			break;
 		}
 	
 	} while (idle_again);
@@ -651,14 +743,14 @@ void LLPluginProcessParent::updatePollset()
 		sPollSet = NULL;
 	}
 	
-	std::list<LLPluginProcessParent*>::iterator iter;
+    mapInstances_t::iterator iter;
 	int count = 0;
 	
 	// Count the number of instances that want to be in the pollset
 	for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
 	{
-		(*iter)->mPolledInput = false;
-		if((*iter)->mPollFD.client_data)
+		(*iter).second->mPolledInput = false;
+        if ((*iter).second->wantsPolling())
 		{
 			// This instance has a socket that needs to be polled.
 			++count;
@@ -686,12 +778,12 @@ void LLPluginProcessParent::updatePollset()
 				// Pollset was created, add all instances to it.
 				for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
 				{
-					if((*iter)->mPollFD.client_data)
+                    if ((*iter).second->wantsPolling())
 					{
-						status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
+						status = apr_pollset_add(sPollSet, &((*iter).second->mPollFD));
 						if(status == APR_SUCCESS)
 						{
-							(*iter)->mPolledInput = true;
+							(*iter).second->mPolledInput = true;
 						}
 						else
 						{
@@ -756,45 +848,27 @@ void LLPluginProcessParent::poll(F64 timeout)
 		if(status == APR_SUCCESS)
 		{
 			// One or more of the descriptors signalled.  Call them.
-			for(int i = 0; i < count; i++)
-			{
-				LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
-				// NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
-				// This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
-				// It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
-				// This means that we can't safely dereference the 'self' pointer here without some extra steps...
-				if(self)
-				{
-					// Make sure this pointer is still in the instances list
-					bool valid = false;
-					{
-						LLMutexLock lock(sInstancesMutex);
-						for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
-						{
-							if(*iter == self)
-							{
-								// Lock the instance's mutex before unlocking the global mutex.  
-								// This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
-								self->mIncomingQueueMutex.lock();
-								valid = true;
-								break;
-							}
-						}
-					}
-					
-					if(valid)
-					{
-						// The instance is still valid.
-						// Pull incoming messages off the socket
-						self->servicePoll();
-						self->mIncomingQueueMutex.unlock();
-					}
-					else
-					{
-						LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
-					}
+            for (int i = 0; i < count; i++)
+            {
+                void *thatId = descriptors[i].client_data;
+
+                ptr_t that;
+                mapInstances_t::iterator it;
+
+                {
+                    LLMutexLock lock(sInstancesMutex);
+                    it = sInstances.find(thatId);
+                    if (it != sInstances.end())
+                        that = (*it).second;
+                }
+
+                if (that)
+                {
+                    that->mIncomingQueueMutex.lock();
+                    that->servicePoll();
+                    that->mIncomingQueueMutex.unlock();
+                }
 
-				}
 			}
 		}
 		else if(APR_STATUS_IS_TIMEUP(status))
@@ -812,6 +886,16 @@ void LLPluginProcessParent::poll(F64 timeout)
 			LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
 		}
 	}
+
+    // Remove instances in the done state from the sInstances map.
+    mapInstances_t::iterator itClean = sInstances.begin();
+    while (itClean != sInstances.end())
+    {
+        if ((*itClean).second->isDone())
+            sInstances.erase(itClean++);
+        else
+            ++itClean;
+    }
 }
 
 void LLPluginProcessParent::servicePoll()
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 24be7eb148d4de936030eb3e4cc5413de58d1b77..df1630255cc52ff165c557cd9d85ba62519b1a18 100755
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -30,6 +30,7 @@
 #define LL_LLPLUGINPROCESSPARENT_H
 
 #include <queue>
+#include <boost/enable_shared_from_this.hpp>
 
 #include "llapr.h"
 #include "llprocess.h"
@@ -40,8 +41,9 @@
 #include "lliosocket.h"
 #include "llthread.h"
 #include "llsd.h"
+#include "llevents.h"
 
-class LLPluginProcessParentOwner
+class LLPluginProcessParentOwner : public boost::enable_shared_from_this < LLPluginProcessParentOwner > 
 {
 public:
 	virtual ~LLPluginProcessParentOwner();
@@ -55,8 +57,11 @@ class LLPluginProcessParentOwner
 class LLPluginProcessParent : public LLPluginMessagePipeOwner
 {
 	LOG_CLASS(LLPluginProcessParent);
+
+    LLPluginProcessParent(LLPluginProcessParentOwner *owner);
 public:
-	LLPluginProcessParent(LLPluginProcessParentOwner *owner);
+    typedef boost::shared_ptr<LLPluginProcessParent> ptr_t;
+
 	~LLPluginProcessParent();
 		
 	void init(const std::string &launcher_filename, 
@@ -89,7 +94,10 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	void sendMessage(const LLPluginMessage &message);
 	
 	void receiveMessage(const LLPluginMessage &message);
-	
+
+    static ptr_t create(LLPluginProcessParentOwner *owner);
+    void requestShutdown();
+
 	// Inherited from LLPluginMessagePipeOwner
 	/*virtual*/ void receiveMessageRaw(const std::string &message);
 	/*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
@@ -121,7 +129,10 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); };
 	static void setUseReadThread(bool use_read_thread);
 	static bool getUseReadThread() { return sUseReadThread; };
+
+    static void shutdown();
 private:
+    typedef std::map<void *, ptr_t> mapInstances_t;
 
 	enum EState
 	{
@@ -133,6 +144,7 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 		STATE_HELLO,			// first message from the plugin process has been received
 		STATE_LOADING,			// process has been asked to load the plugin
 		STATE_RUNNING,			// 
+        STATE_GOODBYE,
 		STATE_LAUNCH_FAILURE,	// Failure before plugin loaded
 		STATE_ERROR,			// generic bailout state
 		STATE_CLEANUP,			// clean everything up
@@ -143,6 +155,9 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	EState mState;
 	void setState(EState state);
 
+    bool wantsPolling() const;
+    void removeFromProcessing();
+
 	bool pluginLockedUp();
 	bool pluginLockedUpOrQuit();
 
@@ -185,12 +200,15 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 	static apr_pollset_t *sPollSet;
 	static bool sPollsetNeedsRebuild;
 	static LLMutex *sInstancesMutex;
-	static std::list<LLPluginProcessParent*> sInstances;
+    static mapInstances_t sInstances;
 	static void dirtyPollSet();
 	static void updatePollset();
 	void servicePoll();
 	static LLThread *sReadThread;
-	
+
+    LLTempBoundListener mPolling;
+    bool pollTick();
+
 	LLMutex mIncomingQueueMutex;
 	std::queue<LLPluginMessage> mIncomingQueue;
 };
diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 6c9ba0ae52fd49b762451b2d09d3789a5de10b4a..684bcf1207fff878300a57f7fb858a6f567ccaee 100755
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -310,4 +310,3 @@ int main(int argc, char **argv)
 
 	return 0;
 }
-
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 547f0bd3989699ec84529952104082b82508da0b..1a51b96fdf25dac9b877504d1a59f051179efdb2 100755
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -46,12 +46,30 @@ BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return FALSE;
 }
 
+// virtual
+BOOL LLFocusableElement::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+	return FALSE;
+}
+
 // virtual
 BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	return FALSE;
 }
 
+// virtual 
+bool LLFocusableElement::wantsKeyUpKeyDown() const
+{
+    return false;
+}
+
+//virtual 
+bool LLFocusableElement::wantsReturnKey() const
+{
+    return false;
+}
+
 // virtual
 LLFocusableElement::~LLFocusableElement()
 {
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index afd2a8ce06bc8d4cbbc857bebe829dc7a8c9d379..0e3d7d8e590be9cef09dc713940e94daa3bbad8a 100755
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -57,8 +57,17 @@ class LLFocusableElement
 
 	// These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus.
 	virtual BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	virtual BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
+    /**
+     * If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages 
+     * even for normal character strokes.  
+     * Default implementation returns false.
+     */
+    virtual bool    wantsKeyUpKeyDown() const;
+    virtual bool    wantsReturnKey() const;
+
 	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
 protected:	
 	virtual void	onFocusReceived();
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a8beb9cfc99c214de105618a55da443c477cd44e..8f7cac1f61ffd8f88ebea7b04d2fccef6858d02e 100755
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -866,6 +866,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 
 	return handled;
 }
+
 BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -898,6 +899,38 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return handled;
 }
 
+BOOL LLView::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+	BOOL handled = FALSE;
+
+	if (getVisible() && getEnabled())
+	{
+		if (called_from_parent)
+		{
+			// Downward traversal
+			handled = childrenHandleKeyUp(key, mask) != NULL;
+		}
+
+		if (!handled)
+		{
+			// For event logging we don't care which widget handles it
+			// So we capture the key at the end of this function once we know if it was handled
+			handled = handleKeyUpHere(key, mask);
+			if (handled)
+			{
+				LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL;
+			}
+		}
+	}
+
+	if (!handled && !called_from_parent && mParentView)
+	{
+		// Upward traversal
+		handled = mParentView->handleKeyUp(key, mask, FALSE);
+	}
+	return handled;
+}
+
 // Called from handleKey()
 // Handles key in this object.  Checking parents and children happens in handleKey()
 BOOL LLView::handleKeyHere(KEY key, MASK mask)
@@ -905,6 +938,13 @@ BOOL LLView::handleKeyHere(KEY key, MASK mask)
 	return FALSE;
 }
 
+// Called from handleKey()
+// Handles key in this object.  Checking parents and children happens in handleKey()
+BOOL LLView::handleKeyUpHere(KEY key, MASK mask)
+{
+	return FALSE;
+}
+
 BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -1020,6 +1060,12 @@ LLView* LLView::childrenHandleKey(KEY key, MASK mask)
 	return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask);
 }
 
+// Called during downward traversal
+LLView* LLView::childrenHandleKeyUp(KEY key, MASK mask)
+{
+	return childrenHandleCharEvent("Key Up", &LLView::handleKeyUp, key, mask);
+}
+
 // Called during downward traversal
 LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 7861c8f72976c26f9254ae52c4c8b7de7f8d3e05..8494bb338adfa4e9e2dbc19821177089280e11d0 100755
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -378,6 +378,7 @@ class LLView
 
 	// inherited from LLFocusableElement
 	/* virtual */ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	/* virtual */ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	/* virtual */ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
 	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -509,6 +510,7 @@ class LLView
 	
 	//virtual BOOL	addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; }
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
+	virtual BOOL	handleKeyUpHere(KEY key, MASK mask);
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
 	virtual void	handleReshape(const LLRect& rect, bool by_user);
@@ -538,6 +540,7 @@ class LLView
 	void			logMouseEvent();
 
 	LLView*	childrenHandleKey(KEY key, MASK mask);
+	LLView*	childrenHandleKeyUp(KEY key, MASK mask);
 	LLView* childrenHandleUnicodeChar(llwchar uni_char);
 	LLView*	childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
 											  BOOL drop,
diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp
index dc40dcdde093f37d73c1d45a47a989abbe145913..2123ed3939bcb9e6ac704c845e98e915ae1ea872 100755
--- a/indra/llwindow/llkeyboardwin32.cpp
+++ b/indra/llwindow/llkeyboardwin32.cpp
@@ -258,7 +258,7 @@ void LLKeyboardWin32::scanKeyboard()
 			// *TODO: I KNOW there must be a better way of
 			// interrogating the key state than this, using async key
 			// state can cause ALL kinds of bugs - Doug
-			if (key < KEY_BUTTON0)
+            if ((key < KEY_BUTTON0) && ((key < '0') || (key > '9')))
 			{
 				// ...under windows make sure the key actually still is down.
 				// ...translate back to windows key
@@ -267,7 +267,7 @@ void LLKeyboardWin32::scanKeyboard()
 				if (!pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000))
 				{
  					//LL_INFOS() << "Key up event missed, resetting" << LL_ENDL;
-					mKeyLevel[key] = FALSE;
+    				mKeyLevel[key] = FALSE;
 				}
 			}
 		}
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index deb8cb90d826a091fca188475eee02e946de60e9..406bc9cf478853e41e548f36b468884540e0ea55 100644
--- a/indra/llwindow/llopenglview-objc.mm
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -28,6 +28,11 @@
 #include "llwindowmacosx-objc.h"
 #import "llappdelegate-objc.h"
 
+
+
+
+//---------------------------
+
 @implementation NSScreen (PointConversion)
 
 + (NSScreen *)currentScreenForMouseLocation
@@ -42,6 +47,7 @@
     return screen;
 }
 
+
 - (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint
 {
     float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x));
@@ -57,6 +63,21 @@
 
 @end
 
+void extractKeyDataFromEvent (NSEvent *theEvent, NativeKeyEventData * eventData)
+{
+    eventData->mKeyEvent = NativeKeyEventData::KEYUNKNOWN;
+    eventData->mEventType = [theEvent type];
+    eventData->mEventModifiers = [theEvent modifierFlags];
+    eventData->mEventKeyCode = [theEvent keyCode];
+    NSString *strEventChars = [theEvent characters];
+    eventData->mEventChars = (strEventChars.length) ? [strEventChars characterAtIndex:0] : 0;
+    NSString *strEventUChars = [theEvent charactersIgnoringModifiers];
+    eventData->mEventUnmodChars = (strEventUChars.length) ? [strEventUChars characterAtIndex:0] : 0;
+    eventData->mEventRepeat = [theEvent isARepeat];
+
+}
+
+
 attributedStringInfo getSegments(NSAttributedString *str)
 {
 	attributedStringInfo segments;
@@ -402,11 +423,20 @@ attributedStringInfo getSegments(NSAttributedString *str)
 
 - (void) keyUp:(NSEvent *)theEvent
 {
-	callKeyUp([theEvent keyCode], [theEvent modifierFlags]);
+    NativeKeyEventData eventData;
+ 
+    extractKeyDataFromEvent( theEvent, &eventData );
+    eventData.mKeyEvent = NativeKeyEventData::KEYUP;
+	callKeyUp(&eventData, [theEvent keyCode], [theEvent modifierFlags]);
 }
 
 - (void) keyDown:(NSEvent *)theEvent
 {
+    NativeKeyEventData eventData;
+    
+    extractKeyDataFromEvent( theEvent, &eventData );
+    eventData.mKeyEvent = NativeKeyEventData::KEYDOWN;
+   
     uint keycode = [theEvent keyCode];
     // We must not depend on flagsChange event to detect modifier flags changed,
     // must depend on the modifire flags in the event parameter.
@@ -414,7 +444,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
     // e.g. OS Window for upload something or Input Window...
     // mModifiers instance variable is for insertText: or insertText:replacementRange:  (by Pell Smit)
 	mModifiers = [theEvent modifierFlags];
-    bool acceptsText = mHasMarkedText ? false : callKeyDown(keycode, mModifiers);
+    bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers);
     unichar ch;
     if (acceptsText &&
         !mMarkedTextAllowed &&
@@ -435,12 +465,17 @@ attributedStringInfo getSegments(NSAttributedString *str)
     // Since SL assumes we receive those, we fake it here.
     if (mModifiers & NSCommandKeyMask && !mHasMarkedText)
     {
-        callKeyUp([theEvent keyCode], mModifiers);
+        eventData.mKeyEvent = NativeKeyEventData::KEYUP;
+        callKeyUp(&eventData, [theEvent keyCode], mModifiers);
     }
 }
 
 - (void)flagsChanged:(NSEvent *)theEvent
 {
+    NativeKeyEventData eventData;
+    
+    extractKeyDataFromEvent( theEvent, &eventData );
+ 
 	mModifiers = [theEvent modifierFlags];
 	callModifier([theEvent modifierFlags]);
      
@@ -462,11 +497,13 @@ attributedStringInfo getSegments(NSAttributedString *str)
     
     if (mModifiers & mask)
     {
-        callKeyDown([theEvent keyCode], 0);
+        eventData.mKeyEvent = NativeKeyEventData::KEYDOWN;
+        callKeyDown(&eventData, [theEvent keyCode], 0);
     }
     else
     {
-        callKeyUp([theEvent keyCode], 0);
+        eventData.mKeyEvent = NativeKeyEventData::KEYUP;
+        callKeyUp(&eventData, [theEvent keyCode], 0);
     }  
 }
 
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index e6e8f27f5345197748254a76da0c79921a8a7feb..dc184b91fbd5129b7b3c945a6ec40ce91668c0db 100755
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -46,6 +46,26 @@ typedef void *CursorRef;
 typedef void *NSWindowRef;
 typedef void *GLViewRef;
 
+
+struct NativeKeyEventData {
+    enum EventType {
+        KEYUNKNOWN,
+        KEYUP,
+        KEYDOWN,
+        KEYCHAR
+    };
+    
+    EventType   mKeyEvent;
+    uint32_t    mEventType;
+    uint32_t    mEventModifiers;
+    uint32_t    mEventKeyCode;
+    uint32_t    mEventChars;
+    uint32_t    mEventUnmodChars;
+    bool        mEventRepeat;
+};
+
+typedef const NativeKeyEventData * NSKeyEventRef;
+
 // These are defined in llappviewermacosx.cpp.
 bool initViewer();
 void handleQuit();
@@ -102,8 +122,8 @@ void setupInputWindow(NSWindowRef window, GLViewRef view);
 
 // These are all implemented in llwindowmacosx.cpp.
 // This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict)
-bool callKeyUp(unsigned short key, unsigned int mask);
-bool callKeyDown(unsigned short key, unsigned int mask);
+bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask);
+bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask);
 void callResetKeys();
 bool callUnicodeCallback(wchar_t character, unsigned int mask);
 void callRightMouseDown(float *pos, unsigned int mask);
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 15e054fb5d13c9e66e9091aa1f1c29d730b12029..0d41884462a828e832e95b7533f31dab754e50cd 100755
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -47,6 +47,10 @@ extern BOOL gDebugWindowProc;
 const S32	BITS_PER_PIXEL = 32;
 const S32	MAX_NUM_RESOLUTIONS = 32;
 
+namespace
+{
+    NSKeyEventRef mRawKeyEvent = NULL;
+}
 //
 // LLWindowMacOSX
 //
@@ -194,14 +198,20 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
 // These functions are used as wrappers for our internal event handling callbacks.
 // It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow.
 
-bool callKeyUp(unsigned short key, unsigned int mask)
+bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask)
 {
-	return gKeyboard->handleKeyUp(key, mask);
+    mRawKeyEvent = event;
+	bool retVal = gKeyboard->handleKeyUp(key, mask);
+    mRawKeyEvent = NULL;
+    return retVal;
 }
 
-bool callKeyDown(unsigned short key, unsigned int mask)
+bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask)
 {
-	return gKeyboard->handleKeyDown(key, mask);
+    mRawKeyEvent = event;
+	bool retVal = gKeyboard->handleKeyDown(key, mask);
+    mRawKeyEvent = NULL;
+    return retVal;
 }
 
 void callResetKeys()
@@ -211,7 +221,23 @@ void callResetKeys()
 
 bool callUnicodeCallback(wchar_t character, unsigned int mask)
 {
-	return gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask);
+    NativeKeyEventData eventData;
+    
+    memset(&eventData, 0, sizeof(NativeKeyEventData));
+    
+    eventData.mKeyEvent = NativeKeyEventData::KEYCHAR;
+    eventData.mEventType = 0;
+    eventData.mEventModifiers = mask;
+    eventData.mEventKeyCode = 0;
+    eventData.mEventChars = character;
+    eventData.mEventUnmodChars = character;
+    eventData.mEventRepeat = false;
+    
+    mRawKeyEvent = &eventData;
+    
+    bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask);
+    mRawKeyEvent = NULL;
+    return result;
 }
 
 void callFocus()
@@ -1713,49 +1739,15 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
 LLSD LLWindowMacOSX::getNativeKeyData()
 {
 	LLSD result = LLSD::emptyMap();
-#if 0
+#if 1
 	if(mRawKeyEvent)
 	{
-		char char_code = 0;
-		UInt32 key_code = 0;
-		UInt32 modifiers = 0;
-		UInt32 keyboard_type = 0;
-
-		GetEventParameter (mRawKeyEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &char_code);
-		GetEventParameter (mRawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key_code);
-		GetEventParameter (mRawKeyEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
-		GetEventParameter (mRawKeyEvent, kEventParamKeyboardType, typeUInt32, NULL, sizeof(UInt32), NULL, &keyboard_type);
-
-		result["char_code"] = (S32)char_code;
-		result["key_code"] = (S32)key_code;
-		result["modifiers"] = (S32)modifiers;
-		result["keyboard_type"] = (S32)keyboard_type;
-
-#if 0
-		// This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc)
-		// cause llsd serialization to create XML that the llsd deserializer won't parse!
-		std::string unicode;
-		S32 err = noErr;
-		EventParamType actualType = typeUTF8Text;
-		UInt32 actualSize = 0;
-		char *buffer = NULL;
-
-		err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL);
-		if(err == noErr)
-		{
-			// allocate a buffer and get the actual data.
-			buffer = new char[actualSize];
-			err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer);
-			if(err == noErr)
-			{
-				unicode.assign(buffer, actualSize);
-			}
-			delete[] buffer;
-		}
-
-		result["unicode"] = unicode;
-#endif
-
+        result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType);
+        result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers);
+        result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode);
+        result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD();
+        result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD();
+        result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat);
 	}
 #endif
 
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 7e0eb9cf315a3e173fc7397c4dab702a8fd698df..875ffe4cd43c02db968708e53844e87d5ed02afe 100755
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -42,6 +42,7 @@
 #include "llgl.h"
 #include "llstring.h"
 #include "lldir.h"
+#include "llsdutil.h"
 #include "llglslshader.h"
 
 // System includes
@@ -2068,6 +2069,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
 			window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
 			window_imp->mKeyVirtualKey = w_param;
+			window_imp->mRawMsg = u_msg;
+			window_imp->mRawWParam = w_param;
+			window_imp->mRawLParam = l_param;
 
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
 			{
@@ -2090,6 +2094,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 		{
 			window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
 			window_imp->mKeyVirtualKey = w_param;
+			window_imp->mRawMsg = u_msg;
+			window_imp->mRawWParam = w_param;
+			window_imp->mRawLParam = l_param;
 
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
 			LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
@@ -2177,6 +2184,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_CHAR:
 			window_imp->mKeyCharCode = w_param;
+			window_imp->mRawMsg = u_msg;
+			window_imp->mRawWParam = w_param;
+			window_imp->mRawLParam = l_param;
 
 			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
 			// to figure out how that works. - Doug
@@ -3239,6 +3249,9 @@ LLSD LLWindowWin32::getNativeKeyData()
 
 	result["scan_code"] = (S32)mKeyScanCode;
 	result["virtual_key"] = (S32)mKeyVirtualKey;
+	result["msg"] = ll_sd_from_U32(mRawMsg);
+	result["w_param"] = ll_sd_from_U32(mRawWParam);
+	result["l_param"] = ll_sd_from_U32(mRawLParam);
 
 	return result;
 }
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 2ca8d48fc7dc96f973a23e077d53bc09224c7aa4..1a775eadaf46caad3648f1bd8eb3d8cda35c21a6 100755
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -126,7 +126,7 @@ class LLWindowWin32 : public LLWindow
 	HCURSOR loadColorCursor(LPCTSTR name);
 	BOOL	isValid();
 	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
-	LLSD	getNativeKeyData();
+	virtual LLSD	getNativeKeyData();
 
 	// Changes display resolution. Returns true if successful
 	BOOL	setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh);
@@ -208,6 +208,9 @@ class LLWindowWin32 : public LLWindow
 	U32				mKeyCharCode;
 	U32				mKeyScanCode;
 	U32				mKeyVirtualKey;
+	U32				mRawMsg;
+	U32				mRawWParam;
+	U32				mRawLParam;
 
 	friend class LLWindowManager;
 };
diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt
index 85318aea3ba9fb43938e901b359a0dc9b574909f..24eb3947b489f074ada8bcbf5feb938527d3de4a 100755
--- a/indra/media_plugins/CMakeLists.txt
+++ b/indra/media_plugins/CMakeLists.txt
@@ -2,16 +2,17 @@
 
 add_subdirectory(base)
 
-add_subdirectory(webkit)
-
-add_subdirectory(gstreamer010)
+if (LINUX)
+    add_subdirectory(gstreamer010)
+endif (LINUX)
 
 if (WINDOWS OR DARWIN)
     add_subdirectory(quicktime)
+    add_subdirectory(cef)
 endif (WINDOWS OR DARWIN)
 
 if (WINDOWS)
     add_subdirectory(winmmshim)
 endif (WINDOWS)
 
-add_subdirectory(example)
+### add_subdirectory(example)
diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
old mode 100755
new mode 100644
similarity index 50%
rename from indra/media_plugins/webkit/CMakeLists.txt
rename to indra/media_plugins/cef/CMakeLists.txt
index 5a8fe90bdd3e9d7c22ee1cc63e8d85ec043b65e9..1f6163e41e2227bce9b185704de7d0cf8d3b155f
--- a/indra/media_plugins/webkit/CMakeLists.txt
+++ b/indra/media_plugins/cef/CMakeLists.txt
@@ -1,6 +1,6 @@
 # -*- cmake -*-
 
-project(media_plugin_webkit)
+project(media_plugin_cef)
 
 include(00-Common)
 include(LLCommon)
@@ -9,17 +9,14 @@ include(LLPlugin)
 include(LLMath)
 include(LLRender)
 include(LLWindow)
-include(UI)
 include(Linking)
 include(PluginAPI)
 include(MediaPluginBase)
 include(OpenGL)
-include(PulseAudio)
 
-include(WebKitLibPlugin)
+include(CEFPlugin)
 
 include_directories(
-    ${PULSEAUDIO_INCLUDE_DIRS}
     ${LLPLUGIN_INCLUDE_DIRS}
     ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
@@ -27,14 +24,14 @@ include_directories(
     ${LLIMAGE_INCLUDE_DIRS}
     ${LLRENDER_INCLUDE_DIRS}
     ${LLWINDOW_INCLUDE_DIRS}
-    ${LLQTWEBKIT_INCLUDE_DIR}
+    ${CEF_INCLUDE_DIR}
 )
 include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
     )
 
 
-### media_plugin_webkit
+### media_plugin_cef
 
 if(NOT WORD_SIZE EQUAL 32)
   if(WINDOWS)
@@ -44,75 +41,72 @@ if(NOT WORD_SIZE EQUAL 32)
   endif(WINDOWS)
 endif(NOT WORD_SIZE EQUAL 32)
 
-set(media_plugin_webkit_SOURCE_FILES
-    media_plugin_webkit.cpp
+set(media_plugin_cef_SOURCE_FILES
+    media_plugin_cef.cpp
     )
 
-set(media_plugin_webkit_HEADER_FILES
+set(media_plugin_cef_HEADER_FILES
     volume_catcher.h
     )
 
-set(media_plugin_webkit_LINK_LIBRARIES
+set (media_plugin_cef_LINK_LIBRARIES
   ${LLPLUGIN_LIBRARIES}
   ${MEDIA_PLUGIN_BASE_LIBRARIES}
   ${LLCOMMON_LIBRARIES}
-  ${WEBKIT_PLUGIN_LIBRARIES}
-  ${PLUGIN_API_WINDOWS_LIBRARIES}
-  ${PULSEAUDIO_LIBRARIES}
-)
+  ${CEF_PLUGIN_LIBRARIES}
+  ${PLUGIN_API_WINDOWS_LIBRARIES})
+
 
 # Select which VolumeCatcher implementation to use
 if (LINUX)
-  if (PULSEAUDIO_FOUND)
-    list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp)
-  else (PULSEAUDIO_FOUND)
-    list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp)
-  endif (PULSEAUDIO_FOUND)
-  list(APPEND media_plugin_webkit_LINK_LIBRARIES
-       ${UI_LIBRARIES}     # for glib/GTK
-       )
+  message(FATAL_ERROR "CEF plugin has been enabled for a Linux compile.\n"
+    "  Please create a volume_catcher implementation for this platform.")
+
 elseif (DARWIN)
-  list(APPEND media_plugin_webkit_SOURCE_FILES mac_volume_catcher.cpp)
+  list(APPEND media_plugin_cef_SOURCE_FILES mac_volume_catcher.cpp)
   find_library(CORESERVICES_LIBRARY CoreServices)
   find_library(AUDIOUNIT_LIBRARY AudioUnit)
-  list(APPEND media_plugin_webkit_LINK_LIBRARIES
+  list(APPEND media_plugin_cef_LINK_LIBRARIES
        ${CORESERVICES_LIBRARY}     # for Component Manager calls
        ${AUDIOUNIT_LIBRARY}        # for AudioUnit calls
        )
 elseif (WINDOWS)
-  list(APPEND media_plugin_webkit_SOURCE_FILES windows_volume_catcher.cpp)
+  list(APPEND media_plugin_cef_SOURCE_FILES windows_volume_catcher.cpp)
 endif (LINUX)
 
-set_source_files_properties(${media_plugin_webkit_HEADER_FILES}
+set_source_files_properties(${media_plugin_cef_HEADER_FILES}
                             PROPERTIES HEADER_FILE_ONLY TRUE)
 
-list(APPEND media_plugin_webkit_SOURCE_FILES ${media_plugin_webkit_HEADER_FILES})
+list(APPEND media_plugin_cef_SOURCE_FILES ${media_plugin_cef_HEADER_FILES})
 
-add_library(media_plugin_webkit
+add_library(media_plugin_cef
     SHARED
-    ${media_plugin_webkit_SOURCE_FILES}
+    ${media_plugin_cef_SOURCE_FILES}
 )
 
-target_link_libraries(media_plugin_webkit ${media_plugin_webkit_LINK_LIBRARIES})
-
-add_dependencies(media_plugin_webkit
+add_dependencies(media_plugin_cef
   ${LLPLUGIN_LIBRARIES}
   ${MEDIA_PLUGIN_BASE_LIBRARIES}
   ${LLCOMMON_LIBRARIES}
 )
 
+target_link_libraries(media_plugin_cef
+  ${media_plugin_cef_LINK_LIBRARIES}
+)
+
 if (WINDOWS)
   set_target_properties(
-    media_plugin_webkit
+    media_plugin_cef
     PROPERTIES
-    LINK_FLAGS "/MANIFEST:NO"
+    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT"
+    LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD"
     )
 endif (WINDOWS)
 
 if (DARWIN)
   # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
   set_target_properties(
-    media_plugin_webkit
+    media_plugin_cef
     PROPERTIES
     PREFIX ""
     BUILD_WITH_INSTALL_RPATH 1
@@ -120,13 +114,4 @@ if (DARWIN)
     LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"
   )
 
-  # copy the webkit dylib to the build directory
-#   add_custom_command(
-#     TARGET media_plugin_webkit POST_BUILD
-# #    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libllqtwebkit.dylib
-#     COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
-#     DEPENDS media_plugin_webkit ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
-#     )
-    
 endif (DARWIN)
-
diff --git a/indra/media_plugins/webkit/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp
old mode 100755
new mode 100644
similarity index 99%
rename from indra/media_plugins/webkit/mac_volume_catcher.cpp
rename to indra/media_plugins/cef/mac_volume_catcher.cpp
index 73e5bf3da30cef155524d82f18c6401892072c26..dddb9c207796f89a41b6376fa0924b6fe83d6cf0
--- a/indra/media_plugins/webkit/mac_volume_catcher.cpp
+++ b/indra/media_plugins/cef/mac_volume_catcher.cpp
@@ -6,7 +6,7 @@
  * $LicenseInfo:firstyear=2010&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2479cc9465f16016ef176db11176ab2fc64f9e9
--- /dev/null
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -0,0 +1,885 @@
+/**
+* @file media_plugin_cef.cpp
+* @brief CEF (Chromium Embedding Framework) plugin for LLMedia API plugin system
+*
+* @cond
+* $LicenseInfo:firstyear=2008&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2010, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+* @endcond
+*/
+
+#include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
+
+#include "llgl.h"
+#include "llsdutil.h"
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#include "boost/function.hpp"
+#include "boost/bind.hpp"
+#include "llCEFLib.h"
+#include "volume_catcher.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginCEF :
+	public MediaPluginBase
+{
+public:
+	MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginCEF();
+
+	/*virtual*/
+	void receiveMessage(const char* message_string);
+
+private:
+	bool init();
+
+	void onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup);
+	void onCustomSchemeURLCallback(std::string url);
+	void onConsoleMessageCallback(std::string message, std::string source, int line);
+	void onStatusMessageCallback(std::string value);
+	void onTitleChangeCallback(std::string title);
+	void onLoadStartCallback();
+	void onRequestExitCallback();
+	void onLoadEndCallback(int httpStatusCode);
+	void onAddressChangeCallback(std::string url);
+	void onNavigateURLCallback(std::string url, std::string target);
+	bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password);
+	void onCursorChangedCallback(LLCEFLib::ECursorType type, unsigned int handle);
+	void onFileDownloadCallback(std::string filename);
+
+	void postDebugMessage(const std::string& msg);
+	void authResponse(LLPluginMessage &message);
+
+	LLCEFLib::EKeyboardModifier decodeModifiers(std::string &modifiers);
+	void deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers);
+	void keyEvent(LLCEFLib::EKeyEvent key_event, int key, LLCEFLib::EKeyboardModifier modifiers, LLSD native_key_data);
+	void unicodeInput(const std::string &utf8str, LLCEFLib::EKeyboardModifier modifiers, LLSD native_key_data);
+
+	void checkEditState();
+    void setVolume(F32 vol);
+
+	bool mEnableMediaPluginDebugging;
+	std::string mHostLanguage;
+	bool mCookiesEnabled;
+	bool mPluginsEnabled;
+	bool mJavascriptEnabled;
+	std::string mUserAgentSubtring;
+	std::string mAuthUsername;
+	std::string mAuthPassword;
+	bool mAuthOK;
+	bool mCanCut;
+	bool mCanCopy;
+	bool mCanPaste;
+	std::string mCachePath;
+	std::string mCookiePath;
+	LLCEFLib* mLLCEFLib;
+
+    VolumeCatcher mVolumeCatcher;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginCEF::MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
+MediaPluginBase(host_send_func, host_user_data)
+{
+	mWidth = 0;
+	mHeight = 0;
+	mDepth = 4;
+	mPixels = 0;
+	mEnableMediaPluginDebugging = true;
+	mHostLanguage = "en";
+	mCookiesEnabled = true;
+	mPluginsEnabled = false;
+	mJavascriptEnabled = true;
+	mUserAgentSubtring = "";
+	mAuthUsername = "";
+	mAuthPassword = "";
+	mAuthOK = false;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+	mCachePath = "";
+	mCookiePath = "";
+	mLLCEFLib = new LLCEFLib();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginCEF::~MediaPluginCEF()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::postDebugMessage(const std::string& msg)
+{
+	if (mEnableMediaPluginDebugging)
+	{
+		std::stringstream str;
+		str << "@Media Msg> " << msg;
+
+		LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
+		debug_message.setValue("message_text", str.str());
+		debug_message.setValue("message_level", "info");
+		sendMessage(debug_message);
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup)
+{
+	if (mPixels && pixels)
+	{
+		if (is_popup)
+		{
+			for (int line = 0; line < height; ++line)
+			{
+				int inverted_y = mHeight - y - height;
+				int src = line * width * mDepth;
+				int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth;
+
+				if (dst + width * mDepth < mWidth * mHeight * mDepth)
+				{
+					memcpy(mPixels + dst, pixels + src, width * mDepth);
+				}
+			}
+		}
+		else
+		{
+			if (mWidth == width && mHeight == height)
+			{
+				memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
+			}
+			
+		}
+		setDirty(0, 0, mWidth, mHeight);
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onConsoleMessageCallback(std::string message, std::string source, int line)
+{
+	std::stringstream str;
+	str << "Console message: " << message << " in file(" << source << ") at line " << line;
+	postDebugMessage(str.str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onStatusMessageCallback(std::string value)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
+	message.setValue("status", value);
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onTitleChangeCallback(std::string title)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+	message.setValue("name", title);
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onLoadStartCallback()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+	//message.setValue("uri", event.getEventUri());  // not easily available here in CEF - needed?
+	message.setValueBoolean("history_back_available", mLLCEFLib->canGoBack());
+	message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onRequestExitCallback()
+{
+	mLLCEFLib->shutdown();
+
+	LLPluginMessage message("base", "goodbye");
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onLoadEndCallback(int httpStatusCode)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+	//message.setValue("uri", event.getEventUri());  // not easily available here in CEF - needed?
+	message.setValueS32("result_code", httpStatusCode);
+	message.setValueBoolean("history_back_available", mLLCEFLib->canGoBack());
+	message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onAddressChangeCallback(std::string url)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+	message.setValue("uri", url);
+	sendMessage(message); 
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onNavigateURLCallback(std::string url, std::string target)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
+	message.setValue("uri", url);
+	message.setValue("target", target);
+	message.setValue("uuid", "");	// not used right now
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onCustomSchemeURLCallback(std::string url)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
+	message.setValue("uri", url);
+	message.setValue("nav_type", "clicked");	// TODO: differentiate between click and navigate to
+	sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password)
+{
+	mAuthOK = false;
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
+	message.setValue("url", host);
+	message.setValue("realm", realm);
+	message.setValueBoolean("blocking_request", true);
+
+	// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+	sendMessage(message);
+
+	if (mAuthOK)
+	{
+		username = mAuthUsername;
+		password = mAuthPassword;
+	}
+
+	return mAuthOK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onFileDownloadCallback(const std::string filename)
+{
+	mAuthOK = false;
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download");
+	message.setValue("filename", filename);
+
+	sendMessage(message);
+}
+
+void MediaPluginCEF::onCursorChangedCallback(LLCEFLib::ECursorType type, unsigned int handle)
+{
+	std::string name = "";
+
+	switch (type)
+	{
+		case LLCEFLib::CT_POINTER:
+			name = "arrow";
+			break;
+		case LLCEFLib::CT_IBEAM:
+			name = "ibeam";
+			break;
+		case LLCEFLib::CT_NORTHSOUTHRESIZE:
+			name = "splitv";
+			break;
+		case LLCEFLib::CT_EASTWESTRESIZE:
+			name = "splith";
+			break;
+		case LLCEFLib::CT_HAND:
+			name = "hand";
+			break;
+
+		default:
+			LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL;
+			break;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
+	message.setValue("name", name);
+	sendMessage(message);
+}
+
+void MediaPluginCEF::authResponse(LLPluginMessage &message)
+{
+	mAuthOK = message.getValueBoolean("ok");
+	if (mAuthOK)
+	{
+		mAuthUsername = message.getValue("username");
+		mAuthPassword = message.getValue("password");
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::receiveMessage(const char* message_string)
+{
+	//  std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+	LLPluginMessage message_in;
+
+	if (message_in.parse(message_string) >= 0)
+	{
+		std::string message_class = message_in.getClass();
+		std::string message_name = message_in.getName();
+		if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+		{
+			if (message_name == "init")
+			{
+				LLPluginMessage message("base", "init_response");
+				LLSD versions = LLSD::emptyMap();
+				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+				message.setValueLLSD("versions", versions);
+
+				std::string plugin_version = "CEF plugin 1.1.3";
+				message.setValue("plugin_version", plugin_version);
+				sendMessage(message);
+			}
+			else if (message_name == "idle")
+			{
+				mLLCEFLib->update();
+
+                mVolumeCatcher.pump();
+				// this seems bad but unless the state changes (it won't until we figure out
+				// how to get CEF to tell us if copy/cut/paste is available) then this function
+				// will return immediately
+				checkEditState();
+			}
+			else if (message_name == "cleanup")
+			{
+				mLLCEFLib->requestExit();
+			}
+			else if (message_name == "shm_added")
+			{
+				SharedSegmentInfo info;
+				info.mAddress = message_in.getValuePointer("address");
+				info.mSize = (size_t)message_in.getValueS32("size");
+				std::string name = message_in.getValue("name");
+
+				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+			}
+			else if (message_name == "shm_remove")
+			{
+				std::string name = message_in.getValue("name");
+
+				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+				if (iter != mSharedSegments.end())
+				{
+					if (mPixels == iter->second.mAddress)
+					{
+						mPixels = NULL;
+						mTextureSegmentName.clear();
+					}
+					mSharedSegments.erase(iter);
+				}
+				else
+				{
+				}
+
+				LLPluginMessage message("base", "shm_remove_response");
+				message.setValue("name", name);
+				sendMessage(message);
+			}
+			else
+			{
+			}
+		}
+		else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+		{
+			if (message_name == "init")
+			{
+				// event callbacks from LLCefLib
+				mLLCEFLib->setOnPageChangedCallback(boost::bind(&MediaPluginCEF::onPageChangedCallback, this, _1, _2, _3, _4, _5, _6));
+				mLLCEFLib->setOnCustomSchemeURLCallback(boost::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, _1));
+				mLLCEFLib->setOnConsoleMessageCallback(boost::bind(&MediaPluginCEF::onConsoleMessageCallback, this, _1, _2, _3));
+				mLLCEFLib->setOnStatusMessageCallback(boost::bind(&MediaPluginCEF::onStatusMessageCallback, this, _1));
+				mLLCEFLib->setOnTitleChangeCallback(boost::bind(&MediaPluginCEF::onTitleChangeCallback, this, _1));
+				mLLCEFLib->setOnLoadStartCallback(boost::bind(&MediaPluginCEF::onLoadStartCallback, this));
+				mLLCEFLib->setOnLoadEndCallback(boost::bind(&MediaPluginCEF::onLoadEndCallback, this, _1));
+				mLLCEFLib->setOnAddressChangeCallback(boost::bind(&MediaPluginCEF::onAddressChangeCallback, this, _1));
+				mLLCEFLib->setOnNavigateURLCallback(boost::bind(&MediaPluginCEF::onNavigateURLCallback, this, _1, _2));
+				mLLCEFLib->setOnHTTPAuthCallback(boost::bind(&MediaPluginCEF::onHTTPAuthCallback, this, _1, _2, _3, _4));
+				mLLCEFLib->setOnFileDownloadCallback(boost::bind(&MediaPluginCEF::onFileDownloadCallback, this, _1));
+				mLLCEFLib->setOnCursorChangedCallback(boost::bind(&MediaPluginCEF::onCursorChangedCallback, this, _1, _2));
+				mLLCEFLib->setOnRequestExitCallback(boost::bind(&MediaPluginCEF::onRequestExitCallback, this));
+
+				LLCEFLib::LLCEFLibSettings settings;
+				settings.initial_width = 1024;
+				settings.initial_height = 1024;
+				settings.plugins_enabled = mPluginsEnabled;
+				settings.javascript_enabled = mJavascriptEnabled;
+				settings.cookies_enabled = mCookiesEnabled;
+				settings.cookie_store_path = mCookiePath;
+				settings.cache_enabled = true;
+				settings.cache_path = mCachePath;
+				settings.accept_language_list = mHostLanguage;
+				settings.user_agent_substring = mLLCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring);
+
+				bool result = mLLCEFLib->init(settings);
+				if (!result)
+				{
+					// if this fails, the media system in viewer will put up a message
+				}
+
+				// Plugin gets to decide the texture parameters to use.
+				mDepth = 4;
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+				message.setValueS32("default_width", 1024);
+				message.setValueS32("default_height", 1024);
+				message.setValueS32("depth", mDepth);
+				message.setValueU32("internalformat", GL_RGB);
+				message.setValueU32("format", GL_BGRA);
+				message.setValueU32("type", GL_UNSIGNED_BYTE);
+				message.setValueBoolean("coords_opengl", true);
+				sendMessage(message);
+			}
+			else if (message_name == "set_user_data_path")
+			{
+				std::string user_data_path_cache = message_in.getValue("cache_path");
+				std::string user_data_path_cookies = message_in.getValue("cookies_path");
+				mCachePath = user_data_path_cache + "cef_cache";
+				mCookiePath = user_data_path_cookies + "cef_cookies";
+			}
+			else if (message_name == "size_change")
+			{
+				std::string name = message_in.getValue("name");
+				S32 width = message_in.getValueS32("width");
+				S32 height = message_in.getValueS32("height");
+				S32 texture_width = message_in.getValueS32("texture_width");
+				S32 texture_height = message_in.getValueS32("texture_height");
+
+				if (!name.empty())
+				{
+					// Find the shared memory region with this name
+					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+					if (iter != mSharedSegments.end())
+					{
+						mPixels = (unsigned char*)iter->second.mAddress;
+						mWidth = width;
+						mHeight = height;
+
+						mTextureWidth = texture_width;
+						mTextureHeight = texture_height;
+					};
+				};
+
+				mLLCEFLib->setSize(mWidth, mHeight);
+
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+				message.setValue("name", name);
+				message.setValueS32("width", width);
+				message.setValueS32("height", height);
+				message.setValueS32("texture_width", texture_width);
+				message.setValueS32("texture_height", texture_height);
+				sendMessage(message);
+
+			}
+			else if (message_name == "set_language_code")
+			{
+				mHostLanguage = message_in.getValue("language");
+			}
+			else if (message_name == "load_uri")
+			{
+				std::string uri = message_in.getValue("uri");
+				mLLCEFLib->navigate(uri);
+			}
+			else if (message_name == "set_cookie")
+			{
+				std::string uri = message_in.getValue("uri");
+				std::string name = message_in.getValue("name");
+				std::string value = message_in.getValue("value");
+				std::string domain = message_in.getValue("domain");
+				std::string path = message_in.getValue("path");
+				bool httponly = message_in.getValueBoolean("httponly");
+				bool secure = message_in.getValueBoolean("secure");
+				mLLCEFLib->setCookie(uri, name, value, domain, path, httponly, secure);
+			}
+			else if (message_name == "mouse_event")
+			{
+				std::string event = message_in.getValue("event");
+
+				S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+
+				// only even send left mouse button events to LLCEFLib
+				// (partially prompted by crash in OS X CEF when sending right button events)
+				// we catch the right click in viewer and display our own context menu anyway
+				S32 button = message_in.getValueS32("button");
+				LLCEFLib::EMouseButton btn = LLCEFLib::MB_MOUSE_BUTTON_LEFT;
+
+				if (event == "down" && button == 0)
+				{
+					mLLCEFLib->mouseButton(btn, LLCEFLib::ME_MOUSE_DOWN, x, y);
+					mLLCEFLib->setFocus(true);
+
+					std::stringstream str;
+					str << "Mouse down at = " << x << ", " << y;
+					postDebugMessage(str.str());
+				}
+				else if (event == "up" && button == 0)
+				{
+					mLLCEFLib->mouseButton(btn, LLCEFLib::ME_MOUSE_UP, x, y);
+
+					std::stringstream str;
+					str << "Mouse up at = " << x << ", " << y;
+					postDebugMessage(str.str());
+				}
+				else if (event == "double_click")
+				{
+					mLLCEFLib->mouseButton(btn, LLCEFLib::ME_MOUSE_DOUBLE_CLICK, x, y);
+				}
+				else
+				{
+					mLLCEFLib->mouseMove(x, y);
+				}
+			}
+			else if (message_name == "scroll_event")
+			{
+				S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+				const int scaling_factor = 40;
+				y *= -scaling_factor;
+
+				mLLCEFLib->mouseWheel(x, y);
+			}
+			else if (message_name == "text_event")
+			{
+				std::string text = message_in.getValue("text");
+				std::string modifiers = message_in.getValue("modifiers");
+				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+
+				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
+			}
+			else if (message_name == "key_event")
+			{
+#if LL_DARWIN
+				std::string event = message_in.getValue("event");
+				S32 key = message_in.getValueS32("key");
+                LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+
+#if 0
+				if (event == "down")
+				{
+					//mLLCEFLib->keyPress(key, true);
+					mLLCEFLib->keyboardEvent(LLCEFLib::KE_KEY_DOWN, (uint32_t)key, 0, LLCEFLib::KM_MODIFIER_NONE, 0, 0, 0);
+
+				}
+				else if (event == "up")
+				{
+					//mLLCEFLib->keyPress(key, false);
+					mLLCEFLib->keyboardEvent(LLCEFLib::KE_KEY_UP, (uint32_t)key, 0, LLCEFLib::KM_MODIFIER_NONE, 0, 0, 0);
+				}
+#else
+                // Treat unknown events as key-up for safety.
+                LLCEFLib::EKeyEvent key_event = LLCEFLib::KE_KEY_UP;
+                if (event == "down")
+                {
+                    key_event = LLCEFLib::KE_KEY_DOWN;
+                }
+                else if (event == "repeat")
+                {
+                    key_event = LLCEFLib::KE_KEY_REPEAT;
+                }
+                
+                keyEvent(key_event, key, LLCEFLib::KM_MODIFIER_NONE, native_key_data);
+              
+#endif
+#elif LL_WINDOWS
+				std::string event = message_in.getValue("event");
+				S32 key = message_in.getValueS32("key");
+				std::string modifiers = message_in.getValue("modifiers");
+				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+
+				// Treat unknown events as key-up for safety.
+				LLCEFLib::EKeyEvent key_event = LLCEFLib::KE_KEY_UP;
+				if (event == "down")
+				{
+					key_event = LLCEFLib::KE_KEY_DOWN;
+				}
+				else if (event == "repeat")
+				{
+					key_event = LLCEFLib::KE_KEY_REPEAT;
+				}
+
+				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
+#endif
+			}
+			else if (message_name == "enable_media_plugin_debugging")
+			{
+				mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");
+			}
+			if (message_name == "auth_response")
+			{
+				authResponse(message_in);
+			}
+			if (message_name == "edit_cut")
+			{
+				mLLCEFLib->editCut();
+			}
+			if (message_name == "edit_copy")
+			{
+				mLLCEFLib->editCopy();
+			}
+			if (message_name == "edit_paste")
+			{
+				mLLCEFLib->editPaste();
+			}
+		}
+		else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+		{
+			if (message_name == "set_page_zoom_factor")
+			{
+				F32 factor = (F32)message_in.getValueReal("factor");
+				mLLCEFLib->setPageZoom(factor);
+			}
+			if (message_name == "browse_stop")
+			{
+				mLLCEFLib->stop();
+			}
+			else if (message_name == "browse_reload")
+			{
+				bool ignore_cache = true;
+				mLLCEFLib->reload(ignore_cache);
+			}
+			else if (message_name == "browse_forward")
+			{
+				mLLCEFLib->goForward();
+			}
+			else if (message_name == "browse_back")
+			{
+				mLLCEFLib->goBack();
+			}
+			else if (message_name == "cookies_enabled")
+			{
+				mCookiesEnabled = message_in.getValueBoolean("enable");
+			}
+			else if (message_name == "set_user_agent")
+			{
+				mUserAgentSubtring = message_in.getValue("user_agent");
+			}
+			else if (message_name == "show_web_inspector")
+			{
+				mLLCEFLib->showDevTools(true);
+			}
+			else if (message_name == "plugins_enabled")
+			{
+				mPluginsEnabled = message_in.getValueBoolean("enable");
+			}
+			else if (message_name == "javascript_enabled")
+			{
+				mJavascriptEnabled = message_in.getValueBoolean("enable");
+			}
+		}
+        else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+        {
+            if (message_name == "set_volume")
+            {
+                F32 volume = (F32)message_in.getValueReal("volume");
+                setVolume(volume);
+            }
+        }
+        else
+		{
+		};
+	}
+}
+
+LLCEFLib::EKeyboardModifier MediaPluginCEF::decodeModifiers(std::string &modifiers)
+{
+	int result = 0;
+
+	if (modifiers.find("shift") != std::string::npos)
+		result |= LLCEFLib::KM_MODIFIER_SHIFT;
+
+	if (modifiers.find("alt") != std::string::npos)
+		result |= LLCEFLib::KM_MODIFIER_ALT;
+
+	if (modifiers.find("control") != std::string::npos)
+		result |= LLCEFLib::KM_MODIFIER_CONTROL;
+
+	if (modifiers.find("meta") != std::string::npos)
+		result |= LLCEFLib::KM_MODIFIER_META;
+
+	return (LLCEFLib::EKeyboardModifier)result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers)
+{
+	native_scan_code = 0;
+	native_virtual_key = 0;
+	native_modifiers = 0;
+
+	if (native_key_data.isMap())
+	{
+#if LL_DARWIN
+		native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
+		native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
+		native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
+#elif LL_WINDOWS
+		native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
+		native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
+		// TODO: I don't think we need to do anything with native modifiers here -- please verify
+#endif
+	};
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::keyEvent(LLCEFLib::EKeyEvent key_event, int key, LLCEFLib::EKeyboardModifier modifiers_x, LLSD native_key_data = LLSD::emptyMap())
+{
+#if LL_DARWIN
+
+    if (!native_key_data.has("event_type") ||
+            !native_key_data.has("event_modifiers") ||
+            !native_key_data.has("event_keycode") ||
+            !native_key_data.has("event_isrepeat"))
+        return;
+    
+    uint32_t eventType = native_key_data["event_type"].asInteger();
+    if (!eventType)
+        return;
+    uint32_t eventModifiers = native_key_data["event_modifiers"].asInteger();
+    uint32_t eventKeycode = native_key_data["event_keycode"].asInteger();
+    char eventChars = static_cast<char>(native_key_data["event_chars"].isUndefined() ? 0 : native_key_data["event_chars"].asInteger());
+    char eventUChars = static_cast<char>(native_key_data["event_umodchars"].isUndefined() ? 0 : native_key_data["event_umodchars"].asInteger());
+    bool eventIsRepeat = native_key_data["event_isrepeat"].asBoolean();
+    
+    mLLCEFLib->keyboardEventOSX(eventType, eventModifiers, (eventChars) ? &eventChars : NULL,
+                                (eventUChars) ? &eventUChars : NULL, eventIsRepeat, eventKeycode);
+    
+#elif LL_WINDOWS
+	U32 msg = ll_U32_from_sd(native_key_data["msg"]);
+	U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
+	U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
+    
+	mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
+#endif
+};
+
+void MediaPluginCEF::unicodeInput(const std::string &utf8str, LLCEFLib::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
+{
+#if LL_DARWIN
+	//mLLCEFLib->keyPress(utf8str[0], true);
+	//mLLCEFLib->keyboardEvent(LLCEFLib::KE_KEY_DOWN, (uint32_t)(utf8str[0]), 0, LLCEFLib::KM_MODIFIER_NONE, 0, 0, 0);
+    if (!native_key_data.has("event_chars") || !native_key_data.has("event_umodchars") ||
+            !native_key_data.has("event_keycode") || !native_key_data.has("event_modifiers"))
+        return;
+    uint32_t unicodeChar = native_key_data["event_chars"].asInteger();
+    uint32_t unmodifiedChar = native_key_data["event_umodchars"].asInteger();
+    uint32_t keyCode = native_key_data["event_keycode"].asInteger();
+    uint32_t rawmodifiers = native_key_data["event_modifiers"].asInteger();
+    
+    mLLCEFLib->injectUnicodeText(unicodeChar, unmodifiedChar, keyCode, rawmodifiers);
+    
+#elif LL_WINDOWS
+	U32 msg = ll_U32_from_sd(native_key_data["msg"]);
+	U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
+	U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
+	mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::checkEditState()
+{
+	bool can_cut = mLLCEFLib->editCanCut();
+	bool can_copy = mLLCEFLib->editCanCopy();
+	bool can_paste = mLLCEFLib->editCanPaste();
+
+	if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
+
+		if (can_cut != mCanCut)
+		{
+			mCanCut = can_cut;
+			message.setValueBoolean("cut", can_cut);
+		}
+
+		if (can_copy != mCanCopy)
+		{
+			mCanCopy = can_copy;
+			message.setValueBoolean("copy", can_copy);
+		}
+
+		if (can_paste != mCanPaste)
+		{
+			mCanPaste = can_paste;
+			message.setValueBoolean("paste", can_paste);
+		}
+
+		sendMessage(message);
+	}
+}
+
+void MediaPluginCEF::setVolume(F32 vol)
+{
+    mVolumeCatcher.setVolume(vol);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::init()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+	message.setValue("name", "CEF Plugin");
+	sendMessage(message);
+
+	return true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
+	void* host_user_data,
+	LLPluginInstance::sendMessageFunction *plugin_send_func,
+	void **plugin_user_data)
+{
+	MediaPluginCEF* self = new MediaPluginCEF(host_send_func, host_user_data);
+	*plugin_send_func = MediaPluginCEF::staticReceiveMessage;
+	*plugin_user_data = (void*)self;
+
+	return 0;
+}
diff --git a/indra/media_plugins/webkit/volume_catcher.h b/indra/media_plugins/cef/volume_catcher.h
old mode 100755
new mode 100644
similarity index 100%
rename from indra/media_plugins/webkit/volume_catcher.h
rename to indra/media_plugins/cef/volume_catcher.h
diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/cef/windows_volume_catcher.cpp
old mode 100755
new mode 100644
similarity index 100%
rename from indra/media_plugins/webkit/windows_volume_catcher.cpp
rename to indra/media_plugins/cef/windows_volume_catcher.cpp
diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt
index 58391007fff486a814a3ffe9fee3da1cd98e8489..d7a1874bf334b3de2cacca3fe3ac1180852e7635 100755
--- a/indra/media_plugins/quicktime/CMakeLists.txt
+++ b/indra/media_plugins/quicktime/CMakeLists.txt
@@ -63,7 +63,8 @@ if (WINDOWS)
   set_target_properties(
     media_plugin_quicktime
     PROPERTIES
-    LINK_FLAGS "/MANIFEST:NO"
+    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT"
+    LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD"
     )
 endif (WINDOWS)
 
diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
index ff1ed8bfbcd52ad415dbeacc9295c6250df66ed0..7ef5a0fe44ed4b14321c70ba1ff3a198b3dd51c0 100755
--- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
+++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
@@ -837,7 +837,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
 			else if(message_name == "cleanup")
 			{
 				// TODO: clean up here
-			}
+                LLPluginMessage message("base", "goodbye");
+                sendMessage(message);
+            }
 			else if(message_name == "shm_added")
 			{
 				SharedSegmentInfo info;
diff --git a/indra/media_plugins/webkit/dummy_volume_catcher.cpp b/indra/media_plugins/webkit/dummy_volume_catcher.cpp
deleted file mode 100755
index d54b31b2ae22d270a80044e43bab4945156bc1e0..0000000000000000000000000000000000000000
--- a/indra/media_plugins/webkit/dummy_volume_catcher.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/** 
- * @file dummy_volume_catcher.cpp
- * @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet.
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "volume_catcher.h"
-
-
-class VolumeCatcherImpl
-{
-};
-
-/////////////////////////////////////////////////////
-
-VolumeCatcher::VolumeCatcher()
-{
-	pimpl = NULL;
-}
-
-VolumeCatcher::~VolumeCatcher()
-{
-}
-
-void VolumeCatcher::setVolume(F32 volume)
-{
-}
-
-void VolumeCatcher::setPan(F32 pan)
-{
-}
-
-void VolumeCatcher::pump()
-{
-}
-
diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp
deleted file mode 100755
index 91be3a89e9a6e58cee506e4312cc250647440351..0000000000000000000000000000000000000000
--- a/indra/media_plugins/webkit/linux_volume_catcher.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/** 
- * @file linux_volume_catcher.cpp
- * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-/*
-  The high-level design is as follows:
-  1) Connect to the PulseAudio daemon
-  2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins)
-  3) Examine any new audio player's PID to see if it belongs to our own process
-  4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance)
-  5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call
- */
-
-#include "linden_common.h"
-
-#include "volume_catcher.h"
-
-
-extern "C" {
-#include <glib.h>
-#include <glib-object.h>
-
-#include <pulse/introspect.h>
-#include <pulse/context.h>
-#include <pulse/subscribe.h>
-#include <pulse/glib-mainloop.h> // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken.
-
-#include "apr_pools.h"
-#include "apr_dso.h"
-}
-
-////////////////////////////////////////////////////
-
-#define DEBUGMSG(...) do {} while(0)
-#define INFOMSG(...) do {} while(0)
-#define WARNMSG(...) do {} while(0)
-
-#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) RTN (*ll##PASYM)(__VA_ARGS__) = NULL
-#include "linux_volume_catcher_pa_syms.inc"
-#include "linux_volume_catcher_paglib_syms.inc"
-#undef LL_PA_SYM
-
-static bool sSymsGrabbed = false;
-static apr_pool_t *sSymPADSOMemoryPool = NULL;
-static apr_dso_handle_t *sSymPADSOHandleG = NULL;
-
-bool grab_pa_syms(std::string pulse_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 *sSymPADSOHandle = NULL;
-
-#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0)
-
-	//attempt to load the shared library
-	apr_pool_create(&sSymPADSOMemoryPool, NULL);
-  
-	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle,
-					       pulse_dso_name.c_str(),
-					       sSymPADSOMemoryPool) ))
-	{
-		INFOMSG("Found DSO: %s", pulse_dso_name.c_str());
-
-#include "linux_volume_catcher_pa_syms.inc"
-#include "linux_volume_catcher_paglib_syms.inc"
-      
-		if ( sSymPADSOHandle )
-		{
-			sSymPADSOHandleG = sSymPADSOHandle;
-			sSymPADSOHandle = NULL;
-		}
-      
-		rtn = !sym_error;
-	}
-	else
-	{
-		INFOMSG("Couldn't load DSO: %s", pulse_dso_name.c_str());
-		rtn = false; // failure
-	}
-
-	if (sym_error)
-	{
-		WARNMSG("Failed to find necessary symbols in PulseAudio libraries.");
-	}
-#undef LL_PA_SYM
-
-	sSymsGrabbed = rtn;
-	return rtn;
-}
-
-
-void ungrab_pa_syms()
-{ 
-	// should be safe to call regardless of whether we've
-	// actually grabbed syms.
-
-	if ( sSymPADSOHandleG )
-	{
-		apr_dso_unload(sSymPADSOHandleG);
-		sSymPADSOHandleG = NULL;
-	}
-	
-	if ( sSymPADSOMemoryPool )
-	{
-		apr_pool_destroy(sSymPADSOMemoryPool);
-		sSymPADSOMemoryPool = NULL;
-	}
-	
-	// NULL-out all of the symbols we'd grabbed
-#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0)
-#include "linux_volume_catcher_pa_syms.inc"
-#include "linux_volume_catcher_paglib_syms.inc"
-#undef LL_PA_SYM
-
-	sSymsGrabbed = false;
-}
-////////////////////////////////////////////////////
-
-// PulseAudio requires a chain of callbacks with C linkage
-extern "C" {
-	void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata);
-	void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata);
-	void callback_context_state(pa_context *context, void *userdata);
-}
-
-
-class VolumeCatcherImpl
-{
-public:
-	VolumeCatcherImpl();
-	~VolumeCatcherImpl();
-
-	void setVolume(F32 volume);
-	void pump(void);
-
-	// for internal use - can't be private because used from our C callbacks
-
-	bool loadsyms(std::string pulse_dso_name);
-	void init();
-	void cleanup();
-
-	void update_all_volumes(F32 volume);
-	void update_index_volume(U32 index, F32 volume);
-	void connected_okay();
-
-	std::set<U32> mSinkInputIndices;
-	std::map<U32,U32> mSinkInputNumChannels;
-	F32 mDesiredVolume;
-	pa_glib_mainloop *mMainloop;
-	pa_context *mPAContext;
-	bool mConnected;
-	bool mGotSyms;
-};
-
-VolumeCatcherImpl::VolumeCatcherImpl()
-	: mDesiredVolume(0.0f),
-	  mMainloop(NULL),
-	  mPAContext(NULL),
-	  mConnected(false),
-	  mGotSyms(false)
-{
-	init();
-}
-
-VolumeCatcherImpl::~VolumeCatcherImpl()
-{
-	cleanup();
-}
-
-bool VolumeCatcherImpl::loadsyms(std::string pulse_dso_name)
-{
-	return grab_pa_syms(pulse_dso_name);
-}
-
-void VolumeCatcherImpl::init()
-{
-	// try to be as defensive as possible because PA's interface is a
-	// bit fragile and (for our purposes) we'd rather simply not function
-	// than crash
-
-	// we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in
-	// libpulse.so.0 - this isn't a great assumption, and the two DSOs should
-	// probably be loaded separately.  Our Linux DSO framework needs refactoring,
-	// we do this sort of thing a lot with practically identical logic...
-	mGotSyms = loadsyms("libpulse-mainloop-glib.so.0");
-	if (!mGotSyms) return;
-
-	// better make double-sure glib itself is initialized properly.
-	if (!g_thread_supported ()) g_thread_init (NULL);
-	g_type_init();
-
-	mMainloop = llpa_glib_mainloop_new(g_main_context_default());
-	if (mMainloop)
-	{
-		pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop);
-		if (api)
-		{
-			pa_proplist *proplist = llpa_proplist_new();
-			if (proplist)
-			{
-				llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player");
-				llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust");
-				llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster");
-				llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1");
-
-				// plain old pa_context_new() is broken!
-				mPAContext = llpa_context_new_with_proplist(api, NULL, proplist);
-				llpa_proplist_free(proplist);
-			}
-		}
-	}
-
-	// Now we've set up a PA context and mainloop, try connecting the
-	// PA context to a PA daemon.
-	if (mPAContext)
-	{
-		llpa_context_set_state_callback(mPAContext, callback_context_state, this);
-		pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN?
-		if (llpa_context_connect(mPAContext, NULL, cflags, NULL) >= 0)
-		{
-			// Okay!  We haven't definitely connected, but we
-			// haven't definitely failed yet.
-		}
-		else
-		{
-			// Failed to connect to PA manager... we'll leave
-			// things like that.  Perhaps we should try again later.
-		}
-	}
-}
-
-void VolumeCatcherImpl::cleanup()
-{
-	mConnected = false;
-
-	if (mGotSyms && mPAContext)
-	{
-		llpa_context_disconnect(mPAContext);
-		llpa_context_unref(mPAContext);
-	}
-	mPAContext = NULL;
-
-	if (mGotSyms && mMainloop)
-	{
-		llpa_glib_mainloop_free(mMainloop);
-	}
-	mMainloop = NULL;
-}
-
-void VolumeCatcherImpl::setVolume(F32 volume)
-{
-	mDesiredVolume = volume;
-	
-	if (!mGotSyms) return;
-
-	if (mConnected && mPAContext)
-	{
-		update_all_volumes(mDesiredVolume);
-	}
-
-	pump();
-}
-
-void VolumeCatcherImpl::pump()
-{
-	gboolean may_block = FALSE;
-	g_main_context_iteration(g_main_context_default(), may_block);
-}
-
-void VolumeCatcherImpl::connected_okay()
-{
-	pa_operation *op;
-
-	// fetch global list of existing sinkinputs
-	if ((op = llpa_context_get_sink_input_info_list(mPAContext,
-							callback_discovered_sinkinput,
-							this)))
-	{
-		llpa_operation_unref(op);
-	}
-
-	// subscribe to future global sinkinput changes
-	llpa_context_set_subscribe_callback(mPAContext,
-					    callback_subscription_alert,
-					    this);
-	if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t)
-					 (PA_SUBSCRIPTION_MASK_SINK_INPUT),
-					 NULL, NULL)))
-	{
-		llpa_operation_unref(op);
-	}
-}
-
-void VolumeCatcherImpl::update_all_volumes(F32 volume)
-{
-	for (std::set<U32>::iterator it = mSinkInputIndices.begin();
-	     it != mSinkInputIndices.end(); ++it)
-	{
-		update_index_volume(*it, volume);
-	}
-}
-
-void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume)
-{
-	static pa_cvolume cvol;
-	llpa_cvolume_set(&cvol, mSinkInputNumChannels[index],
-			 llpa_sw_volume_from_linear(volume));
-	
-	pa_context *c = mPAContext;
-	uint32_t idx = index;
-	const pa_cvolume *cvolumep = &cvol;
-	pa_context_success_cb_t cb = NULL; // okay as null
-	void *userdata = NULL; // okay as null
-
-	pa_operation *op;
-	if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata)))
-	{
-		llpa_operation_unref(op);
-	}
-}
-
-
-void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata)
-{
-	VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
-	llassert(impl);
-
-	if (0 == eol)
-	{
-		pa_proplist *proplist = sii->proplist;
-		pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID));
-		
-		if (sinkpid == getpid()) // does the discovered sinkinput belong to this process?
-		{
-			bool is_new = (impl->mSinkInputIndices.find(sii->index) ==
-				       impl->mSinkInputIndices.end());
-			
-			impl->mSinkInputIndices.insert(sii->index);
-			impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels;
-			
-			if (is_new)
-			{
-				// new!
-				impl->update_index_volume(sii->index, impl->mDesiredVolume);
-			}
-			else
-			{
-				// seen it already, do nothing.
-			}
-		}
-	}
-}
-
-void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata)
-{
-	VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
-	llassert(impl);
-
-	switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
-        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
-		if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) ==
-		    PA_SUBSCRIPTION_EVENT_REMOVE)
-		{
-			// forget this sinkinput, if we were caring about it
-			impl->mSinkInputIndices.erase(index);
-			impl->mSinkInputNumChannels.erase(index);
-		}
-		else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) ==
-			 PA_SUBSCRIPTION_EVENT_NEW)
-		{
-			// ask for more info about this new sinkinput
-			pa_operation *op;
-			if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl)))
-			{
-				llpa_operation_unref(op);
-			}
-		}
-		else
-		{
-			// property change on this sinkinput - we don't care.
-		}
-		break;
-		
-	default:;
-	}
-}
-
-void callback_context_state(pa_context *context, void *userdata)
-{
-	VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
-	llassert(impl);
-	
-	switch (llpa_context_get_state(context))
-	{
-	case PA_CONTEXT_READY:
-		impl->mConnected = true;
-		impl->connected_okay();
-		break;
-	case PA_CONTEXT_TERMINATED:
-		impl->mConnected = false;
-		break;
-	case PA_CONTEXT_FAILED:
-		impl->mConnected = false;
-		break;
-	default:;
-	}
-}
-
-/////////////////////////////////////////////////////
-
-VolumeCatcher::VolumeCatcher()
-{
-	pimpl = new VolumeCatcherImpl();
-}
-
-VolumeCatcher::~VolumeCatcher()
-{
-	delete pimpl;
-	pimpl = NULL;
-}
-
-void VolumeCatcher::setVolume(F32 volume)
-{
-	llassert(pimpl);
-	pimpl->setVolume(volume);
-}
-
-void VolumeCatcher::setPan(F32 pan)
-{
-	// TODO: implement this (if possible)
-}
-
-void VolumeCatcher::pump()
-{
-	llassert(pimpl);
-	pimpl->pump();
-}
diff --git a/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc
deleted file mode 100755
index d806b4842875b2962ceb74943b65f324b26d24ed..0000000000000000000000000000000000000000
--- a/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc
+++ /dev/null
@@ -1,21 +0,0 @@
-// required symbols to grab
-LL_PA_SYM(true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api);
-LL_PA_SYM(true, pa_context_disconnect, void, pa_context *c);
-LL_PA_SYM(true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_get_state, pa_context_state_t, pa_context *c);
-LL_PA_SYM(true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist);
-LL_PA_SYM(true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata);
-LL_PA_SYM(true, pa_context_unref, void, pa_context *c);
-LL_PA_SYM(true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v);
-LL_PA_SYM(true, pa_operation_unref, void, pa_operation *o);
-LL_PA_SYM(true, pa_proplist_free, void, pa_proplist* p);
-LL_PA_SYM(true, pa_proplist_gets, const char*, pa_proplist *p, const char *key);
-LL_PA_SYM(true, pa_proplist_new, pa_proplist*, void);
-LL_PA_SYM(true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value);
-LL_PA_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v);
-
-// optional symbols to grab
diff --git a/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc
deleted file mode 100755
index abf628c96c304692c538124932f02bfb35e6fbca..0000000000000000000000000000000000000000
--- a/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc
+++ /dev/null
@@ -1,6 +0,0 @@
-// required symbols to grab
-LL_PA_SYM(true, pa_glib_mainloop_free, void, pa_glib_mainloop* g);
-LL_PA_SYM(true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g);
-LL_PA_SYM(true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c);
-
-// optional symbols to grab
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
deleted file mode 100755
index 3edeef51e3311e67e3cff32b2292d12664916e17..0000000000000000000000000000000000000000
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ /dev/null
@@ -1,1481 +0,0 @@
-/** 
- * @file media_plugin_webkit.cpp
- * @brief Webkit plugin for LLMedia API plugin system
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-#include "llqtwebkit.h"
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "lltimer.h"
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
-#if LL_LINUX
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-extern "C" {
-# include <glib.h>
-# include <glib-object.h>
-}
-#else
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-#endif // LL_LINUX
-
-# include "volume_catcher.h"
-
-#if LL_WINDOWS
-# include <direct.h>
-#else
-# include <unistd.h>
-# include <stdlib.h>
-#endif
-
-#if LL_WINDOWS
-	// *NOTE:Mani - This captures the module handle for the dll. This is used below
-	// to get the path to this dll for webkit initialization.
-	// I don't know how/if this can be done with apr...
-	namespace {	HMODULE gModuleHandle;};
-	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-	{
-		gModuleHandle = (HMODULE) hinstDLL;
-		return TRUE;
-	}
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginWebKit : 
-		public MediaPluginBase,
-		public LLEmbeddedBrowserWindowObserver
-{
-public:
-	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
-	~MediaPluginWebKit();
-
-	/*virtual*/ void receiveMessage(const char *message_string);
-
-private:
-
-	std::string mProfileDir;
-	std::string mHostLanguage;
-	std::string mUserAgent;
-	bool mCookiesEnabled;
-	bool mJavascriptEnabled;
-	bool mPluginsEnabled;
-	bool mEnableMediaPluginDebugging;
-
-	enum
-	{
-		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet
-		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet.
-		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued
-		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed
-		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws
-		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event
-		INIT_STATE_RUNNING				// All initialization gymnastics are complete.
-	};
-	int mBrowserWindowId;
-	int mInitState;
-	std::string mInitialNavigateURL;
-	bool mNeedsUpdate;
-
-	bool	mCanCut;
-	bool	mCanCopy;
-	bool	mCanPaste;
-	int mLastMouseX;
-	int mLastMouseY;
-	bool mFirstFocus;
-	F32 mBackgroundR;
-	F32 mBackgroundG;
-	F32 mBackgroundB;
-	std::string mTarget;
-	LLTimer mElapsedTime;
-		
-	VolumeCatcher mVolumeCatcher;
-
-	void postDebugMessage( const std::string& msg )
-	{
-		if ( mEnableMediaPluginDebugging )
-		{
-			std::stringstream str;
-			str << "@Media Msg> " << "[" << (double)mElapsedTime.getElapsedTimeF32()  << "] -- " << msg;
-
-			LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
-			debug_message.setValue("message_text", str.str());
-			debug_message.setValue("message_level", "info");
-			sendMessage(debug_message);
-		}
-	}
-	
-	void setInitState(int state)
-	{
-//		std::cerr << "changing init state to " << state << std::endl;
-		mInitState = state;
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void update(int milliseconds)
-	{
-#if LL_QTLINUX_DOESNT_HAVE_GLIB
-		// pump glib generously, as Linux browser plugins are on the
-		// glib main loop, even if the browser itself isn't - ugh
-		// This is NOT NEEDED if Qt itself was built with glib
-		// mainloop integration.
-		GMainContext *mainc = g_main_context_default();
-		while(g_main_context_iteration(mainc, FALSE));
-#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
-
-		// pump qt
-		LLQtWebKit::getInstance()->pump( milliseconds );
-		
-		mVolumeCatcher.pump();
-
-		checkEditState();
-		
-		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			if(!mInitialNavigateURL.empty())
-			{
-				// We already have the initial navigate URL -- kick off the navigate.
-				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
-				mInitialNavigateURL.clear();
-			}
-		}
-		
-		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
-		{
-			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
-
-			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
-			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
-#if !LL_QTWEBKIT_USES_PIXMAPS
-			unsigned int buffer_size = rowspan * height;
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-			
-//			std::cerr << "webkit plugin: updating" << std::endl;
-			
-			// TODO: should get rid of this memcpy if possible
-			if ( mPixels && browser_pixels )
-			{
-//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
-
-#if LL_QTWEBKIT_USES_PIXMAPS
-				// copy the pixel data upside-down because of the co-ord system
-				for (int y=0; y<height; ++y)
-				{
-					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
-				}
-#else
-				memcpy( mPixels, browser_pixels, buffer_size );
-#endif // LL_QTWEBKIT_USES_PIXMAPS
-			}
-
-			if ( mWidth > 0 && mHeight > 0 )
-			{
-//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
-				setDirty( 0, 0, mWidth, mHeight );
-			}
-
-			mNeedsUpdate = false;
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	bool initBrowser()
-	{
-		// already initialized
-		if ( mInitState > INIT_STATE_UNINITIALIZED )
-			return true;
-
-		// set up directories
-		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
-		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-		{
-			LL_WARNS() << "Couldn't get cwd - probably too long - failing to init." << LL_ENDL;
-			return false;
-		}
-		std::string application_dir = std::string( cwd );
-
-#if LL_LINUX
-		// take care to initialize glib properly, because some
-		// versions of Qt don't, and we indirectly need it for (some
-		// versions of) Flash to not crash the browser.
-		if (!g_thread_supported ()) g_thread_init (NULL);
-		g_type_init();
-#endif
-
-#if LL_DARWIN
-		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
-		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
-		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
-		// which gets hit when the plugin is probed by webkit.
-		// Unsetting the environment variable here works around this issue.
-		unsetenv("USERBREAK");
-#endif
-
-#if LL_WINDOWS
-		//*NOTE:Mani - On windows, at least, the component path is the
-		// location of this dll's image file. 
-		std::string component_dir;
-		char dll_path[_MAX_PATH];
-		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
-		while(len && dll_path[ len ] != ('\\') )
-		{
-			len--;
-		}
-		if(len >= 0)
-		{
-			dll_path[len] = 0;
-			component_dir = dll_path;
-		}
-		else
-		{
-			// *NOTE:Mani - This case should be an rare exception. 
-			// GetModuleFileNameA should always give you a full path, no?
-			component_dir = application_dir;
-		}
-#else
-		std::string component_dir = application_dir;
-#endif
-
-		// debug spam sent to viewer and displayed in the log as usual
-		postDebugMessage( "Component dir set to: " + component_dir );
-
-		// window handle - needed on Windows and must be app window.
-#if LL_WINDOWS
-		char window_title[ MAX_PATH ];
-		GetConsoleTitleA( window_title, MAX_PATH );
-		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
-#else
-		void* native_window_handle = 0;
-#endif
-
-		// main browser initialization
-		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
-		if ( result )
-		{
-			mInitState = INIT_STATE_INITIALIZED;
-
-			// debug spam sent to viewer and displayed in the log as usual
-			postDebugMessage( "browser initialized okay" );
-
-			return true;
-		};
-
-		// debug spam sent to viewer and displayed in the log as usual
-		postDebugMessage( "browser nOT initialized." );
-
-		return false;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	bool initBrowserWindow()
-	{
-		// already initialized
-		if ( mInitState > INIT_STATE_INITIALIZED )
-			return true;
-
-		// not enough information to initialize the browser yet.
-		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
-				mTextureWidth < 0 || mTextureHeight < 0 )
-		{
-			return false;
-		};
-		
-		// Set up host language before creating browser window
-		if(!mHostLanguage.empty())
-		{
-			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
-			postDebugMessage( "Setting language to " + mHostLanguage );
-		}
-
-		// turn on/off cookies based on what host app tells us
-		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
-		
-		// turn on/off plugins based on what host app tells us
-		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
-
-		// turn on/off Javascript based on what host app tells us
-#if LLQTWEBKIT_API_VERSION >= 11
-		LLQtWebKit::getInstance()->enableJavaScript( mJavascriptEnabled );
-#else
-		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
-#endif
-
-		std::stringstream str;
-		str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled;
-		postDebugMessage( str.str() );
-
-		// create single browser window
-		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
-
-		str.str("");
-		str.clear();
-		str << "Setting browser window size to " << mWidth << " x " << mHeight;
-		postDebugMessage( str.str() );
-
-		// tell LLQtWebKit about the size of the browser window
-		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-
-		// observer events that LLQtWebKit emits
-		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
-
-		// append details to agent string
-		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
-		postDebugMessage( "Updating user agent with " + mUserAgent );
-
-#if !LL_QTWEBKIT_USES_PIXMAPS
-		// don't flip bitmap
-		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-
-		// set background color
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
-
-		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
-		setInitState(INIT_STATE_NAVIGATING);
-
-		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
-		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
-		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
-		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
-		// where RRGGBB is the background color in HTML style
-		std::stringstream url;
-		
-		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
-		url << "%22%3E%3C/body%3E%3C/html%3E";
-		
-		//LL_DEBUGS() << "data url is: " << url.str() << LL_ENDL;
-
-		// always display loading overlay now
-#if LLQTWEBKIT_API_VERSION >= 16
-		LLQtWebKit::getInstance()->enableLoadingOverlay(mBrowserWindowId, true);
-#else
-		LL_WARNS() << "Ignoring enableLoadingOverlay() call (llqtwebkit version is too old)." << LL_ENDL;
-#endif
-		str.clear();
-		str << "Loading overlay enabled = " << mEnableMediaPluginDebugging << " for mBrowserWindowId = " << mBrowserWindowId;
-		postDebugMessage( str.str() );
-
-		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
-//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
-
-		return true;	
-	}
-
-	void setVolume(F32 vol);
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onCursorChanged(const EventType& event)
-	{
-		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
-		std::string name;
-
-		switch(llqt_cursor)
-		{
-			case LLQtWebKit::C_ARROW:
-				name = "arrow";
-			break;
-			case LLQtWebKit::C_IBEAM:
-				name = "ibeam";
-			break;
-			case LLQtWebKit::C_SPLITV:
-				name = "splitv";
-			break;
-			case LLQtWebKit::C_SPLITH:
-				name = "splith";
-			break;
-			case LLQtWebKit::C_POINTINGHAND:
-				name = "hand";
-			break;
-			
-			default:
-				LL_WARNS() << "Unknown cursor ID: " << (int)llqt_cursor << LL_ENDL;
-			break;
-		}
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
-		message.setValue("name", name);
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onPageChanged( const EventType& event )
-	{
-		if(mInitState == INIT_STATE_WAIT_REDRAW)
-		{
-			setInitState(INIT_STATE_WAIT_COMPLETE);
-		}
-		
-		// flag that an update is required
-		mNeedsUpdate = true;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateBegin(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
-			message.setValue("uri", event.getEventUri());
-			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
-			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
-			sendMessage(message);
-
-			// debug spam sent to viewer and displayed in the log as usual
-			postDebugMessage( "Navigate begin event at: " + event.getEventUri() );
-
-			setStatus(STATUS_LOADING);
-		}
-
-		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
-//			setInitState(INIT_STATE_WAIT_REDRAW);
-			setInitState(INIT_STATE_WAIT_COMPLETE);
-		}
-		
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateComplete(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			if(mInitState < INIT_STATE_RUNNING)
-			{
-				setInitState(INIT_STATE_RUNNING);
-				
-				// Clear the history, so the "back" button doesn't take you back to "about:blank".
-				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
-			}
-			
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
-			message.setValue("uri", event.getEventUri());
-			message.setValueS32("result_code", event.getIntValue());
-			message.setValue("result_string", event.getStringValue());
-			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
-			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
-			sendMessage(message);
-			
-			setStatus(STATUS_LOADED);
-		}
-		else if(mInitState == INIT_STATE_NAVIGATING)
-		{
-			setInitState(INIT_STATE_NAVIGATE_COMPLETE);
-		}
-
-		// debug spam sent to viewer and displayed in the log as usual
-		postDebugMessage( "Navigate complete event at: " + event.getEventUri() );
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onUpdateProgress(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
-			message.setValueS32("percent", event.getIntValue());
-			sendMessage(message);
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onStatusTextChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
-			message.setValue("status", event.getStringValue());
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onTitleChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
-			message.setValue("name", event.getStringValue());
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateErrorPage(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
-		message.setValueS32("status_code", event.getIntValue());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLocationChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
-			message.setValue("uri", event.getEventUri());
-			sendMessage(message);
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkHref(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
-		message.setValue("uri", event.getEventUri());
-		message.setValue("target", event.getStringValue());
-		message.setValue("uuid", event.getStringValue2());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkNoFollow(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
-		message.setValue("uri", event.getEventUri());
-#if LLQTWEBKIT_API_VERSION >= 7
-		message.setValue("nav_type", event.getNavigationType());
-#else
-		message.setValue("nav_type", "clicked");
-#endif
-		sendMessage(message);
-	}
-	
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onCookieChanged(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
-		message.setValue("cookie", event.getStringValue());
-		// These could be passed through as well, but aren't really needed.
-//		message.setValue("uri", event.getEventUri());
-//		message.setValueBoolean("dead", (event.getIntValue() != 0))
-
-		// debug spam
-		postDebugMessage( "Sending cookie_set message from plugin: " + event.getStringValue() );
-
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onWindowCloseRequested(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
-		message.setValue("uuid", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onWindowGeometryChangeRequested(const EventType& event)
-	{
-		int x, y, width, height;
-		event.getRectValue(x, y, width, height);
-
-		// This sometimes gets called with a zero-size request.  Don't pass these along.
-		if(width > 0 && height > 0)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
-			message.setValue("uuid", event.getStringValue());
-			message.setValueS32("x", x);
-			message.setValueS32("y", y);
-			message.setValueS32("width", width);
-			message.setValueS32("height", height);
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	std::string onRequestFilePicker( const EventType& eventIn )
-	{
-		return blockingPickFile();
-	}
-	
-	std::string mAuthUsername;
-	std::string mAuthPassword;
-	bool mAuthOK;
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
-	{
-		mAuthOK = false;
-
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
-		message.setValue("url", in_url);
-		message.setValue("realm", in_realm);
-		message.setValueBoolean("blocking_request", true);
-				
-		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
-		sendMessage(message);
-		
-		if(mAuthOK)
-		{
-			out_username = mAuthUsername;
-			out_password = mAuthPassword;
-		}
-		
-		return mAuthOK;
-	}
-	
-	void authResponse(LLPluginMessage &message)
-	{
-		mAuthOK = message.getValueBoolean("ok");
-		if(mAuthOK)
-		{
-			mAuthUsername = message.getValue("username");
-			mAuthPassword = message.getValue("password");
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLinkHovered(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
-			message.setValue("link", event.getEventUri());
-			message.setValue("title", event.getStringValue());
-			message.setValue("text", event.getStringValue2());
-			sendMessage(message);
-		}
-	}
-	
-	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
-	{
-		int result = 0;
-		
-		if(modifiers.find("shift") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_SHIFT;
-
-		if(modifiers.find("alt") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_ALT;
-		
-		if(modifiers.find("control") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_CONTROL;
-		
-		if(modifiers.find("meta") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_META;
-		
-		return (LLQtWebKit::EKeyboardModifier)result;
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
-	{
-		native_scan_code = 0;
-		native_virtual_key = 0;
-		native_modifiers = 0;
-		
-		if( native_key_data.isMap() )
-		{
-#if LL_DARWIN
-			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
-			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#elif LL_WINDOWS
-			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
-			// TODO: I don't think we need to do anything with native modifiers here -- please verify
-#elif LL_LINUX
-			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
-			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#else
-			// Add other platforms here as needed
-#endif
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
-	{
-		// The incoming values for 'key' will be the ones from indra_constants.h
-		std::string utf8_text;
-		
-		if(key < KEY_SPECIAL)
-		{
-			// Low-ascii characters need to get passed through.
-			utf8_text = (char)key;
-		}
-		
-		// Any special-case handling we want to do for particular keys...
-		switch((KEY)key)
-		{
-			// ASCII codes for some standard keys
-			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break;
-			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break;
-			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break;
-			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break;
-			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break;
-			
-			default:  
-			break;
-		}
-		
-//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
-		
-		uint32_t native_scan_code = 0;
-		uint32_t native_virtual_key = 0;
-		uint32_t native_modifiers = 0;
-		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-		
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
-	{		
-		uint32_t key = LLQtWebKit::KEY_NONE;
-		
-//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
-		
-		if(utf8str.size() == 1)
-		{
-			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
-			// In this case, use it as the key value.
-			key = utf8str[0];
-		}
-
-		uint32_t native_scan_code = 0;
-		uint32_t native_virtual_key = 0;
-		uint32_t native_modifiers = 0;
-		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-		
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
-		checkEditState();
-	};
-	
-	void checkEditState(void)
-	{
-		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
-		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
-		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
-					
-		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
-			
-			if(can_cut != mCanCut)
-			{
-				mCanCut = can_cut;
-				message.setValueBoolean("cut", can_cut);
-			}
-
-			if(can_copy != mCanCopy)
-			{
-				mCanCopy = can_copy;
-				message.setValueBoolean("copy", can_copy);
-			}
-
-			if(can_paste != mCanPaste)
-			{
-				mCanPaste = can_paste;
-				message.setValueBoolean("paste", can_paste);
-			}
-			
-			sendMessage(message);
-			
-		}
-	}
-	
-	std::string mPickedFile;
-	
-	std::string blockingPickFile(void)
-	{
-		mPickedFile.clear();
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
-		message.setValueBoolean("blocking_request", true);
-		
-		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
-		sendMessage(message);
-		
-		return mPickedFile;
-	}
-
-	void onPickFileResponse(const std::string &file)
-	{
-		mPickedFile = file;
-	}
-
-};
-
-MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
-	MediaPluginBase(host_send_func, host_user_data)
-{
-//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
-
-	mBrowserWindowId = 0;
-	mInitState = INIT_STATE_UNINITIALIZED;
-	mNeedsUpdate = true;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-	mLastMouseX = 0;
-	mLastMouseY = 0;
-	mFirstFocus = true;
-	mBackgroundR = 0.0f;
-	mBackgroundG = 0.0f;
-	mBackgroundB = 0.0f;
-
-	mHostLanguage = "en";		// default to english
-	mJavascriptEnabled = true;	// default to on
-	mPluginsEnabled = true;		// default to on
-	mEnableMediaPluginDebugging = false;
-	mUserAgent = "LLPluginMedia Web Browser";
-
-	mElapsedTime.reset();
-}
-
-MediaPluginWebKit::~MediaPluginWebKit()
-{
-	// unhook observer
-	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-
-	// clean up
-	LLQtWebKit::getInstance()->reset();
-
-//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
-}
-
-void MediaPluginWebKit::receiveMessage(const char *message_string)
-{
-//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
-	LLPluginMessage message_in;
-	
-	if(message_in.parse(message_string) >= 0)
-	{
-		std::string message_class = message_in.getClass();
-		std::string message_name = message_in.getName();
-		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
-		{
-			if(message_name == "init")
-			{
-				LLPluginMessage message("base", "init_response");
-				LLSD versions = LLSD::emptyMap();
-				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
-				message.setValueLLSD("versions", versions);
-
-				std::string plugin_version = "Webkit media plugin, Webkit version ";
-				plugin_version += LLQtWebKit::getInstance()->getVersion();
-				message.setValue("plugin_version", plugin_version);
-				sendMessage(message);
-			}
-			else if(message_name == "idle")
-			{
-				// no response is necessary here.
-				F64 time = message_in.getValueReal("time");
-				
-				// Convert time to milliseconds for update()
-				update((int)(time * 1000.0f));
-			}
-			else if(message_name == "cleanup")
-			{
-				// DTOR most likely won't be called but the recent change to the way this process
-				// is (not) killed means we see this message and can do what we need to here.
-				// Note: this cleanup is ultimately what writes cookies to the disk
-				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-				LLQtWebKit::getInstance()->reset();
-			}
-			else if(message_name == "shm_added")
-			{
-				SharedSegmentInfo info;
-				info.mAddress = message_in.getValuePointer("address");
-				info.mSize = (size_t)message_in.getValueS32("size");
-				std::string name = message_in.getValue("name");
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
-//					<< ", size: " << info.mSize 
-//					<< ", address: " << info.mAddress 
-//					<< std::endl;
-
-				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-			
-			}
-			else if(message_name == "shm_remove")
-			{
-				std::string name = message_in.getValue("name");
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
-
-				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-				if(iter != mSharedSegments.end())
-				{
-					if(mPixels == iter->second.mAddress)
-					{
-						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
-						mPixels = NULL;
-						mTextureSegmentName.clear();
-					}
-					mSharedSegments.erase(iter);
-				}
-				else
-				{
-//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
-				}
-
-				// Send the response so it can be cleaned up.
-				LLPluginMessage message("base", "shm_remove_response");
-				message.setValue("name", name);
-				sendMessage(message);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
-		{
-			if(message_name == "set_volume")
-			{
-				F32 volume = (F32)message_in.getValueReal("volume");
-				setVolume(volume);
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-		{
-			if(message_name == "init")
-			{
-				mTarget = message_in.getValue("target");
-				
-				// This is the media init message -- all necessary data for initialization should have been received.
-				if(initBrowser())
-				{
-					
-					// Plugin gets to decide the texture parameters to use.
-					mDepth = 4;
-
-					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
-					message.setValueS32("default_width", 1024);
-					message.setValueS32("default_height", 1024);
-					message.setValueS32("depth", mDepth);
-					message.setValueU32("internalformat", GL_RGBA);
-	#if LL_QTWEBKIT_USES_PIXMAPS
-					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck.
-	#else
-					message.setValueU32("format", GL_RGBA);
-	#endif // LL_QTWEBKIT_USES_PIXMAPS
-					message.setValueU32("type", GL_UNSIGNED_BYTE);
-					message.setValueBoolean("coords_opengl", true);
-					sendMessage(message);
-				}
-				else
-				{
-					// if initialization failed, we're done.
-					mDeleteMe = true;
-				}
-
-			}
-			else if(message_name == "set_user_data_path")
-			{
-				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
-				mProfileDir = user_data_path + "browser_profile";
-
-				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
-			}
-			else if(message_name == "set_language_code")
-			{
-				mHostLanguage = message_in.getValue("language");
-
-				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
-			}
-			else if(message_name == "plugins_enabled")
-			{
-				mPluginsEnabled = message_in.getValueBoolean("enable");
-			}
-			else if(message_name == "javascript_enabled")
-			{
-				mJavascriptEnabled = message_in.getValueBoolean("enable");
-			}
-			else if(message_name == "size_change")
-			{
-				std::string name = message_in.getValue("name");
-				S32 width = message_in.getValueS32("width");
-				S32 height = message_in.getValueS32("height");
-				S32 texture_width = message_in.getValueS32("texture_width");
-				S32 texture_height = message_in.getValueS32("texture_height");
-				mBackgroundR = (F32)message_in.getValueReal("background_r");
-				mBackgroundG = (F32)message_in.getValueReal("background_g");
-				mBackgroundB = (F32)message_in.getValueReal("background_b");
-//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha
-								
-				if(!name.empty())
-				{
-					// Find the shared memory region with this name
-					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-					if(iter != mSharedSegments.end())
-					{
-						mPixels = (unsigned char*)iter->second.mAddress;
-						mWidth = width;
-						mHeight = height;
-
-						if(initBrowserWindow())
-						{
-
-							// size changed so tell the browser
-							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-							
-	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
-	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
-									
-							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
-							
-							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
-							if(real_width <= texture_width)
-							{
-								texture_width = real_width;
-							}
-							else
-							{
-								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
-	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
-								mDeleteMe = true;
-								return;
-							}
-						}
-						else
-						{
-							// Setting up the browser window failed.  This is a fatal error.
-							mDeleteMe = true;
-						}
-
-						
-						mTextureWidth = texture_width;
-						mTextureHeight = texture_height;
-						
-					};
-				};
-
-				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
-				message.setValue("name", name);
-				message.setValueS32("width", width);
-				message.setValueS32("height", height);
-				message.setValueS32("texture_width", texture_width);
-				message.setValueS32("texture_height", texture_height);
-				sendMessage(message);
-
-			}
-			else if(message_name == "load_uri")
-			{
-				std::string uri = message_in.getValue("uri");
-
-//				std::cout << "loading URI: " << uri << std::endl;
-				
-				if(!uri.empty())
-				{
-					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-					{
-						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
-					}
-					else
-					{
-						mInitialNavigateURL = uri;
-					}
-				}
-			}
-			else if(message_name == "mouse_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 button = message_in.getValueS32("button");
-				mLastMouseX = message_in.getValueS32("x");
-				mLastMouseY = message_in.getValueS32("y");
-				std::string modifiers = message_in.getValue("modifiers");
-				
-				// Treat unknown mouse events as mouse-moves.
-				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
-				if(event == "down")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
-				}
-				else if(event == "up")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_UP;
-				}
-				else if(event == "double_click")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
-				}
-				
-				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
-				checkEditState();
-			}
-			else if(message_name == "scroll_event")
-			{
-				S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				std::string modifiers = message_in.getValue("modifiers");
-				
-				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
-				// Qt expects 1 detent to be 120 units.
-				// It also seems that our y scroll direction is inverted vs. what Qt expects.
-				
-				x *= 120;
-				y *= -120;
-				
-				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
-			}
-			else if(message_name == "key_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 key = message_in.getValueS32("key");
-				std::string modifiers = message_in.getValue("modifiers");
-				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-				
-				// Treat unknown events as key-up for safety.
-				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
-				if(event == "down")
-				{
-					key_event = LLQtWebKit::KE_KEY_DOWN;
-				}
-				else if(event == "repeat")
-				{
-					key_event = LLQtWebKit::KE_KEY_REPEAT;
-				}
-				
-				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
-			}
-			else if(message_name == "text_event")
-			{
-				std::string text = message_in.getValue("text");
-				std::string modifiers = message_in.getValue("modifiers");
-				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-				
-				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
-			}
-			if(message_name == "edit_cut")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
-				checkEditState();
-			}
-			if(message_name == "edit_copy")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
-				checkEditState();
-			}
-			if(message_name == "edit_paste")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
-				checkEditState();
-			}
-			if(message_name == "pick_file_response")
-			{
-				onPickFileResponse(message_in.getValue("file"));
-			}
-			if(message_name == "auth_response")
-			{
-				authResponse(message_in);
-			}
-			else
-			if(message_name == "enable_media_plugin_debugging")
-			{
-				mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" );
-			}
-			else
-			if(message_name == "js_enable_object")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				bool enable = message_in.getValueBoolean( "enable" );
-				LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
-#endif
-			}
-			else
-			if(message_name == "js_agent_location")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 x = (F32)message_in.getValueReal("x");
-				F32 y = (F32)message_in.getValueReal("y");
-				F32 z = (F32)message_in.getValueReal("z");
-				LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-			if(message_name == "js_agent_global_location")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 x = (F32)message_in.getValueReal("x");
-				F32 y = (F32)message_in.getValueReal("y");
-				F32 z = (F32)message_in.getValueReal("z");
-				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else			
-			if(message_name == "js_agent_orientation")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 angle = (F32)message_in.getValueReal("angle");
-				LLQtWebKit::getInstance()->setAgentOrientation( angle );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-			if(message_name == "js_agent_region")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				const std::string& region = message_in.getValue("region");
-				LLQtWebKit::getInstance()->setAgentRegion( region );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-				if(message_name == "js_agent_maturity")
-				{
-#if LLQTWEBKIT_API_VERSION >= 9
-					const std::string& maturity = message_in.getValue("maturity");
-					LLQtWebKit::getInstance()->setAgentMaturity( maturity );
-					LLQtWebKit::getInstance()->emitMaturity();
-#endif
-				}
-			else
-			if(message_name == "js_agent_language")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				const std::string& language = message_in.getValue("language");
-				LLQtWebKit::getInstance()->setAgentLanguage( language );
-				LLQtWebKit::getInstance()->emitLanguage();
-#endif
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
-		{
-			if(message_name == "focus")
-			{
-				bool val = message_in.getValueBoolean("focused");
-				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
-				
-				if(mFirstFocus && val)
-				{
-					// On the first focus, post a tab key event.  This fixes a problem with initial focus.
-					std::string empty;
-					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
-					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
-					mFirstFocus = false;
-				}
-			}
-			else if(message_name == "set_page_zoom_factor")
-			{
-#if LLQTWEBKIT_API_VERSION >= 15
-				F32 factor = (F32)message_in.getValueReal("factor");
-				LLQtWebKit::getInstance()->setPageZoomFactor(factor);
-#else
-				LL_WARNS() << "Ignoring setPageZoomFactor message (llqtwebkit version is too old)." << LL_ENDL;
-#endif
-			}
-			else if(message_name == "clear_cache")
-			{
-				LLQtWebKit::getInstance()->clearCache();
-			}
-			else if(message_name == "clear_cookies")
-			{
-				LLQtWebKit::getInstance()->clearAllCookies();
-			}
-			else if(message_name == "enable_cookies")
-			{
-				mCookiesEnabled = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
-			}
-			else if(message_name == "enable_plugins")
-			{
-				mPluginsEnabled = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
-			}
-			else if(message_name == "enable_javascript")
-			{
-				mJavascriptEnabled = message_in.getValueBoolean("enable");
-				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
-			}
-			else if(message_name == "set_cookies")
-			{
-				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
-
-				// debug spam
-				postDebugMessage( "Plugin setting cookie: " + message_in.getValue("cookies") );
-			}
-			else if(message_name == "proxy_setup")
-			{
-				bool val = message_in.getValueBoolean("enable");
-				std::string host = message_in.getValue("host");
-				int port = message_in.getValueS32("port");
-				LLQtWebKit::getInstance()->enableProxy( val, host, port );
-			}
-			else if(message_name == "browse_stop")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
-			}
-			else if(message_name == "browse_reload")
-			{
-				// foo = message_in.getValueBoolean("ignore_cache");
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
-			}
-			else if(message_name == "browse_forward")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
-			}
-			else if(message_name == "browse_back")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
-			}
-			else if(message_name == "set_status_redirect")
-			{
-				int code = message_in.getValueS32("code");
-				std::string url = message_in.getValue("url");
-				if ( 404 == code )	// browser lib only supports 404 right now
-				{
-#if LLQTWEBKIT_API_VERSION < 8
-				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
-#endif
-				};
-			}
-			else if(message_name == "set_user_agent")
-			{
-				mUserAgent = message_in.getValue("user_agent");
-				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
-			}
-			else if(message_name == "show_web_inspector")
-			{
-#if LLQTWEBKIT_API_VERSION >= 10
-				bool val = message_in.getValueBoolean("show");
-				LLQtWebKit::getInstance()->showWebInspector( val );
-#else
-				LL_WARNS() << "Ignoring showWebInspector message (llqtwebkit version is too old)." << LL_ENDL;
-#endif
-			}
-			else if(message_name == "ignore_ssl_cert_errors")
-			{
-#if LLQTWEBKIT_API_VERSION >= 3
-				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
-#else
-				LL_WARNS() << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << LL_ENDL;
-#endif
-			}
-			else if(message_name == "add_certificate_file_path")
-			{
-#if LLQTWEBKIT_API_VERSION >= 6
-				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
-#else
-				LL_WARNS() << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << LL_ENDL;
-#endif
-			}
-			else if(message_name == "init_history")
-			{
-				// Initialize browser history
-				LLSD history = message_in.getValueLLSD("history");
-				// First, clear the URL history
-				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
-				// Then, add the history items in order
-				LLSD::array_iterator iter_history = history.beginArray();
-				LLSD::array_iterator end_history = history.endArray();
-				for(; iter_history != end_history; ++iter_history)
-				{
-					std::string url = (*iter_history).asString();
-					if(! url.empty()) {
-						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
-					}
-				}
-			}
-			else if(message_name == "proxy_window_opened")
-			{
-				std::string target = message_in.getValue("target");
-				std::string uuid = message_in.getValue("uuid");
-				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
-			}
-			else if(message_name == "proxy_window_closed")
-			{
-				std::string uuid = message_in.getValue("uuid");
-				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
-			};
-		}
-		else
-		{
-//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	}
-}
-
-void MediaPluginWebKit::setVolume(F32 volume)
-{
-	mVolumeCatcher.setVolume(volume);
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
-	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
-	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
-	*plugin_user_data = (void*)self;
-
-	return 0;
-}
-
-
diff --git a/indra/media_plugins/winmmshim/CMakeLists.txt b/indra/media_plugins/winmmshim/CMakeLists.txt
index bf74f818093d60144e59752d215c6f669ef01ce6..6890589892eef183a14b709242dcbff815010bb5 100755
--- a/indra/media_plugins/winmmshim/CMakeLists.txt
+++ b/indra/media_plugins/winmmshim/CMakeLists.txt
@@ -22,9 +22,6 @@ set(winmm_shim_HEADER_FILES
 
 list(APPEND winmm_shim_SOURCE_FILES ${winmm_shim_HEADER_FILES})
 
-set_source_files_properties(${media_plugin_webkit_HEADER_FILES}
-                            PROPERTIES HEADER_FILE_ONLY TRUE)
-
 add_library(winmm_shim
     SHARED
     ${winmm_shim_SOURCE_FILES}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 35e7f77a7d840e7c7baade72fdcddb2b7429a529..f9947ae910c033d1a436f921f34a6892a8f1fe51 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -44,7 +44,6 @@ include(OPENAL)
 include(OpenGL)
 include(OpenSSL)
 include(PNG)
-include(Prebuilt)
 include(TemplateCheck)
 include(UI)
 include(UnixInstall)
@@ -62,9 +61,6 @@ if(FMODEX)
   include_directories(${FMODEX_INCLUDE_DIR})
 endif(FMODEX)
 
-# install SLPlugin host executable and its dynamic-library plugins
-use_prebuilt_binary(slplugins)
-
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
     ${JSONCPP_INCLUDE_DIR}
@@ -1780,44 +1776,12 @@ if (WINDOWS)
       ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
       ${CMAKE_CURRENT_SOURCE_DIR}/featuretable_xp.txt
       ${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtcore4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtgui4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtnetwork4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtopengl4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtwebkit4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/qtxmlpatterns4.dll
       ${ARCH_PREBUILT_DIRS_RELEASE}/ssleay32.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qgif4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qico4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qjpeg4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qmng4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qsvg4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/imageformats/qtiff4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qcncodecs4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qjpcodecs4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qkrcodecs4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qtwcodecs4.dll
       ${ARCH_PREBUILT_DIRS_DEBUG}/libeay32.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtcored4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtguid4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtnetworkd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtopengld4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtwebkitd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/qtxmlpatternsd4.dll
       ${ARCH_PREBUILT_DIRS_DEBUG}/ssleay32.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qgifd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qicod4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qjpegd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qmngd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qsvgd4.dll
-      ${ARCH_PREBUILT_DIRS_DEBUG}/imageformats/qtiffd4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qcncodecsd4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qjpcodecsd4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qkrcodecsd4.dll
-      ${ARCH_PREBUILT_DIRS_RELEASE}/codecs/qtwcodecsd4.dll
       SLPlugin
       media_plugin_quicktime
-      media_plugin_webkit
+      media_plugin_cef
       winmm_shim
       windows-crash-logger
       )
@@ -1862,10 +1826,10 @@ if (WINDOWS)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
     endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
 
-##  add_dependencies(${VIEWER_BINARY_NAME}
-##    SLPlugin
-##    windows-crash-logger
-##    )
+    add_dependencies(${VIEWER_BINARY_NAME}
+      SLPlugin
+   windows-crash-logger
+    )
 
     # sets the 'working directory' for debugging from visual studio.
     if (NOT UNATTENDED)
@@ -2032,9 +1996,8 @@ if (LINUX)
   set(COPY_INPUT_DEPENDENCIES
     ${VIEWER_BINARY_NAME}
     linux-crash-logger
-##  SLPlugin
-##  media_plugin_webkit
-##  media_plugin_gstreamer010
+    SLPlugin
+    media_plugin_gstreamer010
     llcommon
     )
 
@@ -2146,7 +2109,7 @@ if (DARWIN)
       ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
     )
 
-##add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit mac-crash-logger)
+  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_cef mac-crash-logger)
   add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
 
   if (ENABLE_SIGNING)
@@ -2201,20 +2164,19 @@ if (PACKAGE)
   if (DARWIN)
     list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
     # *TODO: Generate these search dirs in the cmake files related to each binary.
-##  list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
+    list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
     list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
-##  list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
-##  list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}")
-##  list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/webkit/${CMAKE_CFG_INTDIR}")
+    list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
+    list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}")
     set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2")
-##  set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger")
+    set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger")
     set(VIEWER_EXE_GLOBS "'Second Life' mac-crash-logger")
     set(VIEWER_LIB_GLOB "*.dylib")
   endif (DARWIN)
   if (LINUX)
     list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged")
     set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux.tar.bz2")
-##  set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
+    set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
     set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin")
     set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
     set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4351a7e3a32923a362927db174a077a7ba596685..1454f6ed4b751b190ba93ad2c721979cc0977fbc 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.8.7
+4.0.1
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7ec9f778bf6047f88fbb068485b1af24cc39247a..27cead9879097669421118ecef590ca3143c1559 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -734,7 +734,7 @@
       <string>F32</string>
       <key>Value</key>
       <integer>60</integer>
-    </map>  
+    </map>
     <key>AvatarRotateThresholdFast</key>
     <map>
       <key>Comment</key>
@@ -745,7 +745,7 @@
       <string>F32</string>
       <key>Value</key>
       <integer>2</integer>
-    </map>  
+    </map>
     <key>AvatarBakedTextureUploadTimeout</key>
     <map>
       <key>Comment</key>
@@ -1339,7 +1339,7 @@
       <string>String</string>
       <key>Value</key>
       <string />
-    </map>	
+    </map>
     <key>CacheNumberOfRegionsForObjects</key>
     <map>
       <key>Comment</key>
@@ -3788,7 +3788,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>	
+    </map>
 	<key>FirstSelectedEnabledPopups</key>
     <map>
       <key>Comment</key>
@@ -3799,7 +3799,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>		
+    </map>
     <key>FixedWeather</key>
     <map>
       <key>Comment</key>
@@ -3921,7 +3921,7 @@
       <key>Value</key>
       <string>SW</string>
     </map>
-  
+
     <key>FloaterStatisticsRect</key>
     <map>
       <key>Comment</key>
@@ -4448,7 +4448,7 @@
       <string>String</string>
       <key>Value</key>
       <string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/howto/index.html</string>
-    </map>    
+    </map>
     <key>HomeSidePanelURL</key>
     <map>
       <key>Comment</key>
@@ -4514,7 +4514,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>	
+    </map>
     <key>HostID</key>
     <map>
       <key>Comment</key>
@@ -4602,7 +4602,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>  
+    </map>
     <key>IgnorePixelDepth</key>
     <map>
       <key>Comment</key>
@@ -4657,7 +4657,7 @@
       <string>F32</string>
       <key>Value</key>
       <real>0.5</real>
-    </map> 
+    </map>
 	<key>InspectorShowTime</key>
     <map>
       <key>Comment</key>
@@ -4668,7 +4668,7 @@
       <string>F32</string>
       <key>Value</key>
       <real>3.0</real>
-    </map> 
+    </map>
     <key>InstallLanguage</key>
     <map>
       <key>Comment</key>
@@ -5230,7 +5230,7 @@
       <key>Value</key>
       <string>0.0.0</string>
     </map>
-  
+
     <key>LastSnapshotToProfileHeight</key>
     <map>
       <key>Comment</key>
@@ -6309,7 +6309,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>  
+    </map>
     <key>MenuAccessKeyTime</key>
     <map>
       <key>Comment</key>
@@ -6474,7 +6474,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map> 
+    </map>
     <key>MouseSun</key>
     <map>
       <key>Comment</key>
@@ -6639,7 +6639,7 @@
       <string>String</string>
       <key>Value</key>
       <string />
-    </map>	
+    </map>
     <key>NextLoginLocation</key>
     <map>
       <key>Comment</key>
@@ -6763,7 +6763,7 @@
       <string>String</string>
       <key>Value</key>
       <string>toast</string>
-    </map>  
+    </map>
     <key>NotificationFriendIMOptions</key>
     <map>
       <key>Comment</key>
@@ -6819,7 +6819,7 @@
       <string>String</string>
       <key>Value</key>
       <string>toast</string>
-    </map>  
+    </map>
     <key>NotificationObjectIMOptions</key>
     <map>
       <key>Comment</key>
@@ -6833,7 +6833,7 @@
       <string>String</string>
       <key>Value</key>
       <string>toast</string>
-    </map>  
+    </map>
     <key>NotificationToastLifeTime</key>
     <map>
       <key>Comment</key>
@@ -7392,7 +7392,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>  
+    </map>
     <key>PlaySoundFriendIM</key>
     <map>
       <key>Comment</key>
@@ -7503,7 +7503,7 @@
       <key>Value</key>
       <real>0.9</real>
     </map>
-    
+
    <key>PlainTextChatHistory</key>
     <map>
       <key>Comment</key>
@@ -7515,7 +7515,7 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    
+
     <key>PluginInstancesLow</key>
     <map>
       <key>Comment</key>
@@ -7769,7 +7769,7 @@
       <real>0.4</real>
     </array>
   </map>
-  
+
   <key>PreviewDirection2</key>
   <map>
     <key>Comment</key>
@@ -8081,7 +8081,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>5.0</real>
+    <real>10.0</real>
   </map>
   <key>MediaRollOffMax</key>
   <map>
@@ -8445,7 +8445,7 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-   
+
   <key>RenderLocalLights</key>
   <map>
     <key>Comment</key>
@@ -8672,7 +8672,7 @@
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
-      <string>Boolean</string> 
+      <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
     </map>
@@ -8709,7 +8709,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
- 
+
   <key>RenderAnimateRes</key>
   <map>
     <key>Comment</key>
@@ -8882,7 +8882,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-  
+
   <key>RenderDepthOfField</key>
   <map>
     <key>Comment</key>
@@ -9011,7 +9011,7 @@
     <key>Value</key>
     <real>0.1</real>
   </map>
-  
+
   <key>RenderHighlightBrightness</key>
   <map>
     <key>Comment</key>
@@ -9035,7 +9035,7 @@
     <key>Value</key>
     <real>0.6</real>
   </map>
-  
+
   <key>RenderHighlightColor</key>
   <map>
     <key>Comment</key>
@@ -9064,7 +9064,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-  
+
   <key>RenderSpecularResX</key>
   <map>
     <key>Comment</key>
@@ -10048,7 +10048,7 @@
     <string>Boolean</string>
     <key>Value</key>
     <integer>0</integer>
-  </map>    
+  </map>
   <key>RenderAutoHideSurfaceAreaLimit</key>
   <map>
     <key>Comment</key>
@@ -10534,7 +10534,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>	
+    </map>
     <key>SelectMovableOnly</key>
     <map>
       <key>Comment</key>
@@ -10765,7 +10765,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>1</integer>
-    </map>	
+    </map>
     <key>ShowCrosshairs</key>
     <map>
       <key>Comment</key>
@@ -10842,7 +10842,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>    
+    </map>
     <key>ShowMiniMapButton</key>
     <map>
       <key>Comment</key>
@@ -10909,7 +10909,7 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>ShowObjectRenderingCost</key>                
+    <key>ShowObjectRenderingCost</key>
     <map>
       <key>Comment</key>
       <string>Show the object rendering cost  in  build tools</string>
@@ -10918,9 +10918,9 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>   
-    </map>        
-    <key>ShowNavbarFavoritesPanel</key>    
+      <integer>1</integer>
+    </map>
+    <key>ShowNavbarFavoritesPanel</key>
     <map>
       <key>Comment</key>
       <string>Show/hide navigation bar favorites panel</string>
@@ -10929,9 +10929,9 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>   
+      <integer>1</integer>
     </map>
-    <key>ShowNavbarNavigationPanel</key>        
+    <key>ShowNavbarNavigationPanel</key>
     <map>
       <key>Comment</key>
       <string>Show/hide navigation bar navigation panel</string>
@@ -10940,7 +10940,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>   
+      <integer>1</integer>
     </map>
     <key>ShowWorldMapButton</key>
     <map>
@@ -11096,7 +11096,7 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>ShowPGSearchAll</key>    
+    <key>ShowPGSearchAll</key>
     <map>
       <key>Comment</key>
       <string>Display results of search All that are flagged as general</string>
@@ -11612,7 +11612,7 @@
       <string>S32</string>
       <key>Value</key>
       <integer>0</integer>
-    </map>  
+    </map>
     <key>SnapshotQuality</key>
     <map>
       <key>Comment</key>
@@ -12481,7 +12481,7 @@
       <string>String</string>
       <key>Value</key>
       <string>B56AF90D-6684-48E4-B1E4-722D3DEB2CB6</string>
-    </map>  
+    </map>
     <key>NearByChatChannelUUID</key>
     <map>
       <key>Comment</key>
@@ -12492,7 +12492,7 @@
       <string>String</string>
       <key>Value</key>
       <string>E1158BD6-661C-4981-9DAD-4DCBFF062502</string>
-    </map>  
+    </map>
     <key>NotificationChannelUUID</key>
     <map>
       <key>Comment</key>
@@ -12503,7 +12503,7 @@
       <string>String</string>
       <key>Value</key>
       <string>AEED3193-8709-4693-8558-7452CCA97AE5</string>
-    </map>  
+    </map>
     <key>AlertChannelUUID</key>
     <map>
       <key>Comment</key>
@@ -12514,7 +12514,7 @@
       <string>String</string>
       <key>Value</key>
       <string>F3E07BC8-A973-476D-8C7F-F3B7293975D1</string>
-    </map>  
+    </map>
     <key>UIImgWhiteUUID</key>
     <map>
       <key>Comment</key>
@@ -12536,7 +12536,7 @@
       <string>S32</string>
       <key>Value</key>
       <integer>2</integer>
-    </map> 
+    </map>
     <key>UIMaxComboWidth</key>
     <map>
       <key>Comment</key>
@@ -13449,7 +13449,7 @@
       <string>String</string>
       <key>Value</key>
       <string>[i800,i600]</string>
-    </map>  
+    </map>
     <key>sourceid</key>
     <map>
       <key>Comment</key>
@@ -14670,7 +14670,7 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>1</integer>
-    </map>    
+    </map>
     <key>EnablePlaceProfile</key>
     <map>
       <key>Comment</key>
@@ -15492,7 +15492,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-  
+
   <key>PathfindingLineWidth</key>
   <map>
     <key>Comment</key>
@@ -15533,7 +15533,7 @@
         <real>1.0</real>
       </array>
     </map>
-    
+
     <key>HideUIControls</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5a88db0ff44472945e25f85ba76d2dcad0497058..ca60dd5138a52c683dbeb078e7b72f2eb73beb7c 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -124,6 +124,9 @@
 #include "llleap.h"
 #include "stringize.h"
 #include "llcoros.h"
+#if !LL_LINUX
+#include "cef/llceflib.h"
+#endif
 
 // Third party library includes
 #include <boost/bind.hpp>
@@ -131,7 +134,6 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/regex.hpp>
 
-
 #if LL_WINDOWS
 #	include <share.h> // For _SH_DENYWR in processMarkerFiles
 #else
@@ -1727,6 +1729,9 @@ bool LLAppViewer::cleanup()
 	// to ensure shutdown order
 	LLMortician::setZealous(TRUE);
 
+    // Give any remaining SLPlugin instances a chance to exit cleanly.
+    LLPluginProcessParent::shutdown();
+
 	LLVoiceClient::getInstance()->terminate();
 	
 	disconnectViewer();
@@ -2783,11 +2788,11 @@ bool LLAppViewer::initConfiguration()
 	//
 	gWindowTitle = LLTrans::getString("APP_NAME");
 #if LL_DEBUG
-	gWindowTitle += std::string(" [DEBUG]")
+    gWindowTitle += std::string(" [DEBUG]");
 #endif
 	if (!gArgs.empty())
 	{
-		gWindowTitle += std::string(" ") + gArgs;
+	gWindowTitle += std::string(" ") + gArgs;
 	}
 	LLStringUtil::truncate(gWindowTitle, 255);
 
@@ -3371,8 +3376,11 @@ LLSD LLAppViewer::getViewerInfo() const
 		info["VOICE_VERSION"] = LLTrans::getString("NotConnected");
 	}
 
-	// TODO: Implement media plugin version query
-	info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";
+#if !LL_LINUX
+	info["LLCEFLIB_VERSION"] = LLCEFLIB_VERSION;
+#else
+	info["LLCEFLIB_VERSION"] = "Undefined";
+#endif
 
 	S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN);
 	if (packets_in > 0)
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index b572e1935fef267d0ab8f9086c5c4c6065bb832c..06388b172847b1d47b10e55356cede8b1c1e663b 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -107,6 +107,7 @@
 #include "llpluginclassmedia.h"
 #include "llteleporthistorystorage.h"
 #include "llproxy.h"
+#include "llweb.h"
 
 #include "lllogininstance.h"        // to check if logged in yet
 #include "llsdserialize.h"
@@ -2211,6 +2212,16 @@ BOOL LLPanelPreference::postBuild()
 		gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2));
 	}
 
+#ifdef EXTERNAL_TOS
+	LLRadioGroup* ext_browser_settings = getChild<LLRadioGroup>("preferred_browser_behavior");
+	if (ext_browser_settings)
+	{
+		// turn off ability to set external/internal browser
+		ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true);
+		ext_browser_settings->setEnabled(false);
+	}
+#endif
+
 	apply();
 	return true;
 }
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index ae33acb8420449558df400bec79b19ce73632c47..4cb1ca6cc0d98cd49df9b8aa6f3de5556ec57640 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -46,7 +46,6 @@
 #include "message.h"
 #include "llstartup.h"              // login_alert_done
 
-
 LLFloaterTOS::LLFloaterTOS(const LLSD& data)
 :	LLModalDialog( data["message"].asString() ),
 	mMessage(data["message"].asString()),
@@ -85,7 +84,7 @@ class LLIamHere : public LLHTTPClient::Responder
 	{
 		if ( mParent )
 		{
-			mParent->setSiteIsAlive( true );
+			mParent->setSiteIsAlive(true);
 		}
 	}
 
@@ -136,6 +135,20 @@ BOOL LLFloaterTOS::postBuild()
 	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
 	if ( web_browser )
 	{
+// if we are forced to send users to an external site in their system browser
+// (e.g.) Linux users because of lack of media support for HTML ToS page
+// remove exisiting UI and replace with a link to external page where users can accept ToS
+#ifdef EXTERNAL_TOS
+		LLTextBox* header = getChild<LLTextBox>("tos_heading");
+		if (header)
+			header->setVisible(false);
+
+		LLTextBox* external_prompt = getChild<LLTextBox>("external_tos_required");
+		if (external_prompt)
+			external_prompt->setVisible(true);
+
+		web_browser->setVisible(false);
+#else
 		web_browser->addObserver(this);
 
 		// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
@@ -147,6 +160,7 @@ BOOL LLFloaterTOS::postBuild()
 			// All links from tos_html should be opened in external browser
 			media_plugin->setOverrideClickTarget("_external");
 		}
+#endif
 	}
 
 	return TRUE;
@@ -154,6 +168,13 @@ BOOL LLFloaterTOS::postBuild()
 
 void LLFloaterTOS::setSiteIsAlive( bool alive )
 {
+// if we are forced to send users to an external site in their system browser
+// (e.g.) Linux users because of lack of media support for HTML ToS page
+// force the regular HTML UI to deactivate so alternative is rendered instead.
+#ifdef EXTERNAL_TOS
+	mSiteAlive = false;
+#else
+
 	mSiteAlive = alive;
 	
 	// only do this for TOS pages
@@ -182,6 +203,7 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
 			tos_agreement->setEnabled( true );
 		}
 	}
+#endif
 }
 
 LLFloaterTOS::~LLFloaterTOS()
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 73faed7ef5050951dd80dbeba8d1cdd0a115815b..9cf32499838f6e05c45edb3d7441323014cd4863 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -57,6 +57,7 @@
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "llnotifications.h"
+#include "llnotificationsutil.h"
 #include "lllineeditor.h"
 #include "llfloaterwebcontent.h"
 #include "llwindowshade.h"
@@ -426,6 +427,23 @@ BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
 	return result;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleKeyUpHere(KEY key, MASK mask)
+{
+	BOOL result = FALSE;
+
+	if (mMediaSource)
+	{
+		result = mMediaSource->handleKeyUpHere(key, mask);
+	}
+
+	if (!result)
+		result = LLPanel::handleKeyUpHere(key, mask);
+
+	return result;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 void LLMediaCtrl::onVisibilityChange ( BOOL new_visibility )
@@ -989,19 +1007,23 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 			std::string uuid = self->getClickUUID();
 			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL;
 
-			LLNotification::Params notify_params;
-			notify_params.name = "PopupAttempt";
-			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
-			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
-
-			if (mTrusted)
-			{
-				LLNotifications::instance().forceResponse(notify_params, 0);
-			}
-			else
-			{
-				LLNotifications::instance().add(notify_params);
-			}
+			LLWeb::loadURL(url, target, std::string());
+
+			// CP: removing this code because we no longer support popups so this breaks the flow.
+			//     replaced with a bare call to LLWeb::LoadURL(...)
+			//LLNotification::Params notify_params;
+			//notify_params.name = "PopupAttempt";
+			//notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
+			//notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
+
+			//if (mTrusted)
+			//{
+			//	LLNotifications::instance().forceResponse(notify_params, 0);
+			//}
+			//else
+			//{
+			//	LLNotifications::instance().add(notify_params);
+			//}
 			break;
 		};
 
@@ -1072,6 +1094,13 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 		};
 		break;
 
+		case MEDIA_EVENT_FILE_DOWNLOAD:
+		{
+			//llinfos << "Media event - file download requested - filename is " << self->getFileDownloadFilename() << llendl;
+			//LLNotificationsUtil::add("MediaFileDownloadUnsupported");
+		};
+		break;
+
 		case MEDIA_EVENT_DEBUG_MESSAGE:
 		{
 			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; 
@@ -1150,3 +1179,13 @@ void LLMediaCtrl::updateContextMenuParent(LLView* pNewParent)
 {
 	mContextMenu->updateParent(pNewParent);
 }
+
+bool LLMediaCtrl::wantsKeyUpKeyDown() const
+{
+    return true;
+}
+
+bool LLMediaCtrl::wantsReturnKey() const
+{
+    return true;
+}
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 988733b85a4ac6a50abce6c1baf2789e39837a49..291d87073e65004b04d79f07c2857c3cb1a66b9c 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -151,6 +151,7 @@ class LLMediaCtrl :
 
 		// over-rides
 		virtual BOOL handleKeyHere( KEY key, MASK mask);
+		virtual BOOL handleKeyUpHere(KEY key, MASK mask);
 		virtual void onVisibilityChange ( BOOL new_visibility );
 		virtual BOOL handleUnicodeCharHere(llwchar uni_char);
 		virtual void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE);
@@ -171,6 +172,10 @@ class LLMediaCtrl :
 
 		void updateContextMenuParent(LLView* pNewParent);
 
+        // The Browser windows want keyup and keydown events. Overridden from LLFocusableElement to return true.
+        virtual bool    wantsKeyUpKeyDown() const;
+        virtual bool    wantsReturnKey() const;
+
 	protected:
 		void convertInputCoords(S32& x, S32& y);
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 2081297717fe4f98d6a652ea13f06d3a8b06f534..4d41c792ca52f4467f4d613819ca0f56c357edf6 100755
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -106,7 +106,7 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 	mMouseDownX = x;
 	mMouseDownY = y;
 
-	//left mouse down always picks transparent
+	//left mouse down always picks transparent (but see handleMouseUp)
 	mPick = gViewerWindow->pickImmediate(x, y, TRUE);
 	mPick.mKeyMask = mask;
 
@@ -661,30 +661,52 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 		&& gAgentAvatarp
 		&& !gAgentAvatarp->isSitting()
 		&& !mBlockClickToWalk							// another behavior hasn't cancelled click to walk
-		&& !mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
-		&& (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
-			|| mPick.mObjectID.notNull()))				// or on an object
-	{
-		// handle special cases of steering picks
-		LLViewerObject* avatar_object = mPick.getObject();
-
-		// get pointer to avatar
-		while (avatar_object && !avatar_object->isAvatar())
-		{
-			avatar_object = (LLViewerObject*)avatar_object->getParent();
-		}
-
-		if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
-		{
-			const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
-			// pretend we picked some point a bit in front of avatar
-			mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
-		}
-		gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
-		walkToClickedLocation();
-		LLFirstUse::notMoving(false);
-
-		return TRUE;
+        )
+	{
+        // We may be doing click to walk, but we don't want to use a target on
+        // a transparent object because the user thought they were clicking on
+        // whatever they were seeing through it, so recompute what was clicked on
+        // ignoring transparent objects
+        LLPickInfo savedPick = mPick;
+        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
+                                             FALSE /* ignore transparent */,
+                                             FALSE /* ignore particles */);
+
+        if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
+            && (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
+                || mPick.mObjectID.notNull()))				// or on an object
+        {
+            // handle special cases of steering picks
+            LLViewerObject* avatar_object = mPick.getObject();
+
+            // get pointer to avatar
+            while (avatar_object && !avatar_object->isAvatar())
+            {
+                avatar_object = (LLViewerObject*)avatar_object->getParent();
+            }
+
+            if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+            {
+                const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+                // pretend we picked some point a bit in front of avatar
+                mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
+            }
+            gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+            walkToClickedLocation();
+            LLFirstUse::notMoving(false);
+
+            return TRUE;
+        }
+        else
+        {
+            LL_DEBUGS("maint5901") << "walk target was "
+                                   << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
+                                   << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
+                                   << ", pick object was " << mPick.mObjectID
+                                   << LL_ENDL;
+            // we didn't click to walk, so restore the original target
+            mPick = savedPick;
+        }
 	}
 	gViewerWindow->setCursor(UI_CURSOR_ARROW);
 	if (hasMouseCapture())
@@ -716,14 +738,33 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLToolPie handleDoubleClick (becoming mouseDown)" << LL_ENDL;
 	}
 
+    if (handleMediaDblClick(mPick))
+    {
+        return TRUE;
+    }
+
 	if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
 	{
+        // We may be doing double click to walk, but we don't want to use a target on
+        // a transparent object because the user thought they were clicking on
+        // whatever they were seeing through it, so recompute what was clicked on
+        // ignoring transparent objects
+        LLPickInfo savedPick = mPick;
+        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
+                                             FALSE /* ignore transparent */,
+                                             FALSE /* ignore particles */);
+
 		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
 			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
 		{
 			walkToClickedLocation();
 			return TRUE;
 		}
+        else
+        {
+            // restore the original pick for any other purpose
+            mPick = savedPick;
+        }
 	}
 	else if (gSavedSettings.getBOOL("DoubleClickTeleport"))
 	{
@@ -1404,56 +1445,110 @@ static void handle_click_action_play()
 
 bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 {
-	//FIXME: how do we handle object in different parcel than us?
-	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-	LLPointer<LLViewerObject> objectp = pick.getObject();
-
-
-	if (!parcel ||
-		objectp.isNull() ||
-		pick.mObjectFace < 0 || 
-		pick.mObjectFace >= objectp->getNumTEs()) 
-	{
-		LLViewerMediaFocus::getInstance()->clearFocus();
-
-		return false;
-	}
-
-	// Does this face have media?
-	const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
-	if(!tep)
-		return false;
-
-	LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
-	if(!mep)
-		return false;
-	
-	viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
-
-	if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
-	{
-		if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
-		{
-			// It's okay to give this a null impl
-			LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
-		}
-		else
-		{
-			// Make sure keyboard focus is set to the media focus object.
-			gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
-			LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
-			
-			media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE));
-			mMediaMouseCaptureID = mep->getMediaID();
-			setMouseCapture(TRUE);  // This object will send a mouse-up to the media when it loses capture.
-		}
-
-		return true;
-	}
-
-	LLViewerMediaFocus::getInstance()->clearFocus();
+    //FIXME: how do we handle object in different parcel than us?
+    LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+    LLPointer<LLViewerObject> objectp = pick.getObject();
+
+
+    if (!parcel ||
+        objectp.isNull() ||
+        pick.mObjectFace < 0 ||
+        pick.mObjectFace >= objectp->getNumTEs())
+    {
+        LLViewerMediaFocus::getInstance()->clearFocus();
+
+        return false;
+    }
+
+    // Does this face have media?
+    const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
+    if (!tep)
+        return false;
+
+    LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
+    if (!mep)
+        return false;
+
+    viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
+
+    if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
+    {
+        if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
+        {
+            // It's okay to give this a null impl
+            LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
+        }
+        else
+        {
+            // Make sure keyboard focus is set to the media focus object.
+            gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+            LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
+
+            media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE));
+            mMediaMouseCaptureID = mep->getMediaID();
+            setMouseCapture(TRUE);  // This object will send a mouse-up to the media when it loses capture.
+        }
+
+        return true;
+    }
+
+    LLViewerMediaFocus::getInstance()->clearFocus();
+
+    return false;
+}
 
-	return false;
+bool LLToolPie::handleMediaDblClick(const LLPickInfo& pick)
+{
+    //FIXME: how do we handle object in different parcel than us?
+    LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+    LLPointer<LLViewerObject> objectp = pick.getObject();
+
+
+    if (!parcel ||
+        objectp.isNull() ||
+        pick.mObjectFace < 0 ||
+        pick.mObjectFace >= objectp->getNumTEs())
+    {
+        LLViewerMediaFocus::getInstance()->clearFocus();
+
+        return false;
+    }
+
+    // Does this face have media?
+    const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace);
+    if (!tep)
+        return false;
+
+    LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL;
+    if (!mep)
+        return false;
+
+    viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID());
+
+    if (gSavedSettings.getBOOL("MediaOnAPrimUI"))
+    {
+        if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull())
+        {
+            // It's okay to give this a null impl
+            LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal);
+        }
+        else
+        {
+            // Make sure keyboard focus is set to the media focus object.
+            gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+            LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
+
+            media_impl->mouseDoubleClick(pick.mUVCoords, gKeyboard->currentMask(TRUE));
+            mMediaMouseCaptureID = mep->getMediaID();
+            setMouseCapture(TRUE);  // This object will send a mouse-up to the media when it loses capture.
+        }
+
+        return true;
+    }
+
+    LLViewerMediaFocus::getInstance()->clearFocus();
+
+    return false;
 }
 
 bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 68fe8bc4a5586d8c9371be629e1a669d3c4dd58c..c4a2f4a35b255534d900de578943c8016c21cfa6 100755
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -88,7 +88,8 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	ECursorType cursorFromObject(LLViewerObject* object);
 
 	bool handleMediaClick(const LLPickInfo& info);
-	bool handleMediaHover(const LLPickInfo& info);
+    bool handleMediaDblClick(const LLPickInfo& info);
+    bool handleMediaHover(const LLPickInfo& info);
 	bool handleMediaMouseUp(); 
 	BOOL handleTooltipLand(std::string line, std::string tooltip_msg);
 	BOOL handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg);
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index ada829eb4b35faa5f691e4569d3a7327f0b78383..1ab672aafc743b1ec81468d6712b49faaf2617f2 100755
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -729,7 +729,10 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL
 	return mKeyHandledByUI[translated_key];
 }
 
-
+BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
+{
+	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
+}
 
 BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
 {
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index ca73212ed1262f60737f545be5d333b5da02754d..110dc89d2895bfb14fe33cd89c8f0233924bf521 100755
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -89,6 +89,7 @@ class LLViewerKeyboard
 	LLViewerKeyboard();
 
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
+	BOOL			handleKeyUp(KEY key, MASK mask);
 
 	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 3eae0f8d86ca64d9d64ab29b43e0d91db409ed42..ffae3c0e1f180a16c14261e1d5d78d2cecc14115 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -5,21 +5,21 @@
  * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -66,6 +66,7 @@
 #include "llvoavatar.h"
 #include "llvoavatarself.h"
 #include "llvovolume.h"
+#include "llfloaterreg.h"
 #include "llwebprofile.h"
 #include "llwindow.h"
 #include "llvieweraudio.h"
@@ -167,7 +168,7 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 		{
 			LL_ERRS() << "impl already has an outstanding responder" << LL_ENDL;
 		}
-		
+
 		mMediaImpl->mMimeTypeProbe = this;
 	}
 
@@ -189,19 +190,19 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 		std::string mime_type = media_type.substr(0, idx1);
 
 		LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL;
-		
+
 		// 2xx status codes indicate success.
 		// Most 4xx status codes are successful enough for our purposes.
 		// 499 is the error code for host not found, timeout, etc.
-		// 500 means "Internal Server error" but we decided it's okay to 
+		// 500 means "Internal Server error" but we decided it's okay to
 		//     accept this and go past it in the MIME type probe
 		// 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com
 		// 499 is a code specifc to join.secondlife.com apparently safe to ignore
 //		if(	((status >= 200) && (status < 300))	||
-//			((status >= 400) && (status < 499))	|| 
+//			((status >= 400) && (status < 499))	||
 //			(status == 500) ||
 //			(status == 302) ||
-//			(status == 499) 
+//			(status == 499)
 //			)
 		// We now no longer check the error code returned from the probe.
 		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting.
@@ -229,7 +230,7 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
 		// Make a local copy so we can call loadURI() afterwards.
 		LLViewerMediaImpl *impl = mMediaImpl;
-		
+
 		if(impl && !mInitialized && ! mime_type.empty())
 		{
 			if(impl->initializeMedia(mime_type))
@@ -240,13 +241,13 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 			}
 		}
 	}
-	
+
 public:
 	void cancelRequest()
 	{
 		disconnectOwner();
 	}
-	
+
 private:
 	void disconnectOwner()
 	{
@@ -261,8 +262,8 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 		}
 		mMediaImpl = NULL;
 	}
-	
-	
+
+
 public:
 		LLViewerMediaImpl *mMediaImpl;
 		bool mInitialized;
@@ -284,13 +285,12 @@ class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
 		const LLChannelDescriptors& channels,
 		const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		// We don't care about the content of the response, only the Set-Cookie header.
-		LL_DEBUGS("MediaAuth") << dumpResponse() 
-				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
+		const std::string url = getURL();
+
 		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
-		
+
 		// *TODO: What about bad status codes?  Does this destroy previous cookies?
-		LLViewerMedia::openIDCookieResponse(cookie);
+		LLViewerMedia::openIDCookieResponse(url, cookie);
 	}
 
 };
@@ -313,7 +313,7 @@ LOG_CLASS(LLViewerMediaWebProfileResponder);
 		const LLIOPipe::buffer_ptr_t& buffer)
 	{
 		// We don't care about the content of the response, only the set-cookie header.
-		LL_WARNS("MediaAuth") << dumpResponse() 
+		LL_WARNS("MediaAuth") << dumpResponse()
 				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
 
 		LLSD stripped_content = getResponseHeaders();
@@ -364,7 +364,7 @@ static void remove_media_impl(LLViewerMediaImpl* media)
 {
 	LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin();
 	LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end();
-	
+
 	for(; iter != end; iter++)
 	{
 		if(media == *iter)
@@ -391,8 +391,8 @@ static bool sViewerMediaMuteListObserverInitialized = false;
 // static
 viewer_media_t LLViewerMedia::newMediaImpl(
 											 const LLUUID& texture_id,
-											 S32 media_width, 
-											 S32 media_height, 
+											 S32 media_width,
+											 S32 media_height,
 											 U8 media_auto_scale,
 											 U8 media_loop)
 {
@@ -416,24 +416,24 @@ viewer_media_t LLViewerMedia::newMediaImpl(
 }
 
 viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self)
-{	
+{
 	// Try to find media with the same media ID
 	viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID());
-	
-	LL_DEBUGS() << "called, current URL is \"" << media_entry->getCurrentURL() 
-			<< "\", previous URL is \"" << previous_url 
+
+	LL_DEBUGS() << "called, current URL is \"" << media_entry->getCurrentURL()
+			<< "\", previous URL is \"" << previous_url
 			<< "\", update_from_self is " << (update_from_self?"true":"false")
 			<< LL_ENDL;
-			
+
 	bool was_loaded = false;
 	bool needs_navigate = false;
-	
+
 	if(media_impl)
-	{	
+	{
 		was_loaded = media_impl->hasMedia();
-		
+
 		media_impl->setHomeURL(media_entry->getHomeURL());
-		
+
 		media_impl->mMediaAutoScale = media_entry->getAutoScale();
 		media_impl->mMediaLoop = media_entry->getAutoLoop();
 		media_impl->mMediaWidth = media_entry->getWidthPixels();
@@ -446,7 +446,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 			media_impl->mMediaSource->setLoop(media_impl->mMediaLoop);
 			media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels());
 		}
-		
+
 		bool url_changed = (media_impl->mMediaEntryURL != previous_url);
 		if(media_impl->mMediaEntryURL.empty())
 		{
@@ -454,7 +454,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 			{
 				// The current media URL is now empty.  Unload the media source.
 				media_impl->unload();
-			
+
 				LL_DEBUGS() << "Unloading media instance (new current URL is empty)." << LL_ENDL;
 			}
 		}
@@ -463,26 +463,26 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 			// The current media URL is not empty.
 			// If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent,
 			// do a navigate.
-			bool auto_play = media_impl->isAutoPlayable();			
+			bool auto_play = media_impl->isAutoPlayable();
 			if((was_loaded || auto_play) && !update_from_self)
 			{
 				needs_navigate = url_changed;
 			}
-			
-			LL_DEBUGS() << "was_loaded is " << (was_loaded?"true":"false") 
-					<< ", auto_play is " << (auto_play?"true":"false") 
+
+			LL_DEBUGS() << "was_loaded is " << (was_loaded?"true":"false")
+					<< ", auto_play is " << (auto_play?"true":"false")
 					<< ", needs_navigate is " << (needs_navigate?"true":"false") << LL_ENDL;
 		}
 	}
 	else
 	{
 		media_impl = newMediaImpl(
-			media_entry->getMediaID(), 
+			media_entry->getMediaID(),
 			media_entry->getWidthPixels(),
-			media_entry->getHeightPixels(), 
-			media_entry->getAutoScale(), 
+			media_entry->getHeightPixels(),
+			media_entry->getAutoScale(),
 			media_entry->getAutoLoop());
-		
+
 		media_impl->setHomeURL(media_entry->getHomeURL());
 		media_impl->mMediaAutoPlay = media_entry->getAutoPlay();
 		media_impl->mMediaEntryURL = media_entry->getCurrentURL();
@@ -491,7 +491,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 			needs_navigate = true;
 		}
 	}
-	
+
 	if(media_impl)
 	{
 		if(needs_navigate)
@@ -510,7 +510,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 			LL_DEBUGS() << "updating URL in the media impl to " << media_impl->mMediaEntryURL << LL_ENDL;
 		}
 	}
-	
+
 	return media_impl;
 }
 
@@ -519,7 +519,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
 LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id)
 {
 	LLViewerMediaImpl* result = NULL;
-	
+
 	// Look up the texture ID in the texture id->impl map.
 	impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id);
 	if(iter != sViewerMediaTextureIDMap.end())
@@ -534,7 +534,7 @@ LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& textur
 // static
 std::string LLViewerMedia::getCurrentUserAgent()
 {
-	// Don't use user-visible string to avoid 
+	// Don't use user-visible string to avoid
 	// punctuation and strange characters.
 	std::string skin_name = gSavedSettings.getString("SkinCurrent");
 
@@ -553,7 +553,7 @@ std::string LLViewerMedia::getCurrentUserAgent()
 	codec << LLVersionInfo::getVersion();
 	codec << " (" << channel << "; " << skin_name << " skin)";
 	LL_INFOS() << codec.str() << LL_ENDL;
-	
+
 	return codec.str();
 }
 
@@ -562,7 +562,7 @@ std::string LLViewerMedia::getCurrentUserAgent()
 void LLViewerMedia::updateBrowserUserAgent()
 {
 	std::string user_agent = getCurrentUserAgent();
-	
+
 	impl_list::iterator iter = sViewerMediaImplList.begin();
 	impl_list::iterator end = sViewerMediaImplList.end();
 
@@ -651,7 +651,7 @@ void LLViewerMedia::muteListChanged()
 bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest)
 {
 	bool result = false;
-	
+
 	if (NULL == object)
 	{
 		result = false;
@@ -667,13 +667,13 @@ bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &obj
 	{
 		result = true;
 	}
-	else 
+	else
 	{
 		LL_DEBUGS() << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << LL_ENDL;
 		if(object_interest >= sLowestLoadableImplInterest)
 			result = true;
 	}
-	
+
 	return result;
 }
 
@@ -780,13 +780,13 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc");
 void LLViewerMedia::updateMedia(void *dummy_arg)
 {
 	LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE);
-	
+
 	// Enable/disable the plugin read thread
 	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
-	
+
 	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
 	createSpareBrowserMediaSource();
-	
+
 	sAnyMediaShowing = false;
 	sUpdatedCookies = getCookieStore()->getChangedCookies();
 	if(!sUpdatedCookies.empty())
@@ -794,7 +794,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 		LL_DEBUGS() << "updated cookies will be sent to all loaded plugins: " << LL_ENDL;
 		LL_DEBUGS() << sUpdatedCookies << LL_ENDL;
 	}
-	
+
 	impl_list::iterator iter = sViewerMediaImplList.begin();
 	impl_list::iterator end = sViewerMediaImplList.end();
 
@@ -807,14 +807,14 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 			pimpl->calculateInterest();
 		}
 	}
-	
+
 	// Let the spare media source actually launch
 	if(sSpareBrowserMediaSource)
 	{
 		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE);
 		sSpareBrowserMediaSource->idle();
 	}
-		
+
 	{
 		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT);
 		// Sort the static instance list using our interest criteria
@@ -824,14 +824,14 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	// Go through the list again and adjust according to priority.
 	iter = sViewerMediaImplList.begin();
 	end = sViewerMediaImplList.end();
-	
+
 	F64 total_cpu = 0.0f;
 	int impl_count_total = 0;
 	int impl_count_interest_low = 0;
 	int impl_count_interest_normal = 0;
-	
+
 	std::vector<LLViewerMediaImpl*> proximity_order;
-	
+
 	bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia");
 	bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic");
 	U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal");
@@ -840,19 +840,19 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit");
 	// Setting max_cpu to 0.0 disables CPU usage checking.
 	bool check_cpu_usage = (max_cpu != 0.0f);
-	
+
 	LLViewerMediaImpl* lowest_interest_loadable = NULL;
-	
+
 	// Notes on tweakable params:
 	// max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded.
 	// If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
-	
+
 	{
 		LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC);
 		for(; iter != end; iter++)
 		{
 			LLViewerMediaImpl* pimpl = *iter;
-		
+
 			LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
 
 			if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances))
@@ -883,7 +883,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 			else
 			{
 				// Look at interest and CPU usage for instances that aren't in any of the above states.
-			
+
 				// Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture,
 				// turn it down to low instead of normal.  This may downsample for plugins that support it.
 				bool media_is_small = false;
@@ -897,7 +897,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 				{
 					media_is_small = true;
 				}
-			
+
 				if(pimpl->getInterest() == 0.0f)
 				{
 					// This media is completely invisible, due to being outside the view frustrum or out of range.
@@ -919,11 +919,11 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 					// The next max_low inworld get turned down
 					new_priority = LLPluginClassMedia::PRIORITY_LOW;
 					impl_count_interest_low++;
-				
+
 					// Set the low priority size for downsampling to approximately the size the texture is displayed at.
 					{
 						F32 approximate_interest_dimension = (F32) sqrt(pimpl->getInterest());
-					
+
 						pimpl->setLowPrioritySizeLimit(ll_round(approximate_interest_dimension));
 					}
 				}
@@ -933,18 +933,18 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 					new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
 				}
 			}
-		
+
 			if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED))
 			{
 				// This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest.
 				lowest_interest_loadable = pimpl;
-			
+
 				impl_count_total++;
 			}
 
 			// Overrides if the window is minimized or we lost focus (taking care
 			// not to accidentally "raise" the priority either)
-			if (!gViewerWindow->getActive() /* viewer window minimized? */ 
+			if (!gViewerWindow->getActive() /* viewer window minimized? */
 				&& new_priority > LLPluginClassMedia::PRIORITY_HIDDEN)
 			{
 				new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
@@ -954,7 +954,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 			{
 				new_priority = LLPluginClassMedia::PRIORITY_LOW;
 			}
-		
+
 			if(!inworld_media_enabled)
 			{
 				// If inworld media is locked out, force all inworld media to stay unloaded.
@@ -972,7 +972,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 				}
 			}
 			pimpl->setPriority(new_priority);
-		
+
 			if(pimpl->getUsedInUI())
 			{
 				// Any impls used in the UI should not be in the proximity list.
@@ -984,7 +984,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 			}
 
 			total_cpu += pimpl->getCPUUsage();
-		
+
 			if (!pimpl->getUsedInUI() && pimpl->hasMedia())
 			{
 				sAnyMediaShowing = true;
@@ -1008,7 +1008,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 			sLowestLoadableImplInterest = object->getPixelArea();
 		}
 	}
-	
+
 	if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug"))
 	{
 		// Give impls the same ordering as the priority list
@@ -1017,7 +1017,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	else
 	{
 		LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2);
-		// Use a distance-based sort for proximity values.  
+		// Use a distance-based sort for proximity values.
 		std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
 	}
 
@@ -1026,7 +1026,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 	{
 		proximity_order[i]->mProximity = i;
 	}
-	
+
 	LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << LL_ENDL;
 
 }
@@ -1045,11 +1045,11 @@ void LLViewerMedia::setAllMediaEnabled(bool val)
 	// Set "tentative" autoplay first.  We need to do this here or else
 	// re-enabling won't start up the media below.
 	gSavedSettings.setBOOL("MediaTentativeAutoPlay", val);
-	
-	// Then 
+
+	// Then
 	impl_list::iterator iter = sViewerMediaImplList.begin();
 	impl_list::iterator end = sViewerMediaImplList.end();
-	
+
 	for(; iter != end; iter++)
 	{
 		LLViewerMediaImpl* pimpl = *iter;
@@ -1058,18 +1058,18 @@ void LLViewerMedia::setAllMediaEnabled(bool val)
 			pimpl->setDisabled(!val);
 		}
 	}
-	
+
 	// Also do Parcel Media and Parcel Audio
 	if (val)
 	{
 		if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia())
-		{	
+		{
 			LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
 		}
-		
+
 		if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
 			!LLViewerMedia::isParcelAudioPlaying() &&
-			gAudiop && 
+			gAudiop &&
 			LLViewerMedia::hasParcelAudio())
 		{
 			if (LLAudioEngine::AUDIO_PAUSED == gAudiop->isInternetStreamPlaying())
@@ -1142,26 +1142,26 @@ void LLViewerMedia::clearAllCookies()
 			pimpl->mMediaSource->clear_cookies();
 		}
 	}
-	
+
 	// Clear all cookies from the cookie store
 	getCookieStore()->setAllCookies("");
 
 	// FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly.
 	// It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded.
 	// Until such time as we can centralize cookie storage, the following hack should cover these cases:
-	
+
 	// HACK: Look for cookie files in all possible places and delete them.
 	// NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
-	
+
 	// Places that cookie files can be:
 	// <getOSUserAppDir>/browser_profile/cookies
 	// <getOSUserAppDir>/first_last/browser_profile/cookies  (note that there may be any number of these!)
 	// <getOSUserAppDir>/first_last/plugin_cookies.txt  (note that there may be any number of these!)
-	
+
 	std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter();
 	std::string target;
 	std::string filename;
-	
+
 	LL_DEBUGS() << "base dir = " << base_dir << LL_ENDL;
 
 	// The non-logged-in version is easy
@@ -1174,7 +1174,7 @@ void LLViewerMedia::clearAllCookies()
 	{
 		LLFile::remove(target);
 	}
-	
+
 	// the hard part: iterate over all user directories and delete the cookie file from each one
 	LLDirIterator dir_iter(base_dir, "*_*");
 	while (dir_iter.next(filename))
@@ -1184,26 +1184,26 @@ void LLViewerMedia::clearAllCookies()
 		gDirUtilp->append(target, "cookies");
 		LL_DEBUGS() << "target = " << target << LL_ENDL;
 		if(LLFile::isfile(target))
-		{	
+		{
 			LLFile::remove(target);
 		}
-		
+
 		// Other accounts may have new-style cookie files too -- delete them as well
 		target = gDirUtilp->add(base_dir, filename);
 		gDirUtilp->append(target, PLUGIN_COOKIE_FILE_NAME);
 		LL_DEBUGS() << "target = " << target << LL_ENDL;
 		if(LLFile::isfile(target))
-		{	
+		{
 			LLFile::remove(target);
 		}
 	}
-	
+
 	// If we have an OpenID cookie, re-add it to the cookie store.
-	setOpenIDCookie();
+	setOpenIDCookie(std::string());
 }
-	
+
 /////////////////////////////////////////////////////////////////////////////////////////
-// static 
+// static
 void LLViewerMedia::clearAllCaches()
 {
 	// Clear all plugins' caches
@@ -1215,9 +1215,9 @@ void LLViewerMedia::clearAllCaches()
 		pimpl->clearCache();
 	}
 }
-	
+
 /////////////////////////////////////////////////////////////////////////////////////////
-// static 
+// static
 void LLViewerMedia::setCookiesEnabled(bool enabled)
 {
 	// Set the "cookies enabled" flag for all loaded plugins
@@ -1232,9 +1232,9 @@ void LLViewerMedia::setCookiesEnabled(bool enabled)
 		}
 	}
 }
-	
+
 /////////////////////////////////////////////////////////////////////////////////////////
-// static 
+// static
 void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port)
 {
 	// Set the proxy config for all loaded plugins
@@ -1251,7 +1251,7 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// static 
+// static
 /////////////////////////////////////////////////////////////////////////////////////////
 // static
 LLPluginCookieStore *LLViewerMedia::getCookieStore()
@@ -1260,7 +1260,7 @@ LLPluginCookieStore *LLViewerMedia::getCookieStore()
 	{
 		sCookieStore = new LLPluginCookieStore;
 	}
-	
+
 	return sCookieStore;
 }
 
@@ -1276,7 +1276,7 @@ void LLViewerMedia::loadCookieFile()
 		LL_INFOS() << "can't get path to plugin cookie file - probably not logged in yet." << LL_ENDL;
 		return;
 	}
-	
+
 	// open the file for reading
 	llifstream file(resolved_filename.c_str());
 	if (!file.is_open())
@@ -1284,11 +1284,11 @@ void LLViewerMedia::loadCookieFile()
 		LL_WARNS() << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << LL_ENDL;
 		return;
 	}
-	
+
 	getCookieStore()->readAllCookies(file, true);
 
 	file.close();
-	
+
 	// send the clear_cookies message to all loaded plugins
 	impl_list::iterator iter = sViewerMediaImplList.begin();
 	impl_list::iterator end = sViewerMediaImplList.end();
@@ -1300,9 +1300,9 @@ void LLViewerMedia::loadCookieFile()
 			pimpl->mMediaSource->clear_cookies();
 		}
 	}
-	
+
 	// If we have an OpenID cookie, re-add it to the cookie store.
-	setOpenIDCookie();
+	setOpenIDCookie(std::string());
 }
 
 
@@ -1337,23 +1337,23 @@ void LLViewerMedia::saveCookieFile()
 void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure)
 {
 	std::stringstream cookie;
-	
+
 	cookie << name << "=" << LLPluginCookieStore::quoteString(value);
-	
+
 	if(expires.notNull())
 	{
 		cookie << "; expires=" << expires.asRFC1123();
 	}
-	
+
 	cookie << "; domain=" << domain;
 
 	cookie << "; path=" << path;
-	
+
 	if(secure)
 	{
 		cookie << "; secure";
 	}
-	
+
 	getCookieStore()->setCookies(cookie.str());
 }
 
@@ -1370,7 +1370,7 @@ void LLViewerMedia::addSessionCookie(const std::string &name, const std::string
 void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path )
 {
 	// To remove a cookie, add one with the same name, domain, and path that expires in the past.
-	
+
 	addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path);
 }
 
@@ -1388,9 +1388,34 @@ LLSD LLViewerMedia::getHeaders()
 	return headers;
 }
 
+ /////////////////////////////////////////////////////////////////////////////////////////
+ // static
+bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure)
+{
+	std::size_t name_pos = raw_cookie.find_first_of("=");
+	if (name_pos != std::string::npos)
+	{
+		name = raw_cookie.substr(0, name_pos);
+		std::size_t value_pos = raw_cookie.find_first_of(";", name_pos);
+		if (value_pos != std::string::npos)
+		{
+			value = raw_cookie.substr(name_pos + 1, value_pos - name_pos - 1);
+			path = "/";	// assume root path for now
+
+			httponly = true;	// hard coded for now
+			secure = true;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
 /////////////////////////////////////////////////////////////////////////////////////////
 // static
-void LLViewerMedia::setOpenIDCookie()
+void LLViewerMedia::setOpenIDCookie(const std::string& url)
 {
 	if(!sOpenIDCookie.empty())
 	{
@@ -1398,7 +1423,7 @@ void LLViewerMedia::setOpenIDCookie()
 		// We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that.
 		// We therefore do it here.
 		std::string authority = sOpenIDURL.mAuthority;
-		std::string::size_type host_start = authority.find('@'); 
+		std::string::size_type host_start = authority.find('@');
 		if(host_start == std::string::npos)
 		{
 			// no username/password
@@ -1406,20 +1431,43 @@ void LLViewerMedia::setOpenIDCookie()
 		}
 		else
 		{
-			// Hostname starts after the @. 
+			// Hostname starts after the @.
 			// (If the hostname part is empty, this may put host_start at the end of the string.  In that case, it will end up passing through an empty hostname, which is correct.)
 			++host_start;
 		}
-		std::string::size_type host_end = authority.rfind(':'); 
+		std::string::size_type host_end = authority.rfind(':');
 		if((host_end == std::string::npos) || (host_end < host_start))
 		{
 			// no port
 			host_end = authority.size();
 		}
-		
+
 		getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start));
 
-		// Do a web profile get so we can store the cookie 
+		if (url.length())
+		{
+			LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
+			if (media_instance)
+			{
+				std::string cookie_host = authority.substr(host_start, host_end - host_start);
+				std::string cookie_name = "";
+				std::string cookie_value = "";
+				std::string cookie_path = "";
+				bool httponly = true;
+				bool secure = true;
+				if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) &&
+                    media_instance->getMediaPlugin())
+				{
+					media_instance->getMediaPlugin()->setCookie(url, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure);
+				}
+			}
+		}
+
+		// NOTE: this is the original OpenID cookie code, so of which is no longer needed now that we
+		// are using CEF - it's very intertwined with other code so, for the moment, I'm going to
+		// leave it alone and make a task to come back to it once we're sure the CEF cookie code is robust.
+
+		// Do a web profile get so we can store the cookie
 		LLSD headers = LLSD::emptyMap();
 		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
 		headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
@@ -1430,7 +1478,7 @@ void LLViewerMedia::setOpenIDCookie()
 
 		LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << LL_ENDL;
 		LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL;
-		LLHTTPClient::get(profile_url,  
+		LLHTTPClient::get(profile_url,
 			new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
 			headers);
 	}
@@ -1442,12 +1490,12 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string
 {
 	LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL;
 
-	// post the token to the url 
+	// post the token to the url
 	// the responder will need to extract the cookie(s).
 
 	// Save the OpenID URL for later -- we may need the host when adding the cookie.
 	sOpenIDURL.init(openid_url.c_str());
-	
+
 	// We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies.
 	sOpenIDCookie.clear();
 
@@ -1462,24 +1510,24 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string
 	U8 *data = new U8[size];
 	memcpy(data, openid_token.data(), size);
 
-	LLHTTPClient::postRaw( 
-		openid_url, 
-		data, 
-		size, 
+	LLHTTPClient::postRaw(
+		openid_url,
+		data,
+		size,
 		new LLViewerMediaOpenIDResponder(),
 		headers);
-			
+
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
 // static
-void LLViewerMedia::openIDCookieResponse(const std::string &cookie)
+void LLViewerMedia::openIDCookieResponse(const std::string& url, const std::string &cookie)
 {
 	LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL;
-	
+
 	sOpenIDCookie += cookie;
 
-	setOpenIDCookie();
+	setOpenIDCookie(url);
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -1488,7 +1536,7 @@ void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::stri
 {
 	if(uuid.empty())
 		return;
-		
+
 	for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++)
 	{
 		if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser())
@@ -1525,7 +1573,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
 	if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
 	{
 		// The null owner will keep the browser plugin from fully initializing
-		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
+		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,
 		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
 		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);
 	}
@@ -1537,7 +1585,7 @@ LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
 {
 	LLPluginClassMedia* result = sSpareBrowserMediaSource;
 	sSpareBrowserMediaSource = NULL;
-	return result; 
+	return result;
 };
 
 bool LLViewerMedia::hasInWorldMedia()
@@ -1626,12 +1674,12 @@ void LLViewerMedia::setOnlyAudibleMediaTextureID(const LLUUID& texture_id)
 //////////////////////////////////////////////////////////////////////////////////////////
 // LLViewerMediaImpl
 //////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id, 
-										  S32 media_width, 
-										  S32 media_height, 
-										  U8 media_auto_scale, 
+LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
+										  S32 media_width,
+										  S32 media_height,
+										  U8 media_auto_scale,
 										  U8 media_loop)
-:	
+:
 	mMediaSource( NULL ),
 	mMovieImageHasMips(false),
 	mMediaWidth(media_width),
@@ -1672,7 +1720,7 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 	mTrustedBrowser(false),
 	mZoomFactor(1.0),
     mCleanBrowser(false)
-{ 
+{
 
 	// Set up the mute list observer if it hasn't been set up already.
 	if(!sViewerMediaMuteListObserverInitialized)
@@ -1680,11 +1728,11 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 		LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver);
 		sViewerMediaMuteListObserverInitialized = true;
 	}
-	
+
 	add_media_impl(this);
 
 	setTextureID(texture_id);
-	
+
 	// connect this media_impl to the media texture, creating it if it doesn't exist.0
 	// This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded.
 	LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId);
@@ -1699,7 +1747,7 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 LLViewerMediaImpl::~LLViewerMediaImpl()
 {
 	destroyMediaSource();
-	
+
 	LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ;
 
 	setTextureID();
@@ -1711,7 +1759,7 @@ void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObser
 {
 	// Broadcast to observers using the superclass version
 	LLViewerMediaEventEmitter::emitEvent(plugin, event);
-	
+
 	// If this media is on one or more LLVOVolume objects, tell them about the event as well.
 	std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
 	while(iter != mObjectList.end())
@@ -1727,7 +1775,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
 {
 	bool mimeTypeChanged = (mMimeType != mime_type);
 	bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type));
-	
+
 	if(!mMediaSource || pluginChanged)
 	{
 		// We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type.
@@ -1750,7 +1798,7 @@ void LLViewerMediaImpl::createMediaSource()
 		// This media shouldn't be created yet.
 		return;
 	}
-	
+
 	if(! mMediaURL.empty())
 	{
 		navigateInternal();
@@ -1776,15 +1824,15 @@ void LLViewerMediaImpl::destroyMediaSource()
 	{
 		oldImage->setPlaying(FALSE) ;
 	}
-	
+
 	cancelMimeTypeProbe();
-	
+
 	if(mMediaSource)
 	{
 		mMediaSource->setDeleteOK(true) ;
 		delete mMediaSource;
 		mMediaSource = NULL;
-	}	
+	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1799,11 +1847,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 {
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
 	LLPluginClassMedia* media_source = NULL;
-	
+
 	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
 	// If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
     // Do not use a spare if launching with full viewer control (e.g. Facebook, Twitter and few others)
-	if ((plugin_basename == "media_plugin_webkit") &&
+	if ((plugin_basename == "media_plugin_cef") &&
         !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins") && !clean_browser)
 	{
 		media_source = LLViewerMedia::getSpareBrowserMediaSource();
@@ -1812,7 +1860,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 			media_source->setOwner(owner);
 			media_source->setTarget(target);
 			media_source->setSize(default_width, default_height);
-						
+
 			return media_source;
 		}
 	}
@@ -1824,8 +1872,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 	{
 		std::string launcher_name = gDirUtilp->getLLPluginLauncher();
 		std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename);
-		std::string user_data_path = gDirUtilp->getOSUserAppDir();
-		user_data_path += gDirUtilp->getDirDelimiter();
+
+		std::string user_data_path_cache = gDirUtilp->getCacheDir(false);
+		user_data_path_cache += gDirUtilp->getDirDelimiter();
+
+		std::string user_data_path_cookies = gDirUtilp->getOSUserAppDir();
+		user_data_path_cookies += gDirUtilp->getDirDelimiter();
 
 		// Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.)
 		// If the linden username returned is blank, that can only mean we are
@@ -1836,8 +1888,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 		if ( ! linden_user_dir.empty() )
 		{
 			// gDirUtilp->getLindenUserDir() is whole path, not just Linden name
-			user_data_path = linden_user_dir;
-			user_data_path += gDirUtilp->getDirDelimiter();
+			user_data_path_cookies = linden_user_dir;
+			user_data_path_cookies += gDirUtilp->getDirDelimiter();
 		};
 
 		// See if the plugin executable exists
@@ -1854,7 +1906,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 		{
 			media_source = new LLPluginClassMedia(owner);
 			media_source->setSize(default_width, default_height);
-			media_source->setUserDataPath(user_data_path);
+			media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies);
 			media_source->setLanguageCode(LLUI::getLanguage());
 
 			// collect 'cookies enabled' setting from prefs and send to embedded browser
@@ -1868,12 +1920,15 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 			// collect 'javascript enabled' setting from prefs and send to embedded browser
 			bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
 			media_source->setJavascriptEnabled( javascript_enabled || clean_browser);
-		
+
 			bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
 			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled  || clean_browser);
 
+			// need to set agent string here before instance created
+			media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
+
 			media_source->setTarget(target);
-			
+
 			const std::string plugin_dir = gDirUtilp->getLLPluginDir();
 			if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
 			{
@@ -1886,14 +1941,14 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 			}
 		}
 	}
-	
+
 	LL_WARNS_ONCE("Plugin") << "plugin initialization failed for mime type: " << media_type << LL_ENDL;
 	LLSD args;
 	args["MIME_TYPE"] = media_type;
 	LLNotificationsUtil::add("NoPlugin", args);
 
 	return NULL;
-}							
+}
 
 //////////////////////////////////////////////////////////////////////////////////////////
 bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
@@ -1904,10 +1959,10 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		mMediaWidth = mMediaSource->getSetWidth();
 		mMediaHeight = mMediaSource->getSetHeight();
 	}
-	
+
 	// Always delete the old media impl first.
 	destroyMediaSource();
-	
+
 	// and unconditionally set the mime type
 	mMimeType = media_type;
 
@@ -1915,7 +1970,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 	{
 		// This impl should not be loaded at this time.
 		LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
-		
+
 		return false;
 	}
 
@@ -1926,7 +1981,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 	mCurrentMimeType = mMimeType;
 
 	LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget, mCleanBrowser);
-	
+
 	if (media_source)
 	{
 		media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout"));
@@ -1935,7 +1990,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
 		media_source->focus(mHasFocus);
 		media_source->setBackgroundColor(mBackgroundColor);
-		
+
 		if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors"))
 		{
 			media_source->ignore_ssl_cert_errors(true);
@@ -1943,19 +1998,19 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 
 		// the correct way to deal with certs it to load ours from CA.pem and append them to the ones
 		// Qt/WebKit loads from your system location.
-		// Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority 
+		// Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority
 		// cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg)
 		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" );
 		media_source->addCertificateFilePath( ca_path );
 
 		media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
-		
+
 		if(mClearCache)
 		{
 			mClearCache = false;
 			media_source->clear_cache();
 		}
-		
+
 		// TODO: Only send cookies to plugins that need them
 		//  Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message.
 		//  Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message,
@@ -1966,7 +2021,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		{
 			media_source->set_cookies(all_cookies);
 		}
-				
+
 		mMediaSource = media_source;
 		mMediaSource->setDeleteOK(false) ;
 		updateVolume();
@@ -2009,16 +2064,16 @@ void LLViewerMediaImpl::loadURI()
             std::string sanitized_uri = (u.query().empty() ? uri : u.scheme() + "://" + u.authority() + u.path());
             LL_INFOS() << "Asking media source to load URI: " << sanitized_uri << LL_ENDL;
         }
-		
+
 		mMediaSource->loadURI( uri );
-		
-		// A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, 
+
+		// A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused,
 		// or a seek happened before the media loaded.  In either case, seek to the saved time.
 		if(mPreviousMediaTime != 0.0f)
 		{
 			seek(mPreviousMediaTime);
 		}
-			
+
 		if(mPreviousMediaState == MEDIA_PLAYING)
 		{
 			// This media was playing before this instance was unloaded.
@@ -2071,11 +2126,11 @@ void LLViewerMediaImpl::play()
 			// This may be the case where the plugin's priority is PRIORITY_UNLOADED
 			return;
 		}
-		
+
 		// Only do this if the media source was just loaded.
 		loadURI();
 	}
-	
+
 	// always start the media
 	start();
 }
@@ -2176,10 +2231,10 @@ void LLViewerMediaImpl::updateVolume()
 {
 	if(mMediaSource)
 	{
-		// always scale the volume by the global media volume 
+		// always scale the volume by the global media volume
 		F32 volume = mRequestedVolume * LLViewerMedia::getVolume();
 
-		if (mProximityCamera > 0) 
+		if (mProximityCamera > 0)
 		{
 			if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax"))
 			{
@@ -2218,7 +2273,7 @@ F32 LLViewerMediaImpl::getVolume()
 void LLViewerMediaImpl::focus(bool focus)
 {
 	mHasFocus = focus;
-	
+
 	if (mMediaSource)
 	{
 		// call focus just for the hell of it, even though this apopears to be a nop
@@ -2246,7 +2301,7 @@ std::string LLViewerMediaImpl::getCurrentMediaURL()
 	{
 		return mCurrentMediaURL;
 	}
-	
+
 	return mMediaURL;
 }
 
@@ -2314,17 +2369,17 @@ void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask)
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//static 
+//static
 void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y)
 {
 	F32 texture_x = texture_coords.mV[VX];
 	F32 texture_y = texture_coords.mV[VY];
-	
+
 	// Deal with repeating textures by wrapping the coordinates into the range [0, 1.0)
 	texture_x = fmodf(texture_x, 1.0f);
 	if(texture_x < 0.0f)
 		texture_x = 1.0 + texture_x;
-		
+
 	texture_y = fmodf(texture_y, 1.0f);
 	if(texture_y < 0.0f)
 		texture_y = 1.0 + texture_y;
@@ -2352,7 +2407,7 @@ void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S3
 void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button)
 {
 	if(mMediaSource)
-	{		
+	{
 		S32 x, y;
 		scaleTextureCoords(texture_coords, &x, &y);
 
@@ -2363,7 +2418,7 @@ void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32
 void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask)
 {
 	if(mMediaSource)
-	{		
+	{
 		S32 x, y;
 		scaleTextureCoords(texture_coords, &x, &y);
 
@@ -2371,6 +2426,17 @@ void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask)
 	}
 }
 
+void LLViewerMediaImpl::mouseDoubleClick(const LLVector2& texture_coords, MASK mask)
+{
+    if (mMediaSource)
+    {
+        S32 x, y;
+        scaleTextureCoords(texture_coords, &x, &y);
+
+        mouseDoubleClick(x, y, mask);
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button)
 {
@@ -2405,18 +2471,18 @@ void LLViewerMediaImpl::onMouseCaptureLost()
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) 
-{ 
+BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
+{
 	// NOTE: this is called when the mouse is released when we have capture.
 	// Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event.
-	
+
 	if(hasMouseCapture())
 	{
 		// Release the mouse -- this will also send a mouseup to the media
 		gFocusMgr.setMouseCapture( FALSE );
 	}
 
-	return TRUE; 
+	return TRUE;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -2492,14 +2558,14 @@ void LLViewerMediaImpl::updateJavascriptObject()
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-const std::string& LLViewerMediaImpl::getName() const 
-{ 
+const std::string& LLViewerMediaImpl::getName() const
+{
 	if (mMediaSource)
 	{
 		return mMediaSource->getMediaName();
 	}
-	
-	return LLStringUtil::null; 
+
+	return LLStringUtil::null;
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -2555,21 +2621,21 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
 		// Don't carry media play state across distinct URLs.
 		resetPreviousMediaState();
 	}
-	
+
 	// Always set the current URL and MIME type.
 	mMediaURL = url;
 	mMimeType = mime_type;
     mCleanBrowser = clean_browser;
-	
+
 	// Clear the current media URL, since it will no longer be correct.
 	mCurrentMediaURL.clear();
-	
+
 	// if mime type discovery was requested, we'll need to do it when the media loads
 	mNavigateRediscoverType = rediscover_type;
-	
+
 	// and if this was a server request, the navigate on load will also need to be one.
 	mNavigateServerRequest = server_request;
-	
+
 	// An explicit navigate resets the "failed" flag.
 	mMediaSourceFailed = false;
 
@@ -2585,7 +2651,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
 
 		// This impl should not be loaded at this time.
 		LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
-		
+
 		return;
 	}
 
@@ -2609,13 +2675,13 @@ void LLViewerMediaImpl::navigateInternal()
 		mNavigateSuspendedDeferred = true;
 		return;
 	}
-	
+
 	if(mMimeTypeProbe != NULL)
 	{
 		LL_WARNS() << "MIME type probe already in progress -- bailing out." << LL_ENDL;
 		return;
 	}
-	
+
 	if(mNavigateServerRequest)
 	{
 		setNavState(MEDIANAVSTATE_SERVER_SENT);
@@ -2624,12 +2690,12 @@ void LLViewerMediaImpl::navigateInternal()
 	{
 		setNavState(MEDIANAVSTATE_NONE);
 	}
-			
+
 	// If the caller has specified a non-empty MIME type, look that up in our MIME types list.
 	// If we have a plugin for that MIME type, use that instead of attempting auto-discovery.
 	// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
 	// but the parcel owner has correctly set the MIME type in the parcel media settings.
-	
+
 	if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType()))
 	{
 		std::string plugin_basename = LLMIMETypes::implType(mMimeType);
@@ -2698,27 +2764,47 @@ void LLViewerMediaImpl::navigateStop()
 bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
 {
 	bool result = false;
-	
+
+	if (mMediaSource)
+	{
+		// FIXME: THIS IS SO WRONG.
+		// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
+		if (MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
+		{
+			result = true;
+		}
+
+		if (!result)
+		{
+            LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
+			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN, key, mask, native_key_data);
+		}
+	}
+
+	return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+bool LLViewerMediaImpl::handleKeyUpHere(KEY key, MASK mask)
+{
+	bool result = false;
+
 	if (mMediaSource)
 	{
 		// FIXME: THIS IS SO WRONG.
 		// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
-		if( MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
+		if (MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
 		{
 			result = true;
 		}
-		
-		if(!result)
+
+		if (!result)
 		{
-			
 			LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
-			
-			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data);
-			// Since the viewer internal event dispatching doesn't give us key-up events, simulate one here.
-			(void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data);
+			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP, key, mask, native_key_data);
 		}
 	}
-	
+
 	return result;
 }
 
@@ -2726,7 +2812,7 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
 bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
 {
 	bool result = false;
-	
+
 	if (mMediaSource)
 	{
 		// only accept 'printable' characters, sigh...
@@ -2734,11 +2820,11 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
 			&& uni_char != 127) // SDL thinks this is 'delete' - yuck.
 		{
 			LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
-			
+
 			mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data);
 		}
 	}
-	
+
 	return result;
 }
 
@@ -2817,15 +2903,15 @@ void LLViewerMediaImpl::update()
 		}
 	}
 
-	
+
 	if(mMediaSource == NULL)
 	{
 		return;
 	}
-	
+
 	// Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
 	setNavigateSuspended(true);
-	
+
 	mMediaSource->idle();
 
 	setNavigateSuspended(false);
@@ -2834,7 +2920,7 @@ void LLViewerMediaImpl::update()
 	{
 		return;
 	}
-	
+
 	if(mMediaSource->isPluginExited())
 	{
 		resetPreviousMediaState();
@@ -2846,18 +2932,18 @@ void LLViewerMediaImpl::update()
 	{
 		return;
 	}
-	
+
 	if(mSuspendUpdates || !mVisible)
 	{
 		return;
 	}
-	
+
 	LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
-		
+
 	if(placeholder_image)
 	{
 		LLRect dirty_rect;
-		
+
 		// Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
 		placeholder_image->setPlaying(TRUE);
 
@@ -2868,7 +2954,7 @@ void LLViewerMediaImpl::update()
 			S32 y_pos = llmax(dirty_rect.mBottom, 0);
 			S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
 			S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
-			
+
 			if(width > 0 && height > 0)
 			{
 
@@ -2881,21 +2967,21 @@ void LLViewerMediaImpl::update()
 				// Offset the pixels pointer to match x_pos and y_pos
 				data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
 				data += ( y_pos * mMediaSource->getTextureDepth() );
-				
+
 				{
 					LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
 					placeholder_image->setSubImage(
-							data, 
-							mMediaSource->getBitsWidth(), 
+							data,
+							mMediaSource->getBitsWidth(),
 							mMediaSource->getBitsHeight(),
-							x_pos, 
-							y_pos, 
-							width, 
+							x_pos,
+							y_pos,
+							width,
 							height);
 				}
 
 			}
-			
+
 			mMediaSource->resetDirty();
 		}
 	}
@@ -2916,10 +3002,10 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 		// The code that created this instance will read from the plugin's bits.
 		return NULL;
 	}
-	
+
 	LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-	
-	if (mNeedsNewTexture 
+
+	if (mNeedsNewTexture
 		|| placeholder_image->getUseMipMaps()
 		|| (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
 		|| (placeholder_image->getHeight() != mMediaSource->getTextureHeight())
@@ -2933,7 +3019,7 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 		int texture_width = mMediaSource->getTextureWidth();
 		int texture_height = mMediaSource->getTextureHeight();
 		int texture_depth = mMediaSource->getTextureDepth();
-		
+
 		// MEDIAOPT: check to see if size actually changed before doing work
 		placeholder_image->destroyGLTexture();
 		// MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
@@ -2959,13 +3045,13 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 		// FIXME
 //		placeholder_image->mIsMediaTexture = true;
 		mNeedsNewTexture = false;
-				
-		// If the amount of the texture being drawn by the media goes down in either width or height, 
+
+		// If the amount of the texture being drawn by the media goes down in either width or height,
 		// recreate the texture to avoid leaving parts of the old image behind.
 		mTextureUsedWidth = mMediaSource->getWidth();
 		mTextureUsedHeight = mMediaSource->getHeight();
 	}
-	
+
 	return placeholder_image;
 }
 
@@ -2980,14 +3066,14 @@ LLUUID LLViewerMediaImpl::getMediaTextureID() const
 void LLViewerMediaImpl::setVisible(bool visible)
 {
 	mVisible = visible;
-	
+
 	if(mVisible)
 	{
 		if(mMediaSource && mMediaSource->isPluginExited())
 		{
 			destroyMediaSource();
 		}
-		
+
 		if(!mMediaSource)
 		{
 			createMediaSource();
@@ -3021,12 +3107,12 @@ void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y)
 bool LLViewerMediaImpl::isMediaTimeBased()
 {
 	bool result = false;
-	
+
 	if(mMediaSource)
 	{
 		result = mMediaSource->pluginSupportsMediaTime();
 	}
-	
+
 	return result;
 }
 
@@ -3034,14 +3120,14 @@ bool LLViewerMediaImpl::isMediaTimeBased()
 bool LLViewerMediaImpl::isMediaPlaying()
 {
 	bool result = false;
-	
+
 	if(mMediaSource)
 	{
 		EMediaStatus status = mMediaSource->getStatus();
 		if(status == MEDIA_PLAYING || status == MEDIA_LOADING)
 			result = true;
 	}
-	
+
 	return result;
 }
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -3054,7 +3140,7 @@ bool LLViewerMediaImpl::isMediaPaused()
 		if(mMediaSource->getStatus() == MEDIA_PAUSED)
 			result = true;
 	}
-	
+
 	return result;
 }
 
@@ -3082,7 +3168,7 @@ void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable)
 	{
 		// Only do this on actual state transitions.
 		mIsDisabled = disabled;
-		
+
 		if(mIsDisabled)
 		{
 			// We just disabled this media.  Clear all state.
@@ -3108,13 +3194,13 @@ bool LLViewerMediaImpl::isForcedUnloaded() const
 	{
 		return true;
 	}
-	
+
 	// If this media's class is not supposed to be shown, unload
 	if (!shouldShowBasedOnClass())
 	{
 		return true;
 	}
-	
+
 	return false;
 }
 
@@ -3127,19 +3213,19 @@ bool LLViewerMediaImpl::isPlayable() const
 		// All of the forced-unloaded criteria also imply not playable.
 		return false;
 	}
-	
+
 	if(hasMedia())
 	{
 		// Anything that's already playing is, by definition, playable.
 		return true;
 	}
-	
+
 	if(!mMediaURL.empty())
 	{
 		// If something has navigated the instance, it's ready to be played.
 		return true;
 	}
-	
+
 	return false;
 }
 
@@ -3151,7 +3237,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 	{
 		case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
 		{
-			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; 
+			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;
 			std::string url = plugin->getClickURL();
 			std::string nav_type = plugin->getClickNavType();
 			LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser);
@@ -3170,7 +3256,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 
 			// Reset the last known state of the media to defaults.
 			resetPreviousMediaState();
-			
+
 			// TODO: may want a different message for this case?
 			LLSD args;
 			args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType);
@@ -3192,13 +3278,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			//LLNotificationsUtil::add("MediaPluginFailed", args);
 		}
 		break;
-		
+
 		case MEDIA_EVENT_CURSOR_CHANGED:
 		{
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL;
 
 			std::string cursor = plugin->getCursorName();
-			
+
 			if(cursor == "arrow")
 				mLastSetCursor = UI_CURSOR_ARROW;
 			else if(cursor == "ibeam")
@@ -3214,6 +3300,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		}
 		break;
 
+		case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD:
+		{
+			//llinfos << "Media event - file download requested - filename is " << self->getFileDownloadFilename() << llendl;
+			LLNotificationsUtil::add("MediaFileDownloadUnsupported");
+		}
+		break;
+
 		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:
 		{
 			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL;
@@ -3259,7 +3352,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 			}
 		}
 		break;
-		
+
 		case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED:
 		{
 			LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL;
@@ -3296,15 +3389,15 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		{
 			// Display a file picker
 			std::string response;
-			
+
 			LLFilePicker& picker = LLFilePicker::instance();
 			if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL))
 			{
 				// The user didn't pick a file -- the empty response string will indicate this.
 			}
-			
+
 			response = picker.getFirstFile();
-			
+
 			plugin->sendPickFileResponse(response);
 		}
 		break;
@@ -3460,7 +3553,7 @@ void LLViewerMediaImpl::calculateInterest()
 {
 	LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST);
 	LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId );
-	
+
 	if(texture != NULL)
 	{
 		mInterest = texture->getMaxVirtualSize();
@@ -3470,7 +3563,7 @@ void LLViewerMediaImpl::calculateInterest()
 		// This will be a relatively common case now, since it will always be true for unloaded media.
 		mInterest = 0.0f;
 	}
-	
+
 	// Calculate distance from the avatar, for use in the proximity calculation.
 	mProximityDistance = 0.0f;
 	mProximityCamera = 0.0f;
@@ -3480,7 +3573,7 @@ void LLViewerMediaImpl::calculateInterest()
 		std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
 		LLVOVolume* objp = *iter ;
 		llassert_always(objp != NULL) ;
-		
+
 		// The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them.
 		if(!objp->isHUDAttachment())
 		{
@@ -3493,12 +3586,12 @@ void LLViewerMediaImpl::calculateInterest()
 			mProximityCamera = camera_delta.magVec();
 		}
 	}
-	
+
 	if(mNeedsMuteCheck)
 	{
 		// Check all objects this instance is associated with, and those objects' owners, against the mute list
 		mIsMuted = false;
-		
+
 		std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
 		for(; iter != mObjectList.end() ; ++iter)
 		{
@@ -3525,7 +3618,7 @@ void LLViewerMediaImpl::calculateInterest()
 				}
 			}
 		}
-		
+
 		mNeedsMuteCheck = false;
 	}
 }
@@ -3533,7 +3626,7 @@ void LLViewerMediaImpl::calculateInterest()
 F64 LLViewerMediaImpl::getApproximateTextureInterest()
 {
 	F64 result = 0.0f;
-	
+
 	if(mMediaSource)
 	{
 		result = mMediaSource->getFullWidth();
@@ -3551,8 +3644,8 @@ F64 LLViewerMediaImpl::getApproximateTextureInterest()
 
 void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)
 {
-	mUsedInUI = used_in_ui; 
-	
+	mUsedInUI = used_in_ui;
+
 	// HACK: Force elements used in UI to load right away.
 	// This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded.
 	if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED))
@@ -3572,7 +3665,7 @@ void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)
 
 void LLViewerMediaImpl::setBackgroundColor(LLColor4 color)
 {
-	mBackgroundColor = color; 
+	mBackgroundColor = color;
 
 	if(mMediaSource)
 	{
@@ -3583,12 +3676,12 @@ void LLViewerMediaImpl::setBackgroundColor(LLColor4 color)
 F64 LLViewerMediaImpl::getCPUUsage() const
 {
 	F64 result = 0.0f;
-	
+
 	if(mMediaSource)
 	{
 		result = mMediaSource->getCPUUsage();
 	}
-	
+
 	return result;
 }
 
@@ -3602,19 +3695,19 @@ void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
 			<< " to " << LLPluginClassMedia::priorityToString(priority)
 			<< LL_ENDL;
 	}
-	
+
 	mPriority = priority;
-	
+
 	if(priority == LLPluginClassMedia::PRIORITY_UNLOADED)
 	{
 		if(mMediaSource)
 		{
 			// Need to unload the media source
-			
+
 			// First, save off previous media state
 			mPreviousMediaState = mMediaSource->getStatus();
 			mPreviousMediaTime = mMediaSource->getCurrentTime();
-			
+
 			destroyMediaSource();
 		}
 	}
@@ -3623,7 +3716,7 @@ void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
 	{
 		mMediaSource->setPriority(mPriority);
 	}
-	
+
 	// NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update().
 }
 
@@ -3638,8 +3731,8 @@ void LLViewerMediaImpl::setLowPrioritySizeLimit(int size)
 void LLViewerMediaImpl::setNavState(EMediaNavState state)
 {
 	mMediaNavState = state;
-	
-	switch (state) 
+
+	switch (state)
 	{
 		case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << LL_ENDL; break;
 		case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << LL_ENDL; break;
@@ -3678,7 +3771,7 @@ void LLViewerMediaImpl::cancelMimeTypeProbe()
 		// There doesn't seem to be a way to actually cancel an outstanding request.
 		// Simulate it by telling the LLMimeDiscoveryResponder not to write back any results.
 		mMimeTypeProbe->cancelRequest();
-		
+
 		// The above should already have set mMimeTypeProbe to NULL.
 		if(mMimeTypeProbe != NULL)
 		{
@@ -3687,7 +3780,7 @@ void LLViewerMediaImpl::cancelMimeTypeProbe()
 	}
 }
 
-void LLViewerMediaImpl::addObject(LLVOVolume* obj) 
+void LLViewerMediaImpl::addObject(LLVOVolume* obj)
 {
 	std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
 	for(; iter != mObjectList.end() ; ++iter)
@@ -3701,14 +3794,14 @@ void LLViewerMediaImpl::addObject(LLVOVolume* obj)
 	mObjectList.push_back(obj) ;
 	mNeedsMuteCheck = true;
 }
-	
-void LLViewerMediaImpl::removeObject(LLVOVolume* obj) 
+
+void LLViewerMediaImpl::removeObject(LLVOVolume* obj)
 {
-	mObjectList.remove(obj) ;	
+	mObjectList.remove(obj) ;
 	mNeedsMuteCheck = true;
 }
-	
-const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const 
+
+const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const
 {
 	return &mObjectList ;
 }
@@ -3716,13 +3809,13 @@ const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const
 LLVOVolume *LLViewerMediaImpl::getSomeObject()
 {
 	LLVOVolume *result = NULL;
-	
+
 	std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
 	if(iter != mObjectList.end())
 	{
 		result = *iter;
 	}
-	
+
 	return result;
 }
 
@@ -3735,12 +3828,12 @@ void LLViewerMediaImpl::setTextureID(LLUUID id)
 			// Remove this item's entry from the map
 			sViewerMediaTextureIDMap.erase(mTextureId);
 		}
-		
+
 		if(id.notNull())
 		{
 			sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this));
 		}
-		
+
 		mTextureId = id;
 	}
 }
@@ -3749,7 +3842,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id)
 //
 bool LLViewerMediaImpl::isAutoPlayable() const
 {
-	return (mMediaAutoPlay && 
+	return (mMediaAutoPlay &&
 			gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
 			gSavedSettings.getBOOL("MediaTentativeAutoPlay"));
 }
@@ -3760,20 +3853,20 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const
 {
 	// If this is parcel media or in the UI, return true always
 	if (getUsedInUI() || isParcelMedia()) return true;
-	
+
 	bool attached_to_another_avatar = isAttachedToAnotherAvatar();
 	bool inside_parcel = isInAgentParcel();
-	
+
 	//	LL_INFOS() << " hasFocus = " << hasFocus() <<
 	//	" others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) <<
 	//	" within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) <<
 	//	" outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << LL_ENDL;
-	
+
 	// If it has focus, we should show it
 	// This is incorrect, and causes EXT-6750 (disabled attachment media still plays)
 //	if (hasFocus())
 //		return true;
-	
+
 	// If it is attached to an avatar and the pref is off, we shouldn't show it
 	if (attached_to_another_avatar)
 	{
@@ -3786,7 +3879,7 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const
 
 		return show_media_within_parcel;
 	}
-	else 
+	else
 	{
 		static LLCachedControl<bool> show_media_outside_parcel(gSavedSettings, LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING, true);
 
@@ -3799,7 +3892,7 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const
 bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const
 {
 	bool result = false;
-	
+
 	std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin();
 	std::list< LLVOVolume* >::const_iterator end = mObjectList.end();
 	for ( ; iter != end; iter++)
@@ -3843,7 +3936,7 @@ bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj)
 bool LLViewerMediaImpl::isInAgentParcel() const
 {
 	bool result = false;
-	
+
 	std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin();
 	std::list< LLVOVolume* >::const_iterator end = mObjectList.end();
 	for ( ; iter != end; iter++)
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 1ce42e97b83f9cc2e25996779293ffedd3c36921..ede408dd0ca26016cd7a454b993ec29d50a9e3cf 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -150,7 +150,7 @@ class LLViewerMedia
 	static void removeCookie(const std::string &name, const std::string &domain, const std::string &path = std::string("/") );
 
 	static void openIDSetup(const std::string &openid_url, const std::string &openid_token);
-	static void openIDCookieResponse(const std::string &cookie);
+	static void openIDCookieResponse(const std::string& url, const std::string &cookie);
 	
 	static void proxyWindowOpened(const std::string &target, const std::string &uuid);
 	static void proxyWindowClosed(const std::string &uuid);
@@ -163,7 +163,8 @@ class LLViewerMedia
 	static LLSD getHeaders();
 	
 private:
-	static void setOpenIDCookie();
+	static bool parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure);
+	static void setOpenIDCookie(const std::string& url);
 	static void onTeleportFinished();
 	
 	static LLPluginCookieStore *sCookieStore;
@@ -225,7 +226,8 @@ class LLViewerMediaImpl
 	void mouseDown(const LLVector2& texture_coords, MASK mask, S32 button = 0);
 	void mouseUp(const LLVector2& texture_coords, MASK mask, S32 button = 0);
 	void mouseMove(const LLVector2& texture_coords, MASK mask);
-	void mouseDoubleClick(S32 x,S32 y, MASK mask, S32 button = 0);
+    void mouseDoubleClick(const LLVector2& texture_coords, MASK mask);
+    void mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button = 0);
 	void scrollWheel(S32 x, S32 y, MASK mask);
 	void mouseCapture();
 	
@@ -238,6 +240,7 @@ class LLViewerMediaImpl
 	void navigateInternal();
 	void navigateStop();
 	bool handleKeyHere(KEY key, MASK mask);
+	bool handleKeyUpHere(KEY key, MASK mask);
 	bool handleUnicodeCharHere(llwchar uni_char);
 	bool canNavigateForward();
 	bool canNavigateBack();
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index aa019dfdd80d8536cf0c0d132e145699e70813d8..7b4df3d3da896975a6455a2d27482b4d4d13d4e7 100755
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -352,6 +352,18 @@ BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return true;
 }
 
+BOOL LLViewerMediaFocus::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+    LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
+    if (media_impl)
+    {
+        media_impl->handleKeyUpHere(key, mask);
+    }
+    return true;
+}
+
+
+
 BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
@@ -603,3 +615,13 @@ LLUUID LLViewerMediaFocus::getControlsMediaID()
 	
 	return LLUUID::null;
 }
+
+bool LLViewerMediaFocus::wantsKeyUpKeyDown() const
+{
+    return true;
+}
+
+bool LLViewerMediaFocus::wantsReturnKey() const
+{
+    return true;
+}
diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h
index f03dd8751e4231778bb9af5cf8aa01ae16d64d90..0b2a64868ea0c40710b1c288884c5b1cc959f96e 100755
--- a/indra/newview/llviewermediafocus.h
+++ b/indra/newview/llviewermediafocus.h
@@ -56,6 +56,7 @@ class LLViewerMediaFocus :
 	
 	/*virtual*/ bool	getFocus();
 	/*virtual*/ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	/*virtual*/ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	/*virtual*/ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 
@@ -87,6 +88,10 @@ class LLViewerMediaFocus :
 	// Return the ID of the media instance the controls are currently attached to (either focus or hover).
 	LLUUID getControlsMediaID();
 
+    // The MoaP object wants keyup and keydown events.  Overridden to return true.
+    virtual bool    wantsKeyUpKeyDown() const;
+    virtual bool    wantsReturnKey() const;
+
 protected:
 	/*virtual*/ void	onFocusReceived();
 	/*virtual*/ void	onFocusLost();
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 37b249dddd14c2cbdb8ac373b8be136981d3bcde..fc275eb2f0677211809b4e298458f87f65faabf1 100755
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -590,7 +590,13 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PICK_FILE_REQUEST" << LL_ENDL;
 		}
 		break;
-
+		
+		case MEDIA_EVENT_FILE_DOWNLOAD:
+		{
+			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_FILE_DOWNLOAD" << LL_ENDL;
+		}
+		break;
+		
 		case MEDIA_EVENT_GEOMETRY_CHANGE:
 		{
 			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 6d73a75b744e8aba71a503d98274f0d09a63ce76..2ccf4427b4d0b214171bb746fa78c8a42a8edce9 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1381,7 +1381,11 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 	// it's all entered/processed.
 	if (key == KEY_RETURN && mask == MASK_NONE)
 	{
-		return FALSE;
+        // RIDER: although, at times some of the controlls (in particular the CEF viewer
+        // would like to know about the KEYDOWN for an enter key... so ask and pass it along.
+        LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+        if (keyboard_focus && !keyboard_focus->wantsReturnKey())
+    		return FALSE;
 	}
 
 	return gViewerKeyboard.handleKey(key, mask, repeated);
@@ -1399,10 +1403,9 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 		tool_inspectp->keyUp(key, mask);
 	}
 
-	return FALSE;
+	return gViewerKeyboard.handleKeyUp(key, mask);
 }
 
-
 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
@@ -2019,6 +2022,7 @@ void LLViewerWindow::initWorldUI()
 		}
 		gHUDView = new LLHUDView(hud_rect);
 		getRootView()->addChild(gHUDView);
+		getRootView()->sendChildToBack(gHUDView);
 	}
 
 	LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("state_management_buttons_container");
@@ -2544,21 +2548,67 @@ void LLViewerWindow::draw()
 //#endif
 }
 
+// Takes a single keyup event, usually when UI is visible
+BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask)
+{
+    LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+    if (keyboard_focus
+		&& !(mask & (MASK_CONTROL | MASK_ALT))
+		&& !gFocusMgr.getKeystrokesOnly())
+	{
+		// We have keyboard focus, and it's not an accelerator
+        if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+        {
+            return keyboard_focus->handleKeyUp(key, mask, FALSE);
+        }
+        else if (key < 0x80)
+		{
+			// Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
+			return (gFocusMgr.getKeyboardFocus() != NULL);
+		}
+	}
+
+	if (keyboard_focus)
+	{
+		if (keyboard_focus->handleKeyUp(key, mask, FALSE))
+		{
+			LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned true" << LL_ENDL;
+			LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+			return TRUE;
+		}
+		else {
+			LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned FALSE" << LL_ENDL;
+		}
+	}
+
+	// don't pass keys on to world when something in ui has focus
+	return gFocusMgr.childHasKeyboardFocus(mRootView)
+		|| LLMenuGL::getKeyboardMode()
+		|| (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
 // Takes a single keydown event, usually when UI is visible
 BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 {
 	// hide tooltips on keypress
 	LLToolTipMgr::instance().blockToolTips();
 
-	if (gFocusMgr.getKeyboardFocus() 
+    LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+    if (keyboard_focus
 		&& !(mask & (MASK_CONTROL | MASK_ALT))
 		&& !gFocusMgr.getKeystrokesOnly())
 	{
 		// We have keyboard focus, and it's not an accelerator
-		if (key < 0x80)
+        if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+        {
+            return keyboard_focus->handleKey(key, mask, FALSE );
+        }
+		else if (key < 0x80)
 		{
 			// Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
-			return (gFocusMgr.getKeyboardFocus() != NULL);
+            return (keyboard_focus != NULL);
 		}
 	}
 
@@ -2572,7 +2622,6 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 		return TRUE;
 	}
 
-	LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
 
 	// give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus 
 	// as long as focus isn't locked
@@ -2598,7 +2647,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// give floaters first chance to handle TAB key
 	// so frontmost floater gets focus
 	// if nothing has focus, go to first or last UI element as appropriate
-	if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
+    if (key == KEY_TAB && (mask & MASK_CONTROL || keyboard_focus == NULL))
 	{
 		LL_WARNS() << "LLviewerWindow::handleKey give floaters first chance at tab key " << LL_ENDL;
 		if (gMenuHolder) gMenuHolder->hideMenus();
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 7fde52d4e102cb8b8517603e6efd3b2cf240f68f..17e9ac26362202161e8cbe1b39e94c92842b54da 100755
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -314,6 +314,7 @@ class LLViewerWindow : public LLWindowCallbacks
 	LLView*			getHintHolder() { return mHintHolder.get(); }
 	LLView*			getLoginPanelHolder() { return mLoginPanelHolder.get(); }
 	BOOL			handleKey(KEY key, MASK mask);
+	BOOL			handleKeyUp(KEY key, MASK mask);
 	void			handleScrollWheel	(S32 clicks);
 
 	// add and remove views from "popup" layer
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 0be6e498342c70440b30e0574099337189979687..b37e41fb857429e0e2f8343f6b9eada2a52ea1a3 100755
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -234,6 +234,9 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
 //static
 bool LLWeb::useExternalBrowser(const std::string &url)
 {
+#ifdef EXTERNAL_TOS
+	return true;
+#else
 	if (gSavedSettings.getU32("PreferredBrowserBehavior") == BROWSER_EXTERNAL_ONLY)
 	{
 		return true;
@@ -250,4 +253,5 @@ bool LLWeb::useExternalBrowser(const std::string &url)
 		return !(boost::regex_search(uri_string, matches, pattern));
 	}
 	return false;
+#endif
 }
diff --git a/indra/newview/skins/default/xui/en/floater_tos.xml b/indra/newview/skins/default/xui/en/floater_tos.xml
index af1617eb39d45690ce0e653033e60c26d4cf9939..590d9d18442715467bcc13462aa9af770e2990cb 100755
--- a/indra/newview/skins/default/xui/en/floater_tos.xml
+++ b/indra/newview/skins/default/xui/en/floater_tos.xml
@@ -57,6 +57,21 @@
      width="552">
         Please read the following Terms of Service and Privacy Policy carefully. To continue logging in to [SECOND_LIFE], you must accept the agreement.
     </text>
+     <text
+     type="string"
+     length="1"
+     follows="left|top"
+     font="SansSerif"
+     height="30"
+     layout="topleft"
+     left="16"
+     name="external_tos_required"
+     visible="false"
+     top="32"
+     word_wrap="true"
+     width="552">
+       You will need to go to my.secondlife.com and log in to accept the Terms of Service before you can proceed. Thank you!
+     </text>
     <web_browser
       trusted_content="true" 
      follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 73ca7c529d29af524316251796b035e070d874a6..419ec359a6b940a87d0190bd3424346b705d4a56 100755
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -236,7 +236,7 @@
        name="Web Content Floater Debug Test">
         <menu_item_call.on_click
          function="Advanced.WebContentTest"
-         parameter="http://google.com"/>
+         parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
       </menu_item_call>
       <menu
        create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 26004a3bd59dd20ced847f195df686e4389f2513..4cb0e6752199aa6bc4829b61c37fb249748d457b 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1438,7 +1438,7 @@
                  function="Floater.Show"
                  parameter="bumps" />
         </menu_item_call>
-        <menu_item_separator/>
+        <menu_item_separator/>    
         <menu_item_call
          label="About [APP_NAME]"
          name="About Second Life">
@@ -3171,7 +3171,7 @@
            shortcut="control|shift|Z">
             <menu_item_call.on_click
              function="Advanced.WebContentTest"
-             parameter="http://google.com"/>
+             parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
           </menu_item_call>
           <menu_item_call
            label="FB Connect Test"
diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml
index f5f222333077eb6eabbf606ba0b3bdda15ebf035..7cb4a6e53b17d6f23f8e00eb0fe1e555eb41d2ef 100755
--- a/indra/newview/skins/default/xui/en/mime_types.xml
+++ b/indra/newview/skins/default/xui/en/mime_types.xml
@@ -7,7 +7,7 @@
 		none
 	</defaultwidget>
 	<defaultimpl>
-		media_plugin_webkit
+		media_plugin_cef
 	</defaultimpl>
 	<widgetset name="web">
 		<label name="web_label">
@@ -141,7 +141,7 @@
 			none
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="none/none">
@@ -152,7 +152,7 @@
 			none
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="audio/*">
@@ -185,7 +185,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
@@ -207,7 +207,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/ogg">
@@ -229,7 +229,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/postscript">
@@ -240,7 +240,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/rtf">
@@ -251,7 +251,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/smil">
@@ -262,7 +262,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/xhtml+xml">
@@ -273,7 +273,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/x-director">
@@ -284,7 +284,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="audio/mid">
@@ -339,7 +339,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/gif">
@@ -350,7 +350,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/jpeg">
@@ -361,7 +361,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/png">
@@ -372,7 +372,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="image/svg+xml">
@@ -383,7 +383,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/tiff">
@@ -394,7 +394,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="text/html">
@@ -405,7 +405,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="text/plain">
@@ -416,7 +416,7 @@
 			text
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="text/xml">
@@ -427,7 +427,7 @@
 			text
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/mpeg">
diff --git a/indra/newview/skins/default/xui/en/mime_types_mac.xml b/indra/newview/skins/default/xui/en/mime_types_mac.xml
index 90230f12dd6131c53cee5809424fe77fff307c0d..f71c24b2e4312f5a297ec8474c969bad59acf034 100755
--- a/indra/newview/skins/default/xui/en/mime_types_mac.xml
+++ b/indra/newview/skins/default/xui/en/mime_types_mac.xml
@@ -7,7 +7,7 @@
 		none
 	</defaultwidget>
 	<defaultimpl>
-		media_plugin_webkit
+		media_plugin_cef
 	</defaultimpl>
 	<widgetset name="web">
 		<label name="web_label">
@@ -152,7 +152,7 @@
 			none
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="audio/*">
@@ -185,7 +185,7 @@
 			image
 		</widgettype>
         <impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
@@ -207,7 +207,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/ogg">
@@ -229,7 +229,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/postscript">
@@ -240,7 +240,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/rtf">
@@ -251,7 +251,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/smil">
@@ -262,7 +262,7 @@
 			movie
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/xhtml+xml">
@@ -273,7 +273,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="application/x-director">
@@ -284,7 +284,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="audio/mid">
@@ -339,7 +339,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/gif">
@@ -350,7 +350,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/jpeg">
@@ -361,7 +361,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/png">
@@ -372,7 +372,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="image/svg+xml">
@@ -383,7 +383,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="image/tiff">
@@ -394,7 +394,7 @@
 			image
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="text/html">
@@ -405,7 +405,7 @@
 			web
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="text/plain">
@@ -416,7 +416,7 @@
 			text
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype name="text/xml">
@@ -427,7 +427,7 @@
 			text
 		</widgettype>
 		<impl>
-			media_plugin_webkit
+			media_plugin_cef
 		</impl>
 	</mimetype>
 	<mimetype menu="1" name="video/mpeg">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 570a7625f39aedef4c31c8563eda3fbb652d61ed..271061a0ec57147a4c488e5697cd29abe37d18aa 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1592,10 +1592,23 @@ The object may be out of range or may have been deleted.
    icon="alertmodal.tga"
    name="CannotDownloadFile"
    type="alertmodal">
-Unable to download file
-  <tag>fail</tag>
+    Unable to download file
+    <tag>fail</tag>
   </notification>
 
+  <notification
+  name="MediaFileDownloadUnsupported"
+  label=""
+  type="alert">
+    <unique/>
+    <tag>confirm</tag>
+    You have requested a file download, which is not supported within [SECOND_LIFE].
+    <usetemplate
+     ignoretext="Warn about unsupported file downloads"
+     name="okignore"
+     yestext="OK"/>
+  </notification>
+  
   <notification
    icon="alertmodal.tga"
    name="CannotWriteFile"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index be88ef9b3dad21312323360b535f1e65d7155b16..0b605cf6f7e33a6238b7e1422c500a337d110d95 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -224,19 +224,6 @@
     radio_style="false"
     width="400"
     top_pad="5"/>
-  <check_box
-    top_delta="4"
-    enabled="true"
-    follows="left|top"
-    height="14"
-    initial_value="false"
-    control_name="MediaEnablePopups"
-    label="Enable media browser pop-ups"
-    left_delta="0"
-    mouse_opaque="true"
-    name="media_popup_enabled"
-    width="400"           
-    top_pad="5"/>
   <text
      type="string"
      length="1"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 0b33cea1d4247d166a2d2ea4314a863617cb0cfd..d1f517d45c832bfbd5e799cd1022da0613a6f0b1 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -50,7 +50,7 @@ OpenGL Version: [OPENGL_VERSION]
 libcurl Version: [LIBCURL_VERSION]
 J2C Decoder Version: [J2C_VERSION]
 Audio Driver Version: [AUDIO_DRIVER_VERSION]
-Qt Webkit Version: [QT_WEBKIT_VERSION]
+LLCEFLib/CEF Version: [LLCEFLIB_VERSION]
 Voice Server Version: [VOICE_VERSION]
 	</string>
 	<string name="AboutTraffic">Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%)</string>
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 6f57daf1519a096c00057ddf7b6020a174d9f952..7cb4aeb1215e1162819f20c548c51a06a3906b61 100755
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -26,7 +26,7 @@
 
 #include "linden_common.h"
 #include "../llviewerprecompiledheaders.h"
- 
+
 #include <iostream>
 #include "../test/lltut.h"
 
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index cae6bded9fe9787a538c725a3da2a6728e5e2b3c..f7992dba9033dd3ddadf40c9aab34cad5c28db36 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -340,9 +340,9 @@ def construct(self):
             self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
 
         # Plugin host application
-        # The current slplugin package places slplugin.exe right into the
-        # packages base directory.
-        self.path2basename(pkgdir, "slplugin.exe")
+        self.path2basename(os.path.join(os.pardir,
+                                        'llplugin', 'slplugin', self.args['configuration']),
+                           "slplugin.exe")
         
         self.path2basename("../viewer_components/updater/scripts/windows", "update_install.bat")
         # Get shared libs from the shared libs staging directory
@@ -428,54 +428,121 @@ def construct(self):
         self.path("featuretable_xp.txt")
 
         # Media plugins - QuickTime
-        # Media plugins - WebKit/Qt
-        if self.prefix(src=os.path.join(pkgdir, "llplugin"), dst="llplugin"):
+        if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
             self.path("media_plugin_quicktime.dll")
-            self.path("media_plugin_webkit.dll")
-            self.path("qtcore4.dll")
-            self.path("qtgui4.dll")
-            self.path("qtnetwork4.dll")
-            self.path("qtopengl4.dll")
-            self.path("qtwebkit4.dll")
-            self.path("qtxmlpatterns4.dll")
-
-            # For WebKit/Qt plugin runtimes (image format plugins)
-            if self.prefix(src="imageformats", dst="imageformats"):
-                self.path("qgif4.dll")
-                self.path("qico4.dll")
-                self.path("qjpeg4.dll")
-                self.path("qmng4.dll")
-                self.path("qsvg4.dll")
-                self.path("qtiff4.dll")
-                self.end_prefix()
-
-            # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
-            if self.prefix(src="codecs", dst="codecs"):
-                self.path("qcncodecs4.dll")
-                self.path("qjpcodecs4.dll")
-                self.path("qkrcodecs4.dll")
-                self.path("qtwcodecs4.dll")
-                self.end_prefix()
+            self.end_prefix()
 
-        self.end_prefix()
+        # Media plugins - CEF
+        if self.prefix(src='../media_plugins/cef/%s' % self.args['configuration'], dst="llplugin"):
+            self.path("media_plugin_cef.dll")
+            self.end_prefix()
 
         # winmm.dll shim
         if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst=""):
             self.path("winmm.dll")
             self.end_prefix()
 
+        # CEF runtime files - debug
         if self.args['configuration'].lower() == 'debug':
-            if self.prefix(src=debpkgdir, dst="llplugin"):
-                self.path("libeay32.dll")
-                self.path("ssleay32.dll")
+            if self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'debug'), dst="llplugin"):
+                self.path("d3dcompiler_43.dll")
+                self.path("d3dcompiler_47.dll")
+                self.path("libcef.dll")
+                self.path("libEGL.dll")
+                self.path("libGLESv2.dll")
+                self.path("llceflib_host.exe")
+                self.path("natives_blob.bin")
+                self.path("snapshot_blob.bin")
+                self.path("widevinecdmadapter.dll")
+                self.path("wow_helper.exe")
                 self.end_prefix()
-
         else:
-            if self.prefix(src=relpkgdir, dst="llplugin"):
-                self.path("libeay32.dll")
-                self.path("ssleay32.dll")
+        # CEF runtime files - not debug (release, relwithdebinfo etc.)
+            if self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'release'), dst="llplugin"):
+                self.path("d3dcompiler_43.dll")
+                self.path("d3dcompiler_47.dll")
+                self.path("libcef.dll")
+                self.path("libEGL.dll")
+                self.path("libGLESv2.dll")
+                self.path("llceflib_host.exe")
+                self.path("natives_blob.bin")
+                self.path("snapshot_blob.bin")
+                self.path("widevinecdmadapter.dll")
+                self.path("wow_helper.exe")
                 self.end_prefix()
 
+        # MSVC DLLs needed for CEF and have to be in same directory as plugin
+        if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release'), dst="llplugin"):
+            self.path("msvcp120.dll")
+            self.path("msvcr120.dll")
+            self.end_prefix()
+
+        # CEF files common to all configurations
+        if self.prefix(src=os.path.join(os.pardir, 'packages', 'resources'), dst="llplugin"):
+            self.path("cef.pak")
+            self.path("cef_100_percent.pak")
+            self.path("cef_200_percent.pak")
+            self.path("cef_extensions.pak")
+            self.path("devtools_resources.pak")
+            self.path("icudtl.dat")
+            self.end_prefix()
+
+        if self.prefix(src=os.path.join(os.pardir, 'packages', 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')):
+            self.path("am.pak")
+            self.path("ar.pak")
+            self.path("bg.pak")
+            self.path("bn.pak")
+            self.path("ca.pak")
+            self.path("cs.pak")
+            self.path("da.pak")
+            self.path("de.pak")
+            self.path("el.pak")
+            self.path("en-GB.pak")
+            self.path("en-US.pak")
+            self.path("es-419.pak")
+            self.path("es.pak")
+            self.path("et.pak")
+            self.path("fa.pak")
+            self.path("fi.pak")
+            self.path("fil.pak")
+            self.path("fr.pak")
+            self.path("gu.pak")
+            self.path("he.pak")
+            self.path("hi.pak")
+            self.path("hr.pak")
+            self.path("hu.pak")
+            self.path("id.pak")
+            self.path("it.pak")
+            self.path("ja.pak")
+            self.path("kn.pak")
+            self.path("ko.pak")
+            self.path("lt.pak")
+            self.path("lv.pak")
+            self.path("ml.pak")
+            self.path("mr.pak")
+            self.path("ms.pak")
+            self.path("nb.pak")
+            self.path("nl.pak")
+            self.path("pl.pak")
+            self.path("pt-BR.pak")
+            self.path("pt-PT.pak")
+            self.path("ro.pak")
+            self.path("ru.pak")
+            self.path("sk.pak")
+            self.path("sl.pak")
+            self.path("sr.pak")
+            self.path("sv.pak")
+            self.path("sw.pak")
+            self.path("ta.pak")
+            self.path("te.pak")
+            self.path("th.pak")
+            self.path("tr.pak")
+            self.path("uk.pak")
+            self.path("vi.pak")
+            self.path("zh-CN.pak")
+            self.path("zh-TW.pak")
+            self.end_prefix()
+
         # pull in the crash logger and updater from other projects
         # tag:"crash-logger" here as a cue to the exporter
         self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
@@ -739,14 +806,13 @@ def path_optional(src, dst):
                         dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
                 
                 # our apps
-                for app_bld_dir, app in ((os.path.join(os.pardir,
-                                                       "mac_crash_logger",
-                                                       self.args['configuration']),
-                                          "mac-crash-logger.app"),
+                for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
                                          # plugin launcher
-                                         (pkgdir, "SLPlugin.app"),
+                                         (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
                                          ):
-                    self.path2basename(app_bld_dir, app)
+                    self.path2basename(os.path.join(os.pardir,
+                                                    app_bld_dir, self.args['configuration']),
+                                       app)
 
                     # our apps dependencies on shared libs
                     # for each app, for each dylib we collected in dylibs,
@@ -759,46 +825,57 @@ def path_optional(src, dst):
                             symlinkf(src, dst)
                         except OSError as err:
                             print "Can't symlink %s -> %s: %s" % (src, dst, err)
-                # SLPlugin.app/Contents/Resources gets those Qt4 libraries it needs.
-                if self.prefix(src="", dst="SLPlugin.app/Contents/Resources"):
-                    for libfile in ('libQtCore.4.dylib',
-                                    'libQtCore.4.7.1.dylib',
-                                    'libQtGui.4.dylib',
-                                    'libQtGui.4.7.1.dylib',
-                                    'libQtNetwork.4.dylib',
-                                    'libQtNetwork.4.7.1.dylib',
-                                    'libQtOpenGL.4.dylib',
-                                    'libQtOpenGL.4.7.1.dylib',
-                                    'libQtSvg.4.dylib',
-                                    'libQtSvg.4.7.1.dylib',
-                                    'libQtWebKit.4.dylib',
-                                    'libQtWebKit.4.7.1.dylib',
-                                    'libQtXml.4.dylib',
-                                    'libQtXml.4.7.1.dylib'):
-                        self.path2basename(relpkgdir, libfile)
-                    self.end_prefix("SLPlugin.app/Contents/Resources")
-
-                # Qt4 codecs go to llplugin.  Not certain why but this is the first
-                # location probed according to dtruss so we'll go with that.
-                if self.prefix(src=os.path.join(pkgdir, "llplugin/codecs/"), dst="llplugin/codecs"):
-                    self.path("libq*.dylib")
-                    self.end_prefix("llplugin/codecs")
-
-                # Similarly for imageformats.
-                if self.prefix(src=os.path.join(pkgdir, "llplugin/imageformats/"), dst="llplugin/imageformats"):
-                    self.path("libq*.dylib")
-                    self.end_prefix("llplugin/imageformats")
-
-                # SLPlugin plugins proper
-                if self.prefix(src=os.path.join(pkgdir, "llplugin"), dst="llplugin"):
-                    self.path("media_plugin_quicktime.dylib")
-                    self.path("media_plugin_webkit.dylib")
+
+                # LLCefLib helper apps go inside SLPlugin.app
+                if self.prefix(src="", dst="SLPlugin.app/Contents/Frameworks"):
+                    for helperappfile in ('LLCefLib Helper.app',
+                                          'LLCefLib Helper EH.app'):
+                        self.path2basename(relpkgdir, helperappfile)
+
+                    pluginframeworkpath = self.dst_path_of('Chromium Embedded Framework.framework');
+
+                    self.end_prefix()
+
+                # SLPlugin plugins
+                if self.prefix(src="", dst="llplugin"):
+                    self.path2basename("../media_plugins/quicktime/" + self.args['configuration'],
+                                       "media_plugin_quicktime.dylib")
+                    self.path2basename("../media_plugins/cef/" + self.args['configuration'],
+                                       "media_plugin_cef.dylib")
                     self.end_prefix("llplugin")
 
                 self.end_prefix("Resources")
 
+                # CEF framework goes inside Second Life.app/Contents/Frameworks
+                if self.prefix(src="", dst="Frameworks"):
+                    frameworkfile="Chromium Embedded Framework.framework"
+                    self.path2basename(relpkgdir, frameworkfile)
+                    self.end_prefix("Frameworks")
+
+                # This code constructs a relative path from the
+                # target framework folder back to the location of the symlink.
+                # It needs to be relative so that the symlink still works when
+                # (as is normal) the user moves the app bunlde out of the DMG
+                # and into the /Applications folder. Note we also call 'raise'
+                # to terminate the process if we get an error since without
+                # this symlink, Second Life web media can't possibly work.
+                # Real Framework folder:
+                #   Second Life.app/Contents/Frameworks/Chromium Embedded Framework.framework/
+                # Location of symlink and why it'ds relavie 
+                #   Second Life.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework/
+                frameworkpath = os.path.join(os.pardir, os.pardir, os.pardir, os.pardir, "Frameworks", "Chromium Embedded Framework.framework")
+                try:
+                    symlinkf(frameworkpath, pluginframeworkpath)
+                except OSError as err:
+                    print "Can't symlink %s -> %s: %s" % (frameworkpath, pluginframeworkpath, err)
+                    raise
+
             self.end_prefix("Contents")
 
+        # fix up media_plugin.dylib so it knows where to look for CEF files it needs
+        self.run_command('install_name_tool -change "@executable_path/Chromium Embedded Framework" "@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "%(config)s/Second Life.app/Contents/Resources/llplugin/media_plugin_cef.dylib"' %
+                        { 'config' : self.args['configuration'] })
+
         # NOTE: the -S argument to strip causes it to keep enough info for
         # annotated backtraces (i.e. function names in the crash log).  'strip' with no
         # arguments yields a slightly smaller binary but makes crash logs mostly useless.
@@ -808,7 +885,6 @@ def path_optional(src, dst):
             self.run_command('strip -S %(viewer_binary)r' %
                              { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
 
-
     def copy_finish(self):
         # Force executable permissions to be set for scripts
         # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
@@ -985,7 +1061,7 @@ def construct(self):
         if self.prefix(src="", dst="bin"):
             self.path("secondlife-bin","do-not-directly-run-secondlife-bin")
             self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
-            self.path2basename(pkgdir, "SLPlugin")
+            self.path2basename("../llplugin/slplugin", "SLPlugin")
             self.path2basename("../viewer_components/updater/scripts/linux", "update_install")
             self.end_prefix("bin")
 
@@ -1005,9 +1081,8 @@ def construct(self):
             self.end_prefix(icon_path)
 
         # plugins
-        if self.prefix(src=os.path.join(pkgdir, "llplugin"), dst="bin/llplugin"):
-            self.path("libmedia_plugin_webkit.so")
-            self.path("libmedia_plugin_gstreamer.so")
+        if self.prefix(src="", dst="bin/llplugin"):
+            self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
             self.end_prefix("bin/llplugin")
 
         # llcommon
@@ -1147,37 +1222,6 @@ def construct(self):
                 self.path("libvivoxplatform.so")
                 self.end_prefix("lib")
 
-            # plugin runtime
-            if self.prefix(src=os.path.join(pkgdir, "lib"), dst="lib"):
-                self.path("libQtCore.so*")
-                self.path("libQtGui.so*")
-                self.path("libQtNetwork.so*")
-                self.path("libQtOpenGL.so*")
-                self.path("libQtSvg.so*")
-                self.path("libQtWebKit.so*")
-                self.path("libQtXml.so*")
-                self.end_prefix("lib")
-
-            # For WebKit/Qt plugin runtimes (image format plugins)
-            if self.prefix(src=os.path.join(pkgdir, "llplugin", "imageformats"),
-                           dst="bin/llplugin/imageformats"):
-                self.path("libqgif.so")
-                self.path("libqico.so")
-                self.path("libqjpeg.so")
-                self.path("libqmng.so")
-                self.path("libqsvg.so")
-                self.path("libqtiff.so")
-                self.end_prefix("bin/llplugin/imageformats")
-
-            # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
-            if self.prefix(src=os.path.join(pkgdir, "llplugin", "codecs"),
-                           dst="bin/llplugin/codecs"):
-                self.path("libqcncodecs.so")
-                self.path("libqjpcodecs.so")
-                self.path("libqkrcodecs.so")
-                self.path("libqtwcodecs.so")
-                self.end_prefix("bin/llplugin/codecs")
-
             self.strip_binaries()
 
 
diff --git a/indra/test_apps/llfbconnecttest/CMakeLists.txt b/indra/test_apps/llfbconnecttest/CMakeLists.txt
deleted file mode 100644
index 25aaebb783ce0931a7c933b3a3a18587f8bc40ea..0000000000000000000000000000000000000000
--- a/indra/test_apps/llfbconnecttest/CMakeLists.txt
+++ /dev/null
@@ -1,372 +0,0 @@
-# -*- cmake -*-
-project(llfbconnecttest)
-
-include(00-Common)
-include(FindOpenGL)
-include(LLCommon)
-include(LLPlugin)
-include(Linking)
-include(LLSharedLibs)
-include(PluginAPI)
-include(LLImage)
-include(LLMath)
-include(LLMessage)
-include(LLRender)
-include(LLWindow)
-include(Glut)
-include(Glui)
-
-include_directories(
-    ${LLPLUGIN_INCLUDE_DIRS}
-    ${LLCOMMON_INCLUDE_DIRS}
-    ${LLIMAGE_INCLUDE_DIRS}
-    ${LLMATH_INCLUDE_DIRS}
-    ${LLMESSAGE_INCLUDE_DIRS}
-    ${LLRENDER_INCLUDE_DIRS}
-    ${LLWINDOW_INCLUDE_DIRS}
-)
-
-if (DARWIN)
-    include(CMakeFindFrameworks)
-    find_library(COREFOUNDATION_LIBRARY CoreFoundation)
-endif (DARWIN)
-
-### llfbconnecttest
-
-set(llfbconnecttest_SOURCE_FILES
-    llfbconnecttest.cpp
-    llfbconnecttest.h
-    bookmarks.txt
-    )
-
-add_executable(llfbconnecttest
-    WIN32
-    MACOSX_BUNDLE
-    ${llfbconnecttest_SOURCE_FILES}
-)
-
-set_target_properties(llfbconnecttest
-    PROPERTIES
-    WIN32_EXECUTABLE
-    FALSE
-)
-
-target_link_libraries(llfbconnecttest
-  ${GLUT_LIBRARY}
-  ${GLUI_LIBRARY}
-  ${OPENGL_LIBRARIES}
-  ${LLPLUGIN_LIBRARIES}
-  ${LLMESSAGE_LIBRARIES}
-  ${LLCOMMON_LIBRARIES}
-  ${PLUGIN_API_WINDOWS_LIBRARIES}
-)
-
-if (DARWIN)
-  # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app.
-  target_link_libraries(llfbconnecttest
-    ${COREFOUNDATION_LIBRARY}
-  )
-endif (DARWIN)
-
-add_dependencies(llfbconnecttest
-  stage_third_party_libs
-  SLPlugin
-  media_plugin_webkit
-  ${LLPLUGIN_LIBRARIES}
-  ${LLMESSAGE_LIBRARIES}
-  ${LLCOMMON_LIBRARIES}
-)
-
-# turn off weird GLUI pragma 
-add_definitions(-DGLUI_NO_LIB_PRAGMA)
-
-if (DARWIN OR LINUX)
-  # glui.h contains code that triggers the "overloaded-virtual" warning in gcc.  
-  set_source_files_properties(llfbconnecttest.cpp PROPERTIES COMPILE_FLAGS "-Wno-overloaded-virtual")
-endif (DARWIN OR LINUX)
-
-# Gather build products of the various dependencies into the build directory for the testbed.
-
-if (DARWIN)
-  # path inside the app bundle where we'll need to copy plugins and other related files
-  set(PLUGINS_DESTINATION_DIR
-    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llfbconnecttest.app/Contents/Resources
-  )
-  
-  # create the Contents/Resources directory
-  add_custom_command(
-    TARGET llfbconnecttest POST_BUILD
-    COMMAND ${CMAKE_COMMAND}
-    ARGS
-      -E
-      make_directory
-      ${PLUGINS_DESTINATION_DIR}
-    COMMENT "Creating Resources directory in app bundle."
-  ) 
-else (DARWIN)
-  set(PLUGINS_DESTINATION_DIR
-    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
-  )
-endif (DARWIN)
-
-set(BUILT_SLPLUGIN $<TARGET_FILE:SLPlugin>)
-add_custom_command(TARGET llfbconnecttest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_SLPLUGIN}
-)
-
-set(BUILT_LLCOMMON $<TARGET_FILE:llcommon>)
-add_custom_command(TARGET llfbconnecttest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_LLCOMMON}
-)
-
-
-set(BUILT_WEBKIT_PLUGIN $<TARGET_FILE:media_plugin_webkit>)
-add_custom_command(TARGET llfbconnecttest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_WEBKIT_PLUGIN}
-)
-
-# copy over bookmarks file if llfbconnecttest gets built
-set(BUILT_LLFBCONNECTTEST $<TARGET_FILE:llfbconnecttest>)
-add_custom_command(TARGET llfbconnecttest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/
-  DEPENDS ${BUILT_LLFBCONNECTTEST}
-)
-
-# also copy it to the same place as SLPlugin, which is what the mac wants...
-add_custom_command(TARGET llfbconnecttest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_LLFBCONNECTTEST}
-)
-
-if(WINDOWS)
-  #********************
-  # Plugin test library deploy
-  #
-  # Debug config runtime files required for the FB connect test
-  set(fbconnecttest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
-  set(fbconnecttest_debug_files
-    libeay32.dll
-    libglib-2.0-0.dll
-    libgmodule-2.0-0.dll
-    libgobject-2.0-0.dll
-    libgthread-2.0-0.dll
-    qtcored4.dll
-    qtguid4.dll
-    qtnetworkd4.dll
-    qtopengld4.dll
-    qtwebkitd4.dll
-    ssleay32.dll
-    )
-  copy_if_different(
-    ${fbconnecttest_debug_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Debug"
-    out_targets
-    ${fbconnecttest_debug_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-  
-  # Debug config runtime files required for the FB connect test (Qt image format plugins)
-  set(fbconecttest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/imageformats")
-  set(fbconecttest_debug_files
-    qgifd4.dll
-    qicod4.dll
-    qjpegd4.dll
-    qmngd4.dll
-    qsvgd4.dll
-    qtiffd4.dll
-    )
-  copy_if_different(
-    ${fbconecttest_debug_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Debug/imageformats"
-    out_targets
-    ${fbconecttest_debug_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  # Debug config runtime files required for the FB connect test (Qt codec plugins)
-  set(fbconnecttest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/codecs")
-  set(fbconnecttest_debug_files
-    qcncodecsd4.dll
-    qjpcodecsd4.dll
-    qkrcodecsd4.dll
-    qtwcodecsd4.dll
-    )
-  copy_if_different(
-    ${fbconnecttest_debug_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Debug/codecs"
-    out_targets
-    ${fbconnecttest_debug_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
- 
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
-  set(fbconnecttest_release_files
-    libeay32.dll
-    libglib-2.0-0.dll
-    libgmodule-2.0-0.dll
-    libgobject-2.0-0.dll
-    libgthread-2.0-0.dll
-    qtcore4.dll
-    qtgui4.dll
-    qtnetwork4.dll
-    qtopengl4.dll
-    qtwebkit4.dll
-    qtxmlpatterns4.dll
-    ssleay32.dll
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Release"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt image format plugins)
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/imageformats")
-  set(fbconnecttest_release_files
-    qgif4.dll
-    qico4.dll
-    qjpeg4.dll
-    qmng4.dll
-    qsvg4.dll
-    qtiff4.dll
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Release/imageformats"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/imageformats"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt codec plugins)
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/codecs")
-  set(fbconnecttest_release_files
-    qcncodecs4.dll  
-    qjpcodecs4.dll  
-    qkrcodecs4.dll  
-    qtwcodecs4.dll  
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Release/codecs"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/codecs"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
- 
-   add_custom_target(copy_fbconnecttest_libs ALL
-     DEPENDS 
-     ${fbconnect_test_targets}
-     )
-
-  add_dependencies(llfbconnecttest copy_fbconnecttest_libs)
-
-endif(WINDOWS)
-
-if (DARWIN)
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
-  set(fbconnecttest_release_files
-    libexception_handler.dylib
-    libaprutil-1.0.dylib
-    libapr-1.0.dylib
-    libexpat.1.5.2.dylib
-    libQtCore.4.7.1.dylib
-    libQtCore.4.dylib
-    libQtGui.4.7.1.dylib
-    libQtGui.4.dylib
-    libQtNetwork.4.7.1.dylib
-    libQtNetwork.4.dylib
-    libQtOpenGL.4.7.1.dylib
-    libQtOpenGL.4.dylib
-    libQtWebKit.4.7.1.dylib
-    libQtWebKit.4.dylib
-    libQtSvg.4.7.1.dylib
-    libQtSvg.4.dylib
-    libQtXml.4.7.1.dylib
-    libQtXml.4.dylib
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${PLUGINS_DESTINATION_DIR}"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt image format plugins)
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_PLUGINS}/imageformats")
-  set(fbconnecttest_release_files
-    libqgif.dylib
-    libqico.dylib
-    libqjpeg.dylib
-    libqmng.dylib
-    libqsvg.dylib
-    libqtiff.dylib
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${PLUGINS_DESTINATION_DIR}/imageformats"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt codec plugins)
-  set(fbconnecttest_release_src_dir "${ARCH_PREBUILT_DIRS_PLUGINS}/codecs")
-  set(fbconnecttest_release_files
-    libqcncodecs.dylib
-    libqjpcodecs.dylib
-    libqkrcodecs.dylib
-    libqtwcodecs.dylib
-    )
-  copy_if_different(
-    ${fbconnecttest_release_src_dir}
-    "${PLUGINS_DESTINATION_DIR}/codecs"
-    out_targets
-    ${fbconnecttest_release_files}
-    )
-  set(fbconnect_test_targets ${fbconnect_test_targets} ${out_targets})
-
-  add_custom_target(copy_fbconnecttest_libs ALL
-    DEPENDS 
-    ${fbconnect_test_targets}
-    )
-
-  add_dependencies(llfbconnecttest copy_fbconnecttest_libs)
-endif (DARWIN)
-
-if (LINUX)
-
-endif (LINUX)
-
-ll_deploy_sharedlibs_command(llfbconnecttest) 
diff --git a/indra/test_apps/llfbconnecttest/README.Linden b/indra/test_apps/llfbconnecttest/README.Linden
deleted file mode 100644
index 7488ce680a33fe349cf559c97e2ed357ded0909a..0000000000000000000000000000000000000000
--- a/indra/test_apps/llfbconnecttest/README.Linden
+++ /dev/null
@@ -1,20 +0,0 @@
-
-1.  Description
-
-    Exercises SLPlugin.  Specific functions and goals aren't clear
-    from the source.
-
-2.  Running
-
-  2.1  Mac
-
-    Make certain '.' is included in PATH.  E.g.:
-
-       PATH=.:"$PATH" open build-darwin-i386/test_apps/llfbconnecttest/RelWithDebInfo/llfbconnecttest.app
-
-    Otherwise the program won't find SLPlugin and will timeout and
-    fail after 30 seconds and give you little information as to why.
-
-    Running 'dtruss' on plugin test applications will give you a great
-    deal of insight into why they aren't activating.
-
diff --git a/indra/test_apps/llfbconnecttest/bookmarks.txt b/indra/test_apps/llfbconnecttest/bookmarks.txt
deleted file mode 100644
index 3995627ea9e1caa6d759272d14466231f83a1f1b..0000000000000000000000000000000000000000
--- a/indra/test_apps/llfbconnecttest/bookmarks.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# format is description, url (don't put ',' chars in description :)
-# if no ',' found, whole line is used for both description and url
-Google Home Page,http://www.google.com
-Facebook Home Page,http://www.facebook.com
diff --git a/indra/test_apps/llfbconnecttest/llfbconnecttest.cpp b/indra/test_apps/llfbconnecttest/llfbconnecttest.cpp
deleted file mode 100644
index 483a15c468b9dac99a282e247abd47d151dd626d..0000000000000000000000000000000000000000
--- a/indra/test_apps/llfbconnecttest/llfbconnecttest.cpp
+++ /dev/null
@@ -1,2394 +0,0 @@
-/**
- * @file LLFBConnectTest.cpp
- * @brief Facebook Connect Test App
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "indra_constants.h"
-
-#include "llapr.h"
-#include "llerrorcontrol.h"
-
-#include <math.h>
-#include <iomanip>
-#include <sstream>
-#include <ctime>
-
-#include "llfbconnecttest.h"
-
-#if __APPLE__
-	#include <GLUT/glut.h>
-	#include <CoreFoundation/CoreFoundation.h>
-#else
-	#define FREEGLUT_STATIC
-	#include "GL/freeglut.h"
-	#define GLUI_FREEGLUT
-#endif
-
-#if LL_WINDOWS
-#pragma warning(disable: 4263)
-#pragma warning(disable: 4264)
-#endif
-#include "glui.h"
-
-
-LLFBConnectTest* gApplication = 0;
-static void gluiCallbackWrapper( int control_id );
-
-////////////////////////////////////////////////////////////////////////////////
-//
-static bool isTexture( GLuint texture )
-{
-	bool result = false;
-
-	// glIsTexture will sometimes return false for real textures... do this instead.
-	if(texture != 0)
-		result = true;
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel::mediaPanel()
-{
-	mMediaTextureHandle = 0;
-	mPickTextureHandle = 0;
-	mMediaSource = NULL;
-	mPickTexturePixels = NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel::~mediaPanel()
-{
-	// delete OpenGL texture handles
-	if ( isTexture( mPickTextureHandle ) )
-	{
-		std::cerr << "remMediaPanel: deleting pick texture " << mPickTextureHandle << std::endl;
-		glDeleteTextures( 1, &mPickTextureHandle );
-		mPickTextureHandle = 0;
-	}
-
-	if ( isTexture( mMediaTextureHandle ) )
-	{
-		std::cerr << "remMediaPanel: deleting media texture " << mMediaTextureHandle << std::endl;
-		glDeleteTextures( 1, &mMediaTextureHandle );
-		mMediaTextureHandle = 0;
-	}
-
-	if(mPickTexturePixels)
-	{
-		delete mPickTexturePixels;
-	}
-
-	if(mMediaSource)
-	{
-		delete mMediaSource;
-	}
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLFBConnectTest::LLFBConnectTest( int app_window, int window_width, int window_height ) :
-	mVersionMajor( 2 ),
-	mVersionMinor( 0 ),
-	mVersionPatch( 0 ),
-	mMaxPanels( 25 ),
-	mViewportAspect( 0 ),
-	mAppWindow( app_window ),
-	mCurMouseX( 0 ),
-	mCurMouseY( 0 ),
-	mFuzzyMedia( true ),
-	mSelectedPanel( 0 ),
-	mDistanceCameraToSelectedGeometry( 0.0f ),
-	//mMediaBrowserControlEnableCookies( 0 ),
-	mMediaBrowserControlBackButton( 0 ),
-	mMediaBrowserControlForwardButton( 0 ),
-	//mMediaTimeControlVolume( 100 ),
-	//mMediaTimeControlSeekSeconds( 0 ),
-	//mGluiMediaTimeControlWindowFlag( true ),
-	mGluiMediaBrowserControlWindowFlag( true ),
-	mMediaBrowserControlBackButtonFlag( true ),
-	mMediaBrowserControlForwardButtonFlag( true ),
-	mHomeWebUrl( "https://cryptic-ridge-1632.herokuapp.com/" )
-{
-	// debugging spam
-	std::cout << std::endl << "             GLUT version: " << "3.7.6" << std::endl;	// no way to get real version from GLUT
-	std::cout << std::endl << "             GLUI version: " << GLUI_Master.get_version() << std::endl;
-	std::cout << std::endl << "Media Plugin Test version: " << mVersionMajor << "." << mVersionMinor << "." << mVersionPatch << std::endl;
-
-	// bookmark title
-	mBookmarks.push_back( std::pair< std::string, std::string >( "--- Bookmarks ---", "" ) );
-
-	// insert hardcoded URLs here as required for testing
-	//mBookmarks.push_back( std::pair< std::string, std::string >( "description", "url" ) );
-
-	// read bookmarks from file.
-	// note: uses command in ./CmakeLists.txt which copies bookmmarks file from source directory
-	//       to app directory (WITHOUT build configuration dir) (this is cwd in Windows within MSVC)
-	//		 For example, test_apps\llplugintest and not test_apps\llplugintest\Release
-	//		 This may need to be changed for Mac/Linux builds.
-	// See https://jira.lindenlab.com/browse/DEV-31350 for large list of media URLs from AGNI
-	const std::string bookmarks_filename( "bookmarks.txt" );
-	std::ifstream file_handle( bookmarks_filename.c_str() );
-	if ( file_handle.is_open() )
-	{
-		std::cout << "Reading bookmarks for test" << std::endl;
-		while( ! file_handle.eof() )
-		{
-			std::string line;
-			std::getline( file_handle, line );
-			if ( file_handle.eof() )
-				break;
-
-			if ( line.substr( 0, 1 ) != "#" )
-			{
-				size_t comma_pos = line.find_first_of( ',' );
-				if ( comma_pos != std::string::npos )
-				{
-					std::string description = line.substr( 0, comma_pos );
-					std::string url = line.substr( comma_pos + 1 );
-					mBookmarks.push_back( std::pair< std::string, std::string >( description, url ) );
-				}
-				else
-				{
-					mBookmarks.push_back( std::pair< std::string, std::string >( line, line ) );
-				};
-			};
-		};
-		std::cout << "Read " << mBookmarks.size() << " bookmarks" << std::endl;
-	}
-	else
-	{
-		std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;
-	};
-
-	// initialize linden lab APR module
-	ll_init_apr();
-
-	// Set up llerror logging
-	{
-		LLError::initForApplication(".");
-		LLError::setDefaultLevel(LLError::LEVEL_INFO);
-		//LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG);
-	}
-
-	// lots of randomness in this app
-	srand( ( unsigned int )time( 0 ) );
-
-	// build GUI
-	makeChrome();
-
-	// OpenGL initialilzation
-	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
-	glClearDepth( 1.0f );
-	glEnable( GL_DEPTH_TEST );
-	glEnable( GL_COLOR_MATERIAL );
-	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
-	glDepthFunc( GL_LEQUAL );
-	glEnable( GL_TEXTURE_2D );
-	glDisable( GL_BLEND );
-	glColor3f( 1.0f, 1.0f, 1.0f );
-	glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
-	glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
-
-	// start with a sane view
-	resetView();
-
-	// initial media panel
-	const int num_initial_panels = 1;
-	for( int i = 0; i < num_initial_panels; ++i )
-	{
-		//addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-		addMediaPanel( mHomeWebUrl );
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLFBConnectTest::~LLFBConnectTest()
-{
-	// delete all media panels
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		remMediaPanel( mMediaPanels[ i ] );
-	};
-	
-	// Stop the plugin read thread if it's running.
-	LLPluginProcessParent::setUseReadThread(false);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::reshape( int width, int height )
-{
-	// update viewport (the active window inside the chrome)
-	int viewport_x, viewport_y;
-	int viewport_height, viewport_width;
-	GLUI_Master.get_viewport_area( &viewport_x, &viewport_y, &viewport_width, &viewport_height );
-	mViewportAspect = (float)( viewport_width ) / (float)( viewport_height );
-	glViewport( viewport_x, viewport_y, viewport_width, viewport_height );
-
-	// save these as we'll need them later
-	mWindowWidth = width;
-	mWindowHeight = height;
-
-	// adjust size of URL bar so it doesn't get clipped
-	mUrlEdit->set_w( mWindowWidth - 360 );
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// trigger re-display
-	glutPostRedisplay();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::bindTexture(GLuint texture, GLint row_length, GLint alignment)
-{
-	glEnable( GL_TEXTURE_2D );
-
-	glBindTexture( GL_TEXTURE_2D, texture );
-	glPixelStorei( GL_UNPACK_ROW_LENGTH, row_length );
-	glPixelStorei( GL_UNPACK_ALIGNMENT, alignment );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool LLFBConnectTest::checkGLError(const char *name)
-{
-	bool result = false;
-	GLenum error = glGetError();
-
-	if(error != GL_NO_ERROR)
-	{
-		// For some reason, glGenTextures is returning GL_INVALID_VALUE...
-		std::cout << name << " ERROR 0x" << std::hex << error << std::dec << std::endl;
-		result = true;
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-GLfloat LLFBConnectTest::distanceToCamera( GLfloat point_x, GLfloat point_y, GLfloat point_z )
-{
-	GLdouble camera_pos_x = 0.0f;
-	GLdouble camera_pos_y = 0.0f;
-	GLdouble camera_pos_z = 0.0f;
-
-	GLdouble modelMatrix[16];
-	GLdouble projMatrix[16];
-	GLint viewport[4];
-
-	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
-	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
-	glGetIntegerv(GL_VIEWPORT, viewport);
-
-	gluUnProject(
-		(viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2,
-		0.0,
-		modelMatrix, projMatrix, viewport,
-		&camera_pos_x, &camera_pos_y, &camera_pos_z );
-
-	GLfloat distance =
-		sqrt( ( camera_pos_x - point_x ) * ( camera_pos_x - point_x ) +
-			  ( camera_pos_y - point_y ) * ( camera_pos_y - point_y ) +
-			  ( camera_pos_z - point_z ) * ( camera_pos_z - point_z ) );
-
-	return distance;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::drawGeometry( int panel, bool selected )
-{
-	// texture coordinates for each panel
-	GLfloat non_opengl_texture_coords[ 8 ] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
-	GLfloat opengl_texture_coords[ 8 ] =     { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
-
-	GLfloat *texture_coords = mMediaPanels[ panel ]->mAppTextureCoordsOpenGL?opengl_texture_coords:non_opengl_texture_coords;
-
-	// base coordinates for each panel
-	GLfloat base_vertex_pos[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
-
-	// calculate posiitons
-	const int num_panels = (int)mMediaPanels.size();
-	const int num_rows = (int)sqrt( (float)num_panels );
-	const int num_cols = num_panels / num_rows;
-	const int panel_x = ( panel / num_rows );
-	const int panel_y = ( panel % num_rows );
-
-	// default spacing is small - make it larger if checkbox set - for testing positional audio
-	float spacing = 0.1f;
-	//if ( mLargePanelSpacing )
-	//	spacing = 2.0f;
-
-	const GLfloat offset_x = num_cols * ( 1.0 + spacing ) / 2;
-	const GLfloat offset_y = num_rows * ( 1.0 + spacing ) / 2;
-
-	// Adjust for media aspect ratios
-	{
-		float aspect = 1.0f;
-
-		if(mMediaPanels[ panel ]->mMediaHeight != 0)
-		{
-			aspect = (float)mMediaPanels[ panel ]->mMediaWidth / (float)mMediaPanels[ panel ]->mMediaHeight;
-		}
-
-		if(aspect > 1.0f)
-		{
-			// media is wider than it is high -- adjust the top and bottom in
-			for( int corner = 0; corner < 4; ++corner )
-			{
-				float temp = base_vertex_pos[corner * 2 + 1];
-
-				if(temp < 0.5f)
-					temp += 0.5 - (0.5f / aspect);
-				else
-					temp -= 0.5 - (0.5f / aspect);
-
-				base_vertex_pos[corner * 2 + 1] = temp;
-			}
-		}
-		else if(aspect < 1.0f)
-		{
-			// media is higher than it is wide -- adjust the left and right sides in
-			for( int corner = 0; corner < 4; ++corner )
-			{
-				float temp = base_vertex_pos[corner * 2];
-
-				if(temp < 0.5f)
-					temp += 0.5f - (0.5f * aspect);
-				else
-					temp -= 0.5f - (0.5f * aspect);
-
-				base_vertex_pos[corner * 2] = temp;
-			}
-		}
-	}
-
-	glBegin( GL_QUADS );
-	for( int corner = 0; corner < 4; ++corner )
-	{
-		glTexCoord2f( texture_coords[ corner * 2 ], texture_coords[ corner * 2 + 1 ] );
-		GLfloat x = base_vertex_pos[ corner * 2 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
-		GLfloat y = base_vertex_pos[ corner * 2 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
-
-		glVertex3f( x, y, 0.0f );
-	};
-	glEnd();
-
-	// calculate distance to this panel if it's selected
-	if ( selected )
-	{
-		GLfloat point_x = base_vertex_pos[ 0 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
-		GLfloat point_y = base_vertex_pos[ 0 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
-		GLfloat point_z = 0.0f;
-		mDistanceCameraToSelectedGeometry = distanceToCamera( point_x, point_y, point_z );
-	};
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::startPanelHighlight( float red, float green, float blue, float line_width )
-{
-	glPushAttrib( GL_ALL_ATTRIB_BITS );
-	glEnable( GL_POLYGON_OFFSET_FILL );
-	glPolygonOffset( -2.5f, -2.5f );
-	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
-	glLineWidth( line_width );
-	glColor3f( red, green, blue );
-	glDisable( GL_TEXTURE_2D );
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::endPanelHighlight()
-{
-	glPopAttrib();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::draw( int draw_type )
-{
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		// drawing pick texture
-		if ( draw_type == DrawTypePickTexture )
-		{
-			// only bother with pick if we have something to render
-			// Actually, we need to pick even if we're not ready to render.
-			// Otherwise you can't select and remove a panel which has gone bad.
-			//if ( mMediaPanels[ panel ]->mReadyToRender )
-			{
-				glMatrixMode( GL_TEXTURE );
-				glPushMatrix();
-
-				// pick texture is a power of 2 so no need to scale
-				glLoadIdentity();
-
-				// bind to media texture
-				glLoadIdentity();
-				bindTexture( mMediaPanels[ panel ]->mPickTextureHandle );
-				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-
-				// draw geometry using pick texture
-				drawGeometry( panel, false );
-
-				glMatrixMode( GL_TEXTURE );
-				glPopMatrix();
-			};
-		}
-		else
-		if ( draw_type == DrawTypeMediaTexture )
-		{
-			bool texture_valid = false;
-			bool plugin_exited = false;
-
-			if(mMediaPanels[ panel ]->mMediaSource)
-			{
-				texture_valid = mMediaPanels[ panel ]->mMediaSource->textureValid();
-				plugin_exited = mMediaPanels[ panel ]->mMediaSource->isPluginExited();
-			}
-
-			// save texture matrix (changes for each panel)
-			glMatrixMode( GL_TEXTURE );
-			glPushMatrix();
-
-			// only process texture if the media is ready to draw
-			// (we still want to draw the geometry)
-			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
-			{
-				// bind to media texture
-				bindTexture( mMediaPanels[ panel ]->mMediaTextureHandle );
-
-				if ( mFuzzyMedia )
-				{
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-				}
-				else
-				{
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-				}
-
-				// scale to fit panel
-				glScalef( mMediaPanels[ panel ]->mTextureScaleX,
-							mMediaPanels[ panel ]->mTextureScaleY,
-								1.0f );
-			};
-
-			float intensity = plugin_exited?0.25f:1.0f;
-
-			// highlight the selected panel
-			if ( mSelectedPanel && ( mMediaPanels[ panel ]->mId == mSelectedPanel->mId ) )
-			{
-				startPanelHighlight( intensity, intensity, 0.0f, 5.0f );
-				drawGeometry( panel, true );
-				endPanelHighlight();
-			}
-			else
-			// this panel not able to render yet since it
-			// doesn't have enough information
-			if ( !mMediaPanels[ panel ]->mReadyToRender )
-			{
-				startPanelHighlight( intensity, 0.0f, 0.0f, 2.0f );
-				drawGeometry( panel, false );
-				endPanelHighlight();
-			}
-			else
-			// just display a border around the media
-			{
-				startPanelHighlight( 0.0f, intensity, 0.0f, 2.0f );
-				drawGeometry( panel, false );
-				endPanelHighlight();
-			};
-
-			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
-			{
-				// draw visual geometry
-				drawGeometry( panel, false );
-			}
-
-			// restore texture matrix (changes for each panel)
-			glMatrixMode( GL_TEXTURE );
-			glPopMatrix();
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::display()
-{
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// start with a clean slate
-	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
-	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-	// set up OpenGL view
-	glMatrixMode( GL_PROJECTION );
-	glLoadIdentity();
-	glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f );
-	glMatrixMode( GL_MODELVIEW );
-	glLoadIdentity();
-	glTranslatef( 0.0, 0.0, 0.0f );
-	glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] );
-	glMultMatrixf( mViewRotation );
-
-	// draw pick texture
-	draw( DrawTypePickTexture );
-
-	// read colors and get coordinate values
-	glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelReadColor );
-
-	// clear the pick render (otherwise it may depth-fight with the textures rendered later)
-	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-	// draw visible geometry
-	draw( DrawTypeMediaTexture );
-
-	glutSwapBuffers();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::idle()
-{
-//	checkGLError("LLFBConnectTest::idle");
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// random creation/destruction of panels enabled?
-/*
-	const time_t panel_timeout_time = 5;
-	if ( mRandomPanelCount )
-	{
-		// time for a change
-		static time_t last_panel_time = 0;
-		if ( time( NULL ) - last_panel_time > panel_timeout_time )
-		{
-			if ( rand() % 2 == 0 )
-			{
-				if ( mMediaPanels.size() < 16 )
-				{
-					std::cout << "Randomly adding new panel" << std::endl;
-					addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-				};
-			}
-			else
-			{
-				if ( mMediaPanels.size() > 0 )
-				{
-					std::cout << "Deleting selected panel" << std::endl;
-					remMediaPanel( mSelectedPanel );
-				};
-			};
-			time( &last_panel_time );
-		};
-	};
-
-	// random selection of bookmarks enabled?
-	const time_t bookmark_timeout_time = 5;
-	if ( mRandomBookmarks )
-	{
-		// time for a change
-		static time_t last_bookmark_time = 0;
-		if ( time( NULL ) - last_bookmark_time > bookmark_timeout_time )
-		{
-			// go to a different random bookmark on each panel
-			for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-			{
-				std::string uri = mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second;
-
-				std::cout << "Random: navigating to : " << uri << std::endl;
-
-				std::string mime_type = mimeTypeFromUrl( uri );
-
-				if ( mime_type != mMediaPanels[ panel ]->mMimeType )
-				{
-					replaceMediaPanel( mMediaPanels[ panel ], uri );
-				}
-				else
-				{
-					mMediaPanels[ panel ]->mMediaSource->loadURI( uri );
-					mMediaPanels[ panel ]->mMediaSource->start();
-				};
-			};
-
-			time( &last_bookmark_time );
-		};
-	};
-*/
-	// update UI
-	if ( mSelectedPanel )
-	{
-		// set volume based on slider if we have time media
-		//if ( mGluiMediaTimeControlWindowFlag )
-		//{
-		//	mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
-		//};
-
-		// NOTE: it is absurd that we need cache the state of GLUI controls
-		//       but enabling/disabling controls drags framerate from 500+
-		//		 down to 15. Not a problem for plugin system - only this test
-		// enable/disable time based UI controls based on type of plugin
-		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-		{
-			/*
-			if ( ! mGluiMediaTimeControlWindowFlag )
-			{
-				mGluiMediaTimeControlWindow->enable();
-				mGluiMediaTimeControlWindowFlag = true;
-			};
-			*/
-		}
-		else
-		{
-			/*
-			if ( mGluiMediaTimeControlWindowFlag )
-			{
-				mGluiMediaTimeControlWindow->disable();
-				mGluiMediaTimeControlWindowFlag = false;
-			};
-			*/
-		};
-
-		// enable/disable browser based UI controls based on type of plugin
-		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
-		{
-			if ( ! mGluiMediaBrowserControlWindowFlag )
-			{
-				mGluiMediaBrowserControlWindow->enable();
-				mGluiMediaBrowserControlWindowFlag = true;
-			};
-		}
-		else
-		{
-			if ( mGluiMediaBrowserControlWindowFlag )
-			{
-				mGluiMediaBrowserControlWindow->disable();
-				mGluiMediaBrowserControlWindowFlag = false;
-			};
-		};
-
-		// enable/disable browser back button depending on browser history
-		if ( mSelectedPanel->mMediaSource->getHistoryBackAvailable()  )
-		{
-			if ( ! mMediaBrowserControlBackButtonFlag )
-			{
-				mMediaBrowserControlBackButton->enable();
-				mMediaBrowserControlBackButtonFlag = true;
-			};
-		}
-		else
-		{
-			if ( mMediaBrowserControlBackButtonFlag )
-			{
-				mMediaBrowserControlBackButton->disable();
-				mMediaBrowserControlBackButtonFlag = false;
-			};
-		};
-
-		// enable/disable browser forward button depending on browser history
-		if ( mSelectedPanel->mMediaSource->getHistoryForwardAvailable()  )
-		{
-			if ( ! mMediaBrowserControlForwardButtonFlag )
-			{
-				mMediaBrowserControlForwardButton->enable();
-				mMediaBrowserControlForwardButtonFlag = true;
-			};
-		}
-		else
-		{
-			if ( mMediaBrowserControlForwardButtonFlag )
-			{
-				mMediaBrowserControlForwardButton->disable();
-				mMediaBrowserControlForwardButtonFlag = false;
-			};
-		};
-
-		// NOTE: This is *very* slow and not worth optimising
-		updateStatusBar();
-	};
-
-	// update all the panels
-	for( int panel_index = 0; panel_index < (int)mMediaPanels.size(); ++panel_index )
-	{
-		mediaPanel *panel = mMediaPanels[ panel_index ];
-
-		// call plugins idle function so it can potentially update itself
-		panel->mMediaSource->idle();
-
-		// update each media panel
-		updateMediaPanel( panel );
-
-		LLRect dirty_rect;
-		if ( ! panel->mMediaSource->textureValid() )
-		{
-			//std::cout << "texture invalid, skipping update..." << std::endl;
-		}
-		else
-		if ( panel &&
-			 ( panel->mMediaWidth != panel->mMediaSource->getWidth() ||
-			   panel->mMediaHeight != panel->mMediaSource->getHeight() ) )
-		{
-			//std::cout << "Resize in progress, skipping update..." << std::endl;
-		}
-		else
-		if ( panel->mMediaSource->getDirty( &dirty_rect ) )
-		{
-			const unsigned char* pixels = panel->mMediaSource->getBitsData();
-			if ( pixels && isTexture(panel->mMediaTextureHandle))
-			{
-				int x_offset = dirty_rect.mLeft;
-				int y_offset = dirty_rect.mBottom;
-				int width = dirty_rect.mRight - dirty_rect.mLeft;
-				int height = dirty_rect.mTop - dirty_rect.mBottom;
-
-				if((dirty_rect.mRight <= panel->mTextureWidth) && (dirty_rect.mTop <= panel->mTextureHeight))
-				{
-					// Offset the pixels pointer properly
-					pixels += ( y_offset * panel->mMediaSource->getTextureDepth() * panel->mMediaSource->getBitsWidth() );
-					pixels += ( x_offset * panel->mMediaSource->getTextureDepth() );
-
-					// set up texture
-					bindTexture( panel->mMediaTextureHandle, panel->mMediaSource->getBitsWidth() );
-					if ( mFuzzyMedia )
-					{
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-					}
-					else
-					{
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-					};
-
-					checkGLError("glTexParameteri");
-
-					if(panel->mMediaSource->getTextureFormatSwapBytes())
-					{
-						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-						checkGLError("glPixelStorei");
-					}
-
-					// draw portion that changes into texture
-					glTexSubImage2D( GL_TEXTURE_2D, 0,
-						x_offset,
-						y_offset,
-						width,
-						height,
-						panel->mMediaSource->getTextureFormatPrimary(),
-						panel->mMediaSource->getTextureFormatType(),
-						pixels );
-
-					if(checkGLError("glTexSubImage2D"))
-					{
-						std::cerr << "    panel ID=" << panel->mId << std::endl;
-						std::cerr << "    texture size = " << panel->mTextureWidth << " x " << panel->mTextureHeight << std::endl;
-						std::cerr << "    media size = " << panel->mMediaWidth << " x " << panel->mMediaHeight << std::endl;
-						std::cerr << "    dirty rect = " << dirty_rect.mLeft << ", " << dirty_rect.mBottom << ", " << dirty_rect.mRight << ", " << dirty_rect.mTop << std::endl;
-						std::cerr << "    texture width = " << panel->mMediaSource->getBitsWidth() << std::endl;
-						std::cerr << "    format primary = 0x" << std::hex << panel->mMediaSource->getTextureFormatPrimary() << std::dec << std::endl;
-						std::cerr << "    format type = 0x" << std::hex << panel->mMediaSource->getTextureFormatType() << std::dec << std::endl;
-						std::cerr << "    pixels = " << (void*)pixels << std::endl;
-					}
-
-					if(panel->mMediaSource->getTextureFormatSwapBytes())
-					{
-						glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-						checkGLError("glPixelStorei");
-					}
-
-					panel->mMediaSource->resetDirty();
-
-					panel->mReadyToRender = true;
-				}
-				else
-				{
-					std::cerr << "dirty rect is outside current media size, skipping update" << std::endl;
-				}
-			};
-		};
-	};
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// trigger re-display
-	glutPostRedisplay();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::windowPosToTexturePos( int window_x, int window_y,
-											   int& media_x, int& media_y,
-											   int& id )
-{
-	if ( ! mSelectedPanel )
-	{
-		media_x = 0;
-		media_y = 0;
-		id = 0;
-		return;
-	};
-
-	// record cursor poisiton for a readback next frame
-	mCurMouseX = window_x;
-	// OpenGL app == coordinate system this way
-	// NOTE: unrelated to settings in plugin - this
-	// is just for this app
-	mCurMouseY = mWindowHeight - window_y;
-
-	// extract x (0..1023, y (0..1023) and id (0..15) from RGB components
-	unsigned long pixel_read_color_bits = ( mPixelReadColor[ 0 ] << 16 ) | ( mPixelReadColor[ 1 ] << 8 ) | mPixelReadColor[ 2 ];
-	int texture_x = pixel_read_color_bits & 0x3ff;
-	int texture_y = ( pixel_read_color_bits >> 10 ) & 0x3ff;
-	id = ( pixel_read_color_bits >> 20 ) & 0x0f;
-
-	// scale to size of media (1024 because we use 10 bits for X and Y from 24)
-	media_x = (int)( ( (float)mSelectedPanel->mMediaWidth * (float)texture_x ) / 1024.0f );
-	media_y = (int)( ( (float)mSelectedPanel->mMediaHeight * (float)texture_y ) / 1024.0f );
-
-	// we assume the plugin uses an inverted coordinate scheme like OpenGL
-	// if not, the plugin code inverts the Y coordinate for us - we don't need to
-	media_y = mSelectedPanel->mMediaHeight - media_y;
-
-	if ( media_x > 0 && media_y > 0 )
-	{
-		//std::cout << "      mouse coords: " << mCurMouseX << " x " << mCurMouseY << " and id = " << id  << std::endl;
-		//std::cout << "raw texture coords: " << texture_x << " x " << texture_y << " and id = " << id  << std::endl;
-		//std::cout << "      media coords: " << media_x << " x " << media_y << " and id = " << id  << std::endl;
-		//std::cout << std::endl;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::selectPanelById( int id )
-{
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mId == id )
-		{
-			selectPanel(mMediaPanels[ panel ]);
-			return;
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::selectPanel( mediaPanel* panel )
-{
-	if( mSelectedPanel == panel )
-		return;
-
-	// turn off volume before we delete it
-	if( mSelectedPanel && mSelectedPanel->mMediaSource )
-	{
-		mSelectedPanel->mMediaSource->setVolume( 0.0f );
-		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_LOW );
-	};
-
-	mSelectedPanel = panel;
-
-	if( mSelectedPanel && mSelectedPanel->mMediaSource )
-	{
-		//mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
-		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_NORMAL );
-
-		if(!mSelectedPanel->mStartUrl.empty())
-		{
-			mUrlEdit->set_text(const_cast<char*>(mSelectedPanel->mStartUrl.c_str()) );
-		}
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel*  LLFBConnectTest::findMediaPanel( LLPluginClassMedia* source )
-{
-	mediaPanel *result = NULL;
-
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mMediaSource == source )
-		{
-			result = mMediaPanels[ panel ];
-		}
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLFBConnectTest::findMediaPanel( const std::string &target_name )
-{
-	mediaPanel *result = NULL;
-
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mTarget == target_name )
-		{
-			result = mMediaPanels[ panel ];
-		}
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::navigateToNewURI( std::string uri )
-{
-	if ( uri.length() )
-	{
-		std::string mime_type = mimeTypeFromUrl( uri );
-
-		if ( !mSelectedPanel->mMediaSource->isPluginExited() && (mime_type == mSelectedPanel->mMimeType) )
-		{
-			std::cout << "MIME type is the same" << std::endl;
-			mSelectedPanel->mMediaSource->loadURI( uri );
-			mSelectedPanel->mMediaSource->start();
-			mBookmarkList->do_selection( 0 );
-		}
-		else
-		{
-			std::cout << "MIME type changed or plugin had exited" << std::endl;
-			replaceMediaPanel( mSelectedPanel, uri );
-			mBookmarkList->do_selection( 0 );
-		}
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::initUrlHistory( std::string uris )
-{
-	if ( uris.length() > 0 )
-	{
-		std::cout << "init URL : " << uris << std::endl;
-		LLSD historySD;
-
-		char *cstr, *p;
-		cstr = new char[uris.size()+1];
-		strcpy(cstr, uris.c_str());
-		const char *DELIMS = " ,;";
-		p = strtok(cstr, DELIMS);
-		while (p != NULL) {
-			historySD.insert(0, p);
-			p = strtok(NULL, DELIMS);
-		}
-		mSelectedPanel->mMediaSource->initializeUrlHistory(historySD);
-		delete[] cstr;
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::gluiCallback( int control_id )
-{
-	if ( control_id == mIdBookmarks )
-	{
-		std::string uri = mBookmarks[ mSelBookmark ].second;
-
-		navigateToNewURI( uri );
-	}
-	else
-    if ( control_id == mIdUrlEdit)
-	{
-		std::string uri = mUrlEdit->get_text();
-
-		navigateToNewURI( uri );
-	}
-/*
-	else
-	if ( control_id == mIdUrlInitHistoryEdit )
-	{
-		std::string uri = mUrlInitHistoryEdit->get_text();
-
-		initUrlHistory( uri );
-	}
-	else
-	if ( control_id == mIdControlAddPanel )
-	{
-		addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-	}
-	else
-	if ( control_id == mIdControlRemPanel )
-	{
-		remMediaPanel( mSelectedPanel );
-	}
-	else
-	if ( control_id == mIdDisableTimeout )
-	{
-		// Set the "disable timeout" flag for all active plugins.
-		for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-		{
-			mMediaPanels[ i ]->mMediaSource->setDisableTimeout(mDisableTimeout);
-		}
-	}
-	else
-	if ( control_id == mIdUsePluginReadThread )
-	{
-		LLPluginProcessParent::setUseReadThread(mUsePluginReadThread);
-	}
-	else
-	if ( control_id == mIdControlCrashPlugin )
-	{
-		// send message to plugin and ask it to crash
-		// (switch out for ReleaseCandidate version :) )
-		if(mSelectedPanel && mSelectedPanel->mMediaSource)
-		{
-			mSelectedPanel->mMediaSource->crashPlugin();
-		}
-	}
-	else
-	if ( control_id == mIdControlHangPlugin )
-	{
-		// send message to plugin and ask it to hang
-		// (switch out for ReleaseCandidate version :) )
-		if(mSelectedPanel && mSelectedPanel->mMediaSource)
-		{
-			mSelectedPanel->mMediaSource->hangPlugin();
-		}
-	}
-	else
-*/
-	if ( control_id == mIdControlExitApp )
-	{
-		// text for exiting plugin system cleanly
-		delete this;	// clean up
-		exit( 0 );
-	}
-/*
-	else
-	if ( control_id == mIdMediaTimeControlPlay )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlLoop )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( true );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlPause )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->pause();
-	}
-	else
-	if ( control_id == mIdMediaTimeControlStop )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->stop();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlSeek )
-	{
-		if ( mSelectedPanel )
-		{
-			// get value from spinner
-			float seconds_to_seek = mMediaTimeControlSeekSeconds;
-			mSelectedPanel->mMediaSource->seek( seconds_to_seek );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlRewind )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start(-2.0f);
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlFastForward )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start(2.0f);
-		};
-	}
-	else
-*/
-	if ( control_id == mIdMediaBrowserControlBack )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_back();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlStop )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_stop();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlForward )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_forward();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlHome )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->loadURI( mHomeWebUrl );
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlReload )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_reload( true );
-	}
-/*
-	else
-	if ( control_id == mIdMediaBrowserControlClearCache )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->clear_cache();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlClearCookies )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->clear_cookies();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlEnableCookies )
-	{
-		if ( mSelectedPanel )
-		{
-			if ( mMediaBrowserControlEnableCookies )
-			{
-				mSelectedPanel->mMediaSource->enable_cookies( true );
-			}
-			else
-			{
-				mSelectedPanel->mMediaSource->enable_cookies( false );
-			}
-		};
-	};
-*/
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::keyboard( int key )
-{
-	//if ( key == 'a' || key == 'A' )
-	//	addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-	//else
-	//if ( key == 'r' || key == 'R' )
-	//	remMediaPanel( mSelectedPanel );
-	//else
-	//if ( key == 'd' || key == 'D' )
-	//	dumpPanelInfo();
-	//else
-	if ( key == 27 )
-	{
-		std::cout << "Application finished - exiting..." << std::endl;
-		delete this;
-		exit( 0 );
-	};
-
-	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 , LLSD());
-	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0, LLSD());
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::mouseButton( int button, int state, int x, int y )
-{
-	if ( button == GLUT_LEFT_BUTTON )
-	{
-		if ( state == GLUT_DOWN )
-		{
-			int media_x, media_y, id;
-			windowPosToTexturePos( x, y, media_x, media_y, id );
-
-			if ( mSelectedPanel )
-				mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_DOWN, 0, media_x, media_y, 0 );
-		}
-		else
-		if ( state == GLUT_UP )
-		{
-			int media_x, media_y, id;
-			windowPosToTexturePos( x, y, media_x, media_y, id );
-
-			// only select a panel if we're on a panel
-			// (HACK: strictly speaking this rules out clicking on
-			// the origin of a panel but that's very unlikely)
-			if ( media_x > 0 && media_y > 0 )
-			{
-				selectPanelById( id );
-
-				if ( mSelectedPanel )
-					mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_UP, 0, media_x, media_y, 0 );
-			};
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::mousePassive( int x, int y )
-{
-	int media_x, media_y, id;
-	windowPosToTexturePos( x, y, media_x, media_y, id );
-
-	if ( mSelectedPanel )
-		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::mouseMove( int x, int y )
-{
-	int media_x, media_y, id;
-	windowPosToTexturePos( x, y, media_x, media_y, id );
-
-	if ( mSelectedPanel )
-		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::makeChrome()
-{
-	// IDs used by GLUI
-	int start_id = 0x1000;
-
-	// right side window - geometry manipulators
-#if __APPLE__
-	// the Apple GLUT implementation doesn't seem to set the graphic offset of subwindows correctly when they overlap in certain ways.
-	// Use a separate controls window in this case.
-	// GLUI window at right containing manipulation controls and other buttons
-	int x = glutGet(GLUT_WINDOW_X) + glutGet(GLUT_WINDOW_WIDTH) + 4;
-	int y = glutGet(GLUT_WINDOW_Y);
-	GLUI* right_glui_window = GLUI_Master.create_glui( "", 0, x, y );
-#else
-	GLUI* right_glui_window = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT );
-#endif
-	mViewRotationCtrl = right_glui_window->add_rotation( "Rotation", mViewRotation );
-	mViewTranslationCtrl = right_glui_window->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos );
-	mViewTranslationCtrl->set_speed( 0.01f );
-	mViewScaleCtrl = right_glui_window->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] );
-	mViewScaleCtrl->set_speed( 0.05f );
-	right_glui_window->set_main_gfx_window( mAppWindow );
-
-	// right side window - app controls
-	/*
-	mIdControlAddPanel = start_id++;
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_button( "Add panel", mIdControlAddPanel, gluiCallbackWrapper );
-	right_glui_window->add_statictext( "" );
-	mIdControlRemPanel = start_id++;
-	right_glui_window->add_button( "Rem panel", mIdControlRemPanel, gluiCallbackWrapper );
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	mIdControlCrashPlugin = start_id++;
-	right_glui_window->add_button( "Crash plugin", mIdControlCrashPlugin, gluiCallbackWrapper );
-	mIdControlHangPlugin = start_id++;
-	right_glui_window->add_button( "Hang plugin", mIdControlHangPlugin, gluiCallbackWrapper );
-	*/
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	mIdControlExitApp = start_id++;
-	right_glui_window->add_button( "Exit app", mIdControlExitApp, gluiCallbackWrapper );
-
-	//// top window - holds bookmark UI
-	mIdBookmarks = start_id++;
-	mSelBookmark = 0;
-	GLUI* glui_window_top = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mBookmarkList = glui_window_top->add_listbox( "", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper );
-	// only add the first 50 bookmarks - list can be very long sometimes (30,000+)
-	// when testing list of media URLs from AGNI for example
-	for( unsigned int each = 0; each < mBookmarks.size() && each < 50; ++each )
-		mBookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) );
-	glui_window_top->set_main_gfx_window( mAppWindow );
-
-	glui_window_top->add_column( false );
-	mIdUrlEdit = start_id++;
-	mUrlEdit = glui_window_top->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, 0, mIdUrlEdit, gluiCallbackWrapper );
-	mUrlEdit->set_w( 600 );
-	//GLUI* glui_window_top2 = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	//mIdUrlInitHistoryEdit = start_id++;
-	//mUrlInitHistoryEdit = glui_window_top2->add_edittext( "Init History (separate by commas or semicolons):",
-	//	GLUI_EDITTEXT_TEXT, 0, mIdUrlInitHistoryEdit, gluiCallbackWrapper );
-	//mUrlInitHistoryEdit->set_w( 800 );
-
-	// top window - media controls for "time" media types (e.g. movies)
-/*
-	mGluiMediaTimeControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mGluiMediaTimeControlWindow->set_main_gfx_window( mAppWindow );
-	mIdMediaTimeControlPlay = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "PLAY", mIdMediaTimeControlPlay, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlLoop = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "LOOP", mIdMediaTimeControlLoop, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlPause = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "PAUSE", mIdMediaTimeControlPause, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-
-	GLUI_Button  *button;
-	mIdMediaTimeControlRewind = start_id++;
-	button = mGluiMediaTimeControlWindow->add_button( "<<", mIdMediaTimeControlRewind, gluiCallbackWrapper );
-	button->set_w(30);
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlFastForward = start_id++;
-	button = mGluiMediaTimeControlWindow->add_button( ">>", mIdMediaTimeControlFastForward, gluiCallbackWrapper );
-	button->set_w(30);
-
-	mGluiMediaTimeControlWindow->add_column( true );
-
-	mIdMediaTimeControlStop = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "STOP", mIdMediaTimeControlStop, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlVolume = start_id++;
-	GLUI_Spinner* spinner = mGluiMediaTimeControlWindow->add_spinner( "Volume", 2, &mMediaTimeControlVolume, mIdMediaTimeControlVolume, gluiCallbackWrapper);
-	spinner->set_float_limits( 0, 100 );
-	mGluiMediaTimeControlWindow->add_column( true );
-	mIdMediaTimeControlSeekSeconds = start_id++;
-	spinner = mGluiMediaTimeControlWindow->add_spinner( "", 2, &mMediaTimeControlSeekSeconds, mIdMediaTimeControlSeekSeconds, gluiCallbackWrapper);
-	spinner->set_float_limits( 0, 200 );
-	spinner->set_w( 32 );
-	spinner->set_speed( 0.025f );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlSeek = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "SEEK", mIdMediaTimeControlSeek, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-*/
-
-	// top window - media controls for "browser" media types (e.g. web browser)
-	mGluiMediaBrowserControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mGluiMediaBrowserControlWindow->set_main_gfx_window( mAppWindow );
-	mIdMediaBrowserControlBack = start_id++;
-	mMediaBrowserControlBackButton = mGluiMediaBrowserControlWindow->add_button( "BACK", mIdMediaBrowserControlBack, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlStop = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "STOP", mIdMediaBrowserControlStop, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlForward = start_id++;
-	mMediaBrowserControlForwardButton = mGluiMediaBrowserControlWindow->add_button( "FORWARD", mIdMediaBrowserControlForward, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlHome = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "HOME", mIdMediaBrowserControlHome, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlReload = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "RELOAD", mIdMediaBrowserControlReload, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	/*
-	mIdMediaBrowserControlClearCache = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "CLEAR CACHE", mIdMediaBrowserControlClearCache, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlClearCookies = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "CLEAR COOKIES", mIdMediaBrowserControlClearCookies, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlEnableCookies = start_id++;
-	mMediaBrowserControlEnableCookies = 0;
-	mGluiMediaBrowserControlWindow->add_checkbox( "Enable Cookies", &mMediaBrowserControlEnableCookies, mIdMediaBrowserControlEnableCookies, gluiCallbackWrapper );
-
-	// top window - misc controls
-	GLUI* glui_window_misc_control = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mIdRandomPanelCount = start_id++;
-	mRandomPanelCount = 0;
-	glui_window_misc_control->add_checkbox( "Randomize panel count", &mRandomPanelCount, mIdRandomPanelCount, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-	mIdRandomBookmarks = start_id++;
-	mRandomBookmarks = 0;
-	glui_window_misc_control->add_checkbox( "Randomize bookmarks", &mRandomBookmarks, mIdRandomBookmarks, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdDisableTimeout = start_id++;
-	mDisableTimeout = 0;
-	glui_window_misc_control->add_checkbox( "Disable plugin timeout", &mDisableTimeout, mIdDisableTimeout, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdUsePluginReadThread = start_id++;
-	mUsePluginReadThread = 0;
-	glui_window_misc_control->add_checkbox( "Use plugin read thread", &mUsePluginReadThread, mIdUsePluginReadThread, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdLargePanelSpacing = start_id++;
-	mLargePanelSpacing = 0;
-	glui_window_misc_control->add_checkbox( "Large Panel Spacing", &mLargePanelSpacing, mIdLargePanelSpacing, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-*/
-	// bottom window - status
-	mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM );
-	mStatusText = mBottomGLUIWindow->add_statictext( "" );
-	mBottomGLUIWindow->set_main_gfx_window( mAppWindow );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::resetView()
-{
-	mViewRotationCtrl->reset();
-
-	mViewScaleCtrl->set_x( 0.0f );
-	mViewScaleCtrl->set_y( 0.0f );
-	mViewScaleCtrl->set_z( 1.3f );
-
-	mViewTranslationCtrl->set_x( 0.0f );
-	mViewTranslationCtrl->set_y( 0.0f );
-	mViewTranslationCtrl->set_z( 0.0f );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels )
-{
-	int pick_texture_width = 1024;
-	int pick_texture_height = 1024;
-	int pick_texture_depth = 3;
-	unsigned char* ptr = new unsigned char[ pick_texture_width * pick_texture_height * pick_texture_depth ];
-	for( int y = 0; y < pick_texture_height; ++y )
-	{
-		for( int x = 0; x < pick_texture_width * pick_texture_depth ; x += pick_texture_depth )
-		{
-			unsigned long bits = 0L;
-			bits |= ( id << 20 ) | ( y << 10 ) | ( x / 3 );
-			unsigned char r_component = ( bits >> 16 ) & 0xff;
-			unsigned char g_component = ( bits >> 8 ) & 0xff;
-			unsigned char b_component = bits & 0xff;
-
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 0 ] = r_component;
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 1 ] = g_component;
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 2 ] = b_component;
-		};
-	};
-
-	glGenTextures( 1, texture_handle );
-
-	checkGLError("glGenTextures");
-	std::cout << "glGenTextures returned " << *texture_handle << std::endl;
-
-	bindTexture( *texture_handle );
-	glTexImage2D( GL_TEXTURE_2D, 0,
-					GL_RGB,
-						pick_texture_width, pick_texture_height,
-							0, GL_RGB, GL_UNSIGNED_BYTE, ptr );
-
-	*texture_pixels = ptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-std::string LLFBConnectTest::mimeTypeFromUrl( std::string& url )
-{
-	// default to web
-	std::string mime_type = "text/html";
-
-	// we may need a more advanced MIME type accessor later :-)
-	if ( url.find( ".mov" ) != std::string::npos )	// Movies
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( ".txt" ) != std::string::npos )	// Apple Text descriptors
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( ".mp3" ) != std::string::npos )	// Apple Text descriptors
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( "example://" ) != std::string::npos )	// Example plugin
-		mime_type = "example/example";
-
-	return mime_type;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-std::string LLFBConnectTest::pluginNameFromMimeType( std::string& mime_type )
-{
-#if LL_DARWIN
-	std::string plugin_name( "media_plugin_null.dylib" );
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "media_plugin_quicktime.dylib";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "media_plugin_webkit.dylib";
-
-#elif LL_WINDOWS
-	std::string plugin_name( "media_plugin_null.dll" );
-
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "media_plugin_quicktime.dll";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "media_plugin_webkit.dll";
-	else
-	if ( mime_type == "example/example" )
-		plugin_name = "media_plugin_example.dll";
-
-#elif LL_LINUX
-	std::string plugin_name( "libmedia_plugin_null.so" );
-
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "libmedia_plugin_quicktime.so";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "libmedia_plugin_webkit.so";
-#endif
-	return plugin_name;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLFBConnectTest::addMediaPanel( std::string url )
-{
-	// Get the plugin filename using the URL
-	std::string mime_type = mimeTypeFromUrl( url );
-	std::string plugin_name = pluginNameFromMimeType( mime_type );
-
-	// create a random size for the new media
-	int media_width;
-	int media_height;
-	getRandomMediaSize( media_width, media_height, mime_type );
-	media_width = 1024;
-	media_height = 1536;
-
-	// make a new plugin
-	LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
-
-	// enable cookies so the FB login works
-	media_source->enable_cookies(true);
-
-	// tell the plugin what size we asked for
-	media_source->setSize( media_width, media_height );
-
-	// Use the launcher start and initialize the plugin
-#if LL_DARWIN || LL_LINUX
-	std::string launcher_name( "SLPlugin" );
-#elif LL_WINDOWS
-	std::string launcher_name( "SLPlugin.exe" );
-#endif
-
-	// for this test app, use the cwd as the user data path (ugh).
-#if LL_WINDOWS
-	std::string user_data_path = ".\\";
-#else
-        char cwd[ FILENAME_MAX ];
-	if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-	{
-		std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
-		return NULL;
-	}
-	std::string user_data_path = std::string( cwd ) + "/";
-#endif
-	media_source->setUserDataPath(user_data_path);
-	media_source->init( launcher_name, user_data_path, plugin_name, false );
-	//media_source->setDisableTimeout(mDisableTimeout);
-
-	// make a new panel and save parameters
-	mediaPanel* panel = new mediaPanel;
-	panel->mMediaSource = media_source;
-	panel->mStartUrl = url;
-	panel->mMimeType = mime_type;
-	panel->mMediaWidth = media_width;
-	panel->mMediaHeight = media_height;
-	panel->mTextureWidth = 0;
-	panel->mTextureHeight = 0;
-	panel->mTextureScaleX = 0;
-	panel->mTextureScaleY = 0;
-	panel->mMediaTextureHandle = 0;
-	panel->mPickTextureHandle = 0;
-	panel->mAppTextureCoordsOpenGL = false;	// really need an 'undefined' state here too
-	panel->mReadyToRender = false;
-
-	// look through current media panels to find an unused index number
-	bool id_exists = true;
-	for( int nid = 0; nid < mMaxPanels; ++nid )
-	{
-		// does this id exist already?
-		id_exists = false;
-		for( int pid = 0; pid < (int)mMediaPanels.size(); ++pid )
-		{
-			if ( nid == mMediaPanels[ pid ]->mId )
-			{
-				id_exists = true;
-				break;
-			};
-		};
-
-		// id wasn't found so we can use it
-		if ( ! id_exists )
-		{
-			panel->mId = nid;
-			break;
-		};
-	};
-
-	// if we get here and this flag is set, there is no room for any more panels
-	if ( id_exists )
-	{
-		std::cout << "No room for any more panels" << std::endl;
-	}
-	else
-	{
-		// now we have the ID we can use it to make the
-		// pick texture (id is baked into texture pixels)
-		makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
-
-		// save this in the list of panels
-		mMediaPanels.push_back( panel );
-
-		// select the panel that was just created
-		selectPanel( panel );
-
-		// load and start the URL
-		panel->mMediaSource->loadURI( url );
-		panel->mMediaSource->start();
-
-		std::cout << "Adding new media panel for " << url << "(" << media_width << "x" << media_height << ") with index " << panel->mId << " - total panels = " << mMediaPanels.size() << std::endl;
-	}
-	
-	return panel;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::updateMediaPanel( mediaPanel* panel )
-{
-//	checkGLError("LLFBConnectTest::updateMediaPanel");
-
-	if ( ! panel )
-		return;
-
-	if(!panel->mMediaSource || !panel->mMediaSource->textureValid())
-	{
-		panel->mReadyToRender = false;
-		return;
-	}
-
-	// take a reference copy of the plugin values since they
-	// might change during this lifetime of this function
-	int plugin_media_width = panel->mMediaSource->getWidth();
-	int plugin_media_height = panel->mMediaSource->getHeight();
-	int plugin_texture_width = panel->mMediaSource->getBitsWidth();
-	int plugin_texture_height = panel->mMediaSource->getBitsHeight();
-
-	// If the texture isn't created or the media or texture dimensions changed AND
-	// the sizes are valid then we need to delete the old media texture (if necessary)
-	// then make a new one.
-	if ((panel->mMediaTextureHandle == 0 ||
-		 panel->mMediaWidth != plugin_media_width ||
-		 panel->mMediaHeight != plugin_media_height ||
-		 panel->mTextureWidth != plugin_texture_width ||
-		 panel->mTextureHeight != plugin_texture_height) &&
-		( plugin_media_width > 0 && plugin_media_height > 0 &&
-		  plugin_texture_width > 0 && plugin_texture_height > 0 ) )
-	{
-		std::cout << "Valid media size (" <<  plugin_media_width << " x " << plugin_media_height
-				<< ") and texture size (" <<  plugin_texture_width << " x " << plugin_texture_height
-				<< ") for panel with ID=" << panel->mId << " - making texture" << std::endl;
-
-		// delete old GL texture
-		if ( isTexture( panel->mMediaTextureHandle ) )
-		{
-			std::cerr << "updateMediaPanel: deleting texture " << panel->mMediaTextureHandle << std::endl;
-			glDeleteTextures( 1, &panel->mMediaTextureHandle );
-			panel->mMediaTextureHandle = 0;
-		}
-
-		std::cerr << "before: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
-
-		// make a GL texture based on the dimensions the plugin told us
-		GLuint new_texture = 0;
-		glGenTextures( 1, &new_texture );
-
-		checkGLError("glGenTextures");
-
-		std::cout << "glGenTextures returned " << new_texture << std::endl;
-
-		panel->mMediaTextureHandle = new_texture;
-
-		bindTexture( panel->mMediaTextureHandle );
-
-		std::cout << "Setting texture size to " << plugin_texture_width << " x " << plugin_texture_height << std::endl;
-		glTexImage2D( GL_TEXTURE_2D, 0,
-			GL_RGB,
-				plugin_texture_width, plugin_texture_height,
-					0, GL_RGB, GL_UNSIGNED_BYTE,
-						0 );
-
-
-		std::cerr << "after: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
-	};
-
-	// update our record of the media and texture dimensions
-	// NOTE: do this after we we check for sizes changes
-	panel->mMediaWidth = plugin_media_width;
-	panel->mMediaHeight = plugin_media_height;
-	panel->mTextureWidth = plugin_texture_width;
-	panel->mTextureHeight = plugin_texture_height;
-	if ( plugin_texture_width > 0 )
-	{
-		panel->mTextureScaleX = (double)panel->mMediaWidth / (double)panel->mTextureWidth;
-	};
-	if ( plugin_texture_height > 0 )
-	{
-		panel->mTextureScaleY = (double)panel->mMediaHeight / (double)panel->mTextureHeight;
-	};
-
-	// update the flag which tells us if the media source uses OprnGL coords or not.
-	panel->mAppTextureCoordsOpenGL = panel->mMediaSource->getTextureCoordsOpenGL();
-
-	// Check to see if we have enough to render this panel.
-	// If we do, set a flag that the display functions use so
-	// they only render a panel with media if it's ready.
-	if ( panel->mMediaWidth < 0 ||
-		 panel->mMediaHeight < 0 ||
-		 panel->mTextureWidth < 1 ||
-		 panel->mTextureHeight < 1 ||
-		 panel->mMediaTextureHandle == 0 )
-	{
-		panel->mReadyToRender = false;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLFBConnectTest::replaceMediaPanel( mediaPanel* panel, std::string url )
-{
-	// no media panels so we can't change anything - have to add
-	if ( mMediaPanels.size() == 0 )
-		return NULL;
-
-	// sanity check
-	if ( ! panel )
-		return NULL;
-
-	int index;
-	for(index = 0; index < (int)mMediaPanels.size(); index++)
-	{
-		if(mMediaPanels[index] == panel)
-			break;
-	}
-
-	if(index >= (int)mMediaPanels.size())
-	{
-		// panel isn't in mMediaPanels
-		return NULL;
-	}
-
-	std::cout << "Replacing media panel with index " << panel->mId << std::endl;
-
-	int panel_id = panel->mId;
-
-	if(mSelectedPanel == panel)
-		mSelectedPanel = NULL;
-
-	delete panel;
-
-	// Get the plugin filename using the URL
-	std::string mime_type = mimeTypeFromUrl( url );
-	std::string plugin_name = pluginNameFromMimeType( mime_type );
-
-	// create a random size for the new media
-	int media_width;
-	int media_height;
-	getRandomMediaSize( media_width, media_height, mime_type );
-
-	// make a new plugin
-	LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
-
-	// tell the plugin what size we asked for
-	media_source->setSize( media_width, media_height );
-
-	// Use the launcher start and initialize the plugin
-#if LL_DARWIN || LL_LINUX
-	std::string launcher_name( "SLPlugin" );
-#elif LL_WINDOWS
-	std::string launcher_name( "SLPlugin.exe" );
-#endif
-
-	// for this test app, use the cwd as the user data path (ugh).
-#if LL_WINDOWS
-	std::string user_data_path = ".\\";
-#else
-        char cwd[ FILENAME_MAX ];
-	if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-	{
-		std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
-		return NULL;
-	}
-	std::string user_data_path = std::string( cwd ) + "/";
-#endif
-
-	media_source->setUserDataPath(user_data_path);
-	media_source->init( launcher_name, user_data_path, plugin_name, false );
-	//media_source->setDisableTimeout(mDisableTimeout);
-
-	// make a new panel and save parameters
-	panel = new mediaPanel;
-	panel->mMediaSource = media_source;
-	panel->mStartUrl = url;
-	panel->mMimeType = mime_type;
-	panel->mMediaWidth = media_width;
-	panel->mMediaHeight = media_height;
-	panel->mTextureWidth = 0;
-	panel->mTextureHeight = 0;
-	panel->mTextureScaleX = 0;
-	panel->mTextureScaleY = 0;
-	panel->mMediaTextureHandle = 0;
-	panel->mPickTextureHandle = 0;
-	panel->mAppTextureCoordsOpenGL = false;	// really need an 'undefined' state here too
-	panel->mReadyToRender = false;
-
-	panel->mId = panel_id;
-
-	// Replace the entry in the panels array
-	mMediaPanels[index] = panel;
-
-	// now we have the ID we can use it to make the
-	// pick texture (id is baked into texture pixels)
-	makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
-
-	// select the panel that was just created
-	selectPanel( panel );
-
-	// load and start the URL
-	panel->mMediaSource->loadURI( url );
-	panel->mMediaSource->start();
-	
-	return panel;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::getRandomMediaSize( int& width, int& height, std::string mime_type )
-{
-	// Make a new media source with a random size which we'll either
-	// directly or the media plugin will tell us what it wants later.
-	// Use a random size so we can test support for weird media sizes.
-	// (Almost everything else will get filled in later once the
-	// plugin responds)
-	// NB. Do we need to enforce that width is on 4 pixel boundary?
-	width = ( ( rand() % 170 ) + 30 ) * 4;
-	height = ( ( rand() % 170 ) + 30 ) * 4;
-
-	// adjust this random size if it's a browser so we get
-	// a more useful size for testing..
-	if ( mime_type == "text/html" || mime_type == "example/example"  )
-	{
-		width = ( ( rand() % 100 ) + 100 ) * 4;
-		height = ( width * ( ( rand() % 400 ) + 1000 ) ) / 1000;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::remMediaPanel( mediaPanel* panel )
-{
-	// always leave one panel
-	if ( mMediaPanels.size() == 1 )
-		return;
-
-	// sanity check - don't think this can happen but see above for a case where it might...
-	if ( ! panel )
-		return;
-
-	std::cout << "Removing media panel with index " << panel->mId << " - total panels = " << mMediaPanels.size() - 1 << std::endl;
-
-	if(mSelectedPanel == panel)
-		mSelectedPanel = NULL;
-
-	delete panel;
-
-	// remove from storage list
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		if ( mMediaPanels[ i ] == panel )
-		{
-			mMediaPanels.erase( mMediaPanels.begin() + i );
-			break;
-		};
-	};
-
-	// select the first panel
-	selectPanel( mMediaPanels[ 0 ] );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::updateStatusBar()
-{
-	if ( ! mSelectedPanel )
-		return;
-
-	// cache results - this is a very slow function
-	static int cached_id = -1;
-	static int cached_media_width = -1;
-	static int cached_media_height = -1;
-	static int cached_texture_width = -1;
-	static int cached_texture_height = -1;
-	static bool cached_supports_browser_media = true;
-	static bool cached_supports_time_media = false;
-	static int cached_movie_time = -1;
-	static GLfloat cached_distance = -1.0f;
-
-	static std::string cached_plugin_version = "";
-	if (
-		 cached_id == mSelectedPanel->mId &&
-		 cached_media_width == mSelectedPanel->mMediaWidth &&
-		 cached_media_height  == mSelectedPanel->mMediaHeight &&
-		 cached_texture_width == mSelectedPanel->mTextureWidth &&
-		 cached_texture_height == mSelectedPanel->mTextureHeight &&
-		 cached_supports_browser_media == mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() &&
-		 cached_supports_time_media == mSelectedPanel->mMediaSource->pluginSupportsMediaTime() &&
-		 cached_plugin_version == mSelectedPanel->mMediaSource->getPluginVersion() &&
-		 cached_movie_time == (int)mSelectedPanel->mMediaSource->getCurrentTime() &&
-		 cached_distance == mDistanceCameraToSelectedGeometry
-	   )
-	{
-		// nothing changed so don't spend time here
-		return;
-	};
-
-	std::ostringstream stream( "" );
-
-	stream.str( "" );
-	stream.clear();
-
-	stream << "Id: ";
-	stream << std::setw( 2 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mId;
-	stream << " | ";
-	stream << "Media: ";
-	stream << std::setw( 3 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mMediaWidth;
-	stream << " x ";
-	stream << std::setw( 3 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mMediaHeight;
-	stream << " | ";
-	stream << "Texture: ";
-	stream << std::setw( 4 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mTextureWidth;
-	stream << " x ";
-	stream << std::setw( 4 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mTextureHeight;
-
-	stream << " | ";
-	stream << "Distance: ";
-	stream << std::setw( 6 );
-	stream << std::setprecision( 3 );
-	stream << std::setprecision( 3 );
-	stream << mDistanceCameraToSelectedGeometry;
-	stream << " | ";
-
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
-		stream << "BROWSER";
-	else
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-		stream << "TIME   ";
-	stream << " | ";
-	stream << mSelectedPanel->mMediaSource->getPluginVersion();
-	stream << " | ";
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-	{
-		stream << std::setw( 3 ) << std::setfill( '0' );
-		stream << (int)mSelectedPanel->mMediaSource->getCurrentTime();
-		stream << " / ";
-		stream << std::setw( 3 ) << std::setfill( '0' );
-		stream << (int)mSelectedPanel->mMediaSource->getDuration();
-		stream << " @ ";
-		stream << (int)mSelectedPanel->mMediaSource->getCurrentPlayRate();
-		stream << " | ";
-	};
-
-	glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
-	mStatusText->set_text( const_cast< char*>( stream.str().c_str() ) );
-	glutSetWindow( mAppWindow );
-
-	// caching
-	cached_id = mSelectedPanel->mId;
-	cached_media_width = mSelectedPanel->mMediaWidth;
-	cached_media_height = mSelectedPanel->mMediaHeight;
-	cached_texture_width = mSelectedPanel->mTextureWidth;
-	cached_texture_height = mSelectedPanel->mTextureHeight;
-	cached_supports_browser_media = mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser();
-	cached_supports_time_media = mSelectedPanel->mMediaSource->pluginSupportsMediaTime();
-	cached_plugin_version = mSelectedPanel->mMediaSource->getPluginVersion();
-	cached_movie_time = (int)mSelectedPanel->mMediaSource->getCurrentTime();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::dumpPanelInfo()
-{
-	std::cout << std::endl << "===== Media Panels =====" << std::endl;
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		std::cout << std::setw( 2 ) << std::setfill( '0' );
-		std::cout << i + 1 << "> ";
-		std::cout << "Id: ";
-		std::cout << std::setw( 2 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mId;
-		std::cout << " | ";
-		std::cout << "Media: ";
-		std::cout << std::setw( 3 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mMediaWidth;
-		std::cout << " x ";
-		std::cout << std::setw( 3 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mMediaHeight;
-		std::cout << " | ";
-		std::cout << "Texture: ";
-		std::cout << std::setw( 4 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mTextureWidth;
-		std::cout << " x ";
-		std::cout << std::setw( 4 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mTextureHeight;
-		std::cout << " | ";
-		if ( mMediaPanels[ i ] == mSelectedPanel )
-			std::cout << "(selected)";
-
-		std::cout << std::endl;
-	};
-	std::cout << "========================" << std::endl;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLFBConnectTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
-{
-	// Uncomment this to make things much, much quieter.
-//	return;
-
-	switch(event)
-	{
-		case MEDIA_EVENT_CONTENT_UPDATED:
-			// too spammy -- don't log these
-//			std::cerr <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << std::endl;
-		break;
-
-		case MEDIA_EVENT_TIME_DURATION_UPDATED:
-			// too spammy -- don't log these
-//			std::cerr <<  "Media event:  MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << std::endl;
-		break;
-
-		case MEDIA_EVENT_SIZE_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_SIZE_CHANGED " << std::endl;
-		break;
-
-		case MEDIA_EVENT_CURSOR_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_BEGIN:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_BEGIN " << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_COMPLETE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << std::endl;
-		break;
-
-		case MEDIA_EVENT_PROGRESS_UPDATED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << std::endl;
-		break;
-
-		case MEDIA_EVENT_STATUS_TEXT_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAME_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl;
-			glutSetWindowTitle( self->getMediaName().c_str() );
-		break;
-
-		case MEDIA_EVENT_LOCATION_CHANGED:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl;
-			mediaPanel* panel = findMediaPanel(self);
-			if(panel != NULL)
-			{
-				panel->mStartUrl = self->getLocation();
-				if(panel == mSelectedPanel)
-				{
-					mUrlEdit->set_text(const_cast<char*>(panel->mStartUrl.c_str()) );
-				}
-			}
-		}
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE, uri is: " << self->getClickURL() << std::endl;
-		break;
-			
-		case MEDIA_EVENT_CLICK_LINK_HREF:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, uri is " << self->getClickURL() << ", target is " << self->getClickTarget() << std::endl;
-			// retrieve the event parameters
-			std::string url = self->getClickURL();
-			std::string target = self->getClickTarget();
-			
-			if(target == "_external")
-			{
-				// this should open in an external browser, but since this is a test app we don't care.
-			}
-			else if(target == "_blank")
-			{
-				// Create a new panel with the specified URL.
-				addMediaPanel(url);
-			}
-			else // other named target
-			{
-				mediaPanel *target_panel = findMediaPanel(target);
-				if(target_panel)
-				{
-					target_panel = replaceMediaPanel(target_panel, url);
-				}
-				else
-				{
-					target_panel = addMediaPanel(url);
-				}
-
-				if(target_panel)
-				{
-					target_panel->mTarget = target;
-				}
-			}
-		}
-		break;
-
-		case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << std::endl;
-		break;
-
-		case MEDIA_EVENT_PLUGIN_FAILED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << std::endl;
-		break;
-
-		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl;
-		break;
-
-		case MEDIA_EVENT_CLOSE_REQUEST:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLOSE_REQUEST" << std::endl;
-		break;
-		
-		case MEDIA_EVENT_PICK_FILE_REQUEST:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PICK_FILE_REQUEST" << std::endl;
-			// TODO: display an actual file picker
-			self->sendPickFileResponse("cake");
-		break;
-
-		case MEDIA_EVENT_GEOMETRY_CHANGE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() 
-				<< ", x = " << self->getGeometryX() 
-				<< ", y = " << self->getGeometryY() 
-				<< ", width = " << self->getGeometryWidth() 
-				<< ", height = " << self->getGeometryHeight() 
-				<< std::endl;
-		break;
-
-		case MEDIA_EVENT_AUTH_REQUEST:
-		{
-			//std::cerr <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl;
-
-			// TODO: display an auth dialog
-			self->sendAuthResponse(false, "", "");
-		}
-		break;
-
-		case MEDIA_EVENT_LINK_HOVERED:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl;
-		}
-		break;
-
-		default:
-		{
-			std::cerr <<  "Media event:  <unknown>, code is: " << int(event) << std::endl;
-		}
-		break;
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-static void gluiCallbackWrapper( int control_id )
-{
-	if ( gApplication )
-		gApplication->gluiCallback( control_id );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutReshape( int width, int height )
-{
-	if ( gApplication )
-		gApplication->reshape( width, height );
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutDisplay()
-{
-	if ( gApplication )
-		gApplication->display();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutIdle(int update_ms)
-{
-	GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
-
-	if ( gApplication )
-		gApplication->idle();
-
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutKeyboard( unsigned char key, int x, int y )
-{
-	if ( gApplication )
-		gApplication->keyboard( key );
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMousePassive( int x, int y )
-{
-	if ( gApplication )
-		gApplication->mousePassive( x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMouseMove( int x , int y )
-{
-	if ( gApplication )
-		gApplication->mouseMove( x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMouseButton( int button, int state, int x, int y )
-{
-	if ( gApplication )
-		gApplication->mouseButton( button, state, x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-int main( int argc, char* argv[] )
-{
-#if LL_DARWIN
-	// Set the current working directory to <application bundle>/Contents/Resources/
-	CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
-	if(resources_url != NULL)
-	{
-		CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle);
-		CFRelease(resources_url);
-		if(resources_string != NULL)
-		{
-			char buffer[PATH_MAX] = "";
-			if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8))
-			{
-				chdir(buffer);
-			}
-			CFRelease(resources_string);
-		}
-	}
-#endif
-
-	glutInit( &argc, argv );
-	glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
-
-	const int app_window_x = 80;
-	const int app_window_y = 0;
-	const int app_window_width = 960;
-	const int app_window_height = 960;
-
-	glutInitWindowPosition( app_window_x, app_window_y );
-	glutInitWindowSize( app_window_width, app_window_height );
-
-	int app_window_handle = glutCreateWindow( "LLFBConnectTest" );
-
-	glutDisplayFunc( glutDisplay );
-
-	GLUI_Master.set_glutReshapeFunc( glutReshape );
-	GLUI_Master.set_glutKeyboardFunc( glutKeyboard );
-	GLUI_Master.set_glutMouseFunc( glutMouseButton );
-
-	glutPassiveMotionFunc( glutMousePassive );
-	glutMotionFunc( glutMouseMove );
-
-	glutSetWindow( app_window_handle );
-
-	gApplication = new LLFBConnectTest( app_window_handle, app_window_width, app_window_height );
-
-	// update at approximately 60hz
-	int update_ms = 1000 / 60;
-
-	GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
-
-	glutMainLoop();
-
-	delete gApplication;
-}
diff --git a/indra/test_apps/llfbconnecttest/llfbconnecttest.h b/indra/test_apps/llfbconnecttest/llfbconnecttest.h
deleted file mode 100644
index 77e4d096d058becc59952b773362eb421513e89f..0000000000000000000000000000000000000000
--- a/indra/test_apps/llfbconnecttest/llfbconnecttest.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * @file LLFBConnectTest.cpp
- * @brief Facebook Connect Test App
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_FB_CONNECT_H
-#define LL_FB_CONNECT_H
-
-#include <vector>
-#include <string>
-#include "llpluginclassmedia.h"
-#include "llgl.h"
-
-// Forward declarations
-class GLUI_Rotation;
-class GLUI_Translation;
-class GLUI_Listbox;
-class GLUI_EditText;
-class GLUI_StaticText;
-class GLUI;
-class GLUI_Button;
-
-////////////////////////////////////////////////////////////////////////////////
-//
-struct mediaPanel
-{
-	public:
-		mediaPanel();
-		~mediaPanel();
-		int mId;
-		std::string mStartUrl;
-		std::string mMimeType;
-		std::string mTarget;
-		LLPluginClassMedia *mMediaSource;
-		int mMediaWidth;
-		int mMediaHeight;
-		int mTextureWidth;
-		int mTextureHeight;
-		double mTextureScaleX;
-		double mTextureScaleY;
-		GLuint mMediaTextureHandle;
-		GLuint mPickTextureHandle;
-		unsigned char* mPickTexturePixels;
-		bool mAppTextureCoordsOpenGL;
-		bool mReadyToRender;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class LLFBConnectTest : public LLPluginClassMediaOwner
-{
-	public:
-		LLFBConnectTest( int app_window, int window_width, int window_height );
-		~LLFBConnectTest();
-
-		void reshape( int width, int height );
-		void display();
-		void idle();
-		void gluiCallback( int control_id );
-		void keyboard( int key );
-		void mousePassive( int x, int y );
-		void mouseButton( int button, int state, int x, int y );
-		void mouseMove( int x, int y );
-
-		void bindTexture(GLuint texture, GLint row_length = 0, GLint alignment = 1);
-		bool checkGLError(const char *name = "OpenGL");
-		void drawGeometry( int panel, bool selected );
-		void startPanelHighlight( float red, float green, float blue, float line_width );
-		void endPanelHighlight();
-		enum { DrawTypePickTexture, DrawTypeMediaTexture };
-		void draw( int draw_type );
-		void windowPosToTexturePos( int window_x, int window_y, int& media_x, int& media_y, int& id );
-
-		mediaPanel* addMediaPanel( std::string url );
-		void updateMediaPanel( mediaPanel* panel );
-		void remMediaPanel( mediaPanel* panel );
-		mediaPanel* replaceMediaPanel( mediaPanel* panel, std::string url );
-		void getRandomMediaSize( int& width, int& height, std::string mime_type );
-		void navigateToNewURI( std::string uri );
-        void initUrlHistory( std::string uri );
-		void selectPanelById( int id );
-		void selectPanel( mediaPanel* panel );
-		mediaPanel* findMediaPanel( LLPluginClassMedia* panel );
-		mediaPanel* findMediaPanel( const std::string &target_name );
-		void makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels );
-		void makeChrome();
-		void resetView();
-
-		void dumpPanelInfo();
-		void updateStatusBar();
-
-		GLfloat distanceToCamera( GLfloat point_x, GLfloat point_y, GLfloat point_z );
-		
-
-	// Inherited from LLPluginClassMediaOwner
-	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent);
-
-	private:
-		const int mVersionMajor;
-		const int mVersionMinor;
-		const int mVersionPatch;
-		const int mMaxPanels;
-		int mAppWindow;
-		int mWindowWidth;
-		int mWindowHeight;
-		int mCurMouseX;
-		int mCurMouseY;
-		unsigned char mPixelReadColor[ 3 ];
-		bool mFuzzyMedia;
-		const std::string mHomeWebUrl;
-
-		std::vector< mediaPanel* > mMediaPanels;
-		mediaPanel* mSelectedPanel;
-		std::string mimeTypeFromUrl( std::string& url );
-		std::string pluginNameFromMimeType( std::string& mime_type );
-
-		GLUI_Rotation* mViewRotationCtrl;
-		GLUI_Translation* mViewScaleCtrl;
-		GLUI_Translation* mViewTranslationCtrl;
-		float mViewportAspect;
-		float mViewPos[ 3 ];
-		float mViewRotation[ 16 ];
-
-		float mDistanceCameraToSelectedGeometry;
-
-		std::vector< std::pair< std::string, std::string > > mBookmarks;
-		GLUI_Listbox* mBookmarkList;
-		int mIdBookmarks;
-		int mIdUrlEdit;
-		GLUI_EditText* mUrlEdit;
-		int mSelBookmark;
-
-		int mIdControlExitApp;
-
-		GLUI* mGluiMediaBrowserControlWindow;
-		int mIdMediaBrowserControlBack;
-		GLUI_Button* mMediaBrowserControlBackButton;
-		int mIdMediaBrowserControlStop;
-		int mIdMediaBrowserControlForward;
-		GLUI_Button* mMediaBrowserControlForwardButton;
-		bool mGluiMediaBrowserControlWindowFlag;
-		bool mMediaBrowserControlBackButtonFlag;
-		bool mMediaBrowserControlForwardButtonFlag;
-		int mIdMediaBrowserControlHome;
-		int mIdMediaBrowserControlReload;
-
-		GLUI* mBottomGLUIWindow;
-		GLUI_StaticText* mStatusText;
-};
-
-#endif	// LL_FB_CONNECT_H
-
diff --git a/indra/test_apps/llplugintest/CMakeLists.txt b/indra/test_apps/llplugintest/CMakeLists.txt
index 0c8bdc464df04fbcd9603060288788fedea7aab8..e682eacccaecf1098532be9ef707645014b4019e 100755
--- a/indra/test_apps/llplugintest/CMakeLists.txt
+++ b/indra/test_apps/llplugintest/CMakeLists.txt
@@ -254,138 +254,8 @@ endif (DARWIN)
 #  )
 #endif (DARWIN)
 
-### llmediaplugintest
-
-set(llmediaplugintest_SOURCE_FILES
-    llmediaplugintest.cpp
-    llmediaplugintest.h
-    bookmarks.txt
-    )
-
-add_executable(llmediaplugintest
-    WIN32
-    MACOSX_BUNDLE
-    ${llmediaplugintest_SOURCE_FILES}
-)
-
-set_target_properties(llmediaplugintest
-    PROPERTIES
-    WIN32_EXECUTABLE
-    FALSE
-)
-
-target_link_libraries(llmediaplugintest
-  ${GLUT_LIBRARY}
-  ${GLUI_LIBRARY}
-  ${OPENGL_LIBRARIES}
-  ${LLPLUGIN_LIBRARIES}
-  ${LLMESSAGE_LIBRARIES}
-  ${LLCOMMON_LIBRARIES}
-  ${PLUGIN_API_WINDOWS_LIBRARIES}
-)
-
-if (DARWIN)
-  # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app.
-  target_link_libraries(llmediaplugintest
-    ${COREFOUNDATION_LIBRARY}
-  )
-endif (DARWIN)
-
-add_dependencies(llmediaplugintest
-  stage_third_party_libs
-  SLPlugin
-  media_plugin_quicktime
-  media_plugin_webkit
-  media_plugin_example
-  ${LLPLUGIN_LIBRARIES}
-  ${LLMESSAGE_LIBRARIES}
-  ${LLCOMMON_LIBRARIES}
-)
-
-# turn off weird GLUI pragma 
-add_definitions(-DGLUI_NO_LIB_PRAGMA)
-
-if (DARWIN OR LINUX)
-  # glui.h contains code that triggers the "overloaded-virtual" warning in gcc.  
-  set_source_files_properties(llmediaplugintest.cpp PROPERTIES COMPILE_FLAGS "-Wno-overloaded-virtual")
-endif (DARWIN OR LINUX)
-
 # Gather build products of the various dependencies into the build directory for the testbed.
 
-if (DARWIN)
-  # path inside the app bundle where we'll need to copy plugins and other related files
-  set(PLUGINS_DESTINATION_DIR
-    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llmediaplugintest.app/Contents/Resources
-  )
-  
-  # create the Contents/Resources directory
-  add_custom_command(
-    TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND}
-    ARGS
-      -E
-      make_directory
-      ${PLUGINS_DESTINATION_DIR}
-    COMMENT "Creating Resources directory in app bundle."
-  ) 
-else (DARWIN)
-  set(PLUGINS_DESTINATION_DIR
-    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
-  )
-endif (DARWIN)
-
-set(BUILT_SLPLUGIN $<TARGET_FILE:SLPlugin>)
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_SLPLUGIN}
-)
-
-set(BUILT_LLCOMMON $<TARGET_FILE:llcommon>)
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_LLCOMMON}
-)
-
-set(BUILT_WEBKIT_PLUGIN $<TARGET_FILE:media_plugin_webkit>)
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_WEBKIT_PLUGIN}
-)
-
-if (DARWIN OR WINDOWS)
-  set(BUILT_QUICKTIME_PLUGIN $<TARGET_FILE:media_plugin_quicktime>)
-  add_custom_command(TARGET llmediaplugintest POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
-    DEPENDS ${BUILT_QUICKTIME_PLUGIN}
-  )
-endif (DARWIN OR WINDOWS)
-
-set(BUILT_EXAMPLE_PLUGIN $<TARGET_FILE:media_plugin_example>)
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_EXAMPLE_PLUGIN}  ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_EXAMPLE_PLUGIN}
-)
-
-# copy over bookmarks file if llmediaplugintest gets built
-set(BUILT_LLMEDIAPLUGINTEST $<TARGET_FILE:llmediaplugintest>)
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/
-  DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
-)
-
-# also copy it to the same place as SLPlugin, which is what the mac wants...
-add_custom_command(TARGET llmediaplugintest POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR}
-  DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
-)
-
-if (DARWIN)
-#   add_custom_command(TARGET llmediaplugintest POST_BUILD
-#     COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
-#     DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
-#   )
-endif (DARWIN)
-
 if(WINDOWS)
   #********************
   # Plugin test library deploy
@@ -398,11 +268,6 @@ if(WINDOWS)
     libgmodule-2.0-0.dll
     libgobject-2.0-0.dll
     libgthread-2.0-0.dll
-    qtcored4.dll
-    qtguid4.dll
-    qtnetworkd4.dll
-    qtopengld4.dll
-    qtwebkitd4.dll
     ssleay32.dll
     )
   copy_if_different(
@@ -413,40 +278,6 @@ if(WINDOWS)
     )
   set(plugin_test_targets ${plugin_test_targets} ${out_targets})
   
-  # Debug config runtime files required for the plugin test mule (Qt image format plugins)
-  set(plugintest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/imageformats")
-  set(plugintest_debug_files
-    qgifd4.dll
-    qicod4.dll
-    qjpegd4.dll
-    qmngd4.dll
-    qsvgd4.dll
-    qtiffd4.dll
-    )
-  copy_if_different(
-    ${plugintest_debug_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Debug/imageformats"
-    out_targets
-    ${plugintest_debug_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
-  # Debug config runtime files required for the plugin test mule (Qt codec plugins)
-  set(plugintest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/codecs")
-  set(plugintest_debug_files
-    qcncodecsd4.dll
-    qjpcodecsd4.dll
-    qkrcodecsd4.dll
-    qtwcodecsd4.dll
-    )
-  copy_if_different(
-    ${plugintest_debug_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Debug/codecs"
-    out_targets
-    ${plugintest_debug_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
- 
   # Release & ReleaseDebInfo config runtime files required for the plugin test mule
   set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
   set(plugintest_release_files
@@ -455,12 +286,6 @@ if(WINDOWS)
     libgmodule-2.0-0.dll
     libgobject-2.0-0.dll
     libgthread-2.0-0.dll
-    qtcore4.dll
-    qtgui4.dll
-    qtnetwork4.dll
-    qtopengl4.dll
-    qtwebkit4.dll
-    qtxmlpatterns4.dll
     ssleay32.dll
     )
   copy_if_different(
@@ -479,63 +304,11 @@ if(WINDOWS)
     )
   set(plugin_test_targets ${plugin_test_targets} ${out_targets})
 
-  # Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins)
-  set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/imageformats")
-  set(plugintest_release_files
-    qgif4.dll
-    qico4.dll
-    qjpeg4.dll
-    qmng4.dll
-    qsvg4.dll
-    qtiff4.dll
-    )
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Release/imageformats"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/imageformats"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt codec plugins)
-  set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/codecs")
-  set(plugintest_release_files
-    qcncodecs4.dll  
-    qjpcodecs4.dll  
-    qkrcodecs4.dll  
-    qtwcodecs4.dll  
-    )
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/Release/codecs"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/codecs"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
- 
    add_custom_target(copy_plugintest_libs ALL
      DEPENDS 
      ${plugin_test_targets}
      )
 
-  add_dependencies(llmediaplugintest copy_plugintest_libs)
-
 endif(WINDOWS)
 
 if (DARWIN)
@@ -545,20 +318,6 @@ if (DARWIN)
     libaprutil-1.0.dylib
     libapr-1.0.dylib
     libexpat.1.5.2.dylib
-    libQtCore.4.7.1.dylib
-    libQtCore.4.dylib
-    libQtGui.4.7.1.dylib
-    libQtGui.4.dylib
-    libQtNetwork.4.7.1.dylib
-    libQtNetwork.4.dylib
-    libQtOpenGL.4.7.1.dylib
-    libQtOpenGL.4.dylib
-    libQtWebKit.4.7.1.dylib
-    libQtWebKit.4.dylib
-    libQtSvg.4.7.1.dylib
-    libQtSvg.4.dylib
-    libQtXml.4.7.1.dylib
-    libQtXml.4.dylib
     )
   copy_if_different(
     ${plugintest_release_src_dir}
@@ -568,46 +327,10 @@ if (DARWIN)
     )
   set(plugin_test_targets ${plugin_test_targets} ${out_targets})
 
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt image format plugins)
-  set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_PLUGINS}/imageformats")
-  set(plugintest_release_files
-    libqgif.dylib
-    libqico.dylib
-    libqjpeg.dylib
-    libqmng.dylib
-    libqsvg.dylib
-    libqtiff.dylib
-    )
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${PLUGINS_DESTINATION_DIR}/imageformats"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
-  # Release & ReleaseDebInfo config runtime files required for the FB connect test (Qt codec plugins)
-  set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_PLUGINS}/codecs")
-  set(plugintest_release_files
-    libqcncodecs.dylib
-    libqjpcodecs.dylib
-    libqkrcodecs.dylib
-    libqtwcodecs.dylib
-    )
-  copy_if_different(
-    ${plugintest_release_src_dir}
-    "${PLUGINS_DESTINATION_DIR}/codecs"
-    out_targets
-    ${plugintest_release_files}
-    )
-  set(plugin_test_targets ${plugin_test_targets} ${out_targets})
-
   add_custom_target(copy_plugintest_libs ALL
     DEPENDS 
     ${plugin_test_targets}
     )
 
-  add_dependencies(llmediaplugintest copy_plugintest_libs)
 endif (DARWIN)
 
-ll_deploy_sharedlibs_command(llmediaplugintest) 
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
deleted file mode 100755
index fa4f5abd284d8a2a683ba8aa7756c136a49c2782..0000000000000000000000000000000000000000
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ /dev/null
@@ -1,2377 +0,0 @@
-/**
- * @file LLMediaPluginTest.cpp
- * @brief Primary test application for LLMedia (Separate Process) Plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "indra_constants.h"
-
-#include "llapr.h"
-#include "llerrorcontrol.h"
-
-#include <math.h>
-#include <iomanip>
-#include <sstream>
-#include <ctime>
-
-#include "llmediaplugintest.h"
-
-
-#if LL_WINDOWS
-#pragma warning(disable: 4263)
-#pragma warning(disable: 4264)
-#endif
-
-#if __APPLE__
-	#include <GLUT/glut.h>
-	#include <CoreFoundation/CoreFoundation.h>
-#else
-	#define FREEGLUT_STATIC
-	#include "GL/freeglut.h"
-	#define GLUI_FREEGLUT
-#endif
-
-#include "glui.h"
-
-
-LLMediaPluginTest* gApplication = 0;
-static void gluiCallbackWrapper( int control_id );
-
-////////////////////////////////////////////////////////////////////////////////
-//
-static bool isTexture( GLuint texture )
-{
-	bool result = false;
-
-	// glIsTexture will sometimes return false for real textures... do this instead.
-	if(texture != 0)
-		result = true;
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel::mediaPanel()
-{
-	mMediaTextureHandle = 0;
-	mPickTextureHandle = 0;
-	mMediaSource = NULL;
-	mPickTexturePixels = NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel::~mediaPanel()
-{
-	// delete OpenGL texture handles
-	if ( isTexture( mPickTextureHandle ) )
-	{
-		std::cerr << "remMediaPanel: deleting pick texture " << mPickTextureHandle << std::endl;
-		glDeleteTextures( 1, &mPickTextureHandle );
-		mPickTextureHandle = 0;
-	}
-
-	if ( isTexture( mMediaTextureHandle ) )
-	{
-		std::cerr << "remMediaPanel: deleting media texture " << mMediaTextureHandle << std::endl;
-		glDeleteTextures( 1, &mMediaTextureHandle );
-		mMediaTextureHandle = 0;
-	}
-
-	if(mPickTexturePixels)
-	{
-		delete mPickTexturePixels;
-	}
-
-	if(mMediaSource)
-	{
-		delete mMediaSource;
-	}
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int window_height ) :
-	mVersionMajor( 2 ),
-	mVersionMinor( 0 ),
-	mVersionPatch( 0 ),
-	mMaxPanels( 25 ),
-	mViewportAspect( 0 ),
-	mAppWindow( app_window ),
-	mCurMouseX( 0 ),
-	mCurMouseY( 0 ),
-	mFuzzyMedia( true ),
-	mSelectedPanel( 0 ),
-	mDistanceCameraToSelectedGeometry( 0.0f ),
-	mMediaBrowserControlEnableCookies( 0 ),
-	mMediaBrowserControlBackButton( 0 ),
-	mMediaBrowserControlForwardButton( 0 ),
-	mMediaTimeControlVolume( 100 ),
-	mMediaTimeControlSeekSeconds( 0 ),
-	mGluiMediaTimeControlWindowFlag( true ),
-	mGluiMediaBrowserControlWindowFlag( true ),
-	mMediaBrowserControlBackButtonFlag( true ),
-	mMediaBrowserControlForwardButtonFlag( true ),
-	mHomeWebUrl( "http://www.google.com/" )
-{
-	// debugging spam
-	std::cout << std::endl << "             GLUT version: " << "3.7.6" << std::endl;	// no way to get real version from GLUT
-	std::cout << std::endl << "             GLUI version: " << GLUI_Master.get_version() << std::endl;
-	std::cout << std::endl << "Media Plugin Test version: " << mVersionMajor << "." << mVersionMinor << "." << mVersionPatch << std::endl;
-
-	// bookmark title
-	mBookmarks.push_back( std::pair< std::string, std::string >( "--- Bookmarks ---", "" ) );
-
-	// insert hardcoded URLs here as required for testing
-	//mBookmarks.push_back( std::pair< std::string, std::string >( "description", "url" ) );
-
-	// read bookmarks from file.
-	// note: uses command in ./CmakeLists.txt which copies bookmmarks file from source directory
-	//       to app directory (WITHOUT build configuration dir) (this is cwd in Windows within MSVC)
-	//		 For example, test_apps\llplugintest and not test_apps\llplugintest\Release
-	//		 This may need to be changed for Mac/Linux builds.
-	// See https://jira.lindenlab.com/browse/DEV-31350 for large list of media URLs from AGNI
-	const std::string bookmarks_filename( "bookmarks.txt" );
-	std::ifstream file_handle( bookmarks_filename.c_str() );
-	if ( file_handle.is_open() )
-	{
-		std::cout << "Reading bookmarks for test" << std::endl;
-		while( ! file_handle.eof() )
-		{
-			std::string line;
-			std::getline( file_handle, line );
-			if ( file_handle.eof() )
-				break;
-
-			if ( line.substr( 0, 1 ) != "#" )
-			{
-				size_t comma_pos = line.find_first_of( ',' );
-				if ( comma_pos != std::string::npos )
-				{
-					std::string description = line.substr( 0, comma_pos );
-					std::string url = line.substr( comma_pos + 1 );
-					mBookmarks.push_back( std::pair< std::string, std::string >( description, url ) );
-				}
-				else
-				{
-					mBookmarks.push_back( std::pair< std::string, std::string >( line, line ) );
-				};
-			};
-		};
-		std::cout << "Read " << mBookmarks.size() << " bookmarks" << std::endl;
-	}
-	else
-	{
-		std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;
-	};
-
-	// initialize linden lab APR module
-	ll_init_apr();
-
-	// Set up llerror logging
-	{
-		LLError::initForApplication(".");
-		LLError::setDefaultLevel(LLError::LEVEL_INFO);
-		//LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG);
-	}
-
-	// lots of randomness in this app
-	srand( ( unsigned int )time( 0 ) );
-
-	// build GUI
-	makeChrome();
-
-	// OpenGL initialilzation
-	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
-	glClearDepth( 1.0f );
-	glEnable( GL_DEPTH_TEST );
-	glEnable( GL_COLOR_MATERIAL );
-	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
-	glDepthFunc( GL_LEQUAL );
-	glEnable( GL_TEXTURE_2D );
-	glDisable( GL_BLEND );
-	glColor3f( 1.0f, 1.0f, 1.0f );
-	glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
-	glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
-
-	// start with a sane view
-	resetView();
-
-	// initial media panel
-	const int num_initial_panels = 1;
-	for( int i = 0; i < num_initial_panels; ++i )
-	{
-		//addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-		addMediaPanel( mHomeWebUrl );
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-LLMediaPluginTest::~LLMediaPluginTest()
-{
-	// delete all media panels
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		remMediaPanel( mMediaPanels[ i ] );
-	};
-	
-	// Stop the plugin read thread if it's running.
-	LLPluginProcessParent::setUseReadThread(false);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::reshape( int width, int height )
-{
-	// update viewport (the active window inside the chrome)
-	int viewport_x, viewport_y;
-	int viewport_height, viewport_width;
-	GLUI_Master.get_viewport_area( &viewport_x, &viewport_y, &viewport_width, &viewport_height );
-	mViewportAspect = (float)( viewport_width ) / (float)( viewport_height );
-	glViewport( viewport_x, viewport_y, viewport_width, viewport_height );
-
-	// save these as we'll need them later
-	mWindowWidth = width;
-	mWindowHeight = height;
-
-	// adjust size of URL bar so it doesn't get clipped
-	mUrlEdit->set_w( mWindowWidth - 360 );
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// trigger re-display
-	glutPostRedisplay();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::bindTexture(GLuint texture, GLint row_length, GLint alignment)
-{
-	glEnable( GL_TEXTURE_2D );
-
-	glBindTexture( GL_TEXTURE_2D, texture );
-	glPixelStorei( GL_UNPACK_ROW_LENGTH, row_length );
-	glPixelStorei( GL_UNPACK_ALIGNMENT, alignment );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool LLMediaPluginTest::checkGLError(const char *name)
-{
-	bool result = false;
-	GLenum error = glGetError();
-
-	if(error != GL_NO_ERROR)
-	{
-		// For some reason, glGenTextures is returning GL_INVALID_VALUE...
-		std::cout << name << " ERROR 0x" << std::hex << error << std::dec << std::endl;
-		result = true;
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-GLfloat LLMediaPluginTest::distanceToCamera( GLfloat point_x, GLfloat point_y, GLfloat point_z )
-{
-	GLdouble camera_pos_x = 0.0f;
-	GLdouble camera_pos_y = 0.0f;
-	GLdouble camera_pos_z = 0.0f;
-
-	GLdouble modelMatrix[16];
-	GLdouble projMatrix[16];
-	GLint viewport[4];
-
-	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
-	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
-	glGetIntegerv(GL_VIEWPORT, viewport);
-
-	gluUnProject(
-		(viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2,
-		0.0,
-		modelMatrix, projMatrix, viewport,
-		&camera_pos_x, &camera_pos_y, &camera_pos_z );
-
-	GLfloat distance =
-		sqrt( ( camera_pos_x - point_x ) * ( camera_pos_x - point_x ) +
-			  ( camera_pos_y - point_y ) * ( camera_pos_y - point_y ) +
-			  ( camera_pos_z - point_z ) * ( camera_pos_z - point_z ) );
-
-	return distance;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::drawGeometry( int panel, bool selected )
-{
-	// texture coordinates for each panel
-	GLfloat non_opengl_texture_coords[ 8 ] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
-	GLfloat opengl_texture_coords[ 8 ] =     { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
-
-	GLfloat *texture_coords = mMediaPanels[ panel ]->mAppTextureCoordsOpenGL?opengl_texture_coords:non_opengl_texture_coords;
-
-	// base coordinates for each panel
-	GLfloat base_vertex_pos[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
-
-	// calculate posiitons
-	const int num_panels = (int)mMediaPanels.size();
-	const int num_rows = (int)sqrt( (float)num_panels );
-	const int num_cols = num_panels / num_rows;
-	const int panel_x = ( panel / num_rows );
-	const int panel_y = ( panel % num_rows );
-
-	// default spacing is small - make it larger if checkbox set - for testing positional audio
-	float spacing = 0.1f;
-	if ( mLargePanelSpacing )
-		spacing = 2.0f;
-
-	const GLfloat offset_x = num_cols * ( 1.0 + spacing ) / 2;
-	const GLfloat offset_y = num_rows * ( 1.0 + spacing ) / 2;
-
-	// Adjust for media aspect ratios
-	{
-		float aspect = 1.0f;
-
-		if(mMediaPanels[ panel ]->mMediaHeight != 0)
-		{
-			aspect = (float)mMediaPanels[ panel ]->mMediaWidth / (float)mMediaPanels[ panel ]->mMediaHeight;
-		}
-
-		if(aspect > 1.0f)
-		{
-			// media is wider than it is high -- adjust the top and bottom in
-			for( int corner = 0; corner < 4; ++corner )
-			{
-				float temp = base_vertex_pos[corner * 2 + 1];
-
-				if(temp < 0.5f)
-					temp += 0.5 - (0.5f / aspect);
-				else
-					temp -= 0.5 - (0.5f / aspect);
-
-				base_vertex_pos[corner * 2 + 1] = temp;
-			}
-		}
-		else if(aspect < 1.0f)
-		{
-			// media is higher than it is wide -- adjust the left and right sides in
-			for( int corner = 0; corner < 4; ++corner )
-			{
-				float temp = base_vertex_pos[corner * 2];
-
-				if(temp < 0.5f)
-					temp += 0.5f - (0.5f * aspect);
-				else
-					temp -= 0.5f - (0.5f * aspect);
-
-				base_vertex_pos[corner * 2] = temp;
-			}
-		}
-	}
-
-	glBegin( GL_QUADS );
-	for( int corner = 0; corner < 4; ++corner )
-	{
-		glTexCoord2f( texture_coords[ corner * 2 ], texture_coords[ corner * 2 + 1 ] );
-		GLfloat x = base_vertex_pos[ corner * 2 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
-		GLfloat y = base_vertex_pos[ corner * 2 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
-
-		glVertex3f( x, y, 0.0f );
-	};
-	glEnd();
-
-	// calculate distance to this panel if it's selected
-	if ( selected )
-	{
-		GLfloat point_x = base_vertex_pos[ 0 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
-		GLfloat point_y = base_vertex_pos[ 0 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
-		GLfloat point_z = 0.0f;
-		mDistanceCameraToSelectedGeometry = distanceToCamera( point_x, point_y, point_z );
-	};
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::startPanelHighlight( float red, float green, float blue, float line_width )
-{
-	glPushAttrib( GL_ALL_ATTRIB_BITS );
-	glEnable( GL_POLYGON_OFFSET_FILL );
-	glPolygonOffset( -2.5f, -2.5f );
-	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
-	glLineWidth( line_width );
-	glColor3f( red, green, blue );
-	glDisable( GL_TEXTURE_2D );
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::endPanelHighlight()
-{
-	glPopAttrib();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::draw( int draw_type )
-{
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		// drawing pick texture
-		if ( draw_type == DrawTypePickTexture )
-		{
-			// only bother with pick if we have something to render
-			// Actually, we need to pick even if we're not ready to render.
-			// Otherwise you can't select and remove a panel which has gone bad.
-			//if ( mMediaPanels[ panel ]->mReadyToRender )
-			{
-				glMatrixMode( GL_TEXTURE );
-				glPushMatrix();
-
-				// pick texture is a power of 2 so no need to scale
-				glLoadIdentity();
-
-				// bind to media texture
-				glLoadIdentity();
-				bindTexture( mMediaPanels[ panel ]->mPickTextureHandle );
-				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-
-				// draw geometry using pick texture
-				drawGeometry( panel, false );
-
-				glMatrixMode( GL_TEXTURE );
-				glPopMatrix();
-			};
-		}
-		else
-		if ( draw_type == DrawTypeMediaTexture )
-		{
-			bool texture_valid = false;
-			bool plugin_exited = false;
-
-			if(mMediaPanels[ panel ]->mMediaSource)
-			{
-				texture_valid = mMediaPanels[ panel ]->mMediaSource->textureValid();
-				plugin_exited = mMediaPanels[ panel ]->mMediaSource->isPluginExited();
-			}
-
-			// save texture matrix (changes for each panel)
-			glMatrixMode( GL_TEXTURE );
-			glPushMatrix();
-
-			// only process texture if the media is ready to draw
-			// (we still want to draw the geometry)
-			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
-			{
-				// bind to media texture
-				bindTexture( mMediaPanels[ panel ]->mMediaTextureHandle );
-
-				if ( mFuzzyMedia )
-				{
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-				}
-				else
-				{
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-				}
-
-				// scale to fit panel
-				glScalef( mMediaPanels[ panel ]->mTextureScaleX,
-							mMediaPanels[ panel ]->mTextureScaleY,
-								1.0f );
-			};
-
-			float intensity = plugin_exited?0.25f:1.0f;
-
-			// highlight the selected panel
-			if ( mSelectedPanel && ( mMediaPanels[ panel ]->mId == mSelectedPanel->mId ) )
-			{
-				startPanelHighlight( intensity, intensity, 0.0f, 5.0f );
-				drawGeometry( panel, true );
-				endPanelHighlight();
-			}
-			else
-			// this panel not able to render yet since it
-			// doesn't have enough information
-			if ( !mMediaPanels[ panel ]->mReadyToRender )
-			{
-				startPanelHighlight( intensity, 0.0f, 0.0f, 2.0f );
-				drawGeometry( panel, false );
-				endPanelHighlight();
-			}
-			else
-			// just display a border around the media
-			{
-				startPanelHighlight( 0.0f, intensity, 0.0f, 2.0f );
-				drawGeometry( panel, false );
-				endPanelHighlight();
-			};
-
-			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
-			{
-				// draw visual geometry
-				drawGeometry( panel, false );
-			}
-
-			// restore texture matrix (changes for each panel)
-			glMatrixMode( GL_TEXTURE );
-			glPopMatrix();
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::display()
-{
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// start with a clean slate
-	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
-	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-	// set up OpenGL view
-	glMatrixMode( GL_PROJECTION );
-	glLoadIdentity();
-	glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f );
-	glMatrixMode( GL_MODELVIEW );
-	glLoadIdentity();
-	glTranslatef( 0.0, 0.0, 0.0f );
-	glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] );
-	glMultMatrixf( mViewRotation );
-
-	// draw pick texture
-	draw( DrawTypePickTexture );
-
-	// read colors and get coordinate values
-	glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelReadColor );
-
-	// clear the pick render (otherwise it may depth-fight with the textures rendered later)
-	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-	// draw visible geometry
-	draw( DrawTypeMediaTexture );
-
-	glutSwapBuffers();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::idle()
-{
-//	checkGLError("LLMediaPluginTest::idle");
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// random creation/destruction of panels enabled?
-	const time_t panel_timeout_time = 5;
-	if ( mRandomPanelCount )
-	{
-		// time for a change
-		static time_t last_panel_time = 0;
-		if ( time( NULL ) - last_panel_time > panel_timeout_time )
-		{
-			if ( rand() % 2 == 0 )
-			{
-				if ( mMediaPanels.size() < 16 )
-				{
-					std::cout << "Randomly adding new panel" << std::endl;
-					addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-				};
-			}
-			else
-			{
-				if ( mMediaPanels.size() > 0 )
-				{
-					std::cout << "Deleting selected panel" << std::endl;
-					remMediaPanel( mSelectedPanel );
-				};
-			};
-			time( &last_panel_time );
-		};
-	};
-
-	// random selection of bookmarks enabled?
-	const time_t bookmark_timeout_time = 5;
-	if ( mRandomBookmarks )
-	{
-		// time for a change
-		static time_t last_bookmark_time = 0;
-		if ( time( NULL ) - last_bookmark_time > bookmark_timeout_time )
-		{
-			// go to a different random bookmark on each panel
-			for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-			{
-				std::string uri = mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second;
-
-				std::cout << "Random: navigating to : " << uri << std::endl;
-
-				std::string mime_type = mimeTypeFromUrl( uri );
-
-				if ( mime_type != mMediaPanels[ panel ]->mMimeType )
-				{
-					replaceMediaPanel( mMediaPanels[ panel ], uri );
-				}
-				else
-				{
-					mMediaPanels[ panel ]->mMediaSource->loadURI( uri );
-					mMediaPanels[ panel ]->mMediaSource->start();
-				};
-			};
-
-			time( &last_bookmark_time );
-		};
-	};
-
-	// update UI
-	if ( mSelectedPanel )
-	{
-		// set volume based on slider if we have time media
-		//if ( mGluiMediaTimeControlWindowFlag )
-		//{
-		//	mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
-		//};
-
-		// NOTE: it is absurd that we need cache the state of GLUI controls
-		//       but enabling/disabling controls drags framerate from 500+
-		//		 down to 15. Not a problem for plugin system - only this test
-		// enable/disable time based UI controls based on type of plugin
-		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-		{
-			if ( ! mGluiMediaTimeControlWindowFlag )
-			{
-				mGluiMediaTimeControlWindow->enable();
-				mGluiMediaTimeControlWindowFlag = true;
-			};
-		}
-		else
-		{
-			if ( mGluiMediaTimeControlWindowFlag )
-			{
-				mGluiMediaTimeControlWindow->disable();
-				mGluiMediaTimeControlWindowFlag = false;
-			};
-		};
-
-		// enable/disable browser based UI controls based on type of plugin
-		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
-		{
-			if ( ! mGluiMediaBrowserControlWindowFlag )
-			{
-				mGluiMediaBrowserControlWindow->enable();
-				mGluiMediaBrowserControlWindowFlag = true;
-			};
-		}
-		else
-		{
-			if ( mGluiMediaBrowserControlWindowFlag )
-			{
-				mGluiMediaBrowserControlWindow->disable();
-				mGluiMediaBrowserControlWindowFlag = false;
-			};
-		};
-
-		// enable/disable browser back button depending on browser history
-		if ( mSelectedPanel->mMediaSource->getHistoryBackAvailable()  )
-		{
-			if ( ! mMediaBrowserControlBackButtonFlag )
-			{
-				mMediaBrowserControlBackButton->enable();
-				mMediaBrowserControlBackButtonFlag = true;
-			};
-		}
-		else
-		{
-			if ( mMediaBrowserControlBackButtonFlag )
-			{
-				mMediaBrowserControlBackButton->disable();
-				mMediaBrowserControlBackButtonFlag = false;
-			};
-		};
-
-		// enable/disable browser forward button depending on browser history
-		if ( mSelectedPanel->mMediaSource->getHistoryForwardAvailable()  )
-		{
-			if ( ! mMediaBrowserControlForwardButtonFlag )
-			{
-				mMediaBrowserControlForwardButton->enable();
-				mMediaBrowserControlForwardButtonFlag = true;
-			};
-		}
-		else
-		{
-			if ( mMediaBrowserControlForwardButtonFlag )
-			{
-				mMediaBrowserControlForwardButton->disable();
-				mMediaBrowserControlForwardButtonFlag = false;
-			};
-		};
-
-		// NOTE: This is *very* slow and not worth optimising
-		updateStatusBar();
-	};
-
-	// update all the panels
-	for( int panel_index = 0; panel_index < (int)mMediaPanels.size(); ++panel_index )
-	{
-		mediaPanel *panel = mMediaPanels[ panel_index ];
-
-		// call plugins idle function so it can potentially update itself
-		panel->mMediaSource->idle();
-
-		// update each media panel
-		updateMediaPanel( panel );
-
-		LLRect dirty_rect;
-		if ( ! panel->mMediaSource->textureValid() )
-		{
-			//std::cout << "texture invalid, skipping update..." << std::endl;
-		}
-		else
-		if ( panel &&
-			 ( panel->mMediaWidth != panel->mMediaSource->getWidth() ||
-			   panel->mMediaHeight != panel->mMediaSource->getHeight() ) )
-		{
-			//std::cout << "Resize in progress, skipping update..." << std::endl;
-		}
-		else
-		if ( panel->mMediaSource->getDirty( &dirty_rect ) )
-		{
-			const unsigned char* pixels = panel->mMediaSource->getBitsData();
-			if ( pixels && isTexture(panel->mMediaTextureHandle))
-			{
-				int x_offset = dirty_rect.mLeft;
-				int y_offset = dirty_rect.mBottom;
-				int width = dirty_rect.mRight - dirty_rect.mLeft;
-				int height = dirty_rect.mTop - dirty_rect.mBottom;
-
-				if((dirty_rect.mRight <= panel->mTextureWidth) && (dirty_rect.mTop <= panel->mTextureHeight))
-				{
-					// Offset the pixels pointer properly
-					pixels += ( y_offset * panel->mMediaSource->getTextureDepth() * panel->mMediaSource->getBitsWidth() );
-					pixels += ( x_offset * panel->mMediaSource->getTextureDepth() );
-
-					// set up texture
-					bindTexture( panel->mMediaTextureHandle, panel->mMediaSource->getBitsWidth() );
-					if ( mFuzzyMedia )
-					{
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-					}
-					else
-					{
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
-						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-					};
-
-					checkGLError("glTexParameteri");
-
-					if(panel->mMediaSource->getTextureFormatSwapBytes())
-					{
-						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-						checkGLError("glPixelStorei");
-					}
-
-					// draw portion that changes into texture
-					glTexSubImage2D( GL_TEXTURE_2D, 0,
-						x_offset,
-						y_offset,
-						width,
-						height,
-						panel->mMediaSource->getTextureFormatPrimary(),
-						panel->mMediaSource->getTextureFormatType(),
-						pixels );
-
-					if(checkGLError("glTexSubImage2D"))
-					{
-						std::cerr << "    panel ID=" << panel->mId << std::endl;
-						std::cerr << "    texture size = " << panel->mTextureWidth << " x " << panel->mTextureHeight << std::endl;
-						std::cerr << "    media size = " << panel->mMediaWidth << " x " << panel->mMediaHeight << std::endl;
-						std::cerr << "    dirty rect = " << dirty_rect.mLeft << ", " << dirty_rect.mBottom << ", " << dirty_rect.mRight << ", " << dirty_rect.mTop << std::endl;
-						std::cerr << "    texture width = " << panel->mMediaSource->getBitsWidth() << std::endl;
-						std::cerr << "    format primary = 0x" << std::hex << panel->mMediaSource->getTextureFormatPrimary() << std::dec << std::endl;
-						std::cerr << "    format type = 0x" << std::hex << panel->mMediaSource->getTextureFormatType() << std::dec << std::endl;
-						std::cerr << "    pixels = " << (void*)pixels << std::endl;
-					}
-
-					if(panel->mMediaSource->getTextureFormatSwapBytes())
-					{
-						glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-						checkGLError("glPixelStorei");
-					}
-
-					panel->mMediaSource->resetDirty();
-
-					panel->mReadyToRender = true;
-				}
-				else
-				{
-					std::cerr << "dirty rect is outside current media size, skipping update" << std::endl;
-				}
-			};
-		};
-	};
-
-	// GLUI requires this
-	if ( glutGetWindow() != mAppWindow )
-		glutSetWindow( mAppWindow );
-
-	// trigger re-display
-	glutPostRedisplay();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::windowPosToTexturePos( int window_x, int window_y,
-											   int& media_x, int& media_y,
-											   int& id )
-{
-	if ( ! mSelectedPanel )
-	{
-		media_x = 0;
-		media_y = 0;
-		id = 0;
-		return;
-	};
-
-	// record cursor poisiton for a readback next frame
-	mCurMouseX = window_x;
-	// OpenGL app == coordinate system this way
-	// NOTE: unrelated to settings in plugin - this
-	// is just for this app
-	mCurMouseY = mWindowHeight - window_y;
-
-	// extract x (0..1023, y (0..1023) and id (0..15) from RGB components
-	unsigned long pixel_read_color_bits = ( mPixelReadColor[ 0 ] << 16 ) | ( mPixelReadColor[ 1 ] << 8 ) | mPixelReadColor[ 2 ];
-	int texture_x = pixel_read_color_bits & 0x3ff;
-	int texture_y = ( pixel_read_color_bits >> 10 ) & 0x3ff;
-	id = ( pixel_read_color_bits >> 20 ) & 0x0f;
-
-	// scale to size of media (1024 because we use 10 bits for X and Y from 24)
-	media_x = (int)( ( (float)mSelectedPanel->mMediaWidth * (float)texture_x ) / 1024.0f );
-	media_y = (int)( ( (float)mSelectedPanel->mMediaHeight * (float)texture_y ) / 1024.0f );
-
-	// we assume the plugin uses an inverted coordinate scheme like OpenGL
-	// if not, the plugin code inverts the Y coordinate for us - we don't need to
-	media_y = mSelectedPanel->mMediaHeight - media_y;
-
-	if ( media_x > 0 && media_y > 0 )
-	{
-		//std::cout << "      mouse coords: " << mCurMouseX << " x " << mCurMouseY << " and id = " << id  << std::endl;
-		//std::cout << "raw texture coords: " << texture_x << " x " << texture_y << " and id = " << id  << std::endl;
-		//std::cout << "      media coords: " << media_x << " x " << media_y << " and id = " << id  << std::endl;
-		//std::cout << std::endl;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::selectPanelById( int id )
-{
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mId == id )
-		{
-			selectPanel(mMediaPanels[ panel ]);
-			return;
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::selectPanel( mediaPanel* panel )
-{
-	if( mSelectedPanel == panel )
-		return;
-
-	// turn off volume before we delete it
-	if( mSelectedPanel && mSelectedPanel->mMediaSource )
-	{
-		mSelectedPanel->mMediaSource->setVolume( 0.0f );
-		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_LOW );
-	};
-
-	mSelectedPanel = panel;
-
-	if( mSelectedPanel && mSelectedPanel->mMediaSource )
-	{
-		mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
-		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_NORMAL );
-
-		if(!mSelectedPanel->mStartUrl.empty())
-		{
-			mUrlEdit->set_text(const_cast<char*>(mSelectedPanel->mStartUrl.c_str()) );
-		}
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel*  LLMediaPluginTest::findMediaPanel( LLPluginClassMedia* source )
-{
-	mediaPanel *result = NULL;
-
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mMediaSource == source )
-		{
-			result = mMediaPanels[ panel ];
-		}
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLMediaPluginTest::findMediaPanel( const std::string &target_name )
-{
-	mediaPanel *result = NULL;
-
-	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
-	{
-		if ( mMediaPanels[ panel ]->mTarget == target_name )
-		{
-			result = mMediaPanels[ panel ];
-		}
-	}
-
-	return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::navigateToNewURI( std::string uri )
-{
-	if ( uri.length() )
-	{
-		std::string mime_type = mimeTypeFromUrl( uri );
-
-		if ( !mSelectedPanel->mMediaSource->isPluginExited() && (mime_type == mSelectedPanel->mMimeType) )
-		{
-			std::cout << "MIME type is the same" << std::endl;
-			mSelectedPanel->mMediaSource->loadURI( uri );
-			mSelectedPanel->mMediaSource->start();
-			mBookmarkList->do_selection( 0 );
-		}
-		else
-		{
-			std::cout << "MIME type changed or plugin had exited" << std::endl;
-			replaceMediaPanel( mSelectedPanel, uri );
-			mBookmarkList->do_selection( 0 );
-		}
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::initUrlHistory( std::string uris )
-{
-	if ( uris.length() > 0 )
-	{
-		std::cout << "init URL : " << uris << std::endl;
-		LLSD historySD;
-
-		char *cstr, *p;
-		cstr = new char[uris.size()+1];
-		strcpy(cstr, uris.c_str());
-		const char *DELIMS = " ,;";
-		p = strtok(cstr, DELIMS);
-		while (p != NULL) {
-			historySD.insert(0, p);
-			p = strtok(NULL, DELIMS);
-		}
-		mSelectedPanel->mMediaSource->initializeUrlHistory(historySD);
-		delete[] cstr;
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::gluiCallback( int control_id )
-{
-	if ( control_id == mIdBookmarks )
-	{
-		std::string uri = mBookmarks[ mSelBookmark ].second;
-
-		navigateToNewURI( uri );
-	}
-	else
-    if ( control_id == mIdUrlEdit)
-	{
-		std::string uri = mUrlEdit->get_text();
-
-		navigateToNewURI( uri );
-	}
-	else
-	if ( control_id == mIdUrlInitHistoryEdit )
-	{
-		std::string uri = mUrlInitHistoryEdit->get_text();
-
-		initUrlHistory( uri );
-	}
-	else
-	if ( control_id == mIdControlAddPanel )
-	{
-		addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-	}
-	else
-	if ( control_id == mIdControlRemPanel )
-	{
-		remMediaPanel( mSelectedPanel );
-	}
-	else
-	if ( control_id == mIdDisableTimeout )
-	{
-		// Set the "disable timeout" flag for all active plugins.
-		for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-		{
-			mMediaPanels[ i ]->mMediaSource->setDisableTimeout(mDisableTimeout);
-		}
-	}
-	else
-	if ( control_id == mIdUsePluginReadThread )
-	{
-		LLPluginProcessParent::setUseReadThread(mUsePluginReadThread);
-	}
-	else
-	if ( control_id == mIdControlCrashPlugin )
-	{
-		// send message to plugin and ask it to crash
-		// (switch out for ReleaseCandidate version :) )
-		if(mSelectedPanel && mSelectedPanel->mMediaSource)
-		{
-			mSelectedPanel->mMediaSource->crashPlugin();
-		}
-	}
-	else
-	if ( control_id == mIdControlHangPlugin )
-	{
-		// send message to plugin and ask it to hang
-		// (switch out for ReleaseCandidate version :) )
-		if(mSelectedPanel && mSelectedPanel->mMediaSource)
-		{
-			mSelectedPanel->mMediaSource->hangPlugin();
-		}
-	}
-	else
-	if ( control_id == mIdControlExitApp )
-	{
-		// text for exiting plugin system cleanly
-		delete this;	// clean up
-		exit( 0 );
-	}
-	else
-	if ( control_id == mIdMediaTimeControlPlay )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlLoop )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( true );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlPause )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->pause();
-	}
-	else
-	if ( control_id == mIdMediaTimeControlStop )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->stop();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlSeek )
-	{
-		if ( mSelectedPanel )
-		{
-			// get value from spinner
-			float seconds_to_seek = mMediaTimeControlSeekSeconds;
-			mSelectedPanel->mMediaSource->seek( seconds_to_seek );
-			mSelectedPanel->mMediaSource->start();
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlRewind )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start(-2.0f);
-		};
-	}
-	else
-	if ( control_id == mIdMediaTimeControlFastForward )
-	{
-		if ( mSelectedPanel )
-		{
-			mSelectedPanel->mMediaSource->setLoop( false );
-			mSelectedPanel->mMediaSource->start(2.0f);
-		};
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlBack )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_back();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlStop )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_stop();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlForward )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_forward();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlHome )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->loadURI( mHomeWebUrl );
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlReload )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->browse_reload( true );
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlClearCache )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->clear_cache();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlClearCookies )
-	{
-		if ( mSelectedPanel )
-			mSelectedPanel->mMediaSource->clear_cookies();
-	}
-	else
-	if ( control_id == mIdMediaBrowserControlEnableCookies )
-	{
-		if ( mSelectedPanel )
-		{
-			if ( mMediaBrowserControlEnableCookies )
-			{
-				mSelectedPanel->mMediaSource->enable_cookies( true );
-			}
-			else
-			{
-				mSelectedPanel->mMediaSource->enable_cookies( false );
-			}
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::keyboard( int key )
-{
-	//if ( key == 'a' || key == 'A' )
-	//	addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
-	//else
-	//if ( key == 'r' || key == 'R' )
-	//	remMediaPanel( mSelectedPanel );
-	//else
-	//if ( key == 'd' || key == 'D' )
-	//	dumpPanelInfo();
-	//else
-	if ( key == 27 )
-	{
-		std::cout << "Application finished - exiting..." << std::endl;
-		delete this;
-		exit( 0 );
-	};
-
-	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 , LLSD());
-	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0, LLSD());
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::mouseButton( int button, int state, int x, int y )
-{
-	if ( button == GLUT_LEFT_BUTTON )
-	{
-		if ( state == GLUT_DOWN )
-		{
-			int media_x, media_y, id;
-			windowPosToTexturePos( x, y, media_x, media_y, id );
-
-			if ( mSelectedPanel )
-				mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_DOWN, 0, media_x, media_y, 0 );
-		}
-		else
-		if ( state == GLUT_UP )
-		{
-			int media_x, media_y, id;
-			windowPosToTexturePos( x, y, media_x, media_y, id );
-
-			// only select a panel if we're on a panel
-			// (HACK: strictly speaking this rules out clicking on
-			// the origin of a panel but that's very unlikely)
-			if ( media_x > 0 && media_y > 0 )
-			{
-				selectPanelById( id );
-
-				if ( mSelectedPanel )
-					mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_UP, 0, media_x, media_y, 0 );
-			};
-		};
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::mousePassive( int x, int y )
-{
-	int media_x, media_y, id;
-	windowPosToTexturePos( x, y, media_x, media_y, id );
-
-	if ( mSelectedPanel )
-		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::mouseMove( int x, int y )
-{
-	int media_x, media_y, id;
-	windowPosToTexturePos( x, y, media_x, media_y, id );
-
-	if ( mSelectedPanel )
-		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::makeChrome()
-{
-	// IDs used by GLUI
-	int start_id = 0x1000;
-
-	// right side window - geometry manipulators
-#if __APPLE__
-	// the Apple GLUT implementation doesn't seem to set the graphic offset of subwindows correctly when they overlap in certain ways.
-	// Use a separate controls window in this case.
-	// GLUI window at right containing manipulation controls and other buttons
-	int x = glutGet(GLUT_WINDOW_X) + glutGet(GLUT_WINDOW_WIDTH) + 4;
-	int y = glutGet(GLUT_WINDOW_Y);
-	GLUI* right_glui_window = GLUI_Master.create_glui( "", 0, x, y );
-#else
-	GLUI* right_glui_window = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT );
-#endif
-	mViewRotationCtrl = right_glui_window->add_rotation( "Rotation", mViewRotation );
-	mViewTranslationCtrl = right_glui_window->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos );
-	mViewTranslationCtrl->set_speed( 0.01f );
-	mViewScaleCtrl = right_glui_window->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] );
-	mViewScaleCtrl->set_speed( 0.05f );
-	right_glui_window->set_main_gfx_window( mAppWindow );
-
-	// right side window - app controls
-	mIdControlAddPanel = start_id++;
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_button( "Add panel", mIdControlAddPanel, gluiCallbackWrapper );
-	right_glui_window->add_statictext( "" );
-	mIdControlRemPanel = start_id++;
-	right_glui_window->add_button( "Rem panel", mIdControlRemPanel, gluiCallbackWrapper );
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	mIdControlCrashPlugin = start_id++;
-	right_glui_window->add_button( "Crash plugin", mIdControlCrashPlugin, gluiCallbackWrapper );
-	mIdControlHangPlugin = start_id++;
-	right_glui_window->add_button( "Hang plugin", mIdControlHangPlugin, gluiCallbackWrapper );
-
-	right_glui_window->add_statictext( "" );
-	right_glui_window->add_separator();
-	right_glui_window->add_statictext( "" );
-	mIdControlExitApp = start_id++;
-	right_glui_window->add_button( "Exit app", mIdControlExitApp, gluiCallbackWrapper );
-
-	//// top window - holds bookmark UI
-	mIdBookmarks = start_id++;
-	mSelBookmark = 0;
-	GLUI* glui_window_top = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mBookmarkList = glui_window_top->add_listbox( "", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper );
-	// only add the first 50 bookmarks - list can be very long sometimes (30,000+)
-	// when testing list of media URLs from AGNI for example
-	for( unsigned int each = 0; each < mBookmarks.size() && each < 50; ++each )
-		mBookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) );
-	glui_window_top->set_main_gfx_window( mAppWindow );
-
-	glui_window_top->add_column( false );
-	mIdUrlEdit = start_id++;
-	mUrlEdit = glui_window_top->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, 0, mIdUrlEdit, gluiCallbackWrapper );
-	mUrlEdit->set_w( 600 );
-	GLUI* glui_window_top2 = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mIdUrlInitHistoryEdit = start_id++;
-	mUrlInitHistoryEdit = glui_window_top2->add_edittext( "Init History (separate by commas or semicolons):",
-		GLUI_EDITTEXT_TEXT, 0, mIdUrlInitHistoryEdit, gluiCallbackWrapper );
-	mUrlInitHistoryEdit->set_w( 800 );
-
-	// top window - media controls for "time" media types (e.g. movies)
-	mGluiMediaTimeControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mGluiMediaTimeControlWindow->set_main_gfx_window( mAppWindow );
-	mIdMediaTimeControlPlay = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "PLAY", mIdMediaTimeControlPlay, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlLoop = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "LOOP", mIdMediaTimeControlLoop, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlPause = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "PAUSE", mIdMediaTimeControlPause, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-
-	GLUI_Button  *button;
-	mIdMediaTimeControlRewind = start_id++;
-	button = mGluiMediaTimeControlWindow->add_button( "<<", mIdMediaTimeControlRewind, gluiCallbackWrapper );
-	button->set_w(30);
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlFastForward = start_id++;
-	button = mGluiMediaTimeControlWindow->add_button( ">>", mIdMediaTimeControlFastForward, gluiCallbackWrapper );
-	button->set_w(30);
-
-	mGluiMediaTimeControlWindow->add_column( true );
-
-	mIdMediaTimeControlStop = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "STOP", mIdMediaTimeControlStop, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlVolume = start_id++;
-	GLUI_Spinner* spinner = mGluiMediaTimeControlWindow->add_spinner( "Volume", 2, &mMediaTimeControlVolume, mIdMediaTimeControlVolume, gluiCallbackWrapper);
-	spinner->set_float_limits( 0, 100 );
-	mGluiMediaTimeControlWindow->add_column( true );
-	mIdMediaTimeControlSeekSeconds = start_id++;
-	spinner = mGluiMediaTimeControlWindow->add_spinner( "", 2, &mMediaTimeControlSeekSeconds, mIdMediaTimeControlSeekSeconds, gluiCallbackWrapper);
-	spinner->set_float_limits( 0, 200 );
-	spinner->set_w( 32 );
-	spinner->set_speed( 0.025f );
-	mGluiMediaTimeControlWindow->add_column( false );
-	mIdMediaTimeControlSeek = start_id++;
-	mGluiMediaTimeControlWindow->add_button( "SEEK", mIdMediaTimeControlSeek, gluiCallbackWrapper );
-	mGluiMediaTimeControlWindow->add_column( false );
-
-
-	// top window - media controls for "browser" media types (e.g. web browser)
-	mGluiMediaBrowserControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mGluiMediaBrowserControlWindow->set_main_gfx_window( mAppWindow );
-	mIdMediaBrowserControlBack = start_id++;
-	mMediaBrowserControlBackButton = mGluiMediaBrowserControlWindow->add_button( "BACK", mIdMediaBrowserControlBack, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlStop = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "STOP", mIdMediaBrowserControlStop, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlForward = start_id++;
-	mMediaBrowserControlForwardButton = mGluiMediaBrowserControlWindow->add_button( "FORWARD", mIdMediaBrowserControlForward, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlHome = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "HOME", mIdMediaBrowserControlHome, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlReload = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "RELOAD", mIdMediaBrowserControlReload, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlClearCache = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "CLEAR CACHE", mIdMediaBrowserControlClearCache, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlClearCookies = start_id++;
-	mGluiMediaBrowserControlWindow->add_button( "CLEAR COOKIES", mIdMediaBrowserControlClearCookies, gluiCallbackWrapper );
-	mGluiMediaBrowserControlWindow->add_column( false );
-	mIdMediaBrowserControlEnableCookies = start_id++;
-	mMediaBrowserControlEnableCookies = 0;
-	mGluiMediaBrowserControlWindow->add_checkbox( "Enable Cookies", &mMediaBrowserControlEnableCookies, mIdMediaBrowserControlEnableCookies, gluiCallbackWrapper );
-
-	// top window - misc controls
-	GLUI* glui_window_misc_control = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
-	mIdRandomPanelCount = start_id++;
-	mRandomPanelCount = 0;
-	glui_window_misc_control->add_checkbox( "Randomize panel count", &mRandomPanelCount, mIdRandomPanelCount, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-	mIdRandomBookmarks = start_id++;
-	mRandomBookmarks = 0;
-	glui_window_misc_control->add_checkbox( "Randomize bookmarks", &mRandomBookmarks, mIdRandomBookmarks, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdDisableTimeout = start_id++;
-	mDisableTimeout = 0;
-	glui_window_misc_control->add_checkbox( "Disable plugin timeout", &mDisableTimeout, mIdDisableTimeout, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdUsePluginReadThread = start_id++;
-	mUsePluginReadThread = 0;
-	glui_window_misc_control->add_checkbox( "Use plugin read thread", &mUsePluginReadThread, mIdUsePluginReadThread, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	mIdLargePanelSpacing = start_id++;
-	mLargePanelSpacing = 0;
-	glui_window_misc_control->add_checkbox( "Large Panel Spacing", &mLargePanelSpacing, mIdLargePanelSpacing, gluiCallbackWrapper );
-	glui_window_misc_control->set_main_gfx_window( mAppWindow );
-	glui_window_misc_control->add_column( true );
-
-	// bottom window - status
-	mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM );
-	mStatusText = mBottomGLUIWindow->add_statictext( "" );
-	mBottomGLUIWindow->set_main_gfx_window( mAppWindow );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::resetView()
-{
-	mViewRotationCtrl->reset();
-
-	mViewScaleCtrl->set_x( 0.0f );
-	mViewScaleCtrl->set_y( 0.0f );
-	mViewScaleCtrl->set_z( 3.0f );
-
-	mViewTranslationCtrl->set_x( 0.0f );
-	mViewTranslationCtrl->set_y( 0.0f );
-	mViewTranslationCtrl->set_z( 0.0f );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels )
-{
-	int pick_texture_width = 1024;
-	int pick_texture_height = 1024;
-	int pick_texture_depth = 3;
-	unsigned char* ptr = new unsigned char[ pick_texture_width * pick_texture_height * pick_texture_depth ];
-	for( int y = 0; y < pick_texture_height; ++y )
-	{
-		for( int x = 0; x < pick_texture_width * pick_texture_depth ; x += pick_texture_depth )
-		{
-			unsigned long bits = 0L;
-			bits |= ( id << 20 ) | ( y << 10 ) | ( x / 3 );
-			unsigned char r_component = ( bits >> 16 ) & 0xff;
-			unsigned char g_component = ( bits >> 8 ) & 0xff;
-			unsigned char b_component = bits & 0xff;
-
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 0 ] = r_component;
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 1 ] = g_component;
-			ptr[ y * pick_texture_width * pick_texture_depth + x + 2 ] = b_component;
-		};
-	};
-
-	glGenTextures( 1, texture_handle );
-
-	checkGLError("glGenTextures");
-	std::cout << "glGenTextures returned " << *texture_handle << std::endl;
-
-	bindTexture( *texture_handle );
-	glTexImage2D( GL_TEXTURE_2D, 0,
-					GL_RGB,
-						pick_texture_width, pick_texture_height,
-							0, GL_RGB, GL_UNSIGNED_BYTE, ptr );
-
-	*texture_pixels = ptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-std::string LLMediaPluginTest::mimeTypeFromUrl( std::string& url )
-{
-	// default to web
-	std::string mime_type = "text/html";
-
-	// we may need a more advanced MIME type accessor later :-)
-	if ( url.find( ".mov" ) != std::string::npos )	// Movies
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( ".txt" ) != std::string::npos )	// Apple Text descriptors
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( ".mp3" ) != std::string::npos )	// Apple Text descriptors
-		mime_type = "video/quicktime";
-	else
-	if ( url.find( "example://" ) != std::string::npos )	// Example plugin
-		mime_type = "example/example";
-
-	return mime_type;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-std::string LLMediaPluginTest::pluginNameFromMimeType( std::string& mime_type )
-{
-#if LL_DARWIN
-	std::string plugin_name( "media_plugin_null.dylib" );
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "media_plugin_quicktime.dylib";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "media_plugin_webkit.dylib";
-
-#elif LL_WINDOWS
-	std::string plugin_name( "media_plugin_null.dll" );
-
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "media_plugin_quicktime.dll";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "media_plugin_webkit.dll";
-	else
-	if ( mime_type == "example/example" )
-		plugin_name = "media_plugin_example.dll";
-
-#elif LL_LINUX
-	std::string plugin_name( "libmedia_plugin_null.so" );
-
-	if ( mime_type == "video/quicktime" )
-		plugin_name = "libmedia_plugin_quicktime.so";
-	else
-	if ( mime_type == "text/html" )
-		plugin_name = "libmedia_plugin_webkit.so";
-#endif
-	return plugin_name;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLMediaPluginTest::addMediaPanel( std::string url )
-{
-	// Get the plugin filename using the URL
-	std::string mime_type = mimeTypeFromUrl( url );
-	std::string plugin_name = pluginNameFromMimeType( mime_type );
-
-	// create a random size for the new media
-	int media_width;
-	int media_height;
-	getRandomMediaSize( media_width, media_height, mime_type );
-
-	// make a new plugin
-	LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
-
-	// tell the plugin what size we asked for
-	media_source->setSize( media_width, media_height );
-
-	// Use the launcher start and initialize the plugin
-#if LL_DARWIN || LL_LINUX
-	std::string launcher_name( "SLPlugin" );
-#elif LL_WINDOWS
-	std::string launcher_name( "SLPlugin.exe" );
-#endif
-
-	// for this test app, use the cwd as the user data path (ugh).
-#if LL_WINDOWS
-	std::string user_data_path = ".\\";
-#else
-        char cwd[ FILENAME_MAX ];
-	if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-	{
-		std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
-		return NULL;
-	}
-	std::string user_data_path = std::string( cwd ) + "/";
-#endif
-	media_source->setUserDataPath(user_data_path);
-	media_source->init( launcher_name, user_data_path, plugin_name, false );
-	media_source->setDisableTimeout(mDisableTimeout);
-
-	// make a new panel and save parameters
-	mediaPanel* panel = new mediaPanel;
-	panel->mMediaSource = media_source;
-	panel->mStartUrl = url;
-	panel->mMimeType = mime_type;
-	panel->mMediaWidth = media_width;
-	panel->mMediaHeight = media_height;
-	panel->mTextureWidth = 0;
-	panel->mTextureHeight = 0;
-	panel->mTextureScaleX = 0;
-	panel->mTextureScaleY = 0;
-	panel->mMediaTextureHandle = 0;
-	panel->mPickTextureHandle = 0;
-	panel->mAppTextureCoordsOpenGL = false;	// really need an 'undefined' state here too
-	panel->mReadyToRender = false;
-
-	// look through current media panels to find an unused index number
-	bool id_exists = true;
-	for( int nid = 0; nid < mMaxPanels; ++nid )
-	{
-		// does this id exist already?
-		id_exists = false;
-		for( int pid = 0; pid < (int)mMediaPanels.size(); ++pid )
-		{
-			if ( nid == mMediaPanels[ pid ]->mId )
-			{
-				id_exists = true;
-				break;
-			};
-		};
-
-		// id wasn't found so we can use it
-		if ( ! id_exists )
-		{
-			panel->mId = nid;
-			break;
-		};
-	};
-
-	// if we get here and this flag is set, there is no room for any more panels
-	if ( id_exists )
-	{
-		std::cout << "No room for any more panels" << std::endl;
-	}
-	else
-	{
-		// now we have the ID we can use it to make the
-		// pick texture (id is baked into texture pixels)
-		makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
-
-		// save this in the list of panels
-		mMediaPanels.push_back( panel );
-
-		// select the panel that was just created
-		selectPanel( panel );
-
-		// load and start the URL
-		panel->mMediaSource->loadURI( url );
-		panel->mMediaSource->start();
-
-		std::cout << "Adding new media panel for " << url << "(" << media_width << "x" << media_height << ") with index " << panel->mId << " - total panels = " << mMediaPanels.size() << std::endl;
-	}
-	
-	return panel;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::updateMediaPanel( mediaPanel* panel )
-{
-//	checkGLError("LLMediaPluginTest::updateMediaPanel");
-
-	if ( ! panel )
-		return;
-
-	if(!panel->mMediaSource || !panel->mMediaSource->textureValid())
-	{
-		panel->mReadyToRender = false;
-		return;
-	}
-
-	// take a reference copy of the plugin values since they
-	// might change during this lifetime of this function
-	int plugin_media_width = panel->mMediaSource->getWidth();
-	int plugin_media_height = panel->mMediaSource->getHeight();
-	int plugin_texture_width = panel->mMediaSource->getBitsWidth();
-	int plugin_texture_height = panel->mMediaSource->getBitsHeight();
-
-	// If the texture isn't created or the media or texture dimensions changed AND
-	// the sizes are valid then we need to delete the old media texture (if necessary)
-	// then make a new one.
-	if ((panel->mMediaTextureHandle == 0 ||
-		 panel->mMediaWidth != plugin_media_width ||
-		 panel->mMediaHeight != plugin_media_height ||
-		 panel->mTextureWidth != plugin_texture_width ||
-		 panel->mTextureHeight != plugin_texture_height) &&
-		( plugin_media_width > 0 && plugin_media_height > 0 &&
-		  plugin_texture_width > 0 && plugin_texture_height > 0 ) )
-	{
-		std::cout << "Valid media size (" <<  plugin_media_width << " x " << plugin_media_height
-				<< ") and texture size (" <<  plugin_texture_width << " x " << plugin_texture_height
-				<< ") for panel with ID=" << panel->mId << " - making texture" << std::endl;
-
-		// delete old GL texture
-		if ( isTexture( panel->mMediaTextureHandle ) )
-		{
-			std::cerr << "updateMediaPanel: deleting texture " << panel->mMediaTextureHandle << std::endl;
-			glDeleteTextures( 1, &panel->mMediaTextureHandle );
-			panel->mMediaTextureHandle = 0;
-		}
-
-		std::cerr << "before: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
-
-		// make a GL texture based on the dimensions the plugin told us
-		GLuint new_texture = 0;
-		glGenTextures( 1, &new_texture );
-
-		checkGLError("glGenTextures");
-
-		std::cout << "glGenTextures returned " << new_texture << std::endl;
-
-		panel->mMediaTextureHandle = new_texture;
-
-		bindTexture( panel->mMediaTextureHandle );
-
-		std::cout << "Setting texture size to " << plugin_texture_width << " x " << plugin_texture_height << std::endl;
-		glTexImage2D( GL_TEXTURE_2D, 0,
-			GL_RGB,
-				plugin_texture_width, plugin_texture_height,
-					0, GL_RGB, GL_UNSIGNED_BYTE,
-						0 );
-
-
-		std::cerr << "after: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
-	};
-
-	// update our record of the media and texture dimensions
-	// NOTE: do this after we we check for sizes changes
-	panel->mMediaWidth = plugin_media_width;
-	panel->mMediaHeight = plugin_media_height;
-	panel->mTextureWidth = plugin_texture_width;
-	panel->mTextureHeight = plugin_texture_height;
-	if ( plugin_texture_width > 0 )
-	{
-		panel->mTextureScaleX = (double)panel->mMediaWidth / (double)panel->mTextureWidth;
-	};
-	if ( plugin_texture_height > 0 )
-	{
-		panel->mTextureScaleY = (double)panel->mMediaHeight / (double)panel->mTextureHeight;
-	};
-
-	// update the flag which tells us if the media source uses OprnGL coords or not.
-	panel->mAppTextureCoordsOpenGL = panel->mMediaSource->getTextureCoordsOpenGL();
-
-	// Check to see if we have enough to render this panel.
-	// If we do, set a flag that the display functions use so
-	// they only render a panel with media if it's ready.
-	if ( panel->mMediaWidth < 0 ||
-		 panel->mMediaHeight < 0 ||
-		 panel->mTextureWidth < 1 ||
-		 panel->mTextureHeight < 1 ||
-		 panel->mMediaTextureHandle == 0 )
-	{
-		panel->mReadyToRender = false;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-mediaPanel* LLMediaPluginTest::replaceMediaPanel( mediaPanel* panel, std::string url )
-{
-	// no media panels so we can't change anything - have to add
-	if ( mMediaPanels.size() == 0 )
-		return NULL;
-
-	// sanity check
-	if ( ! panel )
-		return NULL;
-
-	int index;
-	for(index = 0; index < (int)mMediaPanels.size(); index++)
-	{
-		if(mMediaPanels[index] == panel)
-			break;
-	}
-
-	if(index >= (int)mMediaPanels.size())
-	{
-		// panel isn't in mMediaPanels
-		return NULL;
-	}
-
-	std::cout << "Replacing media panel with index " << panel->mId << std::endl;
-
-	int panel_id = panel->mId;
-
-	if(mSelectedPanel == panel)
-		mSelectedPanel = NULL;
-
-	delete panel;
-
-	// Get the plugin filename using the URL
-	std::string mime_type = mimeTypeFromUrl( url );
-	std::string plugin_name = pluginNameFromMimeType( mime_type );
-
-	// create a random size for the new media
-	int media_width;
-	int media_height;
-	getRandomMediaSize( media_width, media_height, mime_type );
-
-	// make a new plugin
-	LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
-
-	// tell the plugin what size we asked for
-	media_source->setSize( media_width, media_height );
-
-	// Use the launcher start and initialize the plugin
-#if LL_DARWIN || LL_LINUX
-	std::string launcher_name( "SLPlugin" );
-#elif LL_WINDOWS
-	std::string launcher_name( "SLPlugin.exe" );
-#endif
-
-	// for this test app, use the cwd as the user data path (ugh).
-#if LL_WINDOWS
-	std::string user_data_path = ".\\";
-#else
-        char cwd[ FILENAME_MAX ];
-	if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-	{
-		std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
-		return NULL;
-	}
-	std::string user_data_path = std::string( cwd ) + "/";
-#endif
-
-	media_source->setUserDataPath(user_data_path);
-	media_source->init( launcher_name, user_data_path, plugin_name, false );
-	media_source->setDisableTimeout(mDisableTimeout);
-
-	// make a new panel and save parameters
-	panel = new mediaPanel;
-	panel->mMediaSource = media_source;
-	panel->mStartUrl = url;
-	panel->mMimeType = mime_type;
-	panel->mMediaWidth = media_width;
-	panel->mMediaHeight = media_height;
-	panel->mTextureWidth = 0;
-	panel->mTextureHeight = 0;
-	panel->mTextureScaleX = 0;
-	panel->mTextureScaleY = 0;
-	panel->mMediaTextureHandle = 0;
-	panel->mPickTextureHandle = 0;
-	panel->mAppTextureCoordsOpenGL = false;	// really need an 'undefined' state here too
-	panel->mReadyToRender = false;
-
-	panel->mId = panel_id;
-
-	// Replace the entry in the panels array
-	mMediaPanels[index] = panel;
-
-	// now we have the ID we can use it to make the
-	// pick texture (id is baked into texture pixels)
-	makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
-
-	// select the panel that was just created
-	selectPanel( panel );
-
-	// load and start the URL
-	panel->mMediaSource->loadURI( url );
-	panel->mMediaSource->start();
-	
-	return panel;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::getRandomMediaSize( int& width, int& height, std::string mime_type )
-{
-	// Make a new media source with a random size which we'll either
-	// directly or the media plugin will tell us what it wants later.
-	// Use a random size so we can test support for weird media sizes.
-	// (Almost everything else will get filled in later once the
-	// plugin responds)
-	// NB. Do we need to enforce that width is on 4 pixel boundary?
-	width = ( ( rand() % 170 ) + 30 ) * 4;
-	height = ( ( rand() % 170 ) + 30 ) * 4;
-
-	// adjust this random size if it's a browser so we get
-	// a more useful size for testing..
-	if ( mime_type == "text/html" || mime_type == "example/example"  )
-	{
-		width = ( ( rand() % 100 ) + 100 ) * 4;
-		height = ( width * ( ( rand() % 400 ) + 1000 ) ) / 1000;
-	};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::remMediaPanel( mediaPanel* panel )
-{
-	// always leave one panel
-	if ( mMediaPanels.size() == 1 )
-		return;
-
-	// sanity check - don't think this can happen but see above for a case where it might...
-	if ( ! panel )
-		return;
-
-	std::cout << "Removing media panel with index " << panel->mId << " - total panels = " << mMediaPanels.size() - 1 << std::endl;
-
-	if(mSelectedPanel == panel)
-		mSelectedPanel = NULL;
-
-	delete panel;
-
-	// remove from storage list
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		if ( mMediaPanels[ i ] == panel )
-		{
-			mMediaPanels.erase( mMediaPanels.begin() + i );
-			break;
-		};
-	};
-
-	// select the first panel
-	selectPanel( mMediaPanels[ 0 ] );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::updateStatusBar()
-{
-	if ( ! mSelectedPanel )
-		return;
-
-	// cache results - this is a very slow function
-	static int cached_id = -1;
-	static int cached_media_width = -1;
-	static int cached_media_height = -1;
-	static int cached_texture_width = -1;
-	static int cached_texture_height = -1;
-	static bool cached_supports_browser_media = true;
-	static bool cached_supports_time_media = false;
-	static int cached_movie_time = -1;
-	static GLfloat cached_distance = -1.0f;
-
-	static std::string cached_plugin_version = "";
-	if (
-		 cached_id == mSelectedPanel->mId &&
-		 cached_media_width == mSelectedPanel->mMediaWidth &&
-		 cached_media_height  == mSelectedPanel->mMediaHeight &&
-		 cached_texture_width == mSelectedPanel->mTextureWidth &&
-		 cached_texture_height == mSelectedPanel->mTextureHeight &&
-		 cached_supports_browser_media == mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() &&
-		 cached_supports_time_media == mSelectedPanel->mMediaSource->pluginSupportsMediaTime() &&
-		 cached_plugin_version == mSelectedPanel->mMediaSource->getPluginVersion() &&
-		 cached_movie_time == (int)mSelectedPanel->mMediaSource->getCurrentTime() &&
-		 cached_distance == mDistanceCameraToSelectedGeometry
-	   )
-	{
-		// nothing changed so don't spend time here
-		return;
-	};
-
-	std::ostringstream stream( "" );
-
-	stream.str( "" );
-	stream.clear();
-
-	stream << "Id: ";
-	stream << std::setw( 2 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mId;
-	stream << " | ";
-	stream << "Media: ";
-	stream << std::setw( 3 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mMediaWidth;
-	stream << " x ";
-	stream << std::setw( 3 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mMediaHeight;
-	stream << " | ";
-	stream << "Texture: ";
-	stream << std::setw( 4 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mTextureWidth;
-	stream << " x ";
-	stream << std::setw( 4 ) << std::setfill( '0' );
-	stream << mSelectedPanel->mTextureHeight;
-
-	stream << " | ";
-	stream << "Distance: ";
-	stream << std::setw( 6 );
-	stream << std::setprecision( 3 );
-	stream << std::setprecision( 3 );
-	stream << mDistanceCameraToSelectedGeometry;
-	stream << " | ";
-
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
-		stream << "BROWSER";
-	else
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-		stream << "TIME   ";
-	stream << " | ";
-	stream << mSelectedPanel->mMediaSource->getPluginVersion();
-	stream << " | ";
-	if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
-	{
-		stream << std::setw( 3 ) << std::setfill( '0' );
-		stream << (int)mSelectedPanel->mMediaSource->getCurrentTime();
-		stream << " / ";
-		stream << std::setw( 3 ) << std::setfill( '0' );
-		stream << (int)mSelectedPanel->mMediaSource->getDuration();
-		stream << " @ ";
-		stream << (int)mSelectedPanel->mMediaSource->getCurrentPlayRate();
-		stream << " | ";
-	};
-
-	glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
-	mStatusText->set_text( const_cast< char*>( stream.str().c_str() ) );
-	glutSetWindow( mAppWindow );
-
-	// caching
-	cached_id = mSelectedPanel->mId;
-	cached_media_width = mSelectedPanel->mMediaWidth;
-	cached_media_height = mSelectedPanel->mMediaHeight;
-	cached_texture_width = mSelectedPanel->mTextureWidth;
-	cached_texture_height = mSelectedPanel->mTextureHeight;
-	cached_supports_browser_media = mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser();
-	cached_supports_time_media = mSelectedPanel->mMediaSource->pluginSupportsMediaTime();
-	cached_plugin_version = mSelectedPanel->mMediaSource->getPluginVersion();
-	cached_movie_time = (int)mSelectedPanel->mMediaSource->getCurrentTime();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::dumpPanelInfo()
-{
-	std::cout << std::endl << "===== Media Panels =====" << std::endl;
-	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
-	{
-		std::cout << std::setw( 2 ) << std::setfill( '0' );
-		std::cout << i + 1 << "> ";
-		std::cout << "Id: ";
-		std::cout << std::setw( 2 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mId;
-		std::cout << " | ";
-		std::cout << "Media: ";
-		std::cout << std::setw( 3 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mMediaWidth;
-		std::cout << " x ";
-		std::cout << std::setw( 3 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mMediaHeight;
-		std::cout << " | ";
-		std::cout << "Texture: ";
-		std::cout << std::setw( 4 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mTextureWidth;
-		std::cout << " x ";
-		std::cout << std::setw( 4 ) << std::setfill( '0' );
-		std::cout << mMediaPanels[ i ]->mTextureHeight;
-		std::cout << " | ";
-		if ( mMediaPanels[ i ] == mSelectedPanel )
-			std::cout << "(selected)";
-
-		std::cout << std::endl;
-	};
-	std::cout << "========================" << std::endl;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
-{
-	// Uncomment this to make things much, much quieter.
-//	return;
-
-	switch(event)
-	{
-		case MEDIA_EVENT_CONTENT_UPDATED:
-			// too spammy -- don't log these
-//			std::cerr <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << std::endl;
-		break;
-
-		case MEDIA_EVENT_TIME_DURATION_UPDATED:
-			// too spammy -- don't log these
-//			std::cerr <<  "Media event:  MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << std::endl;
-		break;
-
-		case MEDIA_EVENT_SIZE_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_SIZE_CHANGED " << std::endl;
-		break;
-
-		case MEDIA_EVENT_CURSOR_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_BEGIN:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_BEGIN " << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_COMPLETE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << std::endl;
-		break;
-
-		case MEDIA_EVENT_PROGRESS_UPDATED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << std::endl;
-		break;
-
-		case MEDIA_EVENT_STATUS_TEXT_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl;
-		break;
-
-		case MEDIA_EVENT_NAME_CHANGED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl;
-			glutSetWindowTitle( self->getMediaName().c_str() );
-		break;
-
-		case MEDIA_EVENT_LOCATION_CHANGED:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl;
-			mediaPanel* panel = findMediaPanel(self);
-			if(panel != NULL)
-			{
-				panel->mStartUrl = self->getLocation();
-				if(panel == mSelectedPanel)
-				{
-					mUrlEdit->set_text(const_cast<char*>(panel->mStartUrl.c_str()) );
-				}
-			}
-		}
-		break;
-
-		case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE, uri is: " << self->getClickURL() << std::endl;
-		break;
-			
-		case MEDIA_EVENT_CLICK_LINK_HREF:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, uri is " << self->getClickURL() << ", target is " << self->getClickTarget() << std::endl;
-			// retrieve the event parameters
-			std::string url = self->getClickURL();
-			std::string target = self->getClickTarget();
-			
-			if(target == "_external")
-			{
-				// this should open in an external browser, but since this is a test app we don't care.
-			}
-			else if(target == "_blank")
-			{
-				// Create a new panel with the specified URL.
-				addMediaPanel(url);
-			}
-			else // other named target
-			{
-				mediaPanel *target_panel = findMediaPanel(target);
-				if(target_panel)
-				{
-					target_panel = replaceMediaPanel(target_panel, url);
-				}
-				else
-				{
-					target_panel = addMediaPanel(url);
-				}
-
-				if(target_panel)
-				{
-					target_panel->mTarget = target;
-				}
-			}
-		}
-		break;
-
-		case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << std::endl;
-		break;
-
-		case MEDIA_EVENT_PLUGIN_FAILED:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << std::endl;
-		break;
-
-		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl;
-		break;
-
-		case MEDIA_EVENT_CLOSE_REQUEST:
-			std::cerr <<  "Media event:  MEDIA_EVENT_CLOSE_REQUEST" << std::endl;
-		break;
-		
-		case MEDIA_EVENT_PICK_FILE_REQUEST:
-			std::cerr <<  "Media event:  MEDIA_EVENT_PICK_FILE_REQUEST" << std::endl;
-			// TODO: display an actual file picker
-			self->sendPickFileResponse("cake");
-		break;
-
-		case MEDIA_EVENT_GEOMETRY_CHANGE:
-			std::cerr <<  "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() 
-				<< ", x = " << self->getGeometryX() 
-				<< ", y = " << self->getGeometryY() 
-				<< ", width = " << self->getGeometryWidth() 
-				<< ", height = " << self->getGeometryHeight() 
-				<< std::endl;
-		break;
-
-		case MEDIA_EVENT_AUTH_REQUEST:
-		{
-			//std::cerr <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl;
-
-			// TODO: display an auth dialog
-			self->sendAuthResponse(false, "", "");
-		}
-		break;
-
-		case MEDIA_EVENT_LINK_HOVERED:
-		{
-			std::cerr <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl;
-		}
-		break;
-
-		default:
-		{
-			std::cerr <<  "Media event:  <unknown>, code is: " << int(event) << std::endl;
-		}
-		break;
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-static void gluiCallbackWrapper( int control_id )
-{
-	if ( gApplication )
-		gApplication->gluiCallback( control_id );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutReshape( int width, int height )
-{
-	if ( gApplication )
-		gApplication->reshape( width, height );
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutDisplay()
-{
-	if ( gApplication )
-		gApplication->display();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutIdle(int update_ms)
-{
-	GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
-
-	if ( gApplication )
-		gApplication->idle();
-
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutKeyboard( unsigned char key, int x, int y )
-{
-	if ( gApplication )
-		gApplication->keyboard( key );
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMousePassive( int x, int y )
-{
-	if ( gApplication )
-		gApplication->mousePassive( x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMouseMove( int x , int y )
-{
-	if ( gApplication )
-		gApplication->mouseMove( x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void glutMouseButton( int button, int state, int x, int y )
-{
-	if ( gApplication )
-		gApplication->mouseButton( button, state, x, y );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-int main( int argc, char* argv[] )
-{
-#if LL_DARWIN
-	// Set the current working directory to <application bundle>/Contents/Resources/
-	CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
-	if(resources_url != NULL)
-	{
-		CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle);
-		CFRelease(resources_url);
-		if(resources_string != NULL)
-		{
-			char buffer[PATH_MAX] = "";
-			if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8))
-			{
-				chdir(buffer);
-			}
-			CFRelease(resources_string);
-		}
-	}
-#endif
-
-	glutInit( &argc, argv );
-	glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
-
-	const int app_window_x = 80;
-	const int app_window_y = 0;
-	const int app_window_width = 960;
-	const int app_window_height = 960;
-
-	glutInitWindowPosition( app_window_x, app_window_y );
-	glutInitWindowSize( app_window_width, app_window_height );
-
-	int app_window_handle = glutCreateWindow( "LLMediaPluginTest" );
-
-	glutDisplayFunc( glutDisplay );
-
-	GLUI_Master.set_glutReshapeFunc( glutReshape );
-	GLUI_Master.set_glutKeyboardFunc( glutKeyboard );
-	GLUI_Master.set_glutMouseFunc( glutMouseButton );
-
-	glutPassiveMotionFunc( glutMousePassive );
-	glutMotionFunc( glutMouseMove );
-
-	glutSetWindow( app_window_handle );
-
-	gApplication = new LLMediaPluginTest( app_window_handle, app_window_width, app_window_height );
-
-	// update at approximately 60hz
-	int update_ms = 1000 / 60;
-
-	GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
-
-	glutMainLoop();
-
-	delete gApplication;
-}
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.h b/indra/test_apps/llplugintest/llmediaplugintest.h
deleted file mode 100755
index 1f6f18e43c41aa8ed118b402f943798880d0aa7e..0000000000000000000000000000000000000000
--- a/indra/test_apps/llplugintest/llmediaplugintest.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * @file LLMediaPluginTest.cpp
- * @brief Primary test application for LLMedia (Separate Process) Plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_MEDIA_PLUGIN_TEST_H
-#define LL_MEDIA_PLUGIN_TEST_H
-
-#include <vector>
-#include <string>
-#include "llpluginclassmedia.h"
-#include "llgl.h"
-
-// Forward declarations
-class GLUI_Rotation;
-class GLUI_Translation;
-class GLUI_Listbox;
-class GLUI_EditText;
-class GLUI_StaticText;
-class GLUI;
-class GLUI_Button;
-
-////////////////////////////////////////////////////////////////////////////////
-//
-struct mediaPanel
-{
-	public:
-		mediaPanel();
-		~mediaPanel();
-		int mId;
-		std::string mStartUrl;
-		std::string mMimeType;
-		std::string mTarget;
-		LLPluginClassMedia *mMediaSource;
-		int mMediaWidth;
-		int mMediaHeight;
-		int mTextureWidth;
-		int mTextureHeight;
-		double mTextureScaleX;
-		double mTextureScaleY;
-		GLuint mMediaTextureHandle;
-		GLuint mPickTextureHandle;
-		unsigned char* mPickTexturePixels;
-		bool mAppTextureCoordsOpenGL;
-		bool mReadyToRender;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class LLMediaPluginTest : public LLPluginClassMediaOwner
-{
-	public:
-		LLMediaPluginTest( int app_window, int window_width, int window_height );
-		~LLMediaPluginTest();
-
-		void reshape( int width, int height );
-		void display();
-		void idle();
-		void gluiCallback( int control_id );
-		void keyboard( int key );
-		void mousePassive( int x, int y );
-		void mouseButton( int button, int state, int x, int y );
-		void mouseMove( int x, int y );
-
-		void bindTexture(GLuint texture, GLint row_length = 0, GLint alignment = 1);
-		bool checkGLError(const char *name = "OpenGL");
-		void drawGeometry( int panel, bool selected );
-		void startPanelHighlight( float red, float green, float blue, float line_width );
-		void endPanelHighlight();
-		enum { DrawTypePickTexture, DrawTypeMediaTexture };
-		void draw( int draw_type );
-		void windowPosToTexturePos( int window_x, int window_y, int& media_x, int& media_y, int& id );
-
-		mediaPanel* addMediaPanel( std::string url );
-		void updateMediaPanel( mediaPanel* panel );
-		void remMediaPanel( mediaPanel* panel );
-		mediaPanel* replaceMediaPanel( mediaPanel* panel, std::string url );
-		void getRandomMediaSize( int& width, int& height, std::string mime_type );
-		void navigateToNewURI( std::string uri );
-        void initUrlHistory( std::string uri );
-		void selectPanelById( int id );
-		void selectPanel( mediaPanel* panel );
-		mediaPanel* findMediaPanel( LLPluginClassMedia* panel );
-		mediaPanel* findMediaPanel( const std::string &target_name );
-		void makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels );
-		void makeChrome();
-		void resetView();
-
-		void dumpPanelInfo();
-		void updateStatusBar();
-
-		GLfloat distanceToCamera( GLfloat point_x, GLfloat point_y, GLfloat point_z );
-		
-
-	// Inherited from LLPluginClassMediaOwner
-	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent);
-
-	private:
-		const int mVersionMajor;
-		const int mVersionMinor;
-		const int mVersionPatch;
-		const int mMaxPanels;
-		int mAppWindow;
-		int mWindowWidth;
-		int mWindowHeight;
-		int mCurMouseX;
-		int mCurMouseY;
-		unsigned char mPixelReadColor[ 3 ];
-		bool mFuzzyMedia;
-		const std::string mHomeWebUrl;
-
-		std::vector< mediaPanel* > mMediaPanels;
-		mediaPanel* mSelectedPanel;
-		std::string mimeTypeFromUrl( std::string& url );
-		std::string pluginNameFromMimeType( std::string& mime_type );
-
-		GLUI_Rotation* mViewRotationCtrl;
-		GLUI_Translation* mViewScaleCtrl;
-		GLUI_Translation* mViewTranslationCtrl;
-		float mViewportAspect;
-		float mViewPos[ 3 ];
-		float mViewRotation[ 16 ];
-
-		float mDistanceCameraToSelectedGeometry;
-
-		int mIdControlAddPanel;
-		int mIdControlRemPanel;
-
-		std::vector< std::pair< std::string, std::string > > mBookmarks;
-		GLUI_Listbox* mBookmarkList;
-		int mIdBookmarks;
-		int mIdUrlEdit;
-		GLUI_EditText* mUrlEdit;
-        int mIdUrlInitHistoryEdit;
-		GLUI_EditText* mUrlInitHistoryEdit;
-		int mSelBookmark;
-		int mIdRandomPanelCount;
-		int mRandomPanelCount;
-		int mIdRandomBookmarks;
-		int mRandomBookmarks;
-		int mIdDisableTimeout;
-		int mDisableTimeout;
-		int mIdUsePluginReadThread;
-		int mUsePluginReadThread;
-		int mIdLargePanelSpacing;
-		int mLargePanelSpacing;
-		int mIdControlCrashPlugin;
-		int mIdControlHangPlugin;
-		int mIdControlExitApp;
-
-		GLUI* mGluiMediaTimeControlWindow;
-		int mIdMediaTimeControlPlay;
-		int mIdMediaTimeControlLoop;
-		int mIdMediaTimeControlPause;
-		int mIdMediaTimeControlStop;
-		int mIdMediaTimeControlSeek;
-		int mIdMediaTimeControlVolume;
-		int mMediaTimeControlVolume;
-		int mIdMediaTimeControlSeekSeconds;
-		int mMediaTimeControlSeekSeconds;
-		int mIdMediaTimeControlRewind;
-		int mIdMediaTimeControlFastForward;
-
-		GLUI* mGluiMediaBrowserControlWindow;
-		int mIdMediaBrowserControlBack;
-		GLUI_Button* mMediaBrowserControlBackButton;
-		int mIdMediaBrowserControlStop;
-		int mIdMediaBrowserControlForward;
-		GLUI_Button* mMediaBrowserControlForwardButton;
-		bool mGluiMediaTimeControlWindowFlag;
-		bool mGluiMediaBrowserControlWindowFlag;
-		bool mMediaBrowserControlBackButtonFlag;
-		bool mMediaBrowserControlForwardButtonFlag;
-		int mIdMediaBrowserControlHome;
-		int mIdMediaBrowserControlReload;
-		int mIdMediaBrowserControlClearCache;
-		int mIdMediaBrowserControlClearCookies;
-		int mIdMediaBrowserControlEnableCookies;
-		int mMediaBrowserControlEnableCookies;
-
-		GLUI* mBottomGLUIWindow;
-		GLUI_StaticText* mStatusText;
-};
-
-#endif	// LL_MEDIA_PLUGIN_TEST_H
-