diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index fc58b48a7b9357c74dc2522286a4ee2b9818b30c..6556aa33a49ed986e3e03adcf7a1612592ea8827 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -112,6 +112,8 @@ void LLPluginClassMedia::reset()
 	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
 	mAllowDownsample = false;
 	mPadding = 0;
+	mLastMouseX = 0;
+	mLastMouseY = 0;
 	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 	mSleepTime = 1.0f / 100.0f;
 	mCanCut = false;
@@ -412,8 +414,20 @@ std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 	return result;
 }
 
-void LLPluginClassMedia::mouseEvent(EMouseEventType type, int x, int y, MASK modifiers)
+void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
 {
+	if(type == MOUSE_EVENT_MOVE)
+	{
+		if((x == mLastMouseX) && (y == mLastMouseY))
+		{
+			// 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)
@@ -425,6 +439,8 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int x, int y, MASK mod
 	}
 	message.setValue("event", temp);
 
+	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.
@@ -515,11 +531,12 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
 	sendMessage(message);
 }
 	
-bool LLPluginClassMedia::textInput(const std::string &text)
+bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
 
 	message.setValue("text", text);
+	message.setValue("modifiers", translateModifiers(modifiers));
 	
 	sendMessage(message);
 	
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 697deec353052ad6113dfc4d2244649bc336f02f..603817b7d092024d8828d2d694c7f71087fd5f4f 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -101,7 +101,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 		MOUSE_EVENT_DOUBLE_CLICK
 	}EMouseEventType;
 	
