diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/cmake/Copy3rdPartyLibs.cmake | 13 | ||||
| -rw-r--r-- | indra/llcommon/llprocess.cpp | 12 | ||||
| -rw-r--r-- | indra/llcommon/llprocess.h | 29 | ||||
| -rw-r--r-- | indra/llcommon/tests/llprocess_test.cpp | 89 | ||||
| -rw-r--r-- | indra/llplugin/llpluginmessagepipe.cpp | 4 | ||||
| -rw-r--r-- | indra/llplugin/llpluginprocesschild.cpp | 457 | ||||
| -rw-r--r-- | indra/llplugin/slplugin/slplugin.cpp | 29 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 2 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.h | 2 | ||||
| -rw-r--r-- | indra/media_plugins/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | indra/media_plugins/cef/media_plugin_cef.cpp | 77 | ||||
| -rw-r--r-- | indra/media_plugins/example/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/media_plugins/example/media_plugin_example.cpp | 707 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/newview/installers/windows/installer_template.nsi | 31 | ||||
| -rw-r--r-- | indra/newview/llviewermedia.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/mime_types.xml | 35 | ||||
| -rwxr-xr-x | indra/newview/viewer_manifest.py | 8 | 
18 files changed, 781 insertions, 724 deletions
| diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 14510d654f..c7fb7a5301 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -102,12 +102,17 @@ if(WINDOWS)              unset(debug_msvc_redist_path CACHE)          endif() +        if(ADDRESS_SIZE EQUAL 32) +            # this folder contains the 32bit DLLs.. (yes really!) +            set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64") +        else(ADDRESS_SIZE EQUAL 32) +            # this folder contains the 64bit DLLs.. (yes really!) +            set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32") +        endif(ADDRESS_SIZE EQUAL 32) +          FIND_PATH(release_msvc_redist_path NAME msvcr${MSVC_VER}.dll              PATHS             -            [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${MSVC_VERDOT}\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC${MSVC_VER}.CRT -            [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64 -            [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32 -            ${MSVC_REDIST_PATH} +            ${registry_find_path}              NO_DEFAULT_PATH              ) diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 8c321d06b9..5753efdc59 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -517,6 +517,10 @@ LLProcessPtr LLProcess::create(const LLSDOrParams& params)  LLProcess::LLProcess(const LLSDOrParams& params):  	mAutokill(params.autokill), +	// Because 'autokill' originally meant both 'autokill' and 'attached', to +	// preserve existing semantics, we promise that mAttached defaults to the +	// same setting as mAutokill. +	mAttached(params.attached.isProvided()? params.attached : params.autokill),  	mPipes(NSLOTS)  {  	// Hmm, when you construct a ptr_vector with a size, it merely reserves @@ -625,9 +629,9 @@ LLProcess::LLProcess(const LLSDOrParams& params):  	// std handles and the like, and that's a bit more detachment than we  	// want. autokill=false just means not to implicitly kill the child when  	// the parent terminates! -//	chkapr(apr_procattr_detach_set(procattr, params.autokill? 0 : 1)); +//	chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1)); -	if (params.autokill) +	if (mAutokill)  	{  #if ! defined(APR_HAS_PROCATTR_AUTOKILL_SET)  		// Our special preprocessor symbol isn't even defined -- wrong APR @@ -696,7 +700,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):  	// take steps to terminate the child. This is all suspenders-and-belt: in  	// theory our destructor should kill an autokill child, but in practice  	// that doesn't always work (e.g. VWR-21538). -	if (params.autokill) +	if (mAutokill)  	{  /*==========================================================================*|  		// NO: There may be an APR bug, not sure -- but at least on Mac, when @@ -799,7 +803,7 @@ LLProcess::~LLProcess()  		sProcessListener.dropPoll(*this);  	} -	if (mAutokill) +	if (mAttached)  	{  		kill("destructor");  	} diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index bfac4567a5..e3386ad88e 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -167,6 +167,7 @@ public:  			args("args"),  			cwd("cwd"),  			autokill("autokill", true), +			attached("attached", true),  			files("files"),  			postend("postend"),  			desc("desc") @@ -183,9 +184,31 @@ public:  		Multiple<std::string> args;  		/// current working directory, if need it changed  		Optional<std::string> cwd; -		/// implicitly kill process on destruction of LLProcess object -		/// (default true) +		/// implicitly kill child process on termination of parent, whether +		/// voluntary or crash (default true)  		Optional<bool> autokill; +		/// implicitly kill process on destruction of LLProcess object +		/// (default same as autokill) +		/// +		/// Originally, 'autokill' conflated two concepts: kill child process on +		/// - destruction of its LLProcess object, and +		/// - termination of parent process, voluntary or otherwise. +		/// +		/// It's useful to tease these apart. Some child processes are sent a +		/// "clean up and terminate" message before the associated LLProcess +		/// object is destroyed. A child process launched with attached=false +		/// has an extra time window from the destruction of its LLProcess +		/// until parent-process termination in which to perform its own +		/// orderly shutdown, yet autokill=true still guarantees that we won't +		/// accumulate orphan instances of such processes indefinitely. With +		/// attached=true, if a child process cannot clean up between the +		/// shutdown message and LLProcess destruction (presumably very soon +		/// thereafter), it's forcibly killed anyway -- which can lead to +		/// distressing user-visible crash indications. +		/// +		/// (The usefulness of attached=true with autokill=false is less +		/// clear, but we don't prohibit that combination.) +		Optional<bool> attached;  		/**  		 * Up to three FileParam items: for child stdin, stdout, stderr.  		 * Passing two FileParam entries means default treatment for stderr, @@ -540,7 +563,7 @@ private:  	std::string mDesc;  	std::string mPostend;  	apr_proc_t mProcess; -	bool mAutokill; +	bool mAutokill, mAttached;  	Status mStatus;  	// explicitly want this ptr_vector to be able to store NULLs  	typedef boost::ptr_vector< boost::nullable<BasePipe> > PipeVector; diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 5ba343b183..b27e125d2e 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -789,6 +789,69 @@ namespace tut      template<> template<>      void object::test<10>()      { +        set_test_name("attached=false"); +        // almost just like autokill=false, except set autokill=true with +        // attached=false. +        NamedTempFile from("from", "not started"); +        NamedTempFile to("to", ""); +        LLProcess::handle phandle(0); +        { +            PythonProcessLauncher py(get_test_name(), +                                     "from __future__ import with_statement\n" +                                     "import sys, time\n" +                                     "with open(sys.argv[1], 'w') as f:\n" +                                     "    f.write('ok')\n" +                                     "# wait for 'go' from test program\n" +                                     "for i in xrange(60):\n" +                                     "    time.sleep(1)\n" +                                     "    with open(sys.argv[2]) as f:\n" +                                     "        go = f.read()\n" +                                     "    if go == 'go':\n" +                                     "        break\n" +                                     "else:\n" +                                     "    with open(sys.argv[1], 'w') as f:\n" +                                     "        f.write('never saw go')\n" +                                     "    sys.exit(1)\n" +                                     "# okay, saw 'go', write 'ack'\n" +                                     "with open(sys.argv[1], 'w') as f:\n" +                                     "    f.write('ack')\n"); +            py.mParams.args.add(from.getName()); +            py.mParams.args.add(to.getName()); +            py.mParams.autokill = true; +            py.mParams.attached = false; +            py.launch(); +            // Capture handle for later +            phandle = py.mPy->getProcessHandle(); +            // Wait for the script to wake up and do its first write +            int i = 0, timeout = 60; +            for ( ; i < timeout; ++i) +            { +                yield(); +                if (readfile(from.getName(), "from autokill script") == "ok") +                    break; +            } +            // If we broke this loop because of the counter, something's wrong +            ensure("script never started", i < timeout); +            // Now destroy the LLProcess, which should NOT kill the child! +        } +        // If the destructor killed the child anyway, give it time to die +        yield(2); +        // How do we know it's not terminated? By making it respond to +        // a specific stimulus in a specific way. +        { +            std::ofstream outf(to.getName().c_str()); +            outf << "go"; +        } // flush and close. +        // now wait for the script to terminate... one way or another. +        waitfor(phandle, "autokill script"); +        // If the LLProcess destructor implicitly called kill(), the +        // script could not have written 'ack' as we expect. +        ensure_equals(get_test_name() + " script output", readfile(from.getName()), "ack"); +    } + +    template<> template<> +    void object::test<11>() +    {          set_test_name("'bogus' test");          CaptureLog recorder;          PythonProcessLauncher py(get_test_name(), @@ -801,7 +864,7 @@ namespace tut      }      template<> template<> -    void object::test<11>() +    void object::test<12>()      {          set_test_name("'file' test");          // Replace this test with one or more real 'file' tests when we @@ -815,7 +878,7 @@ namespace tut      }      template<> template<> -    void object::test<12>() +    void object::test<13>()      {          set_test_name("'tpipe' test");          // Replace this test with one or more real 'tpipe' tests when we @@ -832,7 +895,7 @@ namespace tut      }      template<> template<> -    void object::test<13>() +    void object::test<14>()      {          set_test_name("'npipe' test");          // Replace this test with one or more real 'npipe' tests when we @@ -850,7 +913,7 @@ namespace tut      }      template<> template<> -    void object::test<14>() +    void object::test<15>()      {          set_test_name("internal pipe name warning");          CaptureLog recorder; @@ -914,7 +977,7 @@ namespace tut      } while (0)      template<> template<> -    void object::test<15>() +    void object::test<16>()      {          set_test_name("get*Pipe() validation");          PythonProcessLauncher py(get_test_name(), @@ -934,7 +997,7 @@ namespace tut      }      template<> template<> -    void object::test<16>() +    void object::test<17>()      {          set_test_name("talk to stdin/stdout");          PythonProcessLauncher py(get_test_name(), @@ -992,7 +1055,7 @@ namespace tut      }      template<> template<> -    void object::test<17>() +    void object::test<18>()      {          set_test_name("listen for ReadPipe events");          PythonProcessLauncher py(get_test_name(), @@ -1052,7 +1115,7 @@ namespace tut      }      template<> template<> -    void object::test<18>() +    void object::test<19>()      {          set_test_name("ReadPipe \"eof\" event");          PythonProcessLauncher py(get_test_name(), @@ -1078,7 +1141,7 @@ namespace tut      }      template<> template<> -    void object::test<19>() +    void object::test<20>()      {          set_test_name("setLimit()");          PythonProcessLauncher py(get_test_name(), @@ -1107,7 +1170,7 @@ namespace tut      }      template<> template<> -    void object::test<20>() +    void object::test<21>()      {          set_test_name("peek() ReadPipe data");          PythonProcessLauncher py(get_test_name(), @@ -1160,7 +1223,7 @@ namespace tut      }      template<> template<> -    void object::test<21>() +    void object::test<22>()      {          set_test_name("bad postend");          std::string pumpname("postend"); @@ -1185,7 +1248,7 @@ namespace tut      }      template<> template<> -    void object::test<22>() +    void object::test<23>()      {          set_test_name("good postend");          PythonProcessLauncher py(get_test_name(), @@ -1241,7 +1304,7 @@ namespace tut      };      template<> template<> -    void object::test<23>() +    void object::test<24>()      {          set_test_name("all data visible at postend");          PythonProcessLauncher py(get_test_name(), diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 7e2bf90ad1..9468696507 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -215,7 +215,7 @@ bool LLPluginMessagePipe::pumpOutput()  			else if(APR_STATUS_IS_EOF(status))  			{  				// This is what we normally expect when a plugin exits. -				LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; +				//LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL;  				if(mOwner)  				{ @@ -329,7 +329,7 @@ bool LLPluginMessagePipe::pumpInput(F64 timeout)  				else if(APR_STATUS_IS_EOF(status))  				{  					// This is what we normally expect when a plugin exits. -					LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; +					//LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL;  					if(mOwner)  					{ diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index be80d38305..e24d222cb6 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -1,30 +1,30 @@ -/**  - * @file llpluginprocesschild.cpp - * @brief LLPluginProcessChild handles the child side of the external-process plugin API.  - * - * @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 - */ +/** +* @file llpluginprocesschild.cpp +* @brief LLPluginProcessChild handles the child side of the external-process plugin API. +* +* @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" @@ -50,7 +50,7 @@ LLPluginProcessChild::LLPluginProcessChild()  LLPluginProcessChild::~LLPluginProcessChild()  { -	if(mInstance != NULL) +	if (mInstance != NULL)  	{  		sendMessageToPlugin(LLPluginMessage("base", "cleanup")); @@ -58,7 +58,7 @@ LLPluginProcessChild::~LLPluginProcessChild()  		// appears to fail and lock up which means that a given instance of the slplugin process never exits.   		// This is bad, especially when users try to update their version of SL - it fails because the slplugin   		// process as well as a bunch of plugin specific files are locked and cannot be overwritten. -		exit( 0 ); +		exit(0);  		//delete mInstance;  		//mInstance = NULL;  	} @@ -81,166 +81,173 @@ void LLPluginProcessChild::idle(void)  	bool idle_again;  	do  	{ -		if(APR_STATUS_IS_EOF(mSocketError)) -		{ -			// Plugin socket was closed.  This covers both normal plugin termination and host crashes. -			setState(STATE_ERROR); -		} -		else if(mSocketError != APR_SUCCESS) -		{ -			LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR"<< LL_ENDL; -			setState(STATE_ERROR); -		}	 +		if (mState < STATE_SHUTDOWNREQ) +		{   // Once we have hit the shutdown request state checking for errors might put us in a spurious  +			// error state... don't do that. -		if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) -		{ -			// The pipe has been closed -- we're done. -			// TODO: This could be slightly more subtle, but I'm not sure it needs to be. -			LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL; -			setState(STATE_ERROR); +			if (APR_STATUS_IS_EOF(mSocketError)) +			{ +				// Plugin socket was closed.  This covers both normal plugin termination and host crashes. +				setState(STATE_ERROR); +			} +			else if (mSocketError != APR_SUCCESS) +			{ +				LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR" << LL_ENDL; +				setState(STATE_ERROR); +			} + +			if ((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) +			{ +				// The pipe has been closed -- we're done. +				// TODO: This could be slightly more subtle, but I'm not sure it needs to be. +				LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR" << LL_ENDL; +				setState(STATE_ERROR); +			}  		} -	 +  		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().  		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.  		// When in doubt, don't do it.  		idle_again = false; -		 -		if(mInstance != NULL) + +		if (mInstance != NULL)  		{  			// Provide some time to the plugin  			mInstance->idle();  		} -		 -		switch(mState) + +		switch (mState)  		{ -			case STATE_UNINITIALIZED: +		case STATE_UNINITIALIZED:  			break; -			case STATE_INITIALIZED: -				if(mSocket->blockingConnect(mLauncherHost)) +		case STATE_INITIALIZED: +			if (mSocket->blockingConnect(mLauncherHost)) +			{ +				// This automatically sets mMessagePipe +				new LLPluginMessagePipe(this, mSocket); + +				setState(STATE_CONNECTED); +			} +			else +			{ +				// connect failed +				setState(STATE_ERROR); +			} +			break; + +		case STATE_CONNECTED: +			sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); +			setState(STATE_PLUGIN_LOADING); +			break; + +		case STATE_PLUGIN_LOADING: +			if (!mPluginFile.empty()) +			{ +				mInstance = new LLPluginInstance(this); +				if (mInstance->load(mPluginDir, mPluginFile) == 0)  				{ -					// This automatically sets mMessagePipe -					new LLPluginMessagePipe(this, mSocket); -					 -					setState(STATE_CONNECTED); +					mHeartbeat.start(); +					mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); +					mCPUElapsed = 0.0f; +					setState(STATE_PLUGIN_LOADED);  				}  				else  				{ -					// connect failed  					setState(STATE_ERROR);  				} +			}  			break; -			 -			case STATE_CONNECTED: -				sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); -				setState(STATE_PLUGIN_LOADING); + +		case STATE_PLUGIN_LOADED: +		{ +			setState(STATE_PLUGIN_INITIALIZING); +			LLPluginMessage message("base", "init"); +			sendMessageToPlugin(message); +		} +		break; + +		case STATE_PLUGIN_INITIALIZING: +			// waiting for init_response...  			break; -						 -			case STATE_PLUGIN_LOADING: -				if(!mPluginFile.empty()) + +		case STATE_RUNNING: +			if (mInstance != NULL) +			{ +				// Provide some time to the plugin +				LLPluginMessage message("base", "idle"); +				message.setValueReal("time", PLUGIN_IDLE_SECONDS); +				sendMessageToPlugin(message); + +				mInstance->idle(); + +				if (mHeartbeat.hasExpired())  				{ -					mInstance = new LLPluginInstance(this); -					if(mInstance->load(mPluginDir, mPluginFile) == 0) -					{ -						mHeartbeat.start(); -						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); -						mCPUElapsed = 0.0f; -						setState(STATE_PLUGIN_LOADED); -					} -					else -					{ -						setState(STATE_ERROR); -					} + +					// This just proves that we're not stuck down inside the plugin code. +					LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); + +					// Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. +					// Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. +					// If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. +					heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); + +					sendMessageToParent(heartbeat); + +					mHeartbeat.reset(); +					mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); +					mCPUElapsed = 0.0f;  				} +			} +			// receivePluginMessage will transition to STATE_UNLOADING  			break; -			 -			case STATE_PLUGIN_LOADED: -				{ -					setState(STATE_PLUGIN_INITIALIZING); -					LLPluginMessage message("base", "init"); -					sendMessageToPlugin(message); -				} + +		case STATE_SHUTDOWNREQ: +			// set next state first thing in case "cleanup" message advances state. +			setState(STATE_UNLOADING); +			mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS); + +			if (mInstance != NULL) +			{ +				sendMessageToPlugin(LLPluginMessage("base", "cleanup")); +			}  			break; -			 -			case STATE_PLUGIN_INITIALIZING: -				// waiting for init_response... + +		case STATE_UNLOADING: +			// 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(); +			delete mInstance; +			mInstance = NULL; +			setState(STATE_DONE); +			break; + +		case STATE_ERROR: +			// Close the socket to the launcher +			killSockets(); +			// TODO: Where do we go from here?  Just exit()? +			setState(STATE_DONE); +			break; + +		case STATE_DONE: +			// just sit here.  			break; -			 -			case STATE_RUNNING: -				if(mInstance != NULL) -				{ -					// Provide some time to the plugin -					LLPluginMessage message("base", "idle"); -					message.setValueReal("time", PLUGIN_IDLE_SECONDS); -					sendMessageToPlugin(message); -					 -					mInstance->idle(); -					 -					if(mHeartbeat.hasExpired()) -					{ -						 -						// This just proves that we're not stuck down inside the plugin code. -						LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); -						 -						// Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. -						// Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. -						// If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. -						heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); -						 -						sendMessageToParent(heartbeat); - -						mHeartbeat.reset(); -						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); -						mCPUElapsed = 0.0f; -					} -				} -				// receivePluginMessage will transition to STATE_UNLOADING -			    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: -                // 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; - -			case STATE_ERROR: -				// Close the socket to the launcher -				killSockets();				 -				// TODO: Where do we go from here?  Just exit()? -				setState(STATE_DONE); -			    break; -			 -			case STATE_DONE: -				// just sit here. -			    break;  		} -	 +  	} while (idle_again);  }  void LLPluginProcessChild::sleep(F64 seconds)  {  	deliverQueuedMessages(); -	if(mMessagePipe) +	if (mMessagePipe)  	{  		mMessagePipe->pump(seconds);  	} @@ -253,7 +260,7 @@ void LLPluginProcessChild::sleep(F64 seconds)  void LLPluginProcessChild::pump(void)  {  	deliverQueuedMessages(); -	if(mMessagePipe) +	if (mMessagePipe)  	{  		mMessagePipe->pump(0.0f);  	} @@ -267,26 +274,26 @@ void LLPluginProcessChild::pump(void)  bool LLPluginProcessChild::isRunning(void)  {  	bool result = false; -	 -	if(mState == STATE_RUNNING) + +	if (mState == STATE_RUNNING)  		result = true; -		 +  	return result;  }  bool LLPluginProcessChild::isDone(void)  {  	bool result = false; -	 -	switch(mState) + +	switch (mState)  	{ -		case STATE_DONE: +	case STATE_DONE:  		result = true;  		break; -		default: +	default:  		break;  	} -		 +  	return result;  } @@ -295,12 +302,12 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message)  	if (mInstance)  	{  		std::string buffer = message.generate(); -		 +  		LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;  		LLTimer elapsed; -		 +  		mInstance->sendMessage(buffer); -		 +  		mCPUElapsed += elapsed.getElapsedTimeF64();  	}  	else @@ -328,11 +335,11 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  	LLPluginMessage parsed;  	parsed.parse(message); -	if(mBlockingRequest) +	if (mBlockingRequest)  	{  		// We're blocking the plugin waiting for a response. -		if(parsed.hasValue("blocking_response")) +		if (parsed.hasValue("blocking_response"))  		{  			// This is the message we've been waiting for -- fall through and send it immediately.   			mBlockingResponseReceived = true; @@ -344,34 +351,34 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  			return;  		}  	} -	 +  	bool passMessage = true; -	 +  	// FIXME: how should we handle queueing here? -	 +  	{  		std::string message_class = parsed.getClass(); -		if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) +		if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)  		{  			passMessage = false; -			 +  			std::string message_name = parsed.getName(); -			if(message_name == "load_plugin") +			if (message_name == "load_plugin")  			{  				mPluginFile = parsed.getValue("file");  				mPluginDir = parsed.getValue("dir");  			} -            else if (message_name == "shutdown_plugin") -            { -                setState(STATE_SHUTDOWNREQ); -            } -			else if(message_name == "shm_add") +			else if (message_name == "shutdown_plugin") +			{ +				setState(STATE_SHUTDOWNREQ); +			} +			else if (message_name == "shm_add")  			{  				std::string name = parsed.getValue("name");  				size_t size = (size_t)parsed.getValueS32("size"); -				 +  				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); -				if(iter != mSharedMemoryRegions.end()) +				if (iter != mSharedMemoryRegions.end())  				{  					// Need to remove the old region first  					LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL; @@ -380,20 +387,20 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  				{  					// This is a new region  					LLPluginSharedMemory *region = new LLPluginSharedMemory; -					if(region->attach(name, size)) +					if (region->attach(name, size))  					{  						mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); -						 +  						std::stringstream addr;  						addr << region->getMappedAddress(); -						 +  						// Send the add notification to the plugin  						LLPluginMessage message("base", "shm_added");  						message.setValue("name", name);  						message.setValueS32("size", (S32)size);  						message.setValuePointer("address", region->getMappedAddress());  						sendMessageToPlugin(message); -						 +  						// and send the response to the parent  						message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response");  						message.setValue("name", name); @@ -405,13 +412,13 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  						delete region;  					}  				} -				 +  			} -			else if(message_name == "shm_remove") +			else if (message_name == "shm_remove")  			{  				std::string name = parsed.getValue("name");  				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); -				if(iter != mSharedMemoryRegions.end()) +				if (iter != mSharedMemoryRegions.end())  				{  					// forward the remove request to the plugin -- its response will trigger us to detach the segment.  					LLPluginMessage message("base", "shm_remove"); @@ -423,20 +430,20 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  					LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL;  				}  			} -			else if(message_name == "sleep_time") +			else if (message_name == "sleep_time")  			{  				mSleepTime = llmax(parsed.getValueReal("time"), 1.0 / 100.0); // clamp to maximum of 100Hz  			} -			else if(message_name == "crash") +			else if (message_name == "crash")  			{  				// Crash the plugin  				LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL;  			} -			else if(message_name == "hang") +			else if (message_name == "hang")  			{  				// Hang the plugin  				LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL; -				while(1) +				while (1)  				{  					// wheeeeeeeee......  				} @@ -447,8 +454,8 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  			}  		}  	} -	 -	if(passMessage && mInstance != NULL) + +	if (passMessage && mInstance != NULL)  	{  		LLTimer elapsed; @@ -458,50 +465,50 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)  	}  } -/* virtual */  +/* virtual */  void LLPluginProcessChild::receivePluginMessage(const std::string &message)  {  	LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; -	 -	if(mBlockingRequest) + +	if (mBlockingRequest)  	{  		//   		LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL;  	} -	 +  	// Incoming message from the plugin instance  	bool passMessage = true;  	// FIXME: how should we handle queueing here? -	 +  	// Intercept certain base messages (responses to ones sent by this class)  	{  		// Decode this message  		LLPluginMessage parsed;  		parsed.parse(message); -		 -		if(parsed.hasValue("blocking_request")) + +		if (parsed.hasValue("blocking_request"))  		{  			mBlockingRequest = true;  		}  		std::string message_class = parsed.getClass(); -		if(message_class == "base") +		if (message_class == "base")  		{  			std::string message_name = parsed.getName(); -			if(message_name == "init_response") +			if (message_name == "init_response")  			{  				// The plugin has finished initializing.  				setState(STATE_RUNNING);  				// Don't pass this message up to the parent  				passMessage = false; -				 +  				LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response");  				LLSD versions = parsed.getValueLLSD("versions");  				new_message.setValueLLSD("versions", versions); -				 -				if(parsed.hasValue("plugin_version")) + +				if (parsed.hasValue("plugin_version"))  				{  					std::string plugin_version = parsed.getValue("plugin_version");  					new_message.setValueLLSD("plugin_version", plugin_version); @@ -510,25 +517,25 @@ 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") +			else if (message_name == "goodbye") +			{ +				setState(STATE_UNLOADED); +			} +			else if (message_name == "shm_remove_response")  			{  				// Don't pass this message up to the parent  				passMessage = false;  				std::string name = parsed.getValue("name"); -				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);				 -				if(iter != mSharedMemoryRegions.end()) +				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); +				if (iter != mSharedMemoryRegions.end())  				{  					// detach the shared memory region  					iter->second->detach(); -					 +  					// and remove it from our map  					mSharedMemoryRegions.erase(iter); -					 +  					// Finally, send the response to the parent.  					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response");  					message.setValue("name", name); @@ -541,19 +548,19 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)  			}  		}  	} -	 -	if(passMessage) + +	if (passMessage)  	{  		LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;  		writeMessageRaw(message);  	} -	 -	while(mBlockingRequest) + +	while (mBlockingRequest)  	{  		// The plugin wants to block and wait for a response to this message.  		sleep(mSleepTime);	// this will pump the message pipe and process messages -		if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL)) +		if (mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL))  		{  			// Response has been received, or we've hit an error state.  Stop waiting.  			mBlockingRequest = false; @@ -566,14 +573,14 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)  void LLPluginProcessChild::setState(EState state)  {  	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; -	mState = state;  +	mState = state;  };  void LLPluginProcessChild::deliverQueuedMessages()  { -	if(!mBlockingRequest) +	if (!mBlockingRequest)  	{ -		while(!mMessageQueue.empty()) +		while (!mMessageQueue.empty())  		{  			receiveMessageRaw(mMessageQueue.front());  			mMessageQueue.pop(); diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 684bcf1207..b960565416 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -100,33 +100,8 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(  BOOL PreventSetUnhandledExceptionFilter()  { -// WARNING: This won't work on 64-bit Windows systems so we turn it off it. -//          It should work for any flavor of 32-bit Windows we care about. -//          If it's off, sometimes you will see an OS message when a plugin crashes -#ifndef _WIN64 -	HMODULE hKernel32 = LoadLibraryA( "kernel32.dll" ); -	if ( NULL == hKernel32 ) -		return FALSE; - -	void *pOrgEntry = GetProcAddress( hKernel32, "SetUnhandledExceptionFilter" ); -	if( NULL == pOrgEntry ) -		return FALSE; - -	unsigned char newJump[ 100 ]; -	DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; -	dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far -	void *pNewFunc = &MyDummySetUnhandledExceptionFilter; -	DWORD dwNewEntryAddr = (DWORD) pNewFunc; -	DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; - -	newJump[ 0 ] = 0xE9;  // JMP absolute -	memcpy( &newJump[ 1 ], &dwRelativeAddr, sizeof( pNewFunc ) ); -	SIZE_T bytesWritten; -	BOOL bRet = WriteProcessMemory( GetCurrentProcess(), pOrgEntry, newJump, sizeof( pNewFunc ) + 1, &bytesWritten ); -	return bRet; -#else -	return FALSE; -#endif +	// remove the scary stuff that also isn't supported on 64 bit Windows +	return TRUE;  }  //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 301ae7f9c4..5ec0ada6eb 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3800,7 +3800,7 @@ LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( cons  // When it handled the message, the value to be returned from  // the Window Procedure is set to *result. -BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) +BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result)  {  	if ( mPreeditor )  	{ diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 39ef9b31a4..059a008c45 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -148,7 +148,7 @@ protected:  	U32		fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string);  	void	handleStartCompositionMessage();  	void	handleCompositionMessage(U32 indexes); -	BOOL	handleImeRequests(U32 request, U32 param, LRESULT *result); +	BOOL	handleImeRequests(WPARAM request, LPARAM param, LRESULT *result);  protected:  	// diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 1eadce825e..1a5cc8ec9a 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -5,14 +5,17 @@ add_subdirectory(base)  if (LINUX)      add_subdirectory(gstreamer010)      add_subdirectory(libvlc) +    add_subdirectory(example)  endif (LINUX)  if (DARWIN)      add_subdirectory(cef)      add_subdirectory(libvlc) +    add_subdirectory(example)  endif (DARWIN)  if (WINDOWS)      add_subdirectory(cef)      add_subdirectory(libvlc) +    add_subdirectory(example)  endif (WINDOWS) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 906a5ff6e7..69717be91f 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -55,7 +55,7 @@ public:  private:  	bool init(); -	void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height, bool is_popup); +	void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height);  	void onCustomSchemeURLCallback(std::string url);  	void onConsoleMessageCallback(std::string message, std::string source, int line);  	void onStatusMessageCallback(std::string value); @@ -84,6 +84,7 @@ private:  	bool mCookiesEnabled;  	bool mPluginsEnabled;  	bool mJavascriptEnabled; +	bool mDisableGPU;  	std::string mUserAgentSubtring;  	std::string mAuthUsername;  	std::string mAuthPassword; @@ -95,12 +96,6 @@ private:  	std::string mCookiePath;  	std::string mPickedFile;  	dullahan* mCEFLib; - -	U8 *mPopupBuffer; -	U32 mPopupW; -	U32 mPopupH; -	U32 mPopupX; -	U32 mPopupY;  };  //////////////////////////////////////////////////////////////////////////////// @@ -117,6 +112,7 @@ MediaPluginBase(host_send_func, host_user_data)  	mCookiesEnabled = true;  	mPluginsEnabled = false;  	mJavascriptEnabled = true; +	mDisableGPU = true;  	mUserAgentSubtring = "";  	mAuthUsername = "";  	mAuthPassword = ""; @@ -129,18 +125,13 @@ MediaPluginBase(host_send_func, host_user_data)  	mPickedFile = "";  	mCEFLib = new dullahan(); -	mPopupBuffer = NULL; -	mPopupW = 0; -	mPopupH = 0; -	mPopupX = 0; -	mPopupY = 0;  }  ////////////////////////////////////////////////////////////////////////////////  //  MediaPluginCEF::~MediaPluginCEF()  { -	delete[] mPopupBuffer; +	mCEFLib->shutdown();  }  //////////////////////////////////////////////////////////////////////////////// @@ -161,56 +152,13 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg)  ////////////////////////////////////////////////////////////////////////////////  // -void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height, bool is_popup) +void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height)  { -	if( is_popup ) -	{ -		delete mPopupBuffer; -		mPopupBuffer = NULL; -		mPopupH = 0; -		mPopupW = 0; -		mPopupX = 0; -		mPopupY = 0; -	} -  	if( mPixels && pixels )  	{ -		if (is_popup) +		if (mWidth == width && mHeight == height)  		{ -			if( width > 0 && height> 0 ) -			{ -				mPopupBuffer = new U8[ width * height * mDepth ]; -				memcpy( mPopupBuffer, pixels, width * height * mDepth ); -				mPopupH = height; -				mPopupW = width; -				mPopupX = x; -				mPopupY = mHeight - y - height; -			} -		} -		else -		{ -			if (mWidth == width && mHeight == height) -			{ -				memcpy(mPixels, pixels, mWidth * mHeight * mDepth); -			} -			if( mPopupBuffer && mPopupH && mPopupW ) -			{ -				U32 bufferSize = mWidth * mHeight * mDepth; -				U32 popupStride = mPopupW * mDepth; -				U32 bufferStride = mWidth * mDepth; -				int dstY = mPopupY; - -				int src = 0; -				int dst = dstY  * mWidth * mDepth + mPopupX * mDepth; - -				for( int line = 0; dst + popupStride < bufferSize && line < mPopupH; ++line ) -				{ -					memcpy( mPixels + dst, mPopupBuffer + src, popupStride ); -					src += popupStride; -					dst += bufferStride; -				} -			} - +			memcpy(mPixels, pixels, mWidth * mHeight * mDepth);  		}  		setDirty(0, 0, mWidth, mHeight);  	} @@ -258,10 +206,10 @@ void MediaPluginCEF::onLoadStartCallback()  //  void MediaPluginCEF::onRequestExitCallback()  { -	mCEFLib->shutdown(); -  	LLPluginMessage message("base", "goodbye");  	sendMessage(message); + +	mDeleteMe = true;  }  //////////////////////////////////////////////////////////////////////////////// @@ -477,7 +425,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)  			if (message_name == "init")  			{  				// event callbacks from Dullahan -				mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)); +				mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));  				mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1));  				mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));  				mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); @@ -499,6 +447,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)  				settings.cache_path = mCachePath;  				settings.cookie_store_path = mCookiePath;  				settings.cookies_enabled = mCookiesEnabled; +				settings.disable_gpu = mDisableGPU;  				settings.flash_enabled = mPluginsEnabled;  				settings.flip_mouse_y = false;  				settings.flip_pixels_y = true; @@ -755,6 +704,10 @@ void MediaPluginCEF::receiveMessage(const char* message_string)  			{  				mJavascriptEnabled = message_in.getValueBoolean("enable");  			} +			else if (message_name == "gpu_disabled") +			{ +				mDisableGPU = message_in.getValueBoolean("disable"); +			}  		}          else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)          { diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index d2a17b1d76..42eb378172 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -67,7 +67,7 @@ if (WINDOWS)    set_target_properties(      media_plugin_example      PROPERTIES -    LINK_FLAGS "/MANIFEST:NO" +    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT"      )  endif (WINDOWS) diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp index 66c00cd58c..c296a0413d 100644 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ b/indra/media_plugins/example/media_plugin_example.cpp @@ -1,30 +1,30 @@  /** - * @file media_plugin_example.cpp - * @brief Example 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 - */ +* @file media_plugin_example.cpp +* @brief Example 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" @@ -38,375 +38,354 @@  ////////////////////////////////////////////////////////////////////////////////  // -class MediaPluginExample : -        public MediaPluginBase +class mediaPluginExample : +	public MediaPluginBase  { -    public: -        MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); -        ~MediaPluginExample(); - -        /*virtual*/ void receiveMessage( const char* message_string ); - -    private: -        bool init(); -        void update( F64 milliseconds ); -        void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); -        bool mFirstTime; - -        time_t mLastUpdateTime; -        enum Constants { ENumObjects = 10 }; -        unsigned char* mBackgroundPixels; -        int mColorR[ ENumObjects ]; -        int mColorG[ ENumObjects ]; -        int mColorB[ ENumObjects ]; -        int mXpos[ ENumObjects ]; -        int mYpos[ ENumObjects ]; -        int mXInc[ ENumObjects ]; -        int mYInc[ ENumObjects ]; -        int mBlockSize[ ENumObjects ]; -        bool mMouseButtonDown; -        bool mStopAction; +public: +	mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); +	~mediaPluginExample(); + +	/*virtual*/ void receiveMessage(const char* message_string); + +private: +	bool init(); +	void update(F64 milliseconds); +	bool mFirstTime; + +	time_t mLastUpdateTime; +	enum Constants { ENumObjects = 64 }; +	unsigned char* mBackgroundPixels; +	int mColorR[ENumObjects]; +	int mColorG[ENumObjects]; +	int mColorB[ENumObjects]; +	int mXpos[ENumObjects]; +	int mYpos[ENumObjects]; +	int mXInc[ENumObjects]; +	int mYInc[ENumObjects]; +	int mBlockSize[ENumObjects];  };  ////////////////////////////////////////////////////////////////////////////////  // -MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) : -    MediaPluginBase( host_send_func, host_user_data ) +mediaPluginExample::mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : +MediaPluginBase(host_send_func, host_user_data)  { -    mFirstTime = true; -    mWidth = 0; -    mHeight = 0; -    mDepth = 4; -    mPixels = 0; -    mMouseButtonDown = false; -    mStopAction = false; -    mLastUpdateTime = 0; +	mFirstTime = true; +	mTextureWidth = 0; +	mTextureHeight = 0; +	mWidth = 0; +	mHeight = 0; +	mDepth = 4; +	mPixels = 0; +	mLastUpdateTime = 0; +	mBackgroundPixels = 0;  }  ////////////////////////////////////////////////////////////////////////////////  // -MediaPluginExample::~MediaPluginExample() +mediaPluginExample::~mediaPluginExample()  {  }  ////////////////////////////////////////////////////////////////////////////////  // -void MediaPluginExample::receiveMessage( const char* message_string ) +void mediaPluginExample::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 = "Example plugin 1.0..0"; -                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") -            { -            } -            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) -                    { -                        // 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 == "init") -            { -                // 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); -                message.setValueU32("format", GL_RGBA); -                message.setValueU32("type", GL_UNSIGNED_BYTE); -                message.setValueBoolean("coords_opengl", true); -                sendMessage(message); -            } -            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; -                    }; -                }; - -                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") -            { -            } -            else if(message_name == "mouse_event") -            { -                std::string event = message_in.getValue("event"); -                if(event == "down") -                { - -                } -                else if(event == "up") -                { -                } -                else if(event == "double_click") -                { -                } -            } -        } -        else -        { -//          std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; -        }; -    } +	//  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 = "Example plugin 0.0.0"; +				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") +			{ +				LLPluginMessage message("base", "goodbye"); +				sendMessage(message); + +				mDeleteMe = true; +			} +			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) +					{ +						// 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 == "init") +			{ +				// 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_RGBA); +				message.setValueU32("type", GL_UNSIGNED_BYTE); +				message.setValueBoolean("coords_opengl", true); +				sendMessage(message); +			} +			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; +					}; +				}; + +				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); + +				mFirstTime = true; +				mLastUpdateTime = 0; + +			} +			else if (message_name == "load_uri") +			{ +			} +			else if (message_name == "mouse_event") +			{ +				std::string event = message_in.getValue("event"); +				if (event == "down") +				{ + +				} +				else if (event == "up") +				{ +				} +				else if (event == "double_click") +				{ +				} +			} +		} +		else +		{ +		}; +	}  }  ////////////////////////////////////////////////////////////////////////////////  // -void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) +void mediaPluginExample::update(F64 milliseconds)  { -    // make sure we don't write outside the buffer -    if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) -        return; - -    if ( mBackgroundPixels != NULL ) -    { -        unsigned char *pixel = mBackgroundPixels; -        pixel += y * mWidth * mDepth; -        pixel += ( x * mDepth ); -        pixel[ 0 ] = b; -        pixel[ 1 ] = g; -        pixel[ 2 ] = r; - -        setDirty( x, y, x + 1, y + 1 ); -    }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::update( F64 milliseconds ) -{ -    if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) -        return; - -    if ( mPixels == 0 ) -            return; - -    if ( mFirstTime ) -    { -        for( int n = 0; n < ENumObjects; ++n ) -        { -            mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); -            mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); - -            mColorR[ n ] = rand() % 0x60 + 0x60; -            mColorG[ n ] = rand() % 0x60 + 0x60; -            mColorB[ n ] = rand() % 0x60 + 0x60; - -            mXInc[ n ] = 0; -            while ( mXInc[ n ] == 0 ) -                mXInc[ n ] = rand() % 7 - 3; - -            mYInc[ n ] = 0; -            while ( mYInc[ n ] == 0 ) -                mYInc[ n ] = rand() % 9 - 4; - -            mBlockSize[ n ] = rand() % 0x30 + 0x10; -        }; - -        delete [] mBackgroundPixels; - -        mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; - -        mFirstTime = false; -    }; - -    if ( mStopAction ) -        return; - -    if ( time( NULL ) > mLastUpdateTime + 3 ) -    { -        const int num_squares = rand() % 20 + 4; -        int sqr1_r = rand() % 0x80 + 0x20; -        int sqr1_g = rand() % 0x80 + 0x20; -        int sqr1_b = rand() % 0x80 + 0x20; -        int sqr2_r = rand() % 0x80 + 0x20; -        int sqr2_g = rand() % 0x80 + 0x20; -        int sqr2_b = rand() % 0x80 + 0x20; - -        for ( int y1 = 0; y1 < num_squares; ++y1 ) -        { -            for ( int x1 = 0; x1 < num_squares; ++x1 ) -            { -                int px_start = mWidth * x1 / num_squares; -                int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; -                int py_start = mHeight * y1 / num_squares; -                int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; - -                for( int y2 = py_start; y2 < py_end; ++y2 ) -                { -                    for( int x2 = px_start; x2 < px_end; ++x2 ) -                    { -                        int rowspan = mWidth * mDepth; - -                        if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) -                        { -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; -                        } -                        else -                        { -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; -                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; -                        }; -                    }; -                }; -            }; -        }; - -        time( &mLastUpdateTime ); -    }; - -    memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); - -    for( int n = 0; n < ENumObjects; ++n ) -    { -        if ( rand() % 50 == 0 ) -        { -                mXInc[ n ] = 0; -                while ( mXInc[ n ] == 0 ) -                    mXInc[ n ] = rand() % 7 - 3; - -                mYInc[ n ] = 0; -                while ( mYInc[ n ] == 0 ) -                    mYInc[ n ] = rand() % 9 - 4; -        }; - -        if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) -            mXInc[ n ]= -mXInc[ n ]; - -        if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) -            mYInc[ n ]= -mYInc[ n ]; - -        mXpos[ n ] += mXInc[ n ]; -        mYpos[ n ] += mYInc[ n ]; - -        for( int y = 0; y < mBlockSize[ n ]; ++y ) -        { -            for( int x = 0; x < mBlockSize[ n ]; ++x ) -            { -                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; -                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; -                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; -            }; -        }; -    }; - -    setDirty( 0, 0, mWidth, mHeight ); +	if (mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048) +		return; + +	if (mPixels == 0) +		return; + +	if (mFirstTime) +	{ +		for (int n = 0; n < ENumObjects; ++n) +		{ +			mXpos[n] = (mWidth / 2) + rand() % (mWidth / 16) - (mWidth / 32); +			mYpos[n] = (mHeight / 2) + rand() % (mHeight / 16) - (mHeight / 32); + +			mColorR[n] = rand() % 0x60 + 0x60; +			mColorG[n] = rand() % 0x60 + 0x60; +			mColorB[n] = rand() % 0x60 + 0x60; + +			mXInc[n] = 0; +			while (mXInc[n] == 0) +				mXInc[n] = rand() % 7 - 3; + +			mYInc[n] = 0; +			while (mYInc[n] == 0) +				mYInc[n] = rand() % 9 - 4; + +			mBlockSize[n] = rand() % 0x30 + 0x10; +		}; + +		delete[] mBackgroundPixels; + +		mBackgroundPixels = new unsigned char[mWidth * mHeight * mDepth]; + +		mFirstTime = false; +	}; + +	if (time(NULL) > mLastUpdateTime + 3) +	{ +		const int num_squares = rand() % 20 + 4; +		int sqr1_r = rand() % 0x80 + 0x20; +		int sqr1_g = rand() % 0x80 + 0x20; +		int sqr1_b = rand() % 0x80 + 0x20; +		int sqr2_r = rand() % 0x80 + 0x20; +		int sqr2_g = rand() % 0x80 + 0x20; +		int sqr2_b = rand() % 0x80 + 0x20; + +		for (int y1 = 0; y1 < num_squares; ++y1) +		{ +			for (int x1 = 0; x1 < num_squares; ++x1) +			{ +				int px_start = mWidth * x1 / num_squares; +				int px_end = (mWidth * (x1 + 1)) / num_squares; +				int py_start = mHeight * y1 / num_squares; +				int py_end = (mHeight * (y1 + 1)) / num_squares; + +				for (int y2 = py_start; y2 < py_end; ++y2) +				{ +					for (int x2 = px_start; x2 < px_end; ++x2) +					{ +						int rowspan = mWidth * mDepth; + +						if ((y1 % 2) ^ (x1 % 2)) +						{ +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr1_r; +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr1_g; +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr1_b; +						} +						else +						{ +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr2_r; +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr2_g; +							mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr2_b; +						}; +					}; +				}; +			}; +		}; + +		time(&mLastUpdateTime); +	}; + +	memcpy(mPixels, mBackgroundPixels, mWidth * mHeight * mDepth); + +	for (int n = 0; n < ENumObjects; ++n) +	{ +		if (rand() % 50 == 0) +		{ +			mXInc[n] = 0; +			while (mXInc[n] == 0) +				mXInc[n] = rand() % 7 - 3; + +			mYInc[n] = 0; +			while (mYInc[n] == 0) +				mYInc[n] = rand() % 9 - 4; +		}; + +		if (mXpos[n] + mXInc[n] < 0 || mXpos[n] + mXInc[n] >= mWidth - mBlockSize[n]) +			mXInc[n] = -mXInc[n]; + +		if (mYpos[n] + mYInc[n] < 0 || mYpos[n] + mYInc[n] >= mHeight - mBlockSize[n]) +			mYInc[n] = -mYInc[n]; + +		mXpos[n] += mXInc[n]; +		mYpos[n] += mYInc[n]; + +		for (int y = 0; y < mBlockSize[n]; ++y) +		{ +			for (int x = 0; x < mBlockSize[n]; ++x) +			{ +				mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 0] = mColorR[n]; +				mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 1] = mColorG[n]; +				mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 2] = mColorB[n]; +			}; +		}; +	}; + +	setDirty(0, 0, mWidth, mHeight);  };  ////////////////////////////////////////////////////////////////////////////////  // -bool MediaPluginExample::init() +bool mediaPluginExample::init()  { -    LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); -    message.setValue( "name", "Example Plugin" ); -    sendMessage( message ); +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); +	message.setValue("name", "Example Plugin"); +	sendMessage(message); -    return true; +	return true;  };  ////////////////////////////////////////////////////////////////////////////////  // -int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func, -                        void* host_user_data, -                        LLPluginInstance::sendMessageFunction *plugin_send_func, -                        void **plugin_user_data ) +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, +	void* host_user_data, +	LLPluginInstance::sendMessageFunction *plugin_send_func, +	void **plugin_user_data)  { -    MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); -    *plugin_send_func = MediaPluginExample::staticReceiveMessage; -    *plugin_user_data = ( void* )self; +	mediaPluginExample* self = new mediaPluginExample(host_send_func, host_user_data); +	*plugin_send_func = mediaPluginExample::staticReceiveMessage; +	*plugin_user_data = (void*)self; -    return 0; +	return 0;  } - diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 81a08182c7..62451e4856 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1749,6 +1749,7 @@ if (WINDOWS)        SLPlugin        media_plugin_cef        media_plugin_libvlc +      media_plugin_example        winmm_shim        windows-crash-logger        ) diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index eb07b54d8d..71a33a0dc0 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -90,8 +90,11 @@ InstProgressFlags smooth colored		# New colored smooth look  SetOverwrite on							# Overwrite files by default
  AutoCloseWindow true					# After all files install, close window
 -InstallDir "%%$PROGRAMFILES%%\${INSTNAME}"
 -InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
 +# initial location of install (default when not already installed)
 +#   note: Now we defer looking for existing install until onInit when we
 +#   are able to engage the 32/64 registry function
 +InstallDir "%%PROGRAMFILES%%\${INSTNAME}"
 +
  UninstallText $(UninstallTextMsg)
  DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
  Page directory dirPre
 @@ -118,6 +121,8 @@ Var DO_UNINSTALL_V2     # If non-null, path to a previous Viewer 2 installation  !insertmacro GetParameters
  !insertmacro GetOptions
  !include WinVer.nsh			# For OS and SP detection
 +!include 'LogicLib.nsh'     # for value comparison
 +!include "x64.nsh"			# for 64bit detection
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Pre-directory page callback
 @@ -136,7 +141,21 @@ FunctionEnd  ;; entry to the language ID selector below
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Function .onInit
 +
  %%ENGAGEREGISTRY%%
 +
 +# read the current location of the install for this version
 +# if $0 is empty, this is the first time for this viewer name
 +ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\\Linden Research, Inc.\\${INSTNAME}" ""
 +
 +# viewer with this name not installed before
 +${If} $0 == ""
 +    # nothing to do here
 +${Else}
 +	# use the value we got from registry as install location
 +    StrCpy $INSTDIR $0
 +${EndIf}
 +
  Call CheckCPUFlags							# Make sure we have SSE2 support
  Call CheckWindowsVersion					# Don't install On unsupported systems
      Push $0
 @@ -195,7 +214,9 @@ FunctionEnd  ;; Prep Uninstaller Section
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Function un.onInit
 +
  %%ENGAGEREGISTRY%%
 +
  # Read language from registry and set for uninstaller. Key will be removed on successful uninstall
  	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
      IfErrors lbl_end
 @@ -320,6 +341,10 @@ WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninst  WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe"'
  WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayVersion" "${VERSION_LONG}"
  WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "0x0001D500"		# ~117 MB
 +
 +# from FS:Ansariel
 +WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$INSTEXE"'
 +
  # BUG-2707 Disable SEHOP for installed viewer.
  WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE" "DisableExceptionChainValidation" 1
 @@ -561,7 +586,7 @@ FunctionEnd  Function RemoveProgFilesOnInst
  # Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
 -Delete "$INSTDIR\SecondLife.exe"
 +Delete "$INSTDIR\$INSTEXE"
  # Remove old shader files first so fallbacks will work. See DEV-5663
  RMDir /r "$INSTDIR\app_settings\shaders"
 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9f05ee61bd..900075488f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -604,7 +604,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));  	// HACK: we always try to keep a spare running webkit plugin around to improve launch times. -	createSpareBrowserMediaSource(); +	// 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so +	// removing it for now. +	//createSpareBrowserMediaSource();  	sAnyMediaShowing = false;  	sAnyMediaPlaying = false; diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml index 8d8d546b24..8a810f32a6 100644 --- a/indra/newview/skins/default/xui/en/mime_types.xml +++ b/indra/newview/skins/default/xui/en/mime_types.xml @@ -133,18 +133,29 @@  			media_plugin_libvlc  		</impl>  	</scheme> -  <scheme name="libvlc"> -    <label name="libvlc_label"> -      LibVLC supported media -    </label> -    <widgettype> -      movie -    </widgettype> -    <impl> -      media_plugin_libvlc -    </impl> -  </scheme> -  <mimetype name="blank"> +	<scheme name="example"> +		<label name="example_label"> +			Example Plugin scheme trigger +		</label> +		<widgettype> +			movie +		</widgettype> +		<impl> +			media_plugin_example +		</impl> +	</scheme> +	<scheme name="libvlc"> +		<label name="libvlc_label"> +			LibVLC supported media +		</label> +		<widgettype> +			movie +		</widgettype> +		<impl> +			media_plugin_libvlc +		</impl> +	</scheme> +	<mimetype name="blank">  		<label name="blank_label">  			- None -  		</label> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 3a8cd0c626..fba8a8b159 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -439,6 +439,12 @@ class WindowsManifest(ViewerManifest):              self.path("media_plugin_libvlc.dll")              self.end_prefix() +        # Media plugins - Example (useful for debugging - not shipped with release viewer) +        if self.channel_type() != 'release': +            if self.prefix(src='../media_plugins/example/%s' % self.args['configuration'], dst="llplugin"): +                self.path("media_plugin_example.dll") +                self.end_prefix() +          # CEF runtime files - debug          if self.args['configuration'].lower() == 'debug':              if self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'debug'), dst="llplugin"): @@ -648,7 +654,7 @@ class WindowsManifest(ViewerManifest):                  "%%SOURCE%%":self.get_src_prefix(),                  "%%INST_VARS%%":inst_vars_template % substitution_strings,                  "%%INSTALL_FILES%%":self.nsi_file_commands(True), -                "%%$PROGRAMFILES%%":program_files, +                "%%PROGRAMFILES%%":program_files,                  "%%ENGAGEREGISTRY%%":engage_registry,                  "%%DELETE_FILES%%":self.nsi_file_commands(False)}) | 