-	void mouseEvent(EMouseEventType type, int x, int y, MASK modifiers);
+	void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers);
 
 	typedef enum 
 	{
@@ -115,7 +115,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	void scrollEvent(int x, int y, MASK modifiers);
 	
 	// Text may be unicode (utf8 encoded)
-	bool textInput(const std::string &text);
+	bool textInput(const std::string &text, MASK modifiers);
 	
 	void loadURI(const std::string &uri);
 	
@@ -310,6 +310,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	std::string translateModifiers(MASK modifiers);
 	
 	std::string mCursorName;
+	int			mLastMouseX;
+	int			mLastMouseY;
 
 	LLPluginClassMediaOwner::EMediaStatus mStatus;
 	
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index 6c54f63859b3eb5115370be7f57077262a3b86c3..e42f9739f4fecdcae84943d9e4bd56aa543c6206 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -1,842 +1,861 @@
-/** 
- * @file media_plugin_webkit.cpp
- * @brief Webkit plugin for LLMedia API plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llqtwebkit.h"
-
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.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 fo rthe 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:
-
-	int mBrowserWindowId;
-	bool mBrowserInitialized;
-	bool mNeedsUpdate;
-
-	bool	mCanCut;
-	bool	mCanCopy;
-	bool	mCanPaste;
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void update(int milliseconds)
-	{
-		LLQtWebKit::getInstance()->pump( milliseconds );
-		
-		checkEditState();
-		
-		if ( mNeedsUpdate )
-		{
-			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
-
-			unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
-			
-//			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;
-				memcpy( mPixels, browser_pixels, buffer_size );
-			}
-
-			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 ( mBrowserInitialized )
-			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 directories
-		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
-		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-		{
-			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
-			return false;
-		}
-		std::string application_dir = std::string( cwd );
-
-#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
-		std::string profileDir = application_dir + "/" + "browser_profile";		// cross platform?
-
-		// 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, profileDir, native_window_handle );
-		if ( result )
-		{
-			// create single browser window
-			mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight );
-
-#if LL_WINDOWS
-			// Enable plugins
-			LLQtWebKit::getInstance()->enablePlugins(true);
-#elif LL_DARWIN
-			// Disable plugins
-			LLQtWebKit::getInstance()->enablePlugins(false);
-#elif LL_LINUX
-			// Disable plugins
-			LLQtWebKit::getInstance()->enablePlugins(false);
-#endif
-            
-			// 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( "LLPluginMedia Web Browser" );
-
-			// don't flip bitmap
-			LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
-			
-			// Set the background color to black
-			LLQtWebKit::getInstance()->
-			// set background color to be black - mostly for initial login page
-			LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 );
-
-			// go to the "home page"
-			// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
-//			LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
-
-			// set flag so we don't do this again
-			mBrowserInitialized = true;
-
-			return true;
-		};
-
-		return false;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// 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:
-				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
-			break;
-		}
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
-		message.setValue("name", name);
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onPageChanged( const EventType& event )
-	{
-		// flag that an update is required
-		mNeedsUpdate = true;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateBegin(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
-		message.setValue("uri", event.getEventUri());
-		sendMessage(message);
-
-		setStatus(STATUS_LOADING);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateComplete(const EventType& event)
-	{
-		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);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onUpdateProgress(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
-		message.setValueS32("percent", event.getIntValue());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onStatusTextChange(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
-		message.setValue("status", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onTitleChange(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
-		message.setValue("name", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLocationChange(const EventType& event)
-	{
-		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.getStringValue());
-		message.setValue("target", event.getStringValue2());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkNoFollow(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
-		message.setValue("uri", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseDown( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseDown( mBrowserWindowId, x, y );
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseUp( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseUp( mBrowserWindowId, x, y );
-		LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true );
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void mouseMove( int x, int y )
-	{
-		LLQtWebKit::getInstance()->mouseMove( mBrowserWindowId, x, y );
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void keyPress( int key )
-	{
-		int llqt_key;
-		
-		// The incoming values for 'key' will be the ones from indra_constants.h
-		// the outgoing values are the ones from llqtwebkit.h
-		
-		switch((KEY)key)
-		{
-			// This is the list that the llqtwebkit implementation actually maps into Qt keys.
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CANCEL;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_HELP;			break;
-			case KEY_BACKSPACE:		llqt_key = LL_DOM_VK_BACK_SPACE;		break;
-			case KEY_TAB:			llqt_key = LL_DOM_VK_TAB;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CLEAR;			break;
-			case KEY_RETURN:		llqt_key = LL_DOM_VK_RETURN;			break;
-			case KEY_PAD_RETURN:	llqt_key = LL_DOM_VK_ENTER;			break;
-			case KEY_SHIFT:			llqt_key = LL_DOM_VK_SHIFT;			break;
-			case KEY_CONTROL:		llqt_key = LL_DOM_VK_CONTROL;		break;
-			case KEY_ALT:			llqt_key = LL_DOM_VK_ALT;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_PAUSE;			break;
-			case KEY_CAPSLOCK:		llqt_key = LL_DOM_VK_CAPS_LOCK;		break;
-			case KEY_ESCAPE:		llqt_key = LL_DOM_VK_ESCAPE;			break;
-			case KEY_PAGE_UP:		llqt_key = LL_DOM_VK_PAGE_UP;		break;
-			case KEY_PAGE_DOWN:		llqt_key = LL_DOM_VK_PAGE_DOWN;		break;
-			case KEY_END:			llqt_key = LL_DOM_VK_END;			break;
-			case KEY_HOME:			llqt_key = LL_DOM_VK_HOME;			break;
-			case KEY_LEFT:			llqt_key = LL_DOM_VK_LEFT;			break;
-			case KEY_UP:			llqt_key = LL_DOM_VK_UP;				break;
-			case KEY_RIGHT:			llqt_key = LL_DOM_VK_RIGHT;			break;
-			case KEY_DOWN:			llqt_key = LL_DOM_VK_DOWN;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_PRINTSCREEN;	break;
-			case KEY_INSERT:		llqt_key = LL_DOM_VK_INSERT;			break;
-			case KEY_DELETE:		llqt_key = LL_DOM_VK_DELETE;			break;
-//			case KEY_XXX:			llqt_key = LL_DOM_VK_CONTEXT_MENU;	break;
-			
-			default:
-				if(key < KEY_SPECIAL)
-				{
-					// Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit.
-					llqt_key = key;
-				}
-				else
-				{
-					// Don't pass through untranslated special keys -- they'll be all wrong.
-					llqt_key = 0;
-				}
-			break;
-		}
-		
-//		std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl;
-		
-		if(llqt_key != 0)
-		{
-			LLQtWebKit::getInstance()->keyPress( mBrowserWindowId, llqt_key );
-		}
-
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void unicodeInput( const std::string &utf8str )
-	{
-		LLWString wstr = utf8str_to_wstring(utf8str);
-		
-		unsigned int i;
-		for(i=0; i < wstr.size(); i++)
-		{
-//			std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl;
-			
-			LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i]);
-		}
-
-		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);
-			
-		}
-	}
-
-};
-
-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;
-	mBrowserInitialized = false;
-	mNeedsUpdate = true;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-}
-
-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);
-				
-				// Plugin gets to decide the texture parameters to use.
-				mDepth = 4;
-
-				message.setMessage(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);
-				message.setValueU32("format", GL_RGBA);
-				message.setValueU32("type", GL_UNSIGNED_BYTE);
-				message.setValueBoolean("coords_opengl", true);
-				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")
-			{
-				// TODO: clean up here
-			}
-			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)
-		{
-			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;
-
-						// initialize (only gets called once)
-						initBrowser();
-
-						// 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;
-						}
-						
-						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())
-				{
-					LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
-				}
-			}
-			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");
-				// std::string modifiers = message.getValue("modifiers");
-	
-				if(event == "down")
-				{
-					mouseDown(x, y);
-					//std::cout << "Mouse down at " << x << " x " << y << std::endl;
-				}
-				else if(event == "up")
-				{
-					mouseUp(x, y);
-					//std::cout << "Mouse up at " << x << " x " << y << std::endl;
-				}
-				else if(event == "move")
-				{
-					mouseMove(x, y);
-					//std::cout << ">>>>>>>>>>>>>>>>>>>> Mouse move at " << x << " x " << y << std::endl;
-				}
-			}
-			else if(message_name == "scroll_event")
-			{
-				// S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				// std::string modifiers = message.getValue("modifiers");
-				
-				// We currently ignore horizontal scrolling.
-				// The scroll values are roughly 1 per wheel click, so we need to magnify them by some factor.
-				// Arbitrarily, I choose 16.
-				y *= 16;
-				LLQtWebKit::getInstance()->scrollByLines(mBrowserWindowId, y);
-			}
-			else if(message_name == "key_event")
-			{
-				std::string event = message_in.getValue("event");
-
-				// act on "key down" or "key repeat"
-				if ( (event == "down") || (event == "repeat") )
-				{
-					S32 key = message_in.getValueS32("key");
-					keyPress( key );
-				};
-			}
-			else if(message_name == "text_event")
-			{
-				std::string text = message_in.getValue("text");
-				
-				unicodeInput(text);
-			}
-			if(message_name == "edit_cut")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
-			}
-			if(message_name == "edit_copy")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
-			}
-			if(message_name == "edit_paste")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
-			}
-			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 );
-			}
-			else if(message_name == "clear_cache")
-			{
-				LLQtWebKit::getInstance()->clearCache();
-			}
-			else if(message_name == "clear_cookies")
-			{
-				LLQtWebKit::getInstance()->clearAllCookies();
-			}
-			else if(message_name == "enable_cookies")
-			{
-				bool val = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enableCookies( val );
-			}
-			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
-				{
-					LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
-				};
-			}
-			else if(message_name == "set_user_agent")
-			{
-				std::string user_agent = message_in.getValue("user_agent");
-				LLQtWebKit::getInstance()->setBrowserAgentId( user_agent );
-			}
-			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
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
-			};
-		}
-		else
-		{
-//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	}
-}
-
-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;
-}
-
+/** 
+ * @file media_plugin_webkit.cpp
+ * @brief Webkit plugin for LLMedia API plugin system
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llqtwebkit.h"
+
+#include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.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 fo rthe 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:
+
+	int mBrowserWindowId;
+	bool mBrowserInitialized;
+	bool mNeedsUpdate;
+
+	bool	mCanCut;
+	bool	mCanCopy;
+	bool	mCanPaste;
+	int mLastMouseX;
+	int mLastMouseY;
+	
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void update(int milliseconds)
+	{
+		LLQtWebKit::getInstance()->pump( milliseconds );
+		
+		checkEditState();
+		
+		if ( mNeedsUpdate )
+		{
+			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
+
+			unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
+			
+//			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;
+				memcpy( mPixels, browser_pixels, buffer_size );
+			}
+
+			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 ( mBrowserInitialized )
+			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 directories
+		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
+		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
+		{
+			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
+			return false;
+		}
+		std::string application_dir = std::string( cwd );
+
+#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
+		std::string profileDir = application_dir + "/" + "browser_profile";		// cross platform?
+
+		// 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, profileDir, native_window_handle );
+		if ( result )
+		{
+			// create single browser window
+			mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight );
+
+#if LL_WINDOWS
+			// Enable plugins
+			LLQtWebKit::getInstance()->enablePlugins(true);
+#elif LL_DARWIN
+			// Disable plugins
+			LLQtWebKit::getInstance()->enablePlugins(false);
+#elif LL_LINUX
+			// Disable plugins
+			LLQtWebKit::getInstance()->enablePlugins(false);
+#endif
+            
+			// 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( "LLPluginMedia Web Browser" );
+
+			// don't flip bitmap
+			LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
+			
+			// Set the background color to black
+			LLQtWebKit::getInstance()->
+			// set background color to be black - mostly for initial login page
+			LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 );
+
+			// go to the "home page"
+			// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
+//			LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
+
+			// set flag so we don't do this again
+			mBrowserInitialized = true;
+
+			return true;
+		};
+
+		return false;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// 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:
+				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
+			break;
+		}
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
+		message.setValue("name", name);
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onPageChanged( const EventType& event )
+	{
+		// flag that an update is required
+		mNeedsUpdate = true;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateBegin(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+		message.setValue("uri", event.getEventUri());
+		sendMessage(message);
+
+		setStatus(STATUS_LOADING);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateComplete(const EventType& event)
+	{
+		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);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onUpdateProgress(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
+		message.setValueS32("percent", event.getIntValue());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onStatusTextChange(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
+		message.setValue("status", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onTitleChange(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+		message.setValue("name", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onLocationChange(const EventType& event)
+	{
+		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.getStringValue());
+		message.setValue("target", event.getStringValue2());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onClickLinkNoFollow(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
+		message.setValue("uri", event.getStringValue());
+		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 keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers)
+	{
+		int llqt_key;
+		
+		// The incoming values for 'key' will be the ones from indra_constants.h
+		// the outgoing values are the ones from llqtwebkit.h
+		
+		switch((KEY)key)
+		{
+			// This is the list that the llqtwebkit implementation actually maps into Qt keys.
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CANCEL;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_HELP;			break;
+			case KEY_BACKSPACE:		llqt_key = LL_DOM_VK_BACK_SPACE;		break;
+			case KEY_TAB:			llqt_key = LL_DOM_VK_TAB;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CLEAR;			break;
+			case KEY_RETURN:		llqt_key = LL_DOM_VK_RETURN;			break;
+			case KEY_PAD_RETURN:	llqt_key = LL_DOM_VK_ENTER;			break;
+			case KEY_SHIFT:			llqt_key = LL_DOM_VK_SHIFT;			break;
+			case KEY_CONTROL:		llqt_key = LL_DOM_VK_CONTROL;		break;
+			case KEY_ALT:			llqt_key = LL_DOM_VK_ALT;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_PAUSE;			break;
+			case KEY_CAPSLOCK:		llqt_key = LL_DOM_VK_CAPS_LOCK;		break;
+			case KEY_ESCAPE:		llqt_key = LL_DOM_VK_ESCAPE;			break;
+			case KEY_PAGE_UP:		llqt_key = LL_DOM_VK_PAGE_UP;		break;
+			case KEY_PAGE_DOWN:		llqt_key = LL_DOM_VK_PAGE_DOWN;		break;
+			case KEY_END:			llqt_key = LL_DOM_VK_END;			break;
+			case KEY_HOME:			llqt_key = LL_DOM_VK_HOME;			break;
+			case KEY_LEFT:			llqt_key = LL_DOM_VK_LEFT;			break;
+			case KEY_UP:			llqt_key = LL_DOM_VK_UP;				break;
+			case KEY_RIGHT:			llqt_key = LL_DOM_VK_RIGHT;			break;
+			case KEY_DOWN:			llqt_key = LL_DOM_VK_DOWN;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_PRINTSCREEN;	break;
+			case KEY_INSERT:		llqt_key = LL_DOM_VK_INSERT;			break;
+			case KEY_DELETE:		llqt_key = LL_DOM_VK_DELETE;			break;
+//			case KEY_XXX:			llqt_key = LL_DOM_VK_CONTEXT_MENU;	break;
+			
+			default:
+				if(key < KEY_SPECIAL)
+				{
+					// Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit.
+					llqt_key = key;
+				}
+				else
+				{
+					// Don't pass through untranslated special keys -- they'll be all wrong.
+					llqt_key = 0;
+				}
+			break;
+		}
+		
+//		std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl;
+		
+		if(llqt_key != 0)
+		{
+			LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, key_event, llqt_key, modifiers);
+		}
+
+		checkEditState();
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers)
+	{
+		LLWString wstr = utf8str_to_wstring(utf8str);
+		
+		unsigned int i;
+		for(i=0; i < wstr.size(); i++)
+		{
+//			std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl;
+			
+			LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i], 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);
+			
+		}
+	}
+
+};
+
+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;
+	mBrowserInitialized = false;
+	mNeedsUpdate = true;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+	mLastMouseX = 0;
+	mLastMouseY = 0;
+}
+
+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);
+				
+				// Plugin gets to decide the texture parameters to use.
+				mDepth = 4;
+
+				message.setMessage(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);
+				message.setValueU32("format", GL_RGBA);
+				message.setValueU32("type", GL_UNSIGNED_BYTE);
+				message.setValueBoolean("coords_opengl", true);
+				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")
+			{
+				// TODO: clean up here
+			}
+			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)
+		{
+			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;
+
+						// initialize (only gets called once)
+						initBrowser();
+
+						// 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;
+						}
+						
+						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())
+				{
+					LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, 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");
+				
+				// 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));
+			}
+			else if(message_name == "text_event")
+			{
+				std::string text = message_in.getValue("text");
+				std::string modifiers = message_in.getValue("modifiers");
+				
+				unicodeInput(text, decodeModifiers(modifiers));
+			}
+			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();
+			}
+			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 );
+			}
+			else if(message_name == "clear_cache")
+			{
+				LLQtWebKit::getInstance()->clearCache();
+			}
+			else if(message_name == "clear_cookies")
+			{
+				LLQtWebKit::getInstance()->clearAllCookies();
+			}
+			else if(message_name == "enable_cookies")
+			{
+				bool val = message_in.getValueBoolean("enable");
+				LLQtWebKit::getInstance()->enableCookies( val );
+			}
+			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
+				{
+					LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
+				};
+			}
+			else if(message_name == "set_user_agent")
+			{
+				std::string user_agent = message_in.getValue("user_agent");
+				LLQtWebKit::getInstance()->setBrowserAgentId( user_agent );
+			}
+			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
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
+			};
+		}
+		else
+		{
+//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
+		};
+	}
+}
+
+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/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 15efd0100a853c27beec2c64789bcebea8d18cb0..8f29f908e5c74c70ed77e4fcd08b98320c301871 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -51,6 +51,7 @@
 #include "llpluginclassmedia.h"
 #include "llslurl.h"
 #include "lluictrlfactory.h"	// LLDefaultChildRegistry
+#include "llkeyboard.h"
 
 // linden library includes
 #include "llfocusmgr.h"
@@ -193,7 +194,7 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
 
 	if (mMediaSource)
 	{
-		mMediaSource->mouseMove(x, y);
+		mMediaSource->mouseMove(x, y, mask);
 		gViewerWindow->setCursor(mMediaSource->getLastSetCursor());
 	}
 
@@ -205,7 +206,7 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
 BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )
 {
 	if (mMediaSource && mMediaSource->hasMedia())
-		mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, MASK_NONE);
+		mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE));
 
 	return TRUE;
 }
@@ -218,7 +219,7 @@ BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
 
 	if (mMediaSource)
 	{
-		mMediaSource->mouseUp(x, y);
+		mMediaSource->mouseUp(x, y, mask);
 
 		// *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
 		// in addition to the onFocusReceived() call below.  Undo this. JC
@@ -241,7 +242,50 @@ BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask )
 	convertInputCoords(x, y);
 
 	if (mMediaSource)
-		mMediaSource->mouseDown(x, y);
+		mMediaSource->mouseDown(x, y, mask);
+	
+	gFocusMgr.setMouseCapture( this );
+
+	if (mTakeFocusOnClick)
+	{
+		setFocus( TRUE );
+	}
+
+	return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleRightMouseUp( S32 x, S32 y, MASK mask )
+{
+	convertInputCoords(x, y);
+
+	if (mMediaSource)
+	{
+		mMediaSource->mouseUp(x, y, mask, 1);
+
+		// *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
+		// in addition to the onFocusReceived() call below.  Undo this. JC
+		if (!mTakeFocusOnClick)
+		{
+			mMediaSource->focus(false);
+			gViewerWindow->focusClient();
+		}
+	}
+	
+	gFocusMgr.setMouseCapture( NULL );
+
+	return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
+{
+	convertInputCoords(x, y);
+
+	if (mMediaSource)
+		mMediaSource->mouseDown(x, y, mask, 1);
 	
 	gFocusMgr.setMouseCapture( this );
 
@@ -260,7 +304,7 @@ BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask )
 	convertInputCoords(x, y);
 
 	if (mMediaSource)
-		mMediaSource->mouseLeftDoubleClick( x, y );
+		mMediaSource->mouseDoubleClick( x, y, mask);
 
 	gFocusMgr.setMouseCapture( this );
 
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 5ea03f1e6c0fabae03edb15552255306e0af2272..76ddc61ebf28ec285f07f32b1f9e0a2d48362702 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -86,6 +86,8 @@ class LLMediaCtrl :
 		virtual BOOL handleHover( S32 x, S32 y, MASK mask );
 		virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
 		virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
+		virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+		virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
 		virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
 		virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index b035fd53fd2d47808eecdf3038bb0bb8a7807f00..22ed1ec219602747804f42fb8c0aa804755dd559 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -48,6 +48,7 @@
 #include "lltooltip.h"
 #include "llhudeffecttrail.h"
 #include "llhudmanager.h"
+#include "llkeyboard.h"
 #include "llmediaentry.h"
 #include "llmenugl.h"
 #include "llmutelist.h"
@@ -1048,7 +1049,7 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
 		}
 		else
 		{
-			media_impl->mouseDown(pick.mUVCoords);
+			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.
 		}
@@ -1098,7 +1099,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick)
 			// If this is the focused media face, send mouse move events.
 			if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace))
 			{
-				media_impl->mouseMove(pick.mUVCoords);
+				media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(TRUE));
 				gViewerWindow->setCursor(media_impl->getLastSetCursor());
 			}
 			else
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 0b6ac0e2e244ff4fff3a04b181593c47206a54f3..464ba4a5b1672a15cc02309a8ecfc6a0112358c9 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -48,6 +48,7 @@
 #include "llevent.h"		// LLSimpleListener
 #include "llnotifications.h"
 #include "lluuid.h"
+#include "llkeyboard.h"
 
 #include <boost/bind.hpp>	// for SkinFolder listener
 #include <boost/signals2.hpp>
@@ -792,6 +793,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 		media_source->setLoop(mMediaLoop);
 		media_source->setAutoScale(mMediaAutoScale);
 		media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
+		media_source->focus(mHasFocus);
 		
 		mMediaSource = media_source;
 		return true;
@@ -917,7 +919,7 @@ bool LLViewerMediaImpl::hasFocus() const
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseDown(S32 x, S32 y)
+void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button)
 {
 	scaleMouse(&x, &y);
 	mLastMouseX = x;
@@ -925,12 +927,12 @@ void LLViewerMediaImpl::mouseDown(S32 x, S32 y)
 //	llinfos << "mouse down (" << x << ", " << y << ")" << llendl;
 	if (mMediaSource)
 	{
-		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, 0);
+		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask);
 	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseUp(S32 x, S32 y)
+void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button)
 {
 	scaleMouse(&x, &y);
 	mLastMouseX = x;
@@ -938,12 +940,12 @@ void LLViewerMediaImpl::mouseUp(S32 x, S32 y)
 //	llinfos << "mouse up (" << x << ", " << y << ")" << llendl;
 	if (mMediaSource)
 	{
-		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, 0);
+		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask);
 	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseMove(S32 x, S32 y)
+void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask)
 {
     scaleMouse(&x, &y);
 	mLastMouseX = x;
@@ -951,50 +953,53 @@ void LLViewerMediaImpl::mouseMove(S32 x, S32 y)
 //	llinfos << "mouse move (" << x << ", " << y << ")" << llendl;
 	if (mMediaSource)
 	{
-		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0);
+		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask);
 	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords)
+void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button)
 {
 	if(mMediaSource)
 	{		
 		mouseDown(
 			llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()),
-			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()));
+			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()),
+			mask, button);
 	}
 }
 
-void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords)
+void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button)
 {
 	if(mMediaSource)
 	{		
 		mouseUp(
 			llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()),
-			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()));
+			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()),
+			mask, button);
 	}
 }
 
-void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords)
+void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask)
 {
 	if(mMediaSource)
 	{		
 		mouseMove(
 			llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()),
-			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()));
+			llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight()),
+			mask);
 	}
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y)
+void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button)
 {
 	scaleMouse(&x, &y);
 	mLastMouseX = x;
 	mLastMouseY = y;
 	if (mMediaSource)
 	{
-		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, x, y, 0);
+		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask);
 	}
 }
 
@@ -1003,7 +1008,7 @@ void LLViewerMediaImpl::onMouseCaptureLost()
 {
 	if (mMediaSource)
 	{
-		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, mLastMouseX, mLastMouseY, 0);
+		mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0);
 	}
 }
 
@@ -1240,7 +1245,7 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
 		if (uni_char >= 32 // discard 'control' characters
 			&& uni_char != 127) // SDL thinks this is 'delete' - yuck.
 		{
-			mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)));
+			mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE));
 		}
 	}
 	
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index fc2776ee91eeca10e69a72e08c0a6531081b5ffa..01640de33ad7db10853e6317d97590630b82132e 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -133,13 +133,13 @@ class LLViewerMediaImpl
 	void focus(bool focus);
 	// True if the impl has user focus.
 	bool hasFocus() const;
-	void mouseDown(S32 x, S32 y);
-	void mouseUp(S32 x, S32 y);
-	void mouseMove(S32 x, S32 y);
-	void mouseDown(const LLVector2& texture_coords);
-	void mouseUp(const LLVector2& texture_coords);
-	void mouseMove(const LLVector2& texture_coords);
-	void mouseLeftDoubleClick(S32 x,S32 y );
+	void mouseDown(S32 x, S32 y, MASK mask, S32 button = 0);
+	void mouseUp(S32 x, S32 y, MASK mask, S32 button = 0);
+	void mouseMove(S32 x, S32 y, MASK mask);
+	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 mouseCapture();
 	
 	void navigateBack();
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index cad8b5f0ceca7d61f609d01cfda91752936784a1..ad48ec145ba675156a3fdd4faa876255b0c0d04f 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -77,7 +77,6 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac
 	if (media_impl.notNull() && objectp.notNull())
 	{
 		bool face_auto_zoom = false;
-		media_impl->focus(true);
 
 		mFocusedImplID = media_impl->getMediaTextureID();
 		mFocusedObjectID = objectp->getID();
@@ -101,6 +100,7 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac
 			llwarns << "Can't find media entry for focused face" << llendl;
 		}
 
+		media_impl->focus(true);
 		gFocusMgr.setKeyboardFocus(this);
 		
 		// We must do this before  processing the media HUD zoom, or it may zoom to the wrong face. 
diff --git a/install.xml b/install.xml
index 2f04d1c43757a9fa13c1d1dc13cf3d09bdbc8068..519f8138f5eed3944238be51f36ce2b2dd8c8fb7 100644
--- a/install.xml
+++ b/install.xml
@@ -948,9 +948,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>1859f5f6335d702cc42aeb602669b55e</string>
+            <string>b40a13847ee773c9ee06f641fe0dd1c2</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-darwin-20090827.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-darwin-20091023.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>