Merge branch 'master' into UICleanup

Conflicts:
	indra/llcommon/llstl.h
	indra/newview/jcfloaterareasearch.cpp
	indra/newview/jcfloaterareasearch.h
	indra/newview/llfloateranimpreview.cpp
	indra/newview/llfloateranimpreview.h
	indra/newview/llfloaterperms.cpp
	indra/newview/llfloaterproperties.cpp
	indra/newview/llpanelpermissions.cpp
	indra/newview/llviewermenu.cpp
This commit is contained in:
Shyotl
2013-05-03 21:41:51 -05:00
210 changed files with 10451 additions and 6643 deletions

View File

@@ -30,8 +30,6 @@ include(BuildVersion)
include(UnixInstall)
set (DISABLE_FATAL_WARNINGS CACHE BOOL TRUE)
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Build type. One of: Debug Release RelWithDebInfo" FORCE)

View File

@@ -352,8 +352,13 @@ void AIEngine::mainloop(void)
void AIEngine::flush(void)
{
DoutEntering(dc::statemachine, "AIEngine::flush [" << mName << "]");
engine_state_type_wat engine_state_w(mEngineState);
DoutEntering(dc::statemachine, "AIEngine::flush [" << mName << "]: calling force_killed() on " << engine_state_w->list.size() << " state machines.");
for (queued_type::iterator iter = engine_state_w->list.begin(); iter != engine_state_w->list.end(); ++iter)
{
// To avoid an assertion in ~AIStateMachine.
iter->statemachine().force_killed();
}
engine_state_w->list.clear();
}
@@ -368,7 +373,7 @@ void AIEngine::setMaxCount(F32 StateMachineMaxTime)
sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000;
}
#ifdef CWDEBUG
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
char const* AIStateMachine::event_str(event_type event)
{
switch(event)
@@ -906,6 +911,12 @@ void AIStateMachine::callback(void)
}
}
void AIStateMachine::force_killed(void)
{
multiplex_state_type_wat state_w(mState);
state_w->base_state = bs_killed;
}
void AIStateMachine::kill(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::kill() [" << (void*)this << "]");

View File

@@ -146,12 +146,15 @@ class AIStateMachine : public LLThreadSafeRefCount
typedef AIAccessConst<multiplex_state_type> multiplex_state_type_crat;
typedef AIAccess<multiplex_state_type> multiplex_state_type_rat;
typedef AIAccess<multiplex_state_type> multiplex_state_type_wat;
protected:
// Sub state.
AIThreadSafeSimpleDC<sub_state_type> mSubState;
typedef AIAccessConst<sub_state_type> sub_state_type_crat;
typedef AIAccess<sub_state_type> sub_state_type_rat;
typedef AIAccess<sub_state_type> sub_state_type_wat;
private:
// Mutex protecting everything below and making sure only one thread runs the state machine at a time.
LLMutex mMultiplexMutex;
// Mutex that is locked while calling *_impl() functions and the call back.
@@ -271,7 +274,7 @@ class AIStateMachine : public LLThreadSafeRefCount
// Return stringified state, for debugging purposes.
char const* state_str(base_state_type state);
#ifdef CWDEBUG
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
char const* event_str(event_type event);
#endif
@@ -300,8 +303,9 @@ class AIStateMachine : public LLThreadSafeRefCount
mSleep = 0;
return mSleep != 0;
}
void force_killed(void); // Called from AIEngine::flush().
friend class AIEngine; // Calls multiplex().
friend class AIEngine; // Calls multiplex() and force_killed().
};
bool AIEngine::QueueElementComp::operator()(QueueElement const& e1, QueueElement const& e2) const

View File

@@ -33,12 +33,12 @@
class AIStateMachineThreadBase::Thread : public LLThread {
private:
LLPointer<AIThreadImpl> mImpl;
LLPointer<AIStateMachineThreadBase> mImpl;
bool mNeedCleanup;
public:
Thread(AIThreadImpl* impl) :
Thread(AIStateMachineThreadBase* impl) :
#ifdef LL_DEBUG
LLThread(impl->getName()),
LLThread(impl->impl().getName()),
#else
LLThread("AIStateMachineThreadBase::Thread"),
#endif
@@ -46,7 +46,7 @@ class AIStateMachineThreadBase::Thread : public LLThread {
protected:
/*virtual*/ void run(void)
{
mNeedCleanup = mImpl->thread_done(mImpl->run());
mNeedCleanup = mImpl->impl().thread_done(mImpl->impl().run());
}
/*virtual*/ void terminated(void)
{
@@ -65,7 +65,7 @@ class AIStateMachineThreadBase::Thread : public LLThread {
}
public:
// TODO: Implement a thread pool. For now, just create a new one every time.
static Thread* allocate(AIThreadImpl* impl) { return new Thread(impl); }
static Thread* allocate(AIStateMachineThreadBase* impl) { return new Thread(impl); }
static void completed(Thread* threadp) { delete threadp; }
};
@@ -93,7 +93,7 @@ void AIStateMachineThreadBase::multiplex_impl(state_type run_state)
switch(run_state)
{
case start_thread:
mThread = Thread::allocate(mImpl);
mThread = Thread::allocate(this);
// Set next state.
set_state(wait_stopped);
idle(); // Wait till the thread returns.
@@ -124,10 +124,10 @@ void AIStateMachineThreadBase::abort_impl(void)
{
if (mThread)
{
// If this AIStateMachineThreadBase still exists then the first base class of
// AIStateMachineThread<THREAD_IMPL>, LLPointer<THREAD_IMPL>, also still exists
// and therefore mImpl is valid.
bool need_cleanup = mImpl->state_machine_done(mThread); // Signal the fact that we aborted.
// If this AIStateMachineThreadBase still exists then the AIStateMachineThread<THREAD_IMPL>
// that is derived from it still exists and therefore its member THREAD_IMPL also still exists
// and therefore impl() is valid.
bool need_cleanup = impl().state_machine_done(mThread); // Signal the fact that we aborted.
if (need_cleanup)
{
// This is an unlikely race condition. We have been aborted by our parent,

View File

@@ -73,11 +73,11 @@ enum hello_world_state_type {
// The statemachine class (this is almost a template).
class HelloWorld : public AIStateMachine {
private:
AIStateMachineThread<HelloWorldThread> mHelloWorld;
LLPointer<AIStateMachineThread<HelloWorldThread> > mHelloWorld;
bool mErr;
public:
HelloWorld() : mErr(false) { }
HelloWorld() : mHelloWorld(new AIStateMachineThread<HelloWorldThread>), mErr(false) { }
// Print to stderr or stdout?
void init(bool err) { mErr = err; }
@@ -108,7 +108,7 @@ class HelloWorld : public AIStateMachine {
void HelloWorld::initialize_impl(void)
{
mHelloWorld->init(mErr); // Initialize the thread object.
mHelloWorld->thread_impl().init(mErr); // Initialize the thread object.
set_state(HelloWorld_start);
}
@@ -118,14 +118,14 @@ void HelloWorld::multiplex_impl(state_type run_state)
{
case HelloWorld_start:
{
mHelloWorld.run(this, HelloWorld_done); // Run HelloWorldThread and set the state of 'this' to HelloWorld_done when finished.
mHelloWorld->run(this, HelloWorld_done); // Run HelloWorldThread and set the state of 'this' to HelloWorld_done when finished.
idle(HelloWorld_start); // Always go idle after starting a thread!
break;
}
case HelloWorld_done:
{
// We're done. Lets also abort when the thread reported no success.
if (mHelloWorld->successful()) // Read output/result of thread object.
if (mHelloWorld->thread_impl().successful()) // Read output/result of thread object.
finish();
else
abort();
@@ -139,9 +139,9 @@ void HelloWorld::multiplex_impl(state_type run_state)
class AIStateMachineThreadBase;
// Derive from this to implement the code that must run in another thread.
class AIThreadImpl : public LLThreadSafeRefCount {
class AIThreadImpl {
private:
template<typename THREAD_IMPL> friend struct AIStateMachineThread;
template<typename THREAD_IMPL> friend class AIStateMachineThread;
typedef AIAccess<AIStateMachineThreadBase*> StateMachineThread_wat;
AIThreadSafeSimpleDC<AIStateMachineThreadBase*> mStateMachineThread;
@@ -158,6 +158,9 @@ class AIThreadImpl : public LLThreadSafeRefCount {
public:
char const* getName(void) const { return mName; }
#endif
protected:
virtual ~AIThreadImpl() { }
};
// The base class for statemachine threads.
@@ -178,7 +181,7 @@ class AIStateMachineThreadBase : public AIStateMachine {
static state_type const max_state = wait_stopped + 1;
protected:
AIStateMachineThreadBase(AIThreadImpl* impl) : mImpl(impl) { ref(); /* Never call delete */ }
AIStateMachineThreadBase(void) { }
private:
// Handle initializing the object.
@@ -193,9 +196,11 @@ class AIStateMachineThreadBase : public AIStateMachine {
// Implemenation of state_str for run states.
/*virtual*/ char const* state_str_impl(state_type run_state) const;
// Returns a reference to the implementation code that needs to be run in the thread.
virtual AIThreadImpl& impl(void) = 0;
private:
Thread* mThread; // The thread that the code is run in.
AIThreadImpl* mImpl; // Pointer to the implementation code that needs to be run in the thread.
bool mAbort; // (Inverse of) return value of AIThreadImpl::run(). Only valid in state wait_stopped.
public:
@@ -206,14 +211,22 @@ class AIStateMachineThreadBase : public AIStateMachine {
// The state machine that runs T::run() in a thread.
// THREAD_IMPL Must be derived from AIThreadImpl.
template<typename THREAD_IMPL>
struct AIStateMachineThread : public LLPointer<THREAD_IMPL>, public AIStateMachineThreadBase {
// Constructor.
AIStateMachineThread(void) :
LLPointer<THREAD_IMPL>(new THREAD_IMPL),
AIStateMachineThreadBase(LLPointer<THREAD_IMPL>::get())
{
*AIThreadImpl::StateMachineThread_wat(static_cast<AIThreadImpl*>(LLPointer<THREAD_IMPL>::get())->mStateMachineThread) = this;
}
class AIStateMachineThread : public AIStateMachineThreadBase {
private:
THREAD_IMPL mThreadImpl;
public:
// Constructor.
AIStateMachineThread(void)
{
*AIThreadImpl::StateMachineThread_wat(mThreadImpl.mStateMachineThread) = this;
}
// Accessor.
THREAD_IMPL& thread_impl(void) { return mThreadImpl; }
protected:
/*virtual*/ AIThreadImpl& impl(void) { return mThreadImpl; }
};
#endif

View File

@@ -34,7 +34,7 @@ if (WINDOWS)
endif (MSVC10)
# Remove default /Zm1000 flag that cmake inserts
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# Don't build DLLs.
set(BUILD_SHARED_LIBS OFF)
@@ -270,10 +270,10 @@ endif (DARWIN)
if (LINUX OR DARWIN)
if(${CMAKE_C_COMPILER} MATCHES "gcc*")
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
elseif(${CMAKE_C_COMPILER} MATCHES "clang*")
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor ")
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor")
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable")
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
elseif(${CMAKE_C_COMPILER} MATCHES "icc")
@@ -281,8 +281,11 @@ if (LINUX OR DARWIN)
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
endif()
# Use -DDISABLE_FATAL_WARNINGS:BOOL=FALSE during configuration to enable fatal warnings.
set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.")
if (NOT DISABLE_FATAL_WARNINGS)
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Werror")
set(UNIX_CXX_WARNINGS "${UNIX_CXX_WARNINGS} -Werror")
endif (NOT DISABLE_FATAL_WARNINGS)
set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}")
@@ -333,4 +336,6 @@ MARK_AS_ADVANCED(
CMAKE_SHARED_LINKER_FLAGS_RELEASE
)
include(GooglePerfTools)
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)

View File

@@ -1,4 +1,5 @@
# -*- cmake -*-
include(Prebuilt)
if(WORD_SIZE EQUAL 64)
@@ -47,9 +48,14 @@ else (USE_GOOGLE_PERFTOOLS)
endif (USE_GOOGLE_PERFTOOLS)
if (NOT(DISABLE_TCMALLOC OR USE_GOOGLE_PERFTOOLS OR STANDALONE))
message(STATUS "Building with Google TCMalloc")
set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1)
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
set(GOOGLE_PERFTOOLS_LIBRARIES ${TCMALLOC_LIBRARIES})
if (NOT STATUS_Building_with_Google_TCMalloc)
message(STATUS "Building with Google TCMalloc")
set(STATUS_Building_with_Google_TCMalloc true PARENT_SCOPE)
endif (NOT STATUS_Building_with_Google_TCMalloc)
set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1)
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
set(GOOGLE_PERFTOOLS_LIBRARIES ${TCMALLOC_LIBRARIES})
set(GOOGLE_PERFTOOLS_LINKER_FLAGS ${TCMALLOC_LINKER_FLAGS})
endif()
add_definitions(${TCMALLOC_FLAG})

View File

@@ -1,4 +1,8 @@
# -*- cmake -*-
if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
include(Variables)
if (NOT STANDALONE)
if (WINDOWS)
@@ -45,3 +49,5 @@ else (WINDOWS)
endif (WINDOWS)
mark_as_advanced(DL_LIBRARY PTHREAD_LIBRARY WINDOWS_LIBRARIES)
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)

View File

@@ -1,5 +1,8 @@
# -*- cmake -*-
if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
macro (use_prebuilt_binary _binary)
if(NOT STANDALONE)
get_property(PREBUILT_PACKAGES TARGET prepare PROPERTY PREBUILT)
@@ -9,3 +12,5 @@ macro (use_prebuilt_binary _binary)
endif(_index LESS 0)
endif(NOT STANDALONE)
endmacro (use_prebuilt_binary _binary)
endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)

View File

@@ -92,29 +92,25 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
if(${CMAKE_GENERATOR} MATCHES Xcode)
execute_process(
COMMAND sh -c "xcodebuild -version | grep Xcode | cut -d ' ' -f2 | cut -d'.' -f1-2"
OUTPUT_VARIABLE XCODE_VERSION )
# To support a different SDK update these Xcode settings:
if (XCODE_VERSION GREATER 4.2)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
else (XCODE_VERSION GREATER 4.2)
#SDK Compiler and Deployment targets for XCode
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
endif (XCODE_VERSION GREATER 4.2)
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
else(${CMAKE_GENERATOR} MATCHES Xcode)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
endif(${CMAKE_GENERATOR} MATCHES Xcode)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym)
# Build only for i386 by default, system default on MacOSX 10.6 is x86_64
if (NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES i386)
endif (NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES i386)
set(ARCH i386)
set(WORD_SIZE 32)

View File

@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.6.4)
project(ndPathingLib CXX C)
if( MSVC )
add_definitions(-D_HAS_ITERATOR_DEBUGGING=0 -D_SECURE_SCL=0 -D_CRT_SECURE_NO_WARNINGS=1)
add_definitions(-D_SECURE_SCL=0 -D_CRT_SECURE_NO_WARNINGS=1)
endif( MSVC )
file (GLOB SOURCE_FILES *.cpp )

View File

@@ -465,7 +465,7 @@ void LLAvatarAppearance::computeBodySize()
LLVector3 old_offset = mAvatarOffset;
mAvatarOffset.mV[VZ] = getVisualParamWeight(11001);
mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER);
mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
knee.mV[VZ] * hip_scale.mV[VZ] -
@@ -489,6 +489,25 @@ void LLAvatarAppearance::computeBodySize()
mAvatarOffset.mV[VX] = 0.0f;
mAvatarOffset.mV[VY] = 0.0f;
// Certain configurations of avatars can force the overall height (with offset) to go negative.
// Enforce a constraint to make sure we don't go below 0.1 meters.
// Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f)
{
mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail.
llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f);
if (mWearableData && isSelf())
{
LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0);
if (shape)
{
shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false);
}
}
}
if (new_body_size != mBodySize || old_offset != mAvatarOffset)
{
mBodySize = new_body_size;

View File

@@ -41,6 +41,8 @@ extern const S32 SCRATCH_TEX_WIDTH;
extern const S32 SCRATCH_TEX_HEIGHT;
extern const S32 IMPOSTOR_PERIOD;
static const U32 AVATAR_HOVER = 11001;
//--------------------------------------------------------------------
// Enums
//--------------------------------------------------------------------

View File

@@ -152,8 +152,8 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
<< ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL;
}
result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
// result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
// Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
// In this case, all sounds, PLUS wind and stream will be software.
result = mSystem->setSoftwareChannels(num_channels + 2);

View File

@@ -431,7 +431,7 @@ LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, con
exinfo.cbsize = sizeof(exinfo);
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);
if (result!= FMOD_OK)
{

View File

@@ -33,7 +33,7 @@
#include <apr_portable.h> // apr_os_thread_t, apr_os_thread_current(), apr_os_thread_equal().
#include <iosfwd> // std::ostream.
#include "llpreprocessor.h" // LL_COMMON_API, LL_COMMON_API_TLS
#include "llpreprocessor.h" // LL_COMMON_API, LL_COMMON_API_TLS, LL_UNLIKELY
// Lightweight wrapper around apr_os_thread_t.
// This class introduces no extra assembly code after optimization; it's only intend is to provide type-safety.
@@ -87,6 +87,16 @@ public:
#endif
};
// Debugging function.
inline bool is_single_threaded(AIThreadID& thread_id)
{
if (LL_UNLIKELY(thread_id.is_no_thread()))
{
thread_id.reset();
}
return thread_id.equals_current_thread();
}
// Legacy function.
inline bool is_main_thread(void)
{

View File

@@ -153,7 +153,7 @@ inline S32 LLDynamicArray<Type,BlockSize>::put(const Type &obj)
template <typename Type,int BlockSize>
inline void LLDynamicArray<Type,BlockSize>::operator+=(const LLDynamicArray<Type,BlockSize> &other)
{
insert(this->end(), other.begin(), other.end());
this->insert(this->end(), other.begin(), other.end());
}
//--------------------------------------------------------

View File

@@ -95,7 +95,19 @@ public:
namespace
{
#if LL_WINDOWS
typedef std::filebuf _Myfb;
//typedef std::filebuf _Myfb;
//Singu note: Wrap around std::filebuf to override the open procedure.
// The client encodes filepaths in UTF-8, however Windows uses UTF-16 encoding natively.
// Need to convert paths to UTF-16 before calling std::filebuf::open.
struct _Myfb : public std::filebuf
{
_Myfb() : std::filebuf() {}
_Myfb(_Filet* file) : std::filebuf(file) {}
_Myt *open(const char *filename, std::ios_base::openmode mode, int prot = (int)std::ios_base::_Openprot)
{
return std::filebuf::open(utf8str_to_utf16str(filename).c_str(),mode,prot);
}
};
#else
typedef __gnu_cxx::stdio_filebuf< char > _Myfb;
typedef std::__c_file _Filet;

View File

@@ -57,13 +57,12 @@ inline void ll_aligned_free( void* ptr )
free( ((void**)ptr)[-1] );
}
#if !LL_USE_TCMALLOC
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _aligned_malloc(size, 16);
#elif defined(LL_DARWIN)
#if (LL_DARWIN || LL_USE_TCMALLOC)
return malloc(size); // default osx malloc is 16 byte aligned.
#elif LL_WINDOWS
return _aligned_malloc(size, 16);
#else
void *rtn;
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
@@ -75,10 +74,10 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi
inline void ll_aligned_free_16(void *p)
{
#if defined(LL_WINDOWS)
#if (LL_DARWIN || LL_USE_TCMALLOC)
free(p);
#elif LL_WINDOWS
_aligned_free(p);
#elif defined(LL_DARWIN)
return free(p);
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
@@ -86,10 +85,10 @@ inline void ll_aligned_free_16(void *p)
inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _aligned_realloc(ptr, size, 16);
#elif defined(LL_DARWIN)
#if (LL_DARWIN || LL_USE_TCMALLOC)
return realloc(ptr,size); // default osx malloc is 16 byte aligned.
#elif LL_WINDOWS
return _aligned_realloc(ptr, size, 16);
#else
//FIXME: memcpy is SLOW
void* ret = ll_aligned_malloc_16(size);
@@ -106,18 +105,11 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
#endif
}
#else // USE_TCMALLOC
// ll_aligned_foo_16 are not needed with tcmalloc
#define ll_aligned_malloc_16 malloc
#define ll_aligned_realloc_16(a,b,c) realloc(a,b)
#define ll_aligned_free_16 free
#endif // USE_TCMALLOC
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
{
#if defined(LL_WINDOWS)
#if LL_WINDOWS
return _aligned_malloc(size, 32);
#elif defined(LL_DARWIN)
#elif LL_DARWIN
return ll_aligned_malloc( size, 32 );
#else
void *rtn;
@@ -130,9 +122,9 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
inline void ll_aligned_free_32(void *p)
{
#if defined(LL_WINDOWS)
#if LL_WINDOWS
_aligned_free(p);
#elif defined(LL_DARWIN)
#elif LL_DARWIN
ll_aligned_free( p );
#else
free(p); // posix_memalign() is compatible with heap deallocator

View File

@@ -180,7 +180,6 @@ template <typename T>
//Singu note: This has been generalized to support a broader range of map-esque containers
inline bool is_in_map(const T& inmap, typename const T::key_type& key)
{
typedef typename T::const_iterator map_iter;
if(inmap.find(key) == inmap.end())
{
return false;

View File

@@ -251,7 +251,7 @@ U64 totalTime()
}
else
{
if (current_clock_count >= gLastTotalTimeClockCount)
if (LL_LIKELY(current_clock_count >= gLastTotalTimeClockCount))
{
// No wrapping, we're all okay.
gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;

View File

@@ -34,8 +34,8 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 7;
const S32 LL_VERSION_PATCH = 3;
const S32 LL_VERSION_MINOR = 8;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = ${vBUILD};
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";

View File

@@ -390,11 +390,6 @@ bool LLCrashLogger::init()
// Start state machine thread.
startEngineThread();
// Start curl thread.
AICurlInterface::startCurlThread(64, // CurlMaxTotalConcurrentConnections
8, // CurlConcurrentConnectionsPerHost
true); // NoVerifySSLCert
// We assume that all the logs we're looking for reside on the current drive
gDirUtilp->initAppDirs("SecondLife");
@@ -414,6 +409,9 @@ bool LLCrashLogger::init()
return false;
}
// Start curl thread.
AICurlInterface::startCurlThread(&mCrashSettings);
gServicePump = new LLPumpIO;
//If we've opened the crash logger, assume we can delete the marker file if it exists

View File

@@ -1022,6 +1022,16 @@ void mask_to_string(U32 mask, char* str)
{
*str = ' ';
}
str++;
if (mask & PERM_EXPORT)
{
*str = 'E';
}
else
{
*str = ' ';
}
str++;
*str = '\0';
}

View File

@@ -52,6 +52,9 @@ const PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
// objects, allow copy
const PermissionBit PERM_COPY = (1 << 15); // 0x00008000
// objects, allow exporting
const PermissionBit PERM_EXPORT = (1 << 16); // 0x00010000
// parcels, allow entry, deprecated
//const PermissionBit PERM_ENTER = (1 << 16); // 0x00010000

View File

@@ -24,6 +24,7 @@
* $/LicenseInfo$
*/
#include "sys.h"
#include "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =

View File

@@ -22,9 +22,10 @@ include_directories(
)
set(llmessage_SOURCE_FILES
aiaverage.cpp
aicurl.cpp
aicurleasyrequeststatemachine.cpp
aicurlperhost.cpp
aicurlperservice.cpp
aicurlthread.cpp
aihttpheaders.cpp
aihttptimeout.cpp
@@ -109,9 +110,10 @@ set(llmessage_SOURCE_FILES
set(llmessage_HEADER_FILES
CMakeLists.txt
aiaverage.h
aicurl.h
aicurleasyrequeststatemachine.h
aicurlperhost.h
aicurlperservice.h
aicurlprivate.h
aicurlthread.h
aihttpheaders.h

View File

@@ -0,0 +1,81 @@
/**
* @file aiaverage.cpp
* @brief Implementation of AIAverage
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 11/04/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#include "sys.h"
#include "aiaverage.h"
#include "llerror.h" // llassert
void AIAverage::cleanup(U64 clock_tick)
{
// This expression can fail because the curl thread caches the time in
// sTime_10ms for the duration of an entire loop. Therefore, the time can
// go into the next 40ms and a texture fetch worker thread might call
// cleanup() with that time, setting mCurrentClock to a value (one)
// larger than sTime_10ms / 4. Next, the curl thread can continue to call
// this function with the smaller value; in that case just add the new
// data to the current bucket.
//
// Or, this is just the one-time initialization that happens the first
// time this is called. In that case initialize just mCurrentClock:
// the rest is already initialized upon construction.
if (LL_LIKELY(clock_tick > mCurrentClock))
{
// Advance to the next bucket.
++mCurrentBucket;
mCurrentBucket %= mNrOfBuckets;
// Initialize the new bucket.
mData[mCurrentBucket].time = clock_tick;
// Clean up old buckets.
U64 old_time = clock_tick - mNrOfBuckets;
if (LL_UNLIKELY(mTail == mCurrentBucket) || // Extremely unlikely: only happens when data was added EVERY clock tick for the past mNrOfBuckets clock ticks.
mData[mTail].time <= old_time)
{
do
{
mSum -= mData[mTail].sum;
mN -= mData[mTail].n;
mData[mTail].sum = 0;
mData[mTail].n = 0;
++mTail;
if (LL_UNLIKELY(mTail == mNrOfBuckets))
{
mTail = 0;
}
}
while (mData[mTail].time <= old_time);
}
// This was set to zero when mTail passed this point (likely not this call, but a few calls ago).
llassert(mData[mCurrentBucket].sum == 0 &&
mData[mCurrentBucket].n == 0);
}
mCurrentClock = clock_tick;
return;
}

108
indra/llmessage/aiaverage.h Normal file
View File

@@ -0,0 +1,108 @@
/**
* @file aiaverage.h
* @brief Definition of class AIAverage
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 11/04/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIAVERAGE_H
#define AIAVERAGE_H
#include "llpreprocessor.h"
#include "stdtypes.h" // U32, U64
#include "llthread.h" // LLMutex
#include <cstddef> // size_t
#include <vector>
class AIAverage {
private:
struct Data {
U32 sum; // Accumulated sum of the 'n' passed to operator()(size_t n, U64 clock_tick) with clock_tick == time.
U32 n; // The number of calls to operator().
U64 time; // The clock_tick as passed to operator()(size_t n, U64 clock_tick) that sum corresponds to.
};
U64 mCurrentClock; // The current (last) time that operator() was called with, or -1 when not initialized.
int mTail; // The oldest bucket with still valid data.
int mCurrentBucket; // The bucket that corresponds to mCurrentClock.
size_t mSum; // The sum of all the 'n' passed to operator()(size_t n, U64 clock_tick) for all passed mNrOfBuckets time units.
U32 mN; // The number of calls to operator().
int const mNrOfBuckets; // Size of mData.
std::vector<Data> mData; // The buckets.
LLMutex mLock; // Mutex for all of the above data.
public:
AIAverage(int number_of_buckets) : mCurrentClock(~(U64)0), mTail(0), mCurrentBucket(0), mSum(0), mN(0), mNrOfBuckets(number_of_buckets), mData(number_of_buckets)
{
// Fill mData with all zeroes (much faster than adding a constructor to Data).
std::memset(&*mData.begin(), 0, number_of_buckets * sizeof(Data));
}
size_t addData(U32 n, U64 clock_tick)
{
DoutEntering(dc::curl, "AIAverage::addData(" << n << ", " << clock_tick << ")");
mLock.lock();
if (LL_UNLIKELY(clock_tick != mCurrentClock))
{
cleanup(clock_tick);
}
mSum += n;
mN += 1;
mData[mCurrentBucket].sum += n;
mData[mCurrentBucket].n += 1;
size_t sum = mSum;
mLock.unlock();
Dout(dc::curl, "Current sum: " << sum << ", average: " << (sum / mN));
return sum;
}
size_t truncateData(U64 clock_tick)
{
mLock.lock();
if (clock_tick != mCurrentClock)
{
cleanup(clock_tick);
}
size_t sum = mSum;
mLock.unlock();
return sum;
}
double getAverage(double avg_no_data)
{
mLock.lock();
double avg = mSum;
llassert(mN != 0 || mSum == 0);
if (LL_UNLIKELY(mN == 0))
avg = avg_no_data;
else
avg /= mN;
mLock.unlock();
return avg;
}
private:
void cleanup(U64 clock_tick);
};
#endif // AIAVERAGE

View File

@@ -58,7 +58,7 @@
#include "aihttpheaders.h"
#include "aihttptimeoutpolicy.h"
#include "aicurleasyrequeststatemachine.h"
#include "aicurlperhost.h"
#include "aicurlperservice.h"
//==================================================================================
// Debug Settings
@@ -298,6 +298,7 @@ LLAtomicU32 Stats::easy_init_errors;
LLAtomicU32 Stats::easy_cleanup_calls;
LLAtomicU32 Stats::multi_calls;
LLAtomicU32 Stats::multi_errors;
LLAtomicU32 Stats::running_handles;
LLAtomicU32 Stats::AICurlEasyRequest_count;
LLAtomicU32 Stats::AICurlEasyRequestStateMachine_count;
LLAtomicU32 Stats::BufferedCurlEasyRequest_count;
@@ -460,6 +461,12 @@ void setCAPath(std::string const& path)
CertificateAuthority_w->path = path;
}
// THREAD-SAFE
U32 getNumHTTPRunning(void)
{
return Stats::running_handles;
}
//static
void Stats::print(void)
{
@@ -952,9 +959,9 @@ CurlEasyRequest::~CurlEasyRequest()
// be available anymore.
send_handle_events_to(NULL);
revokeCallbacks();
if (mPerHostPtr)
if (mPerServicePtr)
{
PerHostRequestQueue::release(mPerHostPtr);
AIPerService::release(mPerServicePtr);
}
// This wasn't freed yet if the request never finished.
curl_slist_free_all(mHeaders);
@@ -1084,56 +1091,6 @@ void CurlEasyRequest::applyDefaultOptions(void)
);
}
// url must be of the form
// (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here):
//
// url = sheme ":" hier-part [ "?" query ] [ "#" fragment ]
// hier-part = "//" authority path-abempty
// authority = [ userinfo "@" ] host [ ":" port ]
// path-abempty = *( "/" segment )
//
// That is, a hier-part of the form '/ path-absolute', '/ path-rootless' or
// '/ path-empty' is NOT allowed here. This should be safe because we only
// call this function for curl access, any file access would use APR.
//
// However, as a special exception, this function allows:
//
// url = authority path-abempty
//
// without the 'sheme ":" "//"' parts.
//
// As follows from the ABNF (see RFC, Appendix A):
// - authority is either terminated by a '/' or by the end of the string because
// neither userinfo, host nor port may contain a '/'.
// - userinfo does not contain a '@', and if it exists, is always terminated by a '@'.
// - port does not contain a ':', and if it exists is always prepended by a ':'.
//
// Only called by CurlEasyRequest::finalizeRequest.
static std::string extract_canonical_hostname(std::string const& url)
{
std::string::size_type pos;
std::string::size_type authority = 0; // Default if there is no sheme.
if ((pos = url.find("://")) != url.npos && pos < url.find('/')) authority = pos + 3; // Skip the "sheme://" if any, the second find is to avoid finding a "://" as part of path-abempty.
std::string::size_type host = authority; // Default if there is no userinfo.
if ((pos = url.find('@', authority)) != url.npos) host = pos + 1; // Skip the "userinfo@" if any.
authority = url.length() - 1; // Default last character of host if there is no path-abempty.
if ((pos = url.find('/', host)) != url.npos) authority = pos - 1; // Point to last character of host.
std::string::size_type len = url.find_last_not_of(":0123456789", authority) - host + 1; // Skip trailing ":port", if any.
std::string hostname(url, host, len);
#if APR_CHARSET_EBCDIC
#error Not implemented
#else
// Convert hostname to lowercase in a way that we compare two hostnames equal iff libcurl does.
for (std::string::iterator iter = hostname.begin(); iter != hostname.end(); ++iter)
{
int c = *iter;
if (c >= 'A' && c <= 'Z')
*iter = c + ('a' - 'A');
}
#endif
return hostname;
}
void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine)
{
DoutCurlEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")");
@@ -1156,8 +1113,8 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic
#endif
setopt(CURLOPT_HTTPHEADER, mHeaders);
setoptString(CURLOPT_URL, url);
llassert(!mPerHostPtr);
mLowercaseHostname = extract_canonical_hostname(url);
llassert(!mPerServicePtr);
mLowercaseServicename = AIPerService::extract_canonical_servicename(url);
mTimeoutPolicy = &policy;
state_machine->setTotalDelayTimeout(policy.getTotalDelay());
// The following line is a bit tricky: we store a pointer to the object without increasing its reference count.
@@ -1183,7 +1140,7 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic
// // get less connect time, while it still (also) has to wait for this DNS lookup.
void CurlEasyRequest::set_timeout_opts(void)
{
setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mLowercaseHostname));
setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(getLowercaseHostname()));
setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction());
}
@@ -1279,22 +1236,27 @@ void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_reques
}
#endif
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
AIPerServicePtr CurlEasyRequest::getPerServicePtr(void)
{
if (!mPerHostPtr)
if (!mPerServicePtr)
{
// mPerHostPtr is really just a speed-up cache.
// The reason we can cache it is because mLowercaseHostname is only set
// mPerServicePtr is really just a speed-up cache.
// The reason we can cache it is because mLowercaseServicename is only set
// in finalizeRequest which may only be called once: it never changes.
mPerHostPtr = PerHostRequestQueue::instance(mLowercaseHostname);
mPerServicePtr = AIPerService::instance(mLowercaseServicename);
}
return mPerHostPtr;
return mPerServicePtr;
}
bool CurlEasyRequest::removeFromPerHostQueue(AICurlEasyRequest const& easy_request) const
bool CurlEasyRequest::removeFromPerServiceQueue(AICurlEasyRequest const& easy_request) const
{
// Note that easy_request (must) represent(s) this object; it's just passed for convenience.
return mPerHostPtr && PerHostRequestQueue_wat(*mPerHostPtr)->cancel(easy_request);
return mPerServicePtr && PerServiceRequestQueue_wat(*mPerServicePtr)->cancel(easy_request);
}
std::string CurlEasyRequest::getLowercaseHostname(void) const
{
return mLowercaseServicename.substr(0, mLowercaseServicename.find_last_of(':'));
}
//-----------------------------------------------------------------------------
@@ -1305,8 +1267,9 @@ static int const HTTP_REDIRECTS_DEFAULT = 10;
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex;
bool BufferedCurlEasyRequest::sShuttingDown = false;
AIAverage BufferedCurlEasyRequest::sHTTPBandwidth(25);
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mTotalRawBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
{
AICurlInterface::Stats::BufferedCurlEasyRequest_count++;
}
@@ -1370,7 +1333,7 @@ void BufferedCurlEasyRequest::resetState(void)
mOutput.reset();
mInput.reset();
mRequestTransferedBytes = 0;
mResponseTransferedBytes = 0;
mTotalRawBytes = 0;
mBufferEventsTarget = NULL;
mStatus = HTTP_INTERNAL_ERROR_OTHER;
}

View File

@@ -52,6 +52,7 @@
#include "stdtypes.h" // U16, S32, U32, F64
#include "llatomic.h" // LLAtomicU32
#include "aithreadsafe.h"
#include "aicurlperservice.h" // AIPerServicePtr
// Debug Settings.
extern bool gNoVerifySSLCert;
@@ -60,6 +61,7 @@ class LLSD;
class LLBufferArray;
class LLChannelDescriptors;
class AIHTTPTimeoutPolicy;
class LLControlGroup;
// Some pretty printing for curl easy handle related things:
// Print the lock object related to the current easy handle in every debug output.
@@ -133,6 +135,7 @@ struct Stats {
static LLAtomicU32 easy_cleanup_calls;
static LLAtomicU32 multi_calls;
static LLAtomicU32 multi_errors;
static LLAtomicU32 running_handles;
static LLAtomicU32 AICurlEasyRequest_count;
static LLAtomicU32 AICurlEasyRequestStateMachine_count;
static LLAtomicU32 BufferedCurlEasyRequest_count;
@@ -153,7 +156,7 @@ struct Stats {
// Called to handle changes in Debug Settings.
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue);
bool handleCurlConcurrentConnectionsPerHost(LLSD const& newvalue);
bool handleCurlConcurrentConnectionsPerService(LLSD const& newvalue);
bool handleNoVerifySSLCert(LLSD const& newvalue);
// Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)),
@@ -161,7 +164,7 @@ bool handleNoVerifySSLCert(LLSD const& newvalue);
void initCurl(void);
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentConnectionsPerHost, bool NoVerifySSLCert);
void startCurlThread(LLControlGroup* control_group);
// Called once at the end of application before terminating other threads (most notably the texture thread workers)
// with the purpose to stop the curl thread from doing any call backs to running responders: the responders sometimes
@@ -185,6 +188,22 @@ void setCAFile(std::string const& file);
// Can be used to set the path to the Certificate Authority file.
void setCAPath(std::string const& file);
// Returns number of queued 'add' commands minus the number of queued 'remove' commands.
U32 getNumHTTPCommands(void);
// Returns the number of queued requests.
U32 getNumHTTPQueued(void);
// Returns the number of curl requests currently added to the multi handle.
U32 getNumHTTPAdded(void);
// This used to be LLAppViewer::getTextureFetch()->getNumHTTPRequests().
// Returns the number of active curl easy handles (that are actually attempting to download something).
U32 getNumHTTPRunning(void);
// Cache for gSavedSettings so we have access from llmessage.
extern LLControlGroup* sConfigGroup;
} // namespace AICurlInterface
// Forward declaration (see aicurlprivate.h).

View File

@@ -1,175 +0,0 @@
/**
* @file aiperhost.cpp
* @brief Implementation of PerHostRequestQueue
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 04/11/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#include "sys.h"
#include "aicurlperhost.h"
#include "aicurlthread.h"
#undef AICurlPrivate
namespace AICurlPrivate {
PerHostRequestQueue::threadsafe_instance_map_type PerHostRequestQueue::sInstanceMap;
U32 curl_concurrent_connections_per_host;
//static
PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname)
{
llassert(!hostname.empty());
instance_map_wat instance_map_w(sInstanceMap);
PerHostRequestQueue::iterator iter = instance_map_w->find(hostname);
if (iter == instance_map_w->end())
{
iter = instance_map_w->insert(instance_map_type::value_type(hostname, new RefCountedThreadSafePerHostRequestQueue)).first;
}
// Note: the creation of PerHostRequestQueuePtr MUST be protected by the lock on sInstanceMap (see release()).
return iter->second;
}
//static
void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
{
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
{
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
if (LLApp::isStopped())
{
return;
}
instance_map_wat instance_map_w(sInstanceMap);
// It is possible that 'exactly_two_left' is not up to date anymore.
// Therefore, recheck the condition now that we have locked sInstanceMap.
if (!instance->exactly_two_left())
{
// Some other thread added this host in the meantime.
return;
}
// The reference in the map is the last one; that means there can't be any curl easy requests queued for this host.
llassert(PerHostRequestQueue_wat(*instance)->mQueuedRequests.empty());
// Find the host and erase it from the map.
iterator const end = instance_map_w->end();
for(iterator iter = instance_map_w->begin(); iter != end; ++iter)
{
if (instance == iter->second)
{
instance_map_w->erase(iter);
instance.reset();
return;
}
}
// We should always find the host.
llassert(false);
}
instance.reset();
}
bool PerHostRequestQueue::throttled() const
{
llassert(mAdded <= int(curl_concurrent_connections_per_host));
return mAdded == int(curl_concurrent_connections_per_host);
}
void PerHostRequestQueue::added_to_multi_handle(void)
{
llassert(mAdded < int(curl_concurrent_connections_per_host));
++mAdded;
}
void PerHostRequestQueue::removed_from_multi_handle(void)
{
--mAdded;
llassert(mAdded >= 0);
}
void PerHostRequestQueue::queue(AICurlEasyRequest const& easy_request)
{
mQueuedRequests.push_back(easy_request.get_ptr());
}
bool PerHostRequestQueue::cancel(AICurlEasyRequest const& easy_request)
{
queued_request_type::iterator const end = mQueuedRequests.end();
queued_request_type::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request.get_ptr());
if (cur == end)
return false; // Not found.
// We can't use erase because that uses assignment to move elements,
// because it isn't thread-safe. Therefore, move the element that we found to
// the back with swap (could just swap with the end immediately, but I don't
// want to break the order in which requests where added). Swap is also not
// thread-safe, but OK here because it only touches the objects in the deque,
// and the deque is protected by the lock on the PerHostRequestQueue object.
queued_request_type::iterator prev = cur;
while (++cur != end)
{
prev->swap(*cur); // This is safe,
prev = cur;
}
mQueuedRequests.pop_back(); // if this is safe.
return true;
}
void PerHostRequestQueue::add_queued_to(curlthread::MultiHandle* multi_handle)
{
if (!mQueuedRequests.empty())
{
multi_handle->add_easy_request(mQueuedRequests.front());
mQueuedRequests.pop_front();
}
}
//static
void PerHostRequestQueue::purge(void)
{
instance_map_wat instance_map_w(sInstanceMap);
for (iterator host = instance_map_w->begin(); host != instance_map_w->end(); ++host)
{
Dout(dc::curl, "Purging queue of host \"" << host->first << "\".");
PerHostRequestQueue_wat(*host->second)->mQueuedRequests.clear();
}
}
// Friend functions of RefCountedThreadSafePerHostRequestQueue
void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* per_host)
{
per_host->mReferenceCount++;
}
void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* per_host)
{
if (--per_host->mReferenceCount == 0)
{
delete per_host;
}
}
} // namespace AICurlPrivate

View File

@@ -1,135 +0,0 @@
/**
* @file aicurlperhost.h
* @brief Definition of class PerHostRequestQueue
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 04/11/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AICURLPERHOST_H
#define AICURLPERHOST_H
#include "llerror.h" // llassert
#include <string>
#include <deque>
#include <map>
#include <boost/intrusive_ptr.hpp>
#include "aithreadsafe.h"
class AICurlEasyRequest;
namespace AICurlPrivate {
namespace curlthread { class MultiHandle; }
class PerHostRequestQueue;
class RefCountedThreadSafePerHostRequestQueue;
class ThreadSafeBufferedCurlEasyRequest;
// Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h).
typedef boost::intrusive_ptr<ThreadSafeBufferedCurlEasyRequest> BufferedCurlEasyRequestPtr;
// PerHostRequestQueue objects are created by the curl thread and destructed by the main thread.
// We need locking.
typedef AIThreadSafeSimpleDC<PerHostRequestQueue> threadsafe_PerHostRequestQueue;
typedef AIAccessConst<PerHostRequestQueue> PerHostRequestQueue_crat;
typedef AIAccess<PerHostRequestQueue> PerHostRequestQueue_rat;
typedef AIAccess<PerHostRequestQueue> PerHostRequestQueue_wat;
// We can't put threadsafe_PerHostRequestQueue in a std::map because you can't copy a mutex.
// Therefore, use an intrusive pointer for the threadsafe type.
typedef boost::intrusive_ptr<RefCountedThreadSafePerHostRequestQueue> PerHostRequestQueuePtr;
//-----------------------------------------------------------------------------
// PerHostRequestQueue
// This class provides a static interface to create and maintain instances
// of PerHostRequestQueue objects, so that at any moment there is at most
// one instance per hostname. Those instances then are used to queue curl
// requests when the maximum number of connections for that host already
// have been reached.
class PerHostRequestQueue {
private:
typedef std::map<std::string, PerHostRequestQueuePtr> instance_map_type;
typedef AIThreadSafeSimpleDC<instance_map_type> threadsafe_instance_map_type;
typedef AIAccess<instance_map_type> instance_map_rat;
typedef AIAccess<instance_map_type> instance_map_wat;
static threadsafe_instance_map_type sInstanceMap; // Map of PerHostRequestQueue instances with the hostname as key.
friend class AIThreadSafeSimpleDC<PerHostRequestQueue>; //threadsafe_PerHostRequestQueue
PerHostRequestQueue(void) : mAdded(0) { }
public:
typedef instance_map_type::iterator iterator;
typedef instance_map_type::const_iterator const_iterator;
// Return (possibly create) a unique instance for the given hostname.
static PerHostRequestQueuePtr instance(std::string const& hostname);
// Release instance (object will be deleted if this was the last instance).
static void release(PerHostRequestQueuePtr& instance);
// Remove everything. Called upon viewer exit.
static void purge(void);
private:
typedef std::deque<BufferedCurlEasyRequestPtr> queued_request_type;
int mAdded; // Number of active easy handles with this host.
queued_request_type mQueuedRequests; // Waiting (throttled) requests.
public:
void added_to_multi_handle(void); // Called when an easy handle for this host has been added to the multi handle.
void removed_from_multi_handle(void); // Called when an easy handle for this host is removed again from the multi handle.
bool throttled(void) const; // Returns true if the maximum number of allowed requests for this host have been added to the multi handle.
void queue(AICurlEasyRequest const& easy_request); // Add easy_request to the queue.
bool cancel(AICurlEasyRequest const& easy_request); // Remove easy_request from the queue (if it's there).
void add_queued_to(curlthread::MultiHandle* mh); // Add queued easy handle (if any) to the multi handle. The request is removed from the queue,
// followed by either a call to added_to_multi_handle() or to queue() to add it back.
private:
// Disallow copying.
PerHostRequestQueue(PerHostRequestQueue const&) { }
};
class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue {
public:
RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { }
bool exactly_two_left(void) const { return mReferenceCount == 2; }
private:
// Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero.
LLAtomicU32 mReferenceCount;
friend void intrusive_ptr_add_ref(RefCountedThreadSafePerHostRequestQueue* p);
friend void intrusive_ptr_release(RefCountedThreadSafePerHostRequestQueue* p);
};
extern U32 curl_concurrent_connections_per_host;
} // namespace AICurlPrivate
#endif // AICURLPERHOST_H

View File

@@ -0,0 +1,356 @@
/**
* @file aiperservice.cpp
* @brief Implementation of AIPerService
*
* Copyright (c) 2012, 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 04/11/2012
* Initial version, written by Aleric Inglewood @ SL
*
* 06/04/2013
* Renamed AICurlPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr]
* to allow public access.
*
* 09/04/2013
* Renamed everything "host" to "service" and use "hostname:port" as key
* instead of just "hostname".
*/
#include "sys.h"
#include "aicurlperservice.h"
#include "aicurlthread.h"
#include "llcontrol.h"
AIPerService::threadsafe_instance_map_type AIPerService::sInstanceMap;
LLAtomicS32 AIPerService::sTotalQueued;
bool AIPerService::sQueueEmpty;
bool AIPerService::sQueueFull;
bool AIPerService::sRequestStarvation;
#undef AICurlPrivate
namespace AICurlPrivate {
// Cached value of CurlConcurrentConnectionsPerService.
U32 CurlConcurrentConnectionsPerService;
// Friend functions of RefCountedThreadSafePerServiceRequestQueue
void intrusive_ptr_add_ref(RefCountedThreadSafePerServiceRequestQueue* per_service)
{
per_service->mReferenceCount++;
}
void intrusive_ptr_release(RefCountedThreadSafePerServiceRequestQueue* per_service)
{
if (--per_service->mReferenceCount == 0)
{
delete per_service;
}
}
} // namespace AICurlPrivate
using namespace AICurlPrivate;
AIPerService::AIPerService(void) :
mQueuedCommands(0), mAdded(0), mQueueEmpty(false),
mQueueFull(false), mRequestStarvation(false), mHTTPBandwidth(25), // 25 = 1000 ms / 40 ms.
mConcurrectConnections(CurlConcurrentConnectionsPerService),
mMaxPipelinedRequests(CurlConcurrentConnectionsPerService)
{
}
AIPerService::~AIPerService()
{
}
// Fake copy constructor.
AIPerService::AIPerService(AIPerService const&) : mHTTPBandwidth(0)
{
}
// url must be of the form
// (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here):
//
// url = sheme ":" hier-part [ "?" query ] [ "#" fragment ]
// hier-part = "//" authority path-abempty
// authority = [ userinfo "@" ] host [ ":" port ]
// path-abempty = *( "/" segment )
//
// That is, a hier-part of the form '/ path-absolute', '/ path-rootless' or
// '/ path-empty' is NOT allowed here. This should be safe because we only
// call this function for curl access, any file access would use APR.
//
// However, as a special exception, this function allows:
//
// url = authority path-abempty
//
// without the 'sheme ":" "//"' parts.
//
// As follows from the ABNF (see RFC, Appendix A):
// - authority is either terminated by a '/' or by the end of the string because
// neither userinfo, host nor port may contain a '/'.
// - userinfo does not contain a '@', and if it exists, is always terminated by a '@'.
// - port does not contain a ':', and if it exists is always prepended by a ':'.
//
//static
std::string AIPerService::extract_canonical_servicename(std::string const& url)
{
char const* p = url.data();
char const* const end = p + url.size();
char const* sheme_colon = NULL;
char const* sheme_slash = NULL;
char const* first_ampersand = NULL;
char const* port_colon = NULL;
std::string servicename;
char const* hostname = p; // Default in the case there is no "sheme://userinfo@".
while (p < end)
{
int c = *p;
if (c == ':')
{
if (!port_colon && LLStringOps::isDigit(p[1]))
{
port_colon = p;
}
else if (!sheme_colon && !sheme_slash && !first_ampersand && !port_colon)
{
// Found a colon before any slash or ampersand: this has to be the colon between the sheme and the hier-part.
sheme_colon = p;
}
}
else if (c == '/')
{
if (!sheme_slash && sheme_colon && sheme_colon == p - 1 && !first_ampersand && p[1] == '/')
{
// Found the first '/' in the first occurance of the sequence "://".
sheme_slash = p;
hostname = ++p + 1; // Point hostname to the start of the authority, the default when there is no "userinfo@" part.
servicename.clear(); // Remove the sheme.
}
else
{
// Found slash that is not part of the "sheme://" string. Signals end of authority.
// We're done.
break;
}
}
else if (c == '@')
{
if (!first_ampersand)
{
first_ampersand = p;
hostname = p + 1;
servicename.clear(); // Remove the "userinfo@"
}
}
if (p >= hostname)
{
// Convert hostname to lowercase in a way that we compare two hostnames equal iff libcurl does.
#if APR_CHARSET_EBCDIC
#error Not implemented
#else
if (c >= 'A' && c <= 'Z')
c += ('a' - 'A');
#endif
servicename += c;
}
++p;
}
// Strip of any trailing ":80".
if (p - 3 == port_colon && p[-1] == '0' && p[-2] == '8')
{
return servicename.substr(0, p - hostname - 3);
}
return servicename;
}
//static
AIPerServicePtr AIPerService::instance(std::string const& servicename)
{
llassert(!servicename.empty());
instance_map_wat instance_map_w(sInstanceMap);
AIPerService::iterator iter = instance_map_w->find(servicename);
if (iter == instance_map_w->end())
{
iter = instance_map_w->insert(instance_map_type::value_type(servicename, new RefCountedThreadSafePerServiceRequestQueue)).first;
}
// Note: the creation of AIPerServicePtr MUST be protected by the lock on sInstanceMap (see release()).
return iter->second;
}
//static
void AIPerService::release(AIPerServicePtr& instance)
{
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
{
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
if (LLApp::isStopped())
{
return;
}
instance_map_wat instance_map_w(sInstanceMap);
// It is possible that 'exactly_two_left' is not up to date anymore.
// Therefore, recheck the condition now that we have locked sInstanceMap.
if (!instance->exactly_two_left())
{
// Some other thread added this host in the meantime.
return;
}
// The reference in the map is the last one; that means there can't be any curl easy requests queued for this host.
llassert(PerServiceRequestQueue_rat(*instance)->mQueuedRequests.empty());
// Find the host and erase it from the map.
iterator const end = instance_map_w->end();
for(iterator iter = instance_map_w->begin(); iter != end; ++iter)
{
if (instance == iter->second)
{
instance_map_w->erase(iter);
instance.reset();
return;
}
}
// We should always find the host.
llassert(false);
}
instance.reset();
}
bool AIPerService::throttled() const
{
return mAdded >= mConcurrectConnections;
}
void AIPerService::added_to_multi_handle(void)
{
++mAdded;
}
void AIPerService::removed_from_multi_handle(void)
{
--mAdded;
llassert(mAdded >= 0);
}
void AIPerService::queue(AICurlEasyRequest const& easy_request)
{
mQueuedRequests.push_back(easy_request.get_ptr());
sTotalQueued++;
}
bool AIPerService::cancel(AICurlEasyRequest const& easy_request)
{
queued_request_type::iterator const end = mQueuedRequests.end();
queued_request_type::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request.get_ptr());
if (cur == end)
return false; // Not found.
// We can't use erase because that uses assignment to move elements,
// because it isn't thread-safe. Therefore, move the element that we found to
// the back with swap (could just swap with the end immediately, but I don't
// want to break the order in which requests where added). Swap is also not
// thread-safe, but OK here because it only touches the objects in the deque,
// and the deque is protected by the lock on the AIPerService object.
queued_request_type::iterator prev = cur;
while (++cur != end)
{
prev->swap(*cur); // This is safe,
prev = cur;
}
mQueuedRequests.pop_back(); // if this is safe.
--sTotalQueued;
llassert(sTotalQueued >= 0);
return true;
}
void AIPerService::add_queued_to(curlthread::MultiHandle* multi_handle)
{
if (!mQueuedRequests.empty())
{
multi_handle->add_easy_request(mQueuedRequests.front());
mQueuedRequests.pop_front();
llassert(sTotalQueued > 0);
if (!--sTotalQueued)
{
// We obtained a request from the queue, and after that there we no more request in any queue.
sQueueEmpty = true;
}
else
{
// We obtained a request from the queue, and even after that there was at least one more request in some queue.
sQueueFull = true;
}
if (mQueuedRequests.empty())
{
// We obtained a request from the queue, and after that there we no more request in the queue of this host.
mQueueEmpty = true;
}
else
{
// We obtained a request from the queue, and even after that there was at least one more request in the queue of this host.
mQueueFull = true;
}
}
else
{
// We can add a new request, but there is none in the queue!
mRequestStarvation = true;
if (sTotalQueued == 0)
{
// The queue of every host is empty!
sRequestStarvation = true;
}
}
}
//static
void AIPerService::purge(void)
{
instance_map_wat instance_map_w(sInstanceMap);
for (iterator host = instance_map_w->begin(); host != instance_map_w->end(); ++host)
{
Dout(dc::curl, "Purging queue of host \"" << host->first << "\".");
PerServiceRequestQueue_wat per_service_w(*host->second);
size_t s = per_service_w->mQueuedRequests.size();
per_service_w->mQueuedRequests.clear();
sTotalQueued -= s;
llassert(sTotalQueued >= 0);
}
}
//static
void AIPerService::adjust_concurrent_connections(int increment)
{
instance_map_wat instance_map_w(sInstanceMap);
for (AIPerService::iterator iter = instance_map_w->begin(); iter != instance_map_w->end(); ++iter)
{
PerServiceRequestQueue_wat per_service_w(*iter->second);
U32 old_concurrent_connections = per_service_w->mConcurrectConnections;
per_service_w->mConcurrectConnections = llclamp(old_concurrent_connections + increment, (U32)1, CurlConcurrentConnectionsPerService);
increment = per_service_w->mConcurrectConnections - old_concurrent_connections;
per_service_w->mMaxPipelinedRequests = llmax(per_service_w->mMaxPipelinedRequests + increment, 0);
}
}

View File

@@ -0,0 +1,187 @@
/**
* @file aicurlperservice.h
* @brief Definition of class AIPerService
*
* Copyright (c) 2012, 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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.
*
* CHANGELOG
* and additional copyright holders.
*
* 04/11/2012
* Initial version, written by Aleric Inglewood @ SL
*
* 06/04/2013
* Renamed AIPrivate::PerHostRequestQueue[Ptr] to AIPerHostRequestQueue[Ptr]
* to allow public access.
*
* 09/04/2013
* Renamed everything "host" to "service" and use "hostname:port" as key
* instead of just "hostname".
*/
#ifndef AICURLPERSERVICE_H
#define AICURLPERSERVICE_H
#include "llerror.h" // llassert
#include <string>
#include <deque>
#include <map>
#include <boost/intrusive_ptr.hpp>
#include "aithreadsafe.h"
#include "aiaverage.h"
class AICurlEasyRequest;
class AIPerService;
namespace AICurlPrivate {
namespace curlthread { class MultiHandle; }
class RefCountedThreadSafePerServiceRequestQueue;
class ThreadSafeBufferedCurlEasyRequest;
// Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h).
typedef boost::intrusive_ptr<ThreadSafeBufferedCurlEasyRequest> BufferedCurlEasyRequestPtr;
// AIPerService objects are created by the curl thread and destructed by the main thread.
// We need locking.
typedef AIThreadSafeSimpleDC<AIPerService> threadsafe_PerServiceRequestQueue;
typedef AIAccessConst<AIPerService> PerServiceRequestQueue_crat;
typedef AIAccess<AIPerService> PerServiceRequestQueue_rat;
typedef AIAccess<AIPerService> PerServiceRequestQueue_wat;
} // namespace AICurlPrivate
// We can't put threadsafe_PerServiceRequestQueue in a std::map because you can't copy a mutex.
// Therefore, use an intrusive pointer for the threadsafe type.
typedef boost::intrusive_ptr<AICurlPrivate::RefCountedThreadSafePerServiceRequestQueue> AIPerServicePtr;
//-----------------------------------------------------------------------------
// AIPerService
// This class provides a static interface to create and maintain instances
// of AIPerService objects, so that at any moment there is at most
// one instance per hostname:port. Those instances then are used to queue curl
// requests when the maximum number of connections for that host already
// have been reached.
class AIPerService {
private:
typedef std::map<std::string, AIPerServicePtr> instance_map_type;
typedef AIThreadSafeSimpleDC<instance_map_type> threadsafe_instance_map_type;
typedef AIAccess<instance_map_type> instance_map_rat;
typedef AIAccess<instance_map_type> instance_map_wat;
static threadsafe_instance_map_type sInstanceMap; // Map of AIPerService instances with the hostname as key.
friend class AIThreadSafeSimpleDC<AIPerService>; //threadsafe_PerServiceRequestQueue
AIPerService(void);
public:
~AIPerService();
public:
typedef instance_map_type::iterator iterator;
typedef instance_map_type::const_iterator const_iterator;
// Utility function; extract canonical (lowercase) hostname and port from url.
static std::string extract_canonical_servicename(std::string const& url);
// Return (possibly create) a unique instance for the given hostname.
static AIPerServicePtr instance(std::string const& servicename);
// Release instance (object will be deleted if this was the last instance).
static void release(AIPerServicePtr& instance);
// Remove everything. Called upon viewer exit.
static void purge(void);
private:
typedef std::deque<AICurlPrivate::BufferedCurlEasyRequestPtr> queued_request_type;
int mQueuedCommands; // Number of add commands (minus remove commands) with this host in the command queue.
int mAdded; // Number of active easy handles with this host.
queued_request_type mQueuedRequests; // Waiting (throttled) requests.
static LLAtomicS32 sTotalQueued; // The sum of mQueuedRequests.size() of all AIPerService objects together.
bool mQueueEmpty; // Set to true when the queue becomes precisely empty.
bool mQueueFull; // Set to true when the queue is popped and then still isn't empty;
bool mRequestStarvation; // Set to true when the queue was about to be popped but was already empty.
static bool sQueueEmpty; // Set to true when sTotalQueued becomes precisely zero as the result of popping any queue.
static bool sQueueFull; // Set to true when sTotalQueued is still larger than zero after popping any queue.
static bool sRequestStarvation; // Set to true when any queue was about to be popped when sTotalQueued was already zero.
AIAverage mHTTPBandwidth; // Keeps track on number of bytes received for this service in the past second.
int mConcurrectConnections; // The maximum number of allowed concurrent connections to this service.
int mMaxPipelinedRequests; // The maximum number of accepted requests that didn't finish yet.
public:
void added_to_command_queue(void) { ++mQueuedCommands; }
void removed_from_command_queue(void) { --mQueuedCommands; llassert(mQueuedCommands >= 0); }
void added_to_multi_handle(void); // Called when an easy handle for this host has been added to the multi handle.
void removed_from_multi_handle(void); // Called when an easy handle for this host is removed again from the multi handle.
bool throttled(void) const; // Returns true if the maximum number of allowed requests for this host have been added to the multi handle.
void queue(AICurlEasyRequest const& easy_request); // Add easy_request to the queue.
bool cancel(AICurlEasyRequest const& easy_request); // Remove easy_request from the queue (if it's there).
void add_queued_to(AICurlPrivate::curlthread::MultiHandle* mh);
// Add queued easy handle (if any) to the multi handle. The request is removed from the queue,
// followed by either a call to added_to_multi_handle() or to queue() to add it back.
S32 pipelined_requests(void) const { return mQueuedCommands + mQueuedRequests.size() + mAdded; }
static S32 total_queued_size(void) { return sTotalQueued; }
AIAverage& bandwidth(void) { return mHTTPBandwidth; }
AIAverage const& bandwidth(void) const { return mHTTPBandwidth; }
// Called when CurlConcurrentConnectionsPerService changes.
static void adjust_concurrent_connections(int increment);
// Returns true if curl can handle another request for this host.
// Should return false if the maximum allowed HTTP bandwidth is reached, or when
// the latency between request and actual delivery becomes too large.
static bool wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service, F32 max_kbps, bool no_bandwidth_throttling);
private:
// Disallow copying.
AIPerService(AIPerService const&);
};
namespace AICurlPrivate {
class RefCountedThreadSafePerServiceRequestQueue : public threadsafe_PerServiceRequestQueue {
public:
RefCountedThreadSafePerServiceRequestQueue(void) : mReferenceCount(0) { }
bool exactly_two_left(void) const { return mReferenceCount == 2; }
private:
// Used by AIPerServicePtr. Object is deleted when reference count reaches zero.
LLAtomicU32 mReferenceCount;
friend void intrusive_ptr_add_ref(RefCountedThreadSafePerServiceRequestQueue* p);
friend void intrusive_ptr_release(RefCountedThreadSafePerServiceRequestQueue* p);
};
extern U32 CurlConcurrentConnectionsPerService;
} // namespace AICurlPrivate
#endif // AICURLPERSERVICE_H

View File

@@ -34,7 +34,7 @@
#include <sstream>
#include "llatomic.h"
#include "llrefcount.h"
#include "aicurlperhost.h"
#include "aicurlperservice.h"
#include "aihttptimeout.h"
#include "llhttpclient.h"
@@ -304,8 +304,8 @@ class CurlEasyRequest : public CurlEasyHandle {
CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object.
AIHTTPTimeoutPolicy const* mTimeoutPolicy;
std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url.
PerHostRequestQueuePtr mPerHostPtr; // Pointer to the corresponding PerHostRequestQueue.
std::string mLowercaseServicename; // Lowercase hostname:port (canonicalized) extracted from the url.
AIPerServicePtr mPerServicePtr; // Pointer to the corresponding AIPerService.
LLPointer<curlthread::HTTPTimeout> mTimeout;// Timeout administration object associated with last created CurlSocketInfo.
bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo.
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
@@ -316,7 +316,8 @@ class CurlEasyRequest : public CurlEasyHandle {
public:
// These two are only valid after finalizeRequest.
AIHTTPTimeoutPolicy const* getTimeoutPolicy(void) const { return mTimeoutPolicy; }
std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; }
std::string const& getLowercaseServicename(void) const { return mLowercaseServicename; }
std::string getLowercaseHostname(void) const;
// Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request.
// This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan).
LLPointer<curlthread::HTTPTimeout>& get_timeout_object(void);
@@ -347,10 +348,10 @@ class CurlEasyRequest : public CurlEasyHandle {
inline ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);
inline ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const;
// PerHost API.
PerHostRequestQueuePtr getPerHostPtr(void); // (Optionally create and) return a pointer to the unique
// PerHostRequestQueue corresponding to mLowercaseHostname.
bool removeFromPerHostQueue(AICurlEasyRequest const&) const; // Remove this request from the per-host queue, if queued at all.
// PerService API.
AIPerServicePtr getPerServicePtr(void); // (Optionally create and) return a pointer to the unique
// AIPerService corresponding to mLowercaseServicename.
bool removeFromPerServiceQueue(AICurlEasyRequest const&) const; // Remove this request from the per-host queue, if queued at all.
// Returns true if it was queued.
protected:
// Pass events to parent.
@@ -395,6 +396,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
// Post-initialization, set the parent to pass the events to.
void send_buffer_events_to(AIBufferedCurlEasyRequestEvents* target) { mBufferEventsTarget = target; }
// Called whenever new body data was (might be) received. Keeps track of the used HTTP bandwidth.
void update_body_bandwidth(void);
protected:
// Events from this class.
/*virtual*/ void received_HTTP_header(void);
@@ -410,13 +414,14 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
U32 mStatus; // HTTP status, decoded from the first header line.
std::string mReason; // The "reason" from the same header line.
U32 mRequestTransferedBytes;
U32 mResponseTransferedBytes;
size_t mTotalRawBytes; // Raw body data (still, possibly, compressed) received from the server so far.
AIBufferedCurlEasyRequestEvents* mBufferEventsTarget;
public:
static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()).
static LLMutex sResponderCallbackMutex; // Locked while calling back any overridden ResponderBase::finished and/or accessing sShuttingDown.
static bool sShuttingDown; // If true, no additional calls to ResponderBase::finished will be made anymore.
static AIAverage sHTTPBandwidth; // HTTP bandwidth usage of all services combined.
private:
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.

View File

@@ -32,10 +32,12 @@
#include "aicurlthread.h"
#include "aihttptimeoutpolicy.h"
#include "aihttptimeout.h"
#include "aicurlperhost.h"
#include "aicurlperservice.h"
#include "aiaverage.h"
#include "lltimer.h" // ms_sleep, get_clock_count
#include "llhttpstatuscodes.h"
#include "llbuffer.h"
#include "llcontrol.h"
#include <sys/types.h>
#if !LL_WINDOWS
#include <sys/select.h>
@@ -204,6 +206,8 @@ int ioctlsocket(int fd, int, unsigned long* nonblocking_enable)
namespace AICurlPrivate {
LLAtomicS32 max_pipelined_requests(32);
enum command_st {
cmd_none,
cmd_add,
@@ -264,9 +268,15 @@ void Command::reset(void)
//
// If at this point addRequest is called again, then it is detected that the ThreadSafeBufferedCurlEasyRequest is active.
struct command_queue_st {
std::deque<Command> commands; // The commands
size_t size; // Number of add commands in the queue minus the number of remove commands.
};
// Multi-threaded queue for passing Command objects from the main-thread to the curl-thread.
AIThreadSafeSimpleDC<std::deque<Command> > command_queue;
typedef AIAccess<std::deque<Command> > command_queue_wat;
AIThreadSafeSimpleDC<command_queue_st> command_queue; // Fills 'size' with zero, because it's a global.
typedef AIAccess<command_queue_st> command_queue_wat;
typedef AIAccess<command_queue_st> command_queue_rat;
AIThreadSafeDC<Command> command_being_processed;
typedef AIWriteAccess<Command> command_being_processed_wat;
@@ -1289,7 +1299,7 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
// Access command_queue, and move command to command_being_processed.
{
command_queue_wat command_queue_w(command_queue);
if (command_queue_w->empty())
if (command_queue_w->commands.empty())
{
mWakeUpFlagMutex.lock();
mWakeUpFlag = false;
@@ -1297,8 +1307,22 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
break;
}
// Move the next command from the queue into command_being_processed.
*command_being_processed_wat(command_being_processed) = command_queue_w->front();
command_queue_w->pop_front();
command_st command;
{
command_being_processed_wat command_being_processed_w(command_being_processed);
*command_being_processed_w = command_queue_w->commands.front();
command = command_being_processed_w->command();
}
// Update the size: the number netto number of pending requests in the command queue.
command_queue_w->commands.pop_front();
if (command == cmd_add)
{
command_queue_w->size--;
}
else if (command == cmd_remove)
{
command_queue_w->size++;
}
}
// Access command_being_processed only.
{
@@ -1309,9 +1333,11 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
case cmd_boost: // FIXME: future stuff
break;
case cmd_add:
PerServiceRequestQueue_wat(*AICurlEasyRequest_wat(*command_being_processed_r->easy_request())->getPerServicePtr())->removed_from_command_queue();
multi_handle_w->add_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()));
break;
case cmd_remove:
PerServiceRequestQueue_wat(*AICurlEasyRequest_wat(*command_being_processed_r->easy_request())->getPerServicePtr())->added_to_command_queue(); // Not really, but this has the same effect as 'removed a remove command'.
multi_handle_w->remove_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()), true);
break;
}
@@ -1520,8 +1546,8 @@ void AICurlThread::run(void)
continue;
}
// Clock count used for timeouts.
HTTPTimeout::sClockCount = get_clock_count();
Dout(dc::curl, "HTTPTimeout::sClockCount = " << HTTPTimeout::sClockCount);
HTTPTimeout::sTime_10ms = get_clock_count() * HTTPTimeout::sClockWidth_10ms;
Dout(dc::curl, "HTTPTimeout::sTime_10ms = " << HTTPTimeout::sTime_10ms);
if (ready == 0)
{
multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0);
@@ -1553,7 +1579,7 @@ void AICurlThread::run(void)
multi_handle_w->check_msg_queue();
}
// Clear the queued requests.
PerHostRequestQueue::purge();
AIPerService::purge();
}
AICurlMultiHandle::destroyInstance();
}
@@ -1561,6 +1587,8 @@ void AICurlThread::run(void)
//-----------------------------------------------------------------------------
// MultiHandle
LLAtomicU32 MultiHandle::sTotalAdded;
MultiHandle::MultiHandle(void) : mTimeout(-1), mReadPollSet(NULL), mWritePollSet(NULL)
{
mReadPollSet = new PollSet;
@@ -1653,6 +1681,7 @@ CURLMcode MultiHandle::socket_action(curl_socket_t sockfd, int ev_bitmask)
}
while(res == CURLM_CALL_MULTI_PERFORM);
llassert(mAddedEasyRequests.size() >= (size_t)running_handles);
AICurlInterface::Stats::running_handles = running_handles;
return res;
}
@@ -1677,17 +1706,17 @@ static U32 curl_max_total_concurrent_connections = 32; // Initialized on st
void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request)
{
bool throttled = true; // Default.
PerHostRequestQueuePtr per_host;
AIPerServicePtr per_service;
{
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
per_host = curl_easy_request_w->getPerHostPtr();
PerHostRequestQueue_wat per_host_w(*per_host);
if (mAddedEasyRequests.size() < curl_max_total_concurrent_connections && !per_host_w->throttled())
per_service = curl_easy_request_w->getPerServicePtr();
PerServiceRequestQueue_wat per_service_w(*per_service);
if (mAddedEasyRequests.size() < curl_max_total_concurrent_connections && !per_service_w->throttled())
{
curl_easy_request_w->set_timeout_opts();
if (curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle) == CURLM_OK)
{
per_host_w->added_to_multi_handle(); // (About to be) added to mAddedEasyRequests.
per_service_w->added_to_multi_handle(); // (About to be) added to mAddedEasyRequests.
throttled = false; // Fall through...
}
}
@@ -1696,11 +1725,14 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request)
{ // ... to here.
std::pair<addedEasyRequests_type::iterator, bool> res = mAddedEasyRequests.insert(easy_request);
llassert(res.second); // May not have been added before.
Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
sTotalAdded++;
llassert(sTotalAdded == mAddedEasyRequests.size());
Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() <<
"; now processing " << mAddedEasyRequests.size() << " easy handles [running_handles = " << AICurlInterface::Stats::running_handles << "].");
return;
}
// The request could not be added, we have to queue it.
PerHostRequestQueue_wat(*per_host)->queue(easy_request);
PerServiceRequestQueue_wat(*per_service)->queue(easy_request);
#ifdef SHOW_ASSERT
// Not active yet, but it's no longer an error if next we try to remove the request.
AICurlEasyRequest_wat(*easy_request)->mRemovedPerCommand = false;
@@ -1717,7 +1749,7 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request
#ifdef SHOW_ASSERT
bool removed =
#endif
easy_request_w->removeFromPerHostQueue(easy_request);
easy_request_w->removeFromPerServiceQueue(easy_request);
#ifdef SHOW_ASSERT
if (removed)
{
@@ -1733,12 +1765,12 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request
CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command)
{
CURLMcode res;
PerHostRequestQueuePtr per_host;
AIPerServicePtr per_service;
{
AICurlEasyRequest_wat curl_easy_request_w(**iter);
res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle);
per_host = curl_easy_request_w->getPerHostPtr();
PerHostRequestQueue_wat(*per_host)->removed_from_multi_handle(); // (About to be) removed from mAddedEasyRequests.
per_service = curl_easy_request_w->getPerServicePtr();
PerServiceRequestQueue_wat(*per_service)->removed_from_multi_handle(); // (About to be) removed from mAddedEasyRequests.
#ifdef SHOW_ASSERT
curl_easy_request_w->mRemovedPerCommand = as_per_command;
#endif
@@ -1747,12 +1779,15 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
#endif
mAddedEasyRequests.erase(iter);
--sTotalAdded;
llassert(sTotalAdded == mAddedEasyRequests.size());
#if CWDEBUG
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj <<
"; now processing " << mAddedEasyRequests.size() << " easy handles [running_handles = " << AICurlInterface::Stats::running_handles << "].");
#endif
// Attempt to add a queued request, if any.
PerHostRequestQueue_wat(*per_host)->add_queued_to(this);
PerServiceRequestQueue_wat(*per_service)->add_queued_to(this);
return res;
}
@@ -1795,6 +1830,8 @@ void MultiHandle::check_msg_queue(void)
void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result)
{
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
// Final body bandwidth update.
curl_easy_request_w->update_body_bandwidth();
// Store the result in the easy handle.
curl_easy_request_w->storeResult(result);
#ifdef CWDEBUG
@@ -1926,7 +1963,8 @@ void clearCommandQueue(void)
{
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
command_queue_wat command_queue_w(command_queue);
command_queue_w->clear();
command_queue_w->commands.clear();
command_queue_w->size = 0;
}
//-----------------------------------------------------------------------------
@@ -1988,10 +2026,10 @@ void BufferedCurlEasyRequest::processOutput(void)
if (responseCode == HTTP_INTERNAL_ERROR_LOW_SPEED)
{
// Rewrite error to something understandable.
responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %u bytes). "
responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %lu bytes). "
"To change these values, go to Advanced --> Debug Settings and change CurlTimeoutLowSpeedLimit and CurlTimeoutLowSpeedTime respectively.",
mResponder->getURL().c_str(), mResponder->getHTTPTimeoutPolicy().getLowSpeedLimit(), mResponder->getHTTPTimeoutPolicy().getLowSpeedTime(),
mResponder->getName(), mResponseTransferedBytes);
mResponder->getName(), mTotalRawBytes);
}
setopt(CURLOPT_FRESH_CONNECT, TRUE);
}
@@ -2058,7 +2096,9 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_
// BufferedCurlEasyRequest::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite.
//S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes;
self_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes);
self_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server.
// Update HTTP bandwith.
self_w->update_body_bandwidth();
// Update timeout administration.
if (self_w->httptimeout()->data_received(bytes)) // Update timeout administration.
{
// Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR.
@@ -2067,6 +2107,25 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_
return bytes;
}
void BufferedCurlEasyRequest::update_body_bandwidth(void)
{
double size_download; // Total amount of raw bytes received so far (ie. still compressed, 'bytes' is uncompressed).
getinfo(CURLINFO_SIZE_DOWNLOAD, &size_download);
size_t total_raw_bytes = size_download;
size_t raw_bytes = total_raw_bytes - mTotalRawBytes;
mTotalRawBytes = total_raw_bytes;
// Note that in some cases (like HTTP_PARTIAL_CONTENT), the output of CURLINFO_SIZE_DOWNLOAD lags
// behind and will return 0 the first time, and the value of the previous chunk the next time.
// The last call from MultiHandle::finish_easy_request recorrects this, in that case.
if (raw_bytes > 0)
{
U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2;
AIAverage& http_bandwidth(PerServiceRequestQueue_wat(*getPerServicePtr())->bandwidth());
http_bandwidth.addData(raw_bytes, sTime_40ms);
sHTTPBandwidth.addData(raw_bytes, sTime_40ms);
}
}
//static
size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
{
@@ -2124,7 +2183,7 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
std::string::iterator pos3 = std::find(pos2, end, '\r');
U32 status = 0;
std::string reason;
if (pos3 != end && std::isdigit(*pos1))
if (pos3 != end && LLStringOps::isDigit(*pos1))
{
status = atoi(&header_line[pos1 - begin]);
reason.assign(pos2, pos3);
@@ -2154,6 +2213,11 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
self_w->httptimeout()->being_redirected();
}
}
// Update HTTP bandwidth.
U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2;
AIAverage& http_bandwidth(PerServiceRequestQueue_wat(*self_w->getPerServicePtr())->bandwidth());
http_bandwidth.addData(header_len, sTime_40ms);
sHTTPBandwidth.addData(header_len, sTime_40ms);
// Update timeout administration. This must be done after the status is already known.
if (self_w->httptimeout()->data_received(header_len/*,*/ ASSERT_ONLY_COMMA(self_w->upload_error_status())))
{
@@ -2328,7 +2392,7 @@ void AICurlEasyRequest::addRequest(void)
// Find the last command added.
command_st cmd = cmd_none;
for (std::deque<Command>::iterator iter = command_queue_w->begin(); iter != command_queue_w->end(); ++iter)
for (std::deque<Command>::iterator iter = command_queue_w->commands.begin(); iter != command_queue_w->commands.end(); ++iter)
{
if (*iter == *this)
{
@@ -2354,8 +2418,11 @@ void AICurlEasyRequest::addRequest(void)
}
#endif
// Add a command to add the new request to the multi session to the command queue.
command_queue_w->push_back(Command(*this, cmd_add));
AICurlEasyRequest_wat(*get())->add_queued();
command_queue_w->commands.push_back(Command(*this, cmd_add));
command_queue_w->size++;
AICurlEasyRequest_wat curl_easy_request_w(*get());
PerServiceRequestQueue_wat(*curl_easy_request_w->getPerServicePtr())->added_to_command_queue();
curl_easy_request_w->add_queued();
}
// Something was added to the queue, wake up the thread to get it.
wakeUpCurlThread();
@@ -2378,7 +2445,7 @@ void AICurlEasyRequest::removeRequest(void)
// Find the last command added.
command_st cmd = cmd_none;
for (std::deque<Command>::iterator iter = command_queue_w->begin(); iter != command_queue_w->end(); ++iter)
for (std::deque<Command>::iterator iter = command_queue_w->commands.begin(); iter != command_queue_w->commands.end(); ++iter)
{
if (*iter == *this)
{
@@ -2415,9 +2482,12 @@ void AICurlEasyRequest::removeRequest(void)
}
#endif
// Add a command to remove this request from the multi session to the command queue.
command_queue_w->push_back(Command(*this, cmd_remove));
command_queue_w->commands.push_back(Command(*this, cmd_remove));
command_queue_w->size--;
AICurlEasyRequest_wat curl_easy_request_w(*get());
PerServiceRequestQueue_wat(*curl_easy_request_w->getPerServicePtr())->removed_from_command_queue(); // Note really, but this has the same effect as 'added a remove command'.
// Suppress warning that would otherwise happen if the callbacks are revoked before the curl thread removed the request.
AICurlEasyRequest_wat(*get())->remove_queued();
curl_easy_request_w->remove_queued();
}
// Something was added to the queue, wake up the thread to get it.
wakeUpCurlThread();
@@ -2427,7 +2497,9 @@ void AICurlEasyRequest::removeRequest(void)
namespace AICurlInterface {
void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentConnectionsPerHost, bool NoVerifySSLCert)
LLControlGroup* sConfigGroup;
void startCurlThread(LLControlGroup* control_group)
{
using namespace AICurlPrivate;
using namespace AICurlPrivate::curlthread;
@@ -2435,9 +2507,11 @@ void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentCo
llassert(is_main_thread());
// Cache Debug Settings.
curl_max_total_concurrent_connections = CurlMaxTotalConcurrentConnections;
curl_concurrent_connections_per_host = CurlConcurrentConnectionsPerHost;
gNoVerifySSLCert = NoVerifySSLCert;
sConfigGroup = control_group;
curl_max_total_concurrent_connections = sConfigGroup->getU32("CurlMaxTotalConcurrentConnections");
CurlConcurrentConnectionsPerService = sConfigGroup->getU32("CurlConcurrentConnectionsPerService");
gNoVerifySSLCert = sConfigGroup->getBOOL("NoVerifySSLCert");
max_pipelined_requests = curl_max_total_concurrent_connections;
AICurlThread::sInstance = new AICurlThread;
AICurlThread::sInstance->start();
@@ -2445,19 +2519,24 @@ void startCurlThread(U32 CurlMaxTotalConcurrentConnections, U32 CurlConcurrentCo
bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue)
{
using namespace AICurlPrivate;
using namespace AICurlPrivate::curlthread;
U32 old = curl_max_total_concurrent_connections;
curl_max_total_concurrent_connections = newvalue.asInteger();
max_pipelined_requests += curl_max_total_concurrent_connections - old;
llinfos << "CurlMaxTotalConcurrentConnections set to " << curl_max_total_concurrent_connections << llendl;
return true;
}
bool handleCurlConcurrentConnectionsPerHost(LLSD const& newvalue)
bool handleCurlConcurrentConnectionsPerService(LLSD const& newvalue)
{
using namespace AICurlPrivate;
curl_concurrent_connections_per_host = newvalue.asInteger();
llinfos << "CurlConcurrentConnectionsPerHost set to " << curl_concurrent_connections_per_host << llendl;
U32 new_concurrent_connections = newvalue.asInteger();
AIPerService::adjust_concurrent_connections(new_concurrent_connections - CurlConcurrentConnectionsPerService);
CurlConcurrentConnectionsPerService = new_concurrent_connections;
llinfos << "CurlConcurrentConnectionsPerService set to " << CurlConcurrentConnectionsPerService << llendl;
return true;
}
@@ -2467,5 +2546,215 @@ bool handleNoVerifySSLCert(LLSD const& newvalue)
return true;
}
U32 getNumHTTPCommands(void)
{
using namespace AICurlPrivate;
command_queue_rat command_queue_r(command_queue);
return command_queue_r->size;
}
U32 getNumHTTPQueued(void)
{
return AIPerService::total_queued_size();
}
U32 getNumHTTPAdded(void)
{
return AICurlPrivate::curlthread::MultiHandle::total_added_size();
}
size_t getHTTPBandwidth(void)
{
using namespace AICurlPrivate;
U64 const sTime_40ms = get_clock_count() * curlthread::HTTPTimeout::sClockWidth_40ms;
return BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms);
}
} // namespace AICurlInterface
// Return true if we want at least one more HTTP request for this host.
//
// It's OK if this function is a bit fuzzy, but we don't want it to return
// true a hundred times on a row when it is called fast in a loop.
// Hence the following consideration:
//
// This function is called only from LLTextureFetchWorker::doWork, and when it returns true
// then doWork will call LLHTTPClient::request with a NULL default engine (signaling that
// it is OK to run in any thread).
//
// At the end, LLHTTPClient::request calls AIStateMachine::run, which in turn calls
// AIStateMachine::reset at the end. Because NULL is passed as default_engine, reset will
// call AIStateMachine::multiplex to immediately start running the state machine. This
// causes it to go through the states bs_reset, bs_initialize and then bs_multiplex with
// run state AICurlEasyRequestStateMachine_addRequest. Finally, in this state, multiplex
// calls AICurlEasyRequestStateMachine::multiplex_impl which then calls AICurlEasyRequest::addRequest
// which causes an increment of command_queue_w->size and AIPerService::mQueuedCommands.
//
// It is therefore guaranteed that in one loop of LLTextureFetchWorker::doWork,
// this size is incremented; stopping this function from returning true once we reached the
// threshold of "pipelines" requests (the sum of requests in the command queue, the ones
// throttled and queued in AIPerService::mQueuedRequests and the already
// running requests (in MultiHandle::mAddedEasyRequests)).
//
//static
bool AIPerService::wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service, F32 max_kbps, bool no_bandwidth_throttling)
{
using namespace AICurlPrivate;
using namespace AICurlPrivate::curlthread;
bool reject, equal, increment_threshold, decrement_threshold;
// Whether or not we're going to approve a new request, decrement the global threshold first, when appropriate.
// Atomic read max_pipelined_requests for the below calculations.
S32 const max_pipelined_requests_cache = max_pipelined_requests;
decrement_threshold = sQueueFull && !sQueueEmpty;
// Reset flags.
sQueueEmpty = sQueueFull = false;
if (decrement_threshold)
{
if (max_pipelined_requests_cache > (S32)curl_max_total_concurrent_connections)
{
// Decrement the threshold because since the last call to this function at least one curl request finished
// and was replaced with another request from the queue, but the queue never ran empty: we have too many
// queued requests.
--max_pipelined_requests;
}
}
// Check if it's ok to get a new request for this particular service and update the per-service threshold.
AIAverage* http_bandwidth_ptr;
{
PerServiceRequestQueue_wat per_service_w(*per_service);
S32 const pipelined_requests_per_service = per_service_w->pipelined_requests();
reject = pipelined_requests_per_service >= per_service_w->mMaxPipelinedRequests;
equal = pipelined_requests_per_service == per_service_w->mMaxPipelinedRequests;
increment_threshold = per_service_w->mRequestStarvation;
decrement_threshold = per_service_w->mQueueFull && !per_service_w->mQueueEmpty;
// Reset flags.
per_service_w->mQueueFull = per_service_w->mQueueEmpty = per_service_w->mRequestStarvation = false;
// Grab per service bandwidth object.
http_bandwidth_ptr = &per_service_w->bandwidth();
if (decrement_threshold)
{
if (per_service_w->mMaxPipelinedRequests > per_service_w->mConcurrectConnections)
{
per_service_w->mMaxPipelinedRequests--;
}
}
else if (increment_threshold && reject)
{
if (per_service_w->mMaxPipelinedRequests < 2 * per_service_w->mConcurrectConnections)
{
per_service_w->mMaxPipelinedRequests++;
// Immediately take the new threshold into account.
reject = !equal;
}
}
}
if (reject)
{
// Too many request for this host already.
return false;
}
if (!no_bandwidth_throttling)
{
// Throttle on bandwidth usage.
static size_t throttle_fraction = 1024; // A value between 0 and 1024: each service is throttled when it uses more than max_bandwidth * (throttle_fraction/1024) bandwidth.
static AIAverage fraction(25); // Average over 25 * 40ms = 1 second.
static U64 last_sTime_40ms = 0;
// Truncate the sums to the last second, and get their value.
U64 const sTime_40ms = get_clock_count() * HTTPTimeout::sClockWidth_40ms; // Time in 40ms units.
size_t const max_bandwidth = 125.f * max_kbps; // Convert kbps to bytes per second.
size_t const total_bandwidth = BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); // Bytes received in the past second.
size_t const service_bandwidth = http_bandwidth_ptr->truncateData(sTime_40ms); // Idem for just this service.
if (sTime_40ms > last_sTime_40ms)
{
// Only add throttle_fraction once every 40 ms at most.
// It's ok to ignore other values in the same 40 ms because the value only changes on the scale of 1 second.
fraction.addData(throttle_fraction, sTime_40ms);
last_sTime_40ms = sTime_40ms;
}
double fraction_avg = fraction.getAverage(1024.0); // throttle_fraction averaged over the past second, or 1024 if there is no data.
// Adjust throttle_fraction based on total bandwidth usage.
if (total_bandwidth == 0)
throttle_fraction = 1024;
else
{
// This is the main formula. It can be made plausible by assuming
// an equilibrium where total_bandwidth == max_bandwidth and
// thus throttle_fraction == fraction_avg for more than a second.
//
// Then, more bandwidth is being used (for example because another
// service starts downloading). Assuming that all services that use
// a significant portion of the bandwidth, the new service included,
// must be throttled (all using the same bandwidth; note that the
// new service is immediately throttled at the same value), then
// the limit should be reduced linear with the fraction:
// max_bandwidth / total_bandwidth.
//
// For example, let max_bandwidth be 1. Let there be two throttled
// services, each using 0.5 (fraction_avg = 1024/2). Lets the new
// service use what it can: also 0.5 - then without reduction the
// total_bandwidth would become 1.5, and throttle_fraction would
// become (1024/2) * 1/1.5 = 1024/3: from 2 to 3 services.
//
// In reality, total_bandwidth would rise linear from 1.0 to 1.5 in
// one second if the throttle fraction wasn't changed. However it is
// changed here. The end result is that any change more or less
// linear fades away in one second.
throttle_fraction = fraction_avg * max_bandwidth / total_bandwidth;
}
if (throttle_fraction > 1024)
throttle_fraction = 1024;
if (total_bandwidth > max_bandwidth)
{
throttle_fraction *= 0.95;
}
// Throttle this service if it uses too much bandwidth.
if (service_bandwidth > (max_bandwidth * throttle_fraction / 1024))
{
return false; // wait
}
}
// Check if it's ok to get a new request based on the total number of requests and increment the threshold if appropriate.
{
command_queue_rat command_queue_r(command_queue);
S32 const pipelined_requests = command_queue_r->size + sTotalQueued + MultiHandle::total_added_size();
// We can't take the command being processed (command_being_processed) into account without
// introducing relatively long waiting times for some mutex (namely between when the command
// is moved from command_queue to command_being_processed, till it's actually being added to
// mAddedEasyRequests). The whole purpose of command_being_processed is to reduce the time
// that things are locked to micro seconds, so we'll just accept an off-by-one fuzziness
// here instead.
// The maximum number of requests that may be queued in command_queue is equal to the total number of requests
// that may exist in the pipeline minus the number of requests queued in AIPerService objects, minus
// the number of already running requests.
reject = pipelined_requests >= max_pipelined_requests_cache;
equal = pipelined_requests == max_pipelined_requests_cache;
increment_threshold = sRequestStarvation;
}
if (increment_threshold && reject)
{
if (max_pipelined_requests_cache < 2 * (S32)curl_max_total_concurrent_connections)
{
max_pipelined_requests++;
// Immediately take the new threshold into account.
reject = !equal;
}
}
return !reject;
}

View File

@@ -75,12 +75,13 @@ class MultiHandle : public CurlMultiHandle
typedef std::set<AICurlEasyRequest, AICurlEasyRequestCompare> addedEasyRequests_type;
addedEasyRequests_type mAddedEasyRequests; // All easy requests currently added to the multi handle.
long mTimeout; // The last timeout in ms as set by the callback CURLMOPT_TIMERFUNCTION.
static LLAtomicU32 sTotalAdded; // The (sum of the) size of mAddedEasyRequests (of every MultiHandle, but there is only one).
private:
// Store result and trigger events for easy request.
void finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result);
// Remove easy request at iter (must exist).
// Note that it's possible that a new request from a PerHostRequestQueue::mQueuedRequests is inserted before iter.
// Note that it's possible that a new request from a AIPerService::mQueuedRequests is inserted before iter.
CURLMcode remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command);
static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);
@@ -96,6 +97,9 @@ class MultiHandle : public CurlMultiHandle
// Called from the main loop every time select() timed out.
void handle_stalls(void);
// Return the total number of added curl requests.
static U32 total_added_size(void) { return sTotalAdded; }
public:
//-----------------------------------------------------------------------------
// Curl socket administration:

View File

@@ -75,6 +75,7 @@ namespace AICurlPrivate {
class BufferedCurlEasyRequest {
public:
char const* getLowercaseHostname(void) const { return "hostname.com"; }
char const* getLowercaseServicename(void) const { return "hostname.com:12047"; }
void getinfo(const int&, double* p) { *p = 0.1; }
};
@@ -96,8 +97,9 @@ namespace curlthread {
// HTTPTimeout
//static
F64 const HTTPTimeout::sClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds.
U64 HTTPTimeout::sClockCount; // Clock count, set once per select() exit.
F64 const HTTPTimeout::sClockWidth_10ms = 100.0 / calc_clock_frequency(); // Time between two clock ticks, in 10ms units.
F64 const HTTPTimeout::sClockWidth_40ms = HTTPTimeout::sClockWidth_10ms * 0.25; // Time between two clock ticks, in 40ms units.
U64 HTTPTimeout::sTime_10ms; // Time in 10ms units, set once per select() exit.
// CURL-THREAD
// This is called when body data was sent to the server socket.
@@ -125,7 +127,7 @@ bool HTTPTimeout::data_sent(size_t n, bool finished)
// | |
void HTTPTimeout::reset_lowspeed(void)
{
mLowSpeedClock = sClockCount;
mLowSpeedClock = sTime_10ms;
mLowSpeedOn = true;
mLastBytesSent = false; // We're just starting!
mLastSecond = -1; // This causes lowspeed to initialize the rest.
@@ -162,8 +164,8 @@ void HTTPTimeout::upload_finished(void)
// We finished uploading (if there was a body to upload at all), so no more transfer rate timeouts.
mLowSpeedOn = false;
// Timeout if the server doesn't reply quick enough.
mStalled = sClockCount + mPolicy->getReplyDelay() / sClockWidth;
DoutCurl("upload_finished: mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << mPolicy->getReplyDelay() << " seconds)");
mStalled = sTime_10ms + 100 * mPolicy->getReplyDelay();
DoutCurl("upload_finished: mStalled set to Time_10ms (" << sTime_10ms << ") + " << (mStalled - sTime_10ms) << " (" << mPolicy->getReplyDelay() << " seconds)");
}
// CURL-THREAD
@@ -230,8 +232,7 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
// less than low_speed_limit, we abort.
// When are we?
S32 second = (sClockCount - mLowSpeedClock) * sClockWidth;
llassert(sClockWidth > 0.0);
S32 second = (sTime_10ms - mLowSpeedClock) / 100;
// This REALLY should never happen, but due to another bug it did happened
// and caused something so evil and hard to find that... NEVER AGAIN!
llassert(second >= 0);
@@ -315,8 +316,8 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
// Just give these bytes 4 more seconds to be written to the socket (after which we'll
// assume that the 'upload finished' detection failed and we'll wait another ReplyDelay
// seconds before finally, actually timing out.
mStalled = sClockCount + 4 / sClockWidth;
DoutCurl("mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (4 seconds)");
mStalled = sTime_10ms + 400; // 4 seconds into the future.
DoutCurl("mStalled set to sTime_10ms (" << sTime_10ms << ") + 400 (4 seconds)");
return false;
}
// The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer.
@@ -368,8 +369,8 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished)
while(total_bytes >= mintotalbytes);
}
// If this function isn't called again within max_stall_time seconds, we stalled.
mStalled = sClockCount + max_stall_time / sClockWidth;
DoutCurl("mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << max_stall_time << " seconds)");
mStalled = sTime_10ms + 100 * max_stall_time;
DoutCurl("mStalled set to sTime_10ms (" << sTime_10ms << ") + " << (mStalled - sTime_10ms) << " (" << max_stall_time << " seconds)");
return false;
}
@@ -435,7 +436,7 @@ bool HTTPTimeout::maybe_upload_finished(void)
void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url)
{
#ifndef HTTPTIMEOUT_TESTSUITE
llwarns << "Request to \"" << curl_easy_request->getLowercaseHostname() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
llwarns << "Request to \"" << curl_easy_request->getLowercaseServicename() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
llinfos << "Effective URL: \"" << eff_url << "\"." << llendl;
double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time;
curl_easy_request->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time);

View File

@@ -85,11 +85,12 @@ class HTTPTimeout : public LLRefCount {
S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock.
S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten.
U32 mTotalBytes; // The sum of all bytes in mBuckets.
U64 mLowSpeedClock; // Clock count at which low speed detection (re)started.
U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore.
U64 mLowSpeedClock; // The time (sTime_10ms) at which low speed detection (re)started.
U64 mStalled; // The time (sTime_10ms) at which this transaction is considered to be stalling if nothing is transfered anymore.
public:
static F64 const sClockWidth; // Time between two clock ticks in seconds.
static U64 sClockCount; // Clock count used as 'now' during one loop of the main loop.
static F64 const sClockWidth_10ms; // Time between two clock ticks in 10 ms units.
static F64 const sClockWidth_40ms; // Time between two clock ticks in 40 ms units.
static U64 sTime_10ms; // Time since the epoch in 10 ms units.
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
ThreadSafeBufferedCurlEasyRequest* mLockObj;
#endif
@@ -121,7 +122,7 @@ class HTTPTimeout : public LLRefCount {
void done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code);
// Returns true when we REALLY timed out. Might call upload_finished heuristically.
bool has_stalled(void) { return mStalled < sClockCount && !maybe_upload_finished(); }
bool has_stalled(void) { return mStalled < sTime_10ms && !maybe_upload_finished(); }
// Called from BufferedCurlEasyRequest::processOutput if a timeout occurred.
void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url);

View File

@@ -707,6 +707,13 @@ AIHTTPTimeoutPolicyBase connect_40s(AIHTTPTimeoutPolicyBase::getDebugSettingsCur
connectOp40s
);
// This used to be FETCHING_TIMEOUT (for HTTP textures), being a 15 second timeout from start of request till finishing receiving all data.
// That seems way to demanding however; lets use a 15 second reply delay demand instead.
Reply replyOp15s(15);
AIHTTPTimeoutPolicyBase reply_15s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(),
replyOp15s
);
// End of policy definitions.
//=======================================================================================================
@@ -899,7 +906,7 @@ P2(gamingDataReceived, transfer_18s);
P2(groupMemberDataResponder, transfer_300s);
P2(groupProposalBallotResponder, transfer_300s);
P(homeLocationResponder);
P(HTTPGetResponder);
P2(HTTPGetResponder, reply_15s);
P(iamHereLogin);
P(iamHere);
P(iamHereVoice);

View File

@@ -50,7 +50,6 @@
#include "lldarray.h"
#include "lldir.h"
#include "llerror.h"
#include "llerrorlegacy.h"
#include "llfasttimer.h"
#include "llhttpclient.h"
#include "llhttpnodeadapter.h"

View File

@@ -6,7 +6,6 @@ include(LLPlugin)
include(Linking)
include(PluginAPI)
include(LLMessage)
include(GooglePerfTools)
include_directories(
${LLPLUGIN_INCLUDE_DIRS}

View File

@@ -219,10 +219,6 @@ public:
virtual void saveAs() {}
virtual void saveAsType(BOOL type=false) {}
// <edit>
virtual LLUUID getItemID() { return LLUUID::null; }
// </edit>
void setSnapTarget(LLHandle<LLFloater> handle) { mSnappedTo = handle; }
void clearSnapTarget() { mSnappedTo.markDead(); }
LLHandle<LLFloater> getSnapTarget() const { return mSnappedTo; }

View File

@@ -111,7 +111,7 @@ public:
BOOL focusNextItem(BOOL text_entry_only);
BOOL focusPrevItem(BOOL text_entry_only);
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
virtual BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
BOOL focusLastItem(BOOL prefer_text_fields = FALSE);
// Non Virtuals

View File

@@ -536,6 +536,7 @@ typedef enum e_lscript_runtime_permissions
SCRIPT_PERMISSION_TRACK_CAMERA,
SCRIPT_PERMISSION_CONTROL_CAMERA,
SCRIPT_PERMISSION_TELEPORT,
SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS,
SCRIPT_PERMISSION_EOF
} LSCRIPTRunTimePermissions;
@@ -553,6 +554,7 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] =
(0x1 << 10),// SCRIPT_PERMISSION_TRACK_CAMERA
(0x1 << 11),// SCRIPT_PERMISSION_CONTROL_CAMERA
(0x1 << 12),// SCRIPT_PERMISSION_TELEPORT
(0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS
};
// http_request string constants

View File

@@ -532,6 +532,14 @@ void LLScriptLibrary::init()
addFunction(10.f, 0.f, dummy_func, "llUpdateCharacter", NULL, "l");
addFunction(10.f, 0.f, dummy_func, "llWanderWithin", NULL, "vvl");
// Server RC LeTigre 12.10.12.265819 new function
addFunction(0.f, 0.f, dummy_func, "llGetSimStats", "f", "i");
// Server RC LeTigre 13.03.22.272565 new function
addFunction(0.f, 0.f, dummy_func, "llSetAnimationOverride", NULL, "ss");
addFunction(0.f, 0.f, dummy_func, "llGetAnimationOverride", "s", "s");
addFunction(0.f, 0.f, dummy_func, "llResetAnimationOverride", NULL, "s");
// SL-LSL Functions to be added above this line
// ---------------------------------------------
// NOTE bytecode placement no longer applies, viewers do not compile scripts anymore (confirmed with LL, also noted by Phoenix/Firestorm team.)

View File

@@ -38,7 +38,6 @@ include(LLXML)
#include(LScript)
include(Linking)
include(NDOF)
include(GooglePerfTools)
include(StateMachine)
include(TemplateCheck)
include(UI)
@@ -90,6 +89,7 @@ set(viewer_SOURCE_FILES
floaterao.cpp
floaterlocalassetbrowse.cpp
floatervoicelicense.cpp
generichandlers.cpp
hbfloatergrouptitles.cpp
hippofloaterxml.cpp
hippogridmanager.cpp
@@ -97,6 +97,7 @@ set(viewer_SOURCE_FILES
hippopanelgrids.cpp
importtracker.cpp
jcfloaterareasearch.cpp
lfsimfeaturehandler.cpp
lggdicdownload.cpp
lgghunspell_wrapper.cpp
llaccountingcostmanager.cpp
@@ -184,6 +185,7 @@ set(viewer_SOURCE_FILES
llfloaterbuycontents.cpp
llfloaterbuycurrency.cpp
llfloaterbuyland.cpp
llfloaterbvhpreview.cpp
llfloatercamera.cpp
llfloaterchat.cpp
llfloaterchatterbox.cpp
@@ -590,6 +592,7 @@ set(viewer_HEADER_FILES
floaterao.h
floaterlocalassetbrowse.h
floatervoicelicense.h
generichandlers.h
hbfloatergrouptitles.h
hippofloaterxml.h
hippogridmanager.h
@@ -597,6 +600,7 @@ set(viewer_HEADER_FILES
hippopanelgrids.h
importtracker.h
jcfloaterareasearch.h
lfsimfeaturehandler.h
lggdicdownload.h
lgghunspell_wrapper.h
llaccountingcostmanager.h
@@ -685,6 +689,7 @@ set(viewer_HEADER_FILES
llfloaterbuycontents.h
llfloaterbuycurrency.h
llfloaterbuyland.h
llfloaterbvhpreview.h
llfloatercamera.h
llfloaterchat.h
llfloaterchatterbox.h

View File

@@ -52,7 +52,7 @@ changed changed( integer change ):Triggered various event change the task:(tes
remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY)
http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests
http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL
transaction_result transaction_result(key id, integer success, string data):Triggered when task receives asynchronous data.
transaction_result transaction_result(key id, integer success, string data): Triggered when currency is given to task
path_update path_update(integer type, list reserved):Triggered when the state of a pathfinder character changes. Note; "list reserved" is not currently used
# integer constants
@@ -99,6 +99,7 @@ PERMISSION_CHANGE_LINKS Passed to llRequestPermissions library function to req
PERMISSION_TRACK_CAMERA Passed to llRequestPermissions library function to request permission to track agent's camera
PERMISSION_CONTROL_CAMERA Passed to llRequestPermissions library function to request permission to change agent's camera
PERMISSION_TELEPORT Passed to llRequestPermissions library function to request permission to teleport agent
PERMISSION_OVERRIDE_ANIMATIONS Passed to llRequestPermissions library function to request permission to override agent's animations
DEBUG_CHANNEL Chat channel reserved for debug and error messages from scripts
PUBLIC_CHANNEL Chat channel that broadcasts to all nearby users

View File

@@ -1013,5 +1013,12 @@
<!-- Server RC LeTigre 12.10.12.265819 new function -->
<key>llGetSimStats</key>
<map/>
<!-- Server RC LeTigre 13.03.22.272565 new function -->
<key>llSetAnimationOverride</key>
<map/>
<key>llGetAnimationOverride</key>
<map/>
<key>llResetAnimationOverride</key>
<map/>
</map>
</llsd>

View File

@@ -171,40 +171,7 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>HTTPRequestRate</key>
<map>
<key>Comment</key>
<string>Number of HTTP texture requests fired per second.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>30</integer>
</map>
<key>HTTPMaxRequests</key>
<map>
<key>Comment</key>
<string>Maximum number of simultaneous HTTP requests in progress.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>12</integer>
</map>
<key>HTTPMinRequests</key>
<map>
<key>Comment</key>
<string>Attempt to maintain at least this many HTTP requests in progress by ignoring bandwidth</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>2</integer>
</map>
<key>HTTPThrottleBandwidth</key>
<map>
<key>Comment</key>
@@ -726,6 +693,17 @@ Found in Advanced->Rendering->Info Displays</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FakeAway</key>
<map>
<key>HideFromEditor</key>
<integer>1</integer>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>InstantMessageLogPathAnyAccount</key>
<map>
<key>Comment</key>
@@ -4481,10 +4459,10 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>64</integer>
</map>
<key>CurlConcurrentConnectionsPerHost</key>
<key>CurlConcurrentConnectionsPerService</key>
<map>
<key>Comment</key>
<string>Maximum number of simultaneous curl connections per host</string>
<string>Maximum number of simultaneous curl connections per host:port service</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
@@ -4943,7 +4921,18 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeTexture</key>
<key>DebugStatModeHTTPTexture</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeUDPTexture</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
@@ -5526,6 +5515,28 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>ClickActionBuyEnabled</key>
<map>
<key>Comment</key>
<string>Enable click to buy actions in tool pie menu</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>ClickActionPayEnabled</key>
<map>
<key>Comment</key>
<string>Enable click to pay actions in tool pie menu</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>DoubleClickAutoPilot</key>
<map>
<key>Comment</key>
@@ -5570,10 +5581,21 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<real>0.10000000149</real>
</map>
<key>DragAndDropDistanceThreshold</key>
<map>
<key>Comment</key>
<string>Number of pixels that mouse should move before triggering drag and drop mode</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>3</integer>
</map>
<key>DropShadowButton</key>
<map>
<key>Comment</key>
<string>Drop shadow width for buttons (pixels)</string>
<string>Drop shadow width for buttons (pixels)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -5680,6 +5702,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>EnableGrab</key>
<map>
<key>Comment</key>
<string>Use Ctrl+mouse to grab and manipulate objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>EnableGestureSounds</key>
<map>
<key>Comment</key>
@@ -13041,6 +13074,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>DisableClickSitOtherOwner</key>
<map>
<key>Comment</key>
<string>Never sit by clicking a prim that isn't owned by you</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>PlayIMSound</key>
<map>
<key>Comment</key>
@@ -15107,6 +15151,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>UseTypingBubbles</key>
<map>
<key>Comment</key>
<string>Show typing indicator in avatar nametags</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>UseDebugMenus</key>
<map>
<key>Comment</key>
@@ -16393,6 +16448,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>ClickToWalk</key>
<map>
<key>Comment</key>
<string>Click in world to walk to location</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SimulateFBOFailure</key>
<map>
<key>Comment</key>

View File

@@ -1,15 +1,48 @@
<llsd>
<map>
<map>
<key>CrashSubmitBehavior</key>
<map>
<key>Comment</key>
<string>Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)</string>
<key>Persist</key>
<integer>2</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>2</integer>
</map>
<map>
<key>Comment</key>
<string>Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)</string>
<key>Persist</key>
<integer>2</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>2</integer>
</map>
<key>CurlMaxTotalConcurrentConnections</key>
<map>
<key>Comment</key>
<string>Maximum total number of simultaneous curl connections</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>64</integer>
</map>
<key>CurlConcurrentConnectionsPerService</key>
<map>
<key>Comment</key>
<string>Maximum number of simultaneous curl connections per host:port service</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>16</integer>
</map>
<key>NoVerifySSLCert</key>
<map>
<key>Comment</key>
<string>Do not verify SSL certificates.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
</map>
</llsd>

View File

@@ -314,6 +314,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>EveryoneExport</key>
<map>
<key>Comment</key>
<string>Whether content you upload has exportability permission by default</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RLVaLoginLastLocation</key>
<map>
<key>Comment</key>

View File

@@ -329,6 +329,7 @@ void LLPrefsAscentChat::refreshValues()
mHideTypingNotification = gSavedSettings.getBOOL("AscentHideTypingNotification");
mShowGroupNameInChatIM = gSavedSettings.getBOOL("OptionShowGroupNameInChatIM");
mShowDisplayNameChanges = gSavedSettings.getBOOL("ShowDisplayNameChanges");
mUseTypingBubbles = gSavedSettings.getBOOL("UseTypingBubbles");
mPlayTypingSound = gSavedSettings.getBOOL("PlayTypingSound");
mHideNotificationsInChat = gSavedSettings.getBOOL("HideNotificationsInChat");
mEnableMUPose = gSavedSettings.getBOOL("AscentAllowMUpose");
@@ -545,6 +546,7 @@ void LLPrefsAscentChat::cancel()
gSavedSettings.setBOOL("AscentHideTypingNotification", mHideTypingNotification);
gSavedSettings.setBOOL("OptionShowGroupNameInChatIM", mShowGroupNameInChatIM);
gSavedSettings.setBOOL("ShowDisplayNameChanges", mShowDisplayNameChanges);
gSavedSettings.setBOOL("UseTypingBubbles", mUseTypingBubbles);
gSavedSettings.setBOOL("PlayTypingSound", mPlayTypingSound);
gSavedSettings.setBOOL("HideNotificationsInChat", mHideNotificationsInChat);
gSavedSettings.setBOOL("AscentAllowMUpose", mEnableMUPose);

View File

@@ -66,6 +66,7 @@ protected:
BOOL mHideTypingNotification;
BOOL mShowGroupNameInChatIM;
bool mShowDisplayNameChanges;
bool mUseTypingBubbles;
BOOL mPlayTypingSound;
BOOL mHideNotificationsInChat;
BOOL mEnableMUPose;

View File

@@ -80,6 +80,9 @@ LLPrefsAscentSys::LLPrefsAscentSys()
childSetCommitCallback("AscentCmdLineTP2", onCommitCmdLine, this);
childSetCommitCallback("SinguCmdLineAway", onCommitCmdLine, this);
//Security ----------------------------------------------------------------------------
childSetCommitCallback("disable_click_sit_check", onCommitCheckBox, this);
//Build -------------------------------------------------------------------------------
childSetCommitCallback("next_owner_copy", onCommitCheckBox, this);
childSetEnabled("next_owner_transfer", gSavedSettings.getBOOL("NextOwnerCopy"));
@@ -129,59 +132,57 @@ LLPrefsAscentSys::~LLPrefsAscentSys()
//static
void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, void* user_data)
{
LLPrefsAscentSys* self = (LLPrefsAscentSys*)user_data;
LLPrefsAscentSys* self = static_cast<LLPrefsAscentSys*>(user_data);
// llinfos << "Change to " << ctrl->getControlName() << " aka " << ctrl->getName() << llendl;
if (ctrl->getName() == "speed_rez_check")
{
bool enabled = self->childGetValue("speed_rez_check").asBoolean();
self->childSetEnabled("speed_rez_interval", enabled);
self->childSetEnabled("speed_rez_seconds", enabled);
}
else if (ctrl->getName() == "double_click_teleport_check")
{
bool enabled = self->childGetValue("double_click_teleport_check").asBoolean();
self->childSetEnabled("center_after_teleport_check", enabled);
self->childSetEnabled("offset_teleport_check", enabled);
}
else if (ctrl->getName() == "system_folder_check")
{
bool enabled = self->childGetValue("system_folder_check").asBoolean();
self->childSetEnabled("temp_in_system_check", enabled);
}
else if (ctrl->getName() == "enable_clouds")
{
bool enabled = self->childGetValue("enable_clouds").asBoolean();
self->childSetEnabled("enable_classic_clouds", enabled);
}
else if (ctrl->getName() == "power_user_check")
{
bool enabled = self->childGetValue("power_user_check").asBoolean();
self->childSetEnabled("power_user_confirm_check", enabled);
self->childSetValue("power_user_confirm_check", false);
}
else if (ctrl->getName() == "power_user_confirm_check")
{
bool enabled = self->childGetValue("power_user_confirm_check").asBoolean();
gSavedSettings.setBOOL("AscentPowerfulWizard", enabled);
if (enabled)
{
LLVector3d lpos_global = gAgent.getPositionGlobal();
gAudiop->triggerSound(LLUUID("58a38e89-44c6-c52b-deb8-9f1ddc527319"), gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
LLChat chat;
chat.mSourceType = CHAT_SOURCE_SYSTEM;
chat.mText = LLTrans::getString("PowerUser1") + "\n" + LLTrans::getString("PowerUser2") + "\n" + LLTrans::getString("Unlocked:") + "\n" + LLTrans::getString("PowerUser3") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser4") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser5");
LLFloaterChat::addChat(chat);
}
}
else if (ctrl->getName() == "next_owner_copy")
const std::string name = ctrl->getName();
bool enabled = ctrl->getValue().asBoolean();
if (name == "speed_rez_check")
{
bool copy = gSavedSettings.getBOOL("NextOwnerCopy");
if (!copy) gSavedSettings.setBOOL("NextOwnerTransfer", true);
self->childSetEnabled("next_owner_transfer", copy);
self->childSetEnabled("speed_rez_interval", enabled);
self->childSetEnabled("speed_rez_seconds", enabled);
}
else if (name == "double_click_teleport_check")
{
self->childSetEnabled("center_after_teleport_check", enabled);
self->childSetEnabled("offset_teleport_check", enabled);
}
else if (name == "system_folder_check")
{
self->childSetEnabled("temp_in_system_check", enabled);
}
else if (name == "enable_clouds")
{
self->childSetEnabled("enable_classic_clouds", enabled);
}
else if (name == "power_user_check")
{
self->childSetEnabled("power_user_confirm_check", enabled);
self->childSetValue("power_user_confirm_check", false);
}
else if (name == "power_user_confirm_check")
{
gSavedSettings.setBOOL("AscentPowerfulWizard", enabled);
if (enabled)
{
LLVector3d lpos_global = gAgent.getPositionGlobal();
gAudiop->triggerSound(LLUUID("58a38e89-44c6-c52b-deb8-9f1ddc527319"), gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
LLChat chat;
chat.mSourceType = CHAT_SOURCE_SYSTEM;
chat.mText = LLTrans::getString("PowerUser1") + "\n" + LLTrans::getString("PowerUser2") + "\n" + LLTrans::getString("Unlocked:") + "\n" + LLTrans::getString("PowerUser3") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser4") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser5");
LLFloaterChat::addChat(chat);
}
}
else if (name == "disable_click_sit_check")
{
self->childSetEnabled("disable_click_sit_own_check", !enabled);
}
else if (name == "next_owner_copy")
{
if (!enabled) gSavedSettings.setBOOL("NextOwnerTransfer", true);
self->childSetEnabled("next_owner_transfer", enabled);
}
}
@@ -313,6 +314,7 @@ void LLPrefsAscentSys::refreshValues()
mDetachBridge = gSavedSettings.getBOOL("SGDetachBridge");
mRevokePermsOnStandUp = gSavedSettings.getBOOL("RevokePermsOnStandUp");
mDisableClickSit = gSavedSettings.getBOOL("DisableClickSit");
mDisableClickSitOtherOwner = gSavedSettings.getBOOL("DisableClickSitOtherOwner");
mDisplayScriptJumps = gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps");
mNumScriptDiff = gSavedSettings.getF32("Ascentnumscriptdiff");
@@ -463,6 +465,7 @@ void LLPrefsAscentSys::cancel()
gSavedSettings.setBOOL("SGDetachBridge", mDetachBridge);
gSavedSettings.setBOOL("RevokePermsOnStandUp", mRevokePermsOnStandUp);
gSavedSettings.setBOOL("DisableClickSit", mDisableClickSit);
gSavedSettings.setBOOL("DisableClickSitOtherOwner", mDisableClickSitOtherOwner);
gSavedSettings.setBOOL("AscentDisplayTotalScriptJumps", mDisplayScriptJumps);
gSavedSettings.setF32("Ascentnumscriptdiff", mNumScriptDiff);

View File

@@ -104,6 +104,7 @@ protected:
BOOL mDetachBridge;
BOOL mRevokePermsOnStandUp;
BOOL mDisableClickSit;
bool mDisableClickSitOtherOwner;
BOOL mDisplayScriptJumps;
F32 mNumScriptDiff;
//Build -------------------------------------------------------------------------------

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) The Singularity dev Team and Melanie Thielker
* Refer to the singularity project for a full lst of copyright holders
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Neither the name of the Singularity Viewwer Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "llviewerprecompiledheaders.h"
#include "generichandlers.h"
#include "llviewergenericmessage.h"
#include "llviewerinventory.h"
#include "llappearancemgr.h"
#include "llviewerregion.h"
#include "llagent.h"
GenericHandlers *gGenericHandlers = NULL;
class DispatchReplaceOutfit : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
if (strings.size() != 1) return false;
LLUUID folder_id(strings[0]);
bool success = false;
LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id);
if (cat != NULL)
{
LLAppearanceMgr::instance().wearInventoryCategory(cat, FALSE, FALSE);
success = true;
}
LLViewerRegion* regionp = gAgent.getRegion();
if (!regionp) return true;
std::string url = regionp->getCapability("WearablesLoaded");
if (url.empty()) return true;
LLSD data = LLSD(success);
LLHTTPClient::post(url, data, new LLHTTPClient::ResponderIgnore);
return true;
}
};
static DispatchReplaceOutfit sDispatchReplaceOutfit;
GenericHandlers::GenericHandlers()
{
gGenericDispatcher.addHandler("replaceoutfit", &sDispatchReplaceOutfit);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) The Singularity dev Team and Melanie Thielker
* Refer to the singularity project for a full lst of copyright holders
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Neither the name of the Singularity Viewwer Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class GenericHandlers
{
public:
GenericHandlers();
};
extern GenericHandlers *gGenericHandlers;

View File

@@ -40,6 +40,8 @@
#include <llradiogroup.h>
#include <lluictrlfactory.h>
#include "llavatarnamecache.h"
#include "llfloateravatarpicker.h"
#include "llviewerwindow.h"
@@ -58,10 +60,12 @@ class HippoFloaterXmlImpl : public LLFloater
BOOL postBuild();
void onClose(bool quitting);
static bool execute(LLUICtrl *ctrl,
static bool execute(LLFloater *floater, LLUICtrl *ctrl,
const std::string &cmds, std::string::size_type &offset,
std::string &response);
U32 mChannel;
private:
std::string mName;
bool mIsNotifyOnClose;
@@ -160,7 +164,7 @@ void XmlData::release(const std::string &floaterName)
// create HippoFloaterXmlImpl
HippoFloaterXmlImpl::HippoFloaterXmlImpl(const std::string &name, const std::string &xml) :
mName(name), mIsNotifyOnClose(false)
mName(name), mIsNotifyOnClose(false), mChannel(CHANNEL)
{
gInstances[mName] = this;
LLUICtrlFactory::getInstance()->buildFloaterFromBuffer(this, xml);
@@ -218,10 +222,10 @@ void HippoFloaterXml::execute(const std::string &cmds)
if (token == "{") {
if (floater) {
std::string response;
if (!floater->execute(floater, cmds, offset, response))
if (!floater->execute(floater, floater, cmds, offset, response))
break;
if (!response.empty())
send_chat_from_viewer(response, CHAT_TYPE_WHISPER, CHANNEL);
send_chat_from_viewer(response, CHAT_TYPE_WHISPER, floater->mChannel);
}
} else
@@ -265,29 +269,56 @@ void HippoFloaterXml::execute(const std::string &cmds)
// ********************************************************************
// generic notification callbacks
static void notifyCallback(void *c)
static void notifyCallback(void *c, void *f)
{
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
LLUICtrl *ctrl = (LLUICtrl *)c;
std::string msg = "NOTIFY:";
msg += ctrl->getName();
msg += ':';
msg += ctrl->getValue().asString();
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, floaterp->mChannel);
}
void callbackAvatarPick(void *c, void *f, const uuid_vec_t& ids, const std::vector<LLAvatarName>& names)
{
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
LLUICtrl *ctrl = (LLUICtrl *)c;
LLUUID id = ids[0];
std::string msg = "PICKER:";
msg += ctrl->getName();
msg += ':';
msg += id.asString();
msg += ':';
msg += names[0].getCompleteName();
send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, floaterp->mChannel);
}
static void pickerCallback(void *c, void *f)
{
LLUICtrl *ctrl = (LLUICtrl *)c;
HippoFloaterXmlImpl* floaterp = (HippoFloaterXmlImpl*)f;
floaterp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&callbackAvatarPick, ctrl, floaterp, _1, _2), FALSE, TRUE));
//send_chat_from_viewer(msg, CHAT_TYPE_WHISPER, CHANNEL);
}
void HippoFloaterXmlImpl::onClose(bool quitting)
{
if (mIsNotifyOnClose)
send_chat_from_viewer("NOTIFY:" + mName + ":closed",
CHAT_TYPE_WHISPER, CHANNEL);
CHAT_TYPE_WHISPER, mChannel);
LLFloater::onClose(quitting);
}
// ********************************************************************
// execute commands on instance
bool HippoFloaterXmlImpl::execute(LLUICtrl *ctrl,
bool HippoFloaterXmlImpl::execute(LLFloater *floater, LLUICtrl *ctrl,
const std::string &cmds, std::string::size_type &offset,
std::string &response)
{
@@ -313,24 +344,38 @@ bool HippoFloaterXmlImpl::execute(LLUICtrl *ctrl,
if (!child) return false;
if (!cmdGetToken(cmds, offset, token)) return false;
if (token != "{") return false;
if (!execute(child, cmds, offset, response))
if (!execute(floater, child, cmds, offset, response))
return false;
} else if (key == "setValue") {
ctrl->setValue(value);
} else if (key == "channel") {
if (HippoFloaterXmlImpl *floater = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
floater->mChannel = atoi(value.c_str());
}
} else if (key == "setLabel") {
/*ctrl->setLabel(value);*/
} else if (key == "setVisible") {
ctrl->setVisible(value != "0");
} else if (key == "setEnabled") {
ctrl->setEnabled(value != "0");
} else if (key == "notify") {
bool set = (value != "0");
if (HippoFloaterXmlImpl *floater = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
floater->mIsNotifyOnClose = set;
if (HippoFloaterXmlImpl *floaterp = dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
floaterp->mIsNotifyOnClose = set;
} else {
if (set)
ctrl->setCommitCallback(boost::bind(&notifyCallback, _1), ctrl);
ctrl->setCommitCallback(boost::bind(&notifyCallback, _1, floater), ctrl);
else
ctrl->setCommitCallback(0);
}
} else if (key == "picker") {
bool set = (value != "0");
if (!dynamic_cast<HippoFloaterXmlImpl*>(ctrl)) {
if (set)
ctrl->setCommitCallback(boost::bind(&pickerCallback, _1, floater), ctrl);
else
ctrl->setCommitCallback(0);
}
}
}
}

View File

@@ -52,13 +52,16 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) :
mXmlState(XML_VOID),
mVoiceConnector("SLVoice"),
mIsInProductionGrid(false),
mIsInAvination(false),
mRenderCompat(true),
mInvLinks(false),
mAutoUpdate(false),
mMaxAgentGroups(-1),
mCurrencySymbol("OS$"),
mCurrencyText("OS Dollars"),
mRealCurrencySymbol("US$"),
mDirectoryFee(30)
mDirectoryFee(30),
mUPCSupported(false)
{
}
@@ -66,37 +69,6 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) :
// ********************************************************************
// Getters
HippoGridInfo::Platform HippoGridInfo::getPlatform()
{
return mPlatform;
}
bool HippoGridInfo::isOpenSimulator() const
{
return (mPlatform == HippoGridInfo::PLATFORM_OPENSIM || mPlatform == HippoGridInfo::PLATFORM_AURORA);
}
bool HippoGridInfo::isAurora() const
{
return (mPlatform == HippoGridInfo::PLATFORM_AURORA);
}
bool HippoGridInfo::isSecondLife() const
{
return (mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE);
}
bool HippoGridInfo::isInProductionGrid() const
{
llassert(mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE);
return mIsInProductionGrid;
}
const std::string& HippoGridInfo::getGridName() const
{
return mGridName;
}
const std::string& HippoGridInfo::getGridOwner() const
{
if(isSecondLife())
@@ -110,68 +82,6 @@ const std::string& HippoGridInfo::getGridOwner() const
}
}
const std::string& HippoGridInfo::getLoginUri() const
{
return mLoginUri;
}
const std::string& HippoGridInfo::getLoginPage() const
{
return mLoginPage;
}
const std::string& HippoGridInfo::getHelperUri() const
{
return mHelperUri;
}
const std::string& HippoGridInfo::getWebSite() const
{
return mWebSite;
}
const std::string& HippoGridInfo::getSupportUrl() const
{
return mSupportUrl;
}
const std::string& HippoGridInfo::getRegisterUrl() const
{
return mRegisterUrl;
}
const std::string& HippoGridInfo::getPasswordUrl() const
{
return mPasswordUrl;
}
const std::string& HippoGridInfo::getSearchUrl() const
{
return mSearchUrl;
}
const std::string& HippoGridInfo::getGridMessage() const
{
return mGridMessage;
}
bool HippoGridInfo::isRenderCompat() const
{
return mRenderCompat;
}
const std::string& HippoGridInfo::getCurrencySymbol() const
{
return mCurrencySymbol;
}
const std::string& HippoGridInfo::getRealCurrencySymbol() const
{
return mRealCurrencySymbol;
}
// ********************************************************************
// Setters
@@ -181,6 +91,7 @@ void HippoGridInfo::setPlatform(Platform platform)
if (mPlatform == PLATFORM_SECONDLIFE)
{
mCurrencySymbol = "L$";
mCurrencyText = "Linden Dollars";
}
}
@@ -240,6 +151,10 @@ void HippoGridInfo::setGridNick(std::string gridNick)
{
mIsInProductionGrid = true;
}
if(gridNick == "avination")
{
mIsInAvination = true;
}
}
void HippoGridInfo::setLoginUri(const std::string& loginUri)
@@ -250,6 +165,11 @@ void HippoGridInfo::setLoginUri(const std::string& loginUri)
{
mIsInProductionGrid = true;
}
if (utf8str_tolower(LLURI(uri).hostName()) == "login.avination.com" ||
utf8str_tolower(LLURI(uri).hostName()) == "login.avination.net")
{
mIsInAvination = true;
}
}
void HippoGridInfo::setLoginPage(const std::string& loginPage)
@@ -303,6 +223,11 @@ void HippoGridInfo::setCurrencySymbol(const std::string& sym)
mCurrencySymbol = sym.substr(0, 3);
}
void HippoGridInfo::setCurrencyText(const std::string& text)
{
mCurrencyText = text;
}
void HippoGridInfo::setRealCurrencySymbol(const std::string& sym)
{
mRealCurrencySymbol = sym.substr(0, 3);
@@ -456,8 +381,11 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le
{
case XML_GRIDNICK:
{
if (self->mGridNick == "") self->mGridNick.assign(s, len);
self->mGridNick = sanitizeGridNick(self->mGridNick);
if (self->mGridNick == "")
{
self->mGridNick.assign(s, len);
self->mGridNick = sanitizeGridNick(self->mGridNick);
}
break;
}
@@ -489,7 +417,15 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le
break;
}
case XML_GRIDNAME: self->mGridName.assign(s, len); break;
case XML_GRIDNAME:
{
if (self->mGridName == "")
{
self->mGridName.assign(s, len);
}
break;
}
case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break;
case XML_WEBSITE: self->mWebSite.assign(s, len); break;
case XML_SUPPORT: self->mSupportUrl.assign(s, len); break;
@@ -676,6 +612,19 @@ void HippoGridInfo::setAutoUpdate(bool b)
mAutoUpdate = b;
}
bool HippoGridInfo::getUPCSupported()
{
if(isSecondLife())
return false;
else
return mUPCSupported;
}
void HippoGridInfo::setUPCSupported(bool b)
{
mUPCSupported = b;
}
// ********************************************************************
// ********************************************************************
// HippoGridManager
@@ -747,13 +696,6 @@ HippoGridInfo* HippoGridManager::getGrid(const std::string& grid) const
}
}
HippoGridInfo* HippoGridManager::getConnectedGrid() const
{
return (mConnectedGrid)? mConnectedGrid: getCurrentGrid();
}
HippoGridInfo* HippoGridManager::getCurrentGrid() const
{
HippoGridInfo* grid = getGrid(mCurrentGrid);

View File

@@ -36,31 +36,33 @@ public:
explicit HippoGridInfo(const std::string& gridName);
Platform getPlatform();
bool isOpenSimulator() const;
bool isAurora() const;
bool isSecondLife() const;
bool isInProductionGrid() const; // Should only be called if isSecondLife() returns true.
const std::string& getGridName() const;
Platform getPlatform() { return mPlatform; }
bool isOpenSimulator() const { return (mPlatform == PLATFORM_OPENSIM || mPlatform == PLATFORM_AURORA); }
bool isAurora() const { return (mPlatform == PLATFORM_AURORA); }
bool isSecondLife() const { return (mPlatform == PLATFORM_SECONDLIFE); }
bool isAvination() const { return mIsInAvination; }
bool isInProductionGrid() const { llassert(mPlatform == PLATFORM_SECONDLIFE); return mIsInProductionGrid; } // Should only be called if isSecondLife() returns true.
const std::string& getGridName() const { return mGridName; }
const std::string& getGridOwner() const;
const std::string& getLoginUri() const;
const std::string& getLoginPage() const;
const std::string& getHelperUri() const;
const std::string& getWebSite() const;
const std::string& getSupportUrl() const;
const std::string& getRegisterUrl() const;
const std::string& getPasswordUrl() const;
const std::string& getLoginUri() const { return mLoginUri; }
const std::string& getLoginPage() const { return mLoginPage; }
const std::string& getHelperUri() const { return mHelperUri; }
const std::string& getWebSite() const { return mWebSite; }
const std::string& getSupportUrl() const { return mSupportUrl; }
const std::string& getRegisterUrl() const { return mRegisterUrl; }
const std::string& getPasswordUrl() const { return mPasswordUrl; }
// Returns the url base used for the Web Search tab
const std::string& getSearchUrl() const;
const std::string& getGridMessage() const;
const std::string& getSearchUrl() const { return mSearchUrl; }
const std::string& getGridMessage() const { return mGridMessage; }
const std::string& getVoiceConnector() const { return mVoiceConnector; }
std::string getSearchUrl(SearchType ty, bool is_web) const;
bool isRenderCompat() const;
std::string getGridNick();
bool isRenderCompat() const { return mRenderCompat; }
std::string getGridNick();
int getMaxAgentGroups() const { return mMaxAgentGroups; }
const std::string& getCurrencySymbol() const;
const std::string& getRealCurrencySymbol() const;
const std::string& getCurrencySymbol() const { return mCurrencySymbol; }
const std::string& getCurrencyText() const { return mCurrencyText; }
const std::string& getRealCurrencySymbol() const { return mRealCurrencySymbol; }
std::string getUploadFee() const;
std::string getGroupCreationFee() const;
std::string getDirectoryFee() const;
@@ -82,8 +84,11 @@ public:
void setRenderCompat(bool compat);
void setMaxAgentGroups(int max) { mMaxAgentGroups = max; }
void setVoiceConnector(const std::string& vc) { mVoiceConnector = vc; }
void setUPCSupported(bool on);
bool getUPCSupported();
void setCurrencySymbol(const std::string& sym);
void setCurrencyText(const std::string& text);
void setRealCurrencySymbol(const std::string& sym);
void setDirectoryFee(int fee);
bool supportsInvLinks();
@@ -113,12 +118,15 @@ private:
std::string mSearchUrl;
std::string mVoiceConnector;
bool mIsInProductionGrid;
bool mIsInAvination;
bool mRenderCompat;
bool mInvLinks;
bool mAutoUpdate;
bool mUPCSupported;
int mMaxAgentGroups;
std::string mCurrencySymbol;
std::string mCurrencyText;
std::string mRealCurrencySymbol;
int mDirectoryFee;
std::string mGridMessage;
@@ -152,7 +160,8 @@ public:
void discardAndReload();
HippoGridInfo* getGrid(const std::string& grid) const;
HippoGridInfo* getConnectedGrid() const;
HippoGridInfo* getConnectedGrid() const { return mConnectedGrid ? mConnectedGrid : getCurrentGrid(); }
HippoGridInfo* getCurrentGrid() const;
const std::string& getDefaultGridNick() const;
const std::string& getCurrentGridNick() const;

View File

@@ -133,7 +133,7 @@ BOOL HippoPanelGridsImpl::postBuild()
requires<LLButton>("btn_add");
requires<LLButton>("btn_copy");
requires<LLButton>("btn_default");
//requires<LLButton>("btn_gridinfo");
requires<LLButton>("btn_gridinfo");
requires<LLButton>("btn_help_render_compat");
if (!checkRequirements()) return false;
@@ -146,7 +146,7 @@ BOOL HippoPanelGridsImpl::postBuild()
childSetAction("btn_add", onClickAdd, this);
childSetAction("btn_copy", onClickCopy, this);
childSetAction("btn_default", onClickDefault, this);
//childSetAction("btn_gridinfo", onClickGridInfo, this);
childSetAction("btn_gridinfo", onClickGridInfo, this);
childSetAction("btn_help_render_compat", onClickHelpRenderCompat, this);
childSetAction("btn_advanced", onClickAdvanced, this);

View File

@@ -0,0 +1,66 @@
/* Copyright (C) 2013 Liru Færs
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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 */
#include "llviewerprecompiledheaders.h"
#include "lfsimfeaturehandler.h"
#include "llagent.h"
#include "llenvmanager.h"
#include "llviewerregion.h"
#include "hippogridmanager.h"
LFSimFeatureHandler::LFSimFeatureHandler()
: mSupportsExport(false)
{
if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) // Remove this line if we ever handle SecondLife sim features
LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LFSimFeatureHandler::handleRegionChange, this));
}
void LFSimFeatureHandler::handleRegionChange()
{
if (LLViewerRegion* region = gAgent.getRegion())
{
if (region->getFeaturesReceived())
{
setSupportedFeatures();
}
else
{
region->setFeaturesReceivedCallback(boost::bind(&LFSimFeatureHandler::setSupportedFeatures, this));
}
}
}
void LFSimFeatureHandler::setSupportedFeatures()
{
if (LLViewerRegion* region = gAgent.getRegion())
{
LLSD info;
region->getSimulatorFeatures(info);
//if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) // Non-SL specific sim features
{
mSupportsExport = info.has("ExportSupported");
}
}
}
boost::signals2::connection LFSimFeatureHandler::setSupportsExportCallback(const boost::signals2::signal<void()>::slot_type& slot)
{
return mSupportsExport.connect(slot);
}

View File

@@ -0,0 +1,70 @@
/* Copyright (C) 2013 Liru Færs
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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 */
#ifndef LFSIMFEATUREHANDLER_H
#define LFSIMFEATUREHANDLER_H
#include "llsingleton.h"
template<typename Type>
class SignaledType
{
public:
SignaledType(Type b) : mValue(b) {}
template<typename Slot>
boost::signals2::connection connect(Slot slot) { return mSignal.connect(slot); }
SignaledType& operator =(Type val)
{
if (val != mValue)
{
mValue = val;
mSignal();
}
return *this;
}
operator Type() const { return mValue; }
private:
boost::signals2::signal<void()> mSignal;
Type mValue;
};
class LFSimFeatureHandler : public LLSingleton<LFSimFeatureHandler>
{
protected:
friend class LLSingleton<LFSimFeatureHandler>;
LFSimFeatureHandler();
public:
void handleRegionChange();
void setSupportedFeatures();
// Connection setters
boost::signals2::connection setSupportsExportCallback(const boost::signals2::signal<void()>::slot_type& slot);
// Accessors
bool simSupportsExport() const { return mSupportsExport; }
private:
// SignaledTypes
SignaledType<bool> mSupportsExport;
};
#endif //LFSIMFEATUREHANDLER_H

View File

@@ -4,14 +4,20 @@ Second Life - Linux Voice Support README
WHAT IS IT?
-=-=-=-=-=-
Linux Voice Support is a new feature in testing which allows users
of the Linux Second Life client to participate in voice-chat with other
residents and groups inside Second Life, with an appropriate
headset/microphone.
Linux Voice Support is a feature in testing which allows users of the Linux
Second Life client to participate in voice-chat with other residents and
groups inside Second Life, with an appropriate headset/microphone.
Linux Voice Support is currently EXPERIMENTAL and is known to still
have some compatibility issues.
SINGULARITY MULTI-VOICE
-=-=-=-=-=-=-=-=-=-=-=-
Singularity multi-voice is an experimental feature that allows you to run multiple
SLVoice daemons at the same time, in order to do this, the debug setting VoiceMultiInstance
must be TRUE, this allows multiple instances of the viewer to run concurrently and
each connect to voice.
REQUIREMENTS
-=-=-=-=-=-=
@@ -29,6 +35,13 @@ systems:
* Fedora Core 6 with (unknown) audio chipset
* Ubuntu 8.04 (Hardy) with (unknown) audio chipset
TESTING YOUR SETTINGS
-=-=-=-=-=-=-=-=-=-=-
* The Second Life region 'Voice Echo Canyon' is a great place for testing
your hardware settings and quality - it will 'echo' your voice back to you
when you speak.
KNOWN PROBLEMS
-=-=-=-=-=-=-=
@@ -41,12 +54,12 @@ TROUBLESHOOTING
PROBLEM 1: I don't see a white dot over the head of my avatar or other
Voice-using avatars.
SOLUTION:
a. Ensure that 'Enable voice chat' is enabled in the Voice Chat
preferences window and that you are in a voice-enabled area (you
will see a blue headphone icon in the SL menu-bar).
a. Ensure that 'Enable voice chat' is enabled in the 'Voice Chat' section of the
Preferences window, and that you are in a voice-enabled area
(you will see a blue headphone icon in the SL menu-bar).
b. If the above does not help, exit Second Life and ensure that any
remaining 'SLVoice' processes (as reported by 'ps', 'top' or similar)
are killed.
are killed before restarting.
PROBLEM 2: I have a white dot over my head but I never see (or hear!) anyone
except myself listed in the Active Speakers dialog when I'm sure that other
@@ -65,12 +78,13 @@ c. Update to the latest version of ALSA manually. For a guide, see the
PROBLEM 3: I can hear other people, but they cannot hear me.
SOLUTION:
a. Ensure that you have the 'Talk' button activated while you are trying to
speak.
a. Ensure that you have the 'Talk' button (at the bottom of the Second Life
window)activated while you are trying to speak.
b. Ensure that your microphone jack is inserted into the correct socket of your
sound card, where appropriate.
c. Use your system mixer-setting program or the 'alsamixer' program to ensure
that microphone input is set as the active input source and is not muted.
c. Use your system mixer-setting program (such as the PulseAudio 'volume
control' applet or the ALSA 'alsamixer' program) to ensure that microphone
input is set as the active input source and is not muted.
d. Verify that audio input works in other applications, i.e. Audacity
PROBLEM 4: Other people just hear bursts of loud noise when I speak.

View File

@@ -15,7 +15,7 @@ Life itself - please see <http://www.secondlife.com/whatis/>.
5.3. Blank window after minimizing it
5.4. Audio
5.5. 'Alt' key for camera controls doesn't work
5.6. In-world streaming movie/music playback
5.6. In-world streaming movie, music and Flash playback
6. Advanced Troubleshooting
6.1. Audio
6.2. OpenGL
@@ -75,10 +75,11 @@ Life Linux client is very similar to that for Windows, as detailed at:
3. INSTALLING & RUNNING
-=-=-=-=-=-=-=-=-=-=-=-
The Second Life Linux client entirely runs out of the directory you have
unpacked it into - no installation step is required.
The Singularity Linux client can entirely run from the directory you have
unpacked it into - no installation step is required. If you wish to
perform a separate installation step anyway, you may run './install.sh'
Run ./secondlife from the installation directory to start Second Life.
Run ./singularity from the installation directory to start Singularity.
For in-world MOVIE and MUSIC PLAYBACK, you will need (32-bit) GStreamer 0.10
installed on your system. This is optional - it is not required for general
@@ -168,12 +169,15 @@ SOLUTION:- Some window managers eat the Alt key for their own purposes; you
example, the 'Windows' key!) which will allow the Alt key to function
properly with mouse actions in Second Life and other applications.
PROBLEM 6:- In-world movie and/or music playback doesn't work for me.
PROBLEM 6:- In-world movie, music, or Flash playback doesn't work for me.
SOLUTION:- You need to have a working installation of GStreamer 0.10; this
is usually an optional package for most versions of Linux. If you have
installed GStreamer 0.10 and you can play some music/movies but not others
then you need to install a wider selection of GStreamer plugins, either
from your vendor or an appropriate third party.
from your vendor (i.e. the 'Ugly' plugins) or an appropriate third party.
For Flash playback, you need to have Flash 10 installed for your normal
web browser (for example, Firefox). PulseAudio is required for Flash
volume control / muting to fully function inside Second Life.
6. ADVANCED TROUBLESHOOTING

View File

@@ -0,0 +1,106 @@
#!/bin/bash
# Install Singularity Viewer. This script can install the viewer both
# system-wide and for an individual user.
VT102_STYLE_NORMAL='\E[0m'
VT102_COLOR_RED='\E[31m'
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
tarball_path=${RUN_PATH}
function prompt()
{
local prompt=$1
local input
echo -n "$prompt"
while read input; do
case $input in
[Yy]* )
return 1
;;
[Nn]* )
return 0
;;
* )
echo "Please enter yes or no."
echo -n "$prompt"
esac
done
}
function die()
{
warn $1
exit 1
}
function warn()
{
echo -n -e $VT102_COLOR_RED
echo $1
echo -n -e $VT102_STYLE_NORMAL
}
function homedir_install()
{
warn "You are not running as a privileged user, so you will only be able"
warn "to install Singularity Viewer in your home directory. If you"
warn "would like to install Singularity Viewer system-wide, please run"
warn "this script as the root user, or with the 'sudo' command."
echo
prompt "Proceed with the installation? [Y/N]: "
if [[ $? == 0 ]]; then
exit 0
fi
install_to_prefix "$HOME/.singularity-install"
$HOME/.singularity-install/refresh_desktop_app_entry.sh
}
function root_install()
{
local default_prefix="/opt/singularity-install"
echo -n "Enter the desired installation directory [${default_prefix}]: ";
read
if [[ "$REPLY" = "" ]] ; then
local install_prefix=$default_prefix
else
local install_prefix=$REPLY
fi
install_to_prefix "$install_prefix"
mkdir -p /usr/local/share/applications
${install_prefix}/refresh_desktop_app_entry.sh
}
function install_to_prefix()
{
test -e "$1" && backup_previous_installation "$1"
mkdir -p "$1" || die "Failed to create installation directory!"
echo " - Installing to $1"
cp -a "${tarball_path}"/* "$1/" || die "Failed to complete the installation!"
}
function backup_previous_installation()
{
local backup_dir="$1".backup-$(date -I)
echo " - Backing up previous installation to $backup_dir"
mv "$1" "$backup_dir" || die "Failed to create backup of existing installation!"
}
if [ "$UID" == "0" ]; then
root_install
else
homedir_install
fi

View File

@@ -0,0 +1,36 @@
#!/bin/bash
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
install_prefix=${RUN_PATH}
function install_desktop_entry()
{
local installation_prefix="$1"
local desktop_entries_dir="$2"
local desktop_entry="\
[Desktop Entry]\n\
Name=Singularity\n\
Comment=Client for Online Virtual Worlds, such as Second Life\n\
Exec=${installation_prefix}/singularity\n\
Icon=${installation_prefix}/singularity_icon.png\n\
Terminal=false\n\
Type=Application\n\
Categories=Application;Network;\n\
StartupNotify=true\n\
X-Desktop-File-Install-Version=3.0"
echo " - Installing menu entries in ${desktop_entries_dir}"
mkdir -vp "${desktop_entries_dir}"
echo -e $desktop_entry > "${desktop_entries_dir}/singularity-viewer.desktop" || "Failed to install application menu!"
}
if [ "$UID" == "0" ]; then
# system-wide
install_desktop_entry "$install_prefix" /usr/local/share/applications
else
# user-specific
install_desktop_entry "$install_prefix" "$HOME/.local/share/applications"
fi

View File

@@ -4,10 +4,10 @@
## These options are for self-assisted troubleshooting during this beta
## testing phase; you should not usually need to touch them.
## - Avoids using any OpenAL audio driver.
#export LL_BAD_OPENAL_DRIVER=x
## - Avoids using any FMOD Ex audio driver.
#export LL_BAD_FMODEX_DRIVER=x
## - Avoids using any OpenAL audio driver.
#export LL_BAD_OPENAL_DRIVER=x
## - Avoids using any FMOD audio driver.
#export LL_BAD_FMOD_DRIVER=x
@@ -20,7 +20,6 @@
## - Avoids using the FMOD or FMOD Ex ESD audio driver.
#export LL_BAD_FMOD_ESD=x
## - Avoids the optional OpenGL extensions which have proven most problematic
## on some hardware. Disabling this option may cause BETTER PERFORMANCE but
## may also cause CRASHES and hangs on some unstable combinations of drivers
@@ -109,6 +108,10 @@ cd "${RUN_PATH}"
# Re-register the secondlife:// protocol handler every launch, for now.
./register_secondlifeprotocol.sh
# Re-register the application with the desktop system every launch, for now.
./refresh_desktop_app_entry.sh
## Before we mess with LD_LIBRARY_PATH, save the old one to restore for
## subprocesses that care.
export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"
@@ -138,7 +141,7 @@ if [ -n "$LL_TCMALLOC" ]; then
fi
export VIEWER_BINARY='singularity-do-not-run-directly'
BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)')
BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)' | sed -e 's/ / /g')
if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then
SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib64:`pwd`/lib32:$LD_LIBRARY_PATH"'
else
@@ -147,16 +150,11 @@ fi
export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY'
export SL_OPT="`cat gridargs.dat` $@"
# Run the program
# Run the program.
eval ${SL_ENV} ${SL_CMD} ${SL_OPT} || LL_RUN_ERR=runerr
# Handle any resulting errors
if [ -n "$LL_RUN_ERR" ]; then
LL_RUN_ERR_MSG=""
if [ "$LL_RUN_ERR" = "runerr" ]; then
# generic error running the binary
echo '*** Bad shutdown. ***'
fi
# generic error running the binary
echo '*** Bad shutdown. ***'
fi

View File

@@ -229,9 +229,6 @@ private:
// Statics
//
BOOL LLAgent::exlPhantom = 0;
BOOL LLAgent::mForceTPose = 0;
const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;
std::map<std::string, std::string> LLAgent::sTeleportErrorMessages;
@@ -652,17 +649,6 @@ BOOL LLAgent::getFlying() const
return mControlFlags & AGENT_CONTROL_FLY;
}
// Better Set Phantom options ~Charbl
void LLAgent::setPhantom(BOOL phantom)
{
exlPhantom = phantom;
}
BOOL LLAgent::getPhantom()
{
return exlPhantom;
}
//-----------------------------------------------------------------------------
// setFlying()
//-----------------------------------------------------------------------------
@@ -727,8 +713,14 @@ void LLAgent::setFlying(BOOL fly)
//-----------------------------------------------------------------------------
// toggleFlying()
//-----------------------------------------------------------------------------
// static
void LLAgent::toggleFlying()
{
if ( gAgent.mAutoPilot )
{
LLToolPie::instance().stopClickToWalk();
}
BOOL fly = !gAgent.getFlying();
gAgent.setFlying( fly );
@@ -758,20 +750,6 @@ void LLAgent::standUp()
// [/RLVa:KB]
}
void LLAgent::togglePhantom()
{
BOOL phan = !(exlPhantom);
setPhantom( phan );
}
void LLAgent::toggleTPosed()
{
BOOL posed = !(mForceTPose);
setTPosed(posed);
}
void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id)
{
llinfos << "called" << llendl;
@@ -1315,17 +1293,6 @@ LLQuaternion LLAgent::getQuat() const
//-----------------------------------------------------------------------------
U32 LLAgent::getControlFlags()
{
/*
// HACK -- avoids maintenance of control flags when camera mode is turned on or off,
// only worries about it when the flags are measured
if (mCameraMode == CAMERA_MODE_MOUSELOOK)
{
if ( !(mControlFlags & AGENT_CONTROL_MOUSELOOK) )
{
mControlFlags |= AGENT_CONTROL_MOUSELOOK;
}
}
*/
return mControlFlags;
}
@@ -1419,9 +1386,8 @@ void LLAgent::setAFK()
//-----------------------------------------------------------------------------
void LLAgent::clearAFK()
{
if (gSavedSettings.getBOOL("FakeAway")) return;
gAwayTriggerTimer.reset();
if (!gSavedSettings.controlExists("FakeAway")) gSavedSettings.declareBOOL("FakeAway", FALSE, "", NO_PERSIST);
if (gSavedSettings.getBOOL("FakeAway") == TRUE) return;
// Gods can sometimes get into away state (via gestures)
// without setting the appropriate control flag. JC
@@ -1917,8 +1883,7 @@ BOOL LLAgent::needsRenderHead()
//-----------------------------------------------------------------------------
void LLAgent::startTyping()
{
if (gSavedSettings.getBOOL("FakeAway"))
return;
if (gSavedSettings.getBOOL("FakeAway")) return;
mTypingTimer.reset();
if (getRenderState() & AGENT_STATE_TYPING)
@@ -2035,6 +2000,7 @@ void LLAgent::endAnimationUpdateUI()
{
(*mMouselookModeOutSignal)();
}
// Only pop if we have pushed...
if (TRUE == mViewsPushed)
{
@@ -4092,6 +4058,7 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
return;
}
// [/RLVa:KB]
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id));
startTeleportRequest();
}
@@ -4189,6 +4156,7 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
}
}
// [/RLVa:KB]
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global));
startTeleportRequest();
}
@@ -4261,6 +4229,7 @@ void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
return;
}
// [/RLVa:KB]
mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global));
startTeleportRequest();
}
@@ -4729,6 +4698,16 @@ void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& dire
gMessageSystem->addString("DirectoryVisibility", directory_visibility);
gAgent.sendReliableMessage();
}
void LLAgent::dumpGroupInfo()
{
llinfos << "group " << mGroupName << llendl;
llinfos << "ID " << mGroupID << llendl;
llinfos << "powers " << mGroupPowers << llendl;
llinfos << "title " << mGroupTitle << llendl;
//llinfos << "insig " << mGroupInsigniaID << llendl;
}
// Draw a representation of current autopilot target
void LLAgent::renderAutoPilotTarget()
{
@@ -4974,4 +4953,5 @@ void LLTeleportRequestViaLocationLookAt::restartTeleport()
{
gAgent.doTeleportViaLocationLookAt(getPosGlobal());
}
// EOF

View File

@@ -94,12 +94,13 @@ struct LLGroupData
// forward declarations
//
//------------------------------------------------------------------------
// LLAgent
//------------------------------------------------------------------------
class LLAgent : public LLOldEvents::LLObservable
{
LOG_CLASS(LLAgent);
public:
friend class LLAgentDropGroupViewerNode;
@@ -160,7 +161,7 @@ public:
public:
void getName(std::string& name); //Legacy
void buildFullname(std::string &name) const; //Legacy
// *TODO remove, is not used as of August 20, 2009
//*TODO remove, is not used as of August 20, 2009
void buildFullnameAndTitle(std::string &name) const;
//--------------------------------------------------------------------
@@ -169,11 +170,11 @@ public:
public:
// On the very first login, gender isn't chosen until the user clicks
// in a dialog. We don't render the avatar until they choose.
BOOL isGenderChosen() const { return mGenderChosen; }
void setGenderChosen(BOOL b) { mGenderChosen = b; }
private:
BOOL isGenderChosen() const { return mGenderChosen; }
void setGenderChosen(BOOL b) { mGenderChosen = b; }
private:
BOOL mGenderChosen;
/** Identity
** **
*******************************************************************************/
@@ -182,7 +183,7 @@ public:
** **
** POSITION
**/
//--------------------------------------------------------------------
// Position
//--------------------------------------------------------------------
@@ -215,9 +216,9 @@ public:
void resetAxes();
void resetAxes(const LLVector3 &look_at); // Makes reasonable left and up
// The following three get*Axis functions return direction avatar is looking, not camera.
const LLVector3& getAtAxis() const { return mFrameAgent.getAtAxis(); }
const LLVector3& getUpAxis() const { return mFrameAgent.getUpAxis(); }
const LLVector3& getLeftAxis() const { return mFrameAgent.getLeftAxis(); }
const LLVector3& getAtAxis() const { return mFrameAgent.getAtAxis(); }
const LLVector3& getUpAxis() const { return mFrameAgent.getUpAxis(); }
const LLVector3& getLeftAxis() const { return mFrameAgent.getLeftAxis(); }
LLQuaternion getQuat() const; // Returns the quat that represents the rotation of the agent in the absolute frame
private:
LLVector3d mAgentOriginGlobal; // Origin of agent coords from global coords
@@ -229,7 +230,7 @@ private:
//--------------------------------------------------------------------
public:
void setStartPosition(U32 location_id); // Marks current location as start, sends information to servers
void setHomePosRegion( const U64& region_handle, const LLVector3& pos_region );
void setHomePosRegion(const U64& region_handle, const LLVector3& pos_region);
BOOL getHomePosGlobal(LLVector3d* pos_global);
private:
BOOL mHaveHomePosition;
@@ -277,18 +278,18 @@ public:
private:
std::set<U64> mRegionsVisited; // Stat - what distinct regions has the avatar been to?
F64 mDistanceTraveled; // Stat - how far has the avatar moved?
LLVector3d mLastPositionGlobal; // Used to calculate travel distance
LLVector3d mLastPositionGlobal; // Used to calculate travel distance
/** Position
** **
*******************************************************************************/
/********************************************************************************
** **
** ACTIONS
**/
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Fidget
//--------------------------------------------------------------------
// Trigger random fidget animations
@@ -311,7 +312,7 @@ public:
static void toggleFlying();
static bool enableFlying();
BOOL canFly(); // Does this parcel allow you to fly?
//--------------------------------------------------------------------
// Chat
//--------------------------------------------------------------------
@@ -405,7 +406,7 @@ public:
BOOL getBusy() const;
private:
BOOL mIsBusy;
//--------------------------------------------------------------------
// Grab
//--------------------------------------------------------------------
@@ -443,7 +444,7 @@ private:
//--------------------------------------------------------------------
// Animations
//--------------------------------------------------------------------
//--------------------------------------------------------------------
public:
void stopCurrentAnimations();
void requestStopMotion(LLMotion* motion);
@@ -675,7 +676,7 @@ public:
// ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp).
void setAOTransition();
private:
LLAgentAccess *mAgentAccess;
LLAgentAccess * mAgentAccess;
//--------------------------------------------------------------------
// God
@@ -720,7 +721,8 @@ public:
bool isAdult() const;
void setTeen(bool teen);
void setMaturity(char text);
static int convertTextToMaturity(char text);
static int convertTextToMaturity(char text);
private:
bool mIsDoSendMaturityPreferenceToServer;
unsigned int mMaturityPreferenceRequestId;
@@ -743,7 +745,6 @@ private:
bool validateMaturity(const LLSD& newvalue);
/** Access
** **
*******************************************************************************/
@@ -778,20 +779,20 @@ private:
// HUD
//--------------------------------------------------------------------
public:
const LLColor4 &getEffectColor();
void setEffectColor(const LLColor4 &color);
const LLColor4 &getEffectColor();
void setEffectColor(const LLColor4 &color);
private:
LLColor4 *mEffectColor;
/** Rendering
** **
*******************************************************************************/
/********************************************************************************
** **
** GROUPS
**/
public:
const LLUUID &getGroupID() const { return mGroupID; }
// Get group information by group_id, or FALSE if not in group.
@@ -828,7 +829,7 @@ public:
private:
std::string mGroupTitle; // Honorific, like "Sir"
BOOL mHideGroupTitle;
//--------------------------------------------------------------------
// Group Powers
//--------------------------------------------------------------------
@@ -882,54 +883,22 @@ public:
/** Messaging
** **
*******************************************************************************/
*******************************************************************************/
/********************************************************************************
** **
** DEBUGGING
**/
public:
static void clearVisualParams(void *);
void dumpGroupInfo();
static void clearVisualParams(void *);
friend std::ostream& operator<<(std::ostream &s, const LLAgent &sphere);
/** Debugging
** **
*******************************************************************************/
/********************************************************************************
** **
** Phantom mode!
**/
public:
static BOOL getPhantom();
static void setPhantom(BOOL phantom);
static void togglePhantom();
private:
static BOOL exlPhantom;
/** PHANTOM
** **
*******************************************************************************/
/********************************************************************************
** **
** Depreciated stuff. Move when ready.
**/
public:
//What's this t-posed stuff from?
static BOOL isTPosed() { return mForceTPose; }
static void setTPosed(BOOL TPose) { mForceTPose = TPose; }
static void toggleTPosed();
private:
static BOOL mForceTPose;
/** DEPRECIATED
** **
*******************************************************************************/
};
extern LLAgent gAgent;

View File

@@ -135,7 +135,7 @@ void LLInitialWearablesFetch::processContents()
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
LLFindWearables is_wearable;
llassert_always(mComplete.size() != 0);
llassert(mComplete.size() != 0);
gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH, is_wearable);

View File

@@ -3,10 +3,9 @@
* @brief The LLAppViewer class definitions
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Second Life Viewer Source Code
* Copyright (c) 2007-2009, 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
@@ -30,8 +29,8 @@
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llappviewer.h"
#include "hippogridmanager.h"
@@ -56,14 +55,13 @@
#include "llmeshrepository.h"
#include "llmodaldialog.h"
#include "llpumpio.h"
#include "llimpanel.h"
#include "llmimetypes.h"
#include "llstartup.h"
#include "llfocusmgr.h"
#include "llviewerjoystick.h"
#include "llfloaterjoystick.h"
#include "llares.h"
#include "llfloatersnapshot.h"
#include "llcurl.h"
#include "llcalc.h"
#include "lltexturestats.h"
#include "llviewerwindow.h"
#include "llviewerdisplay.h"
@@ -80,7 +78,9 @@
#include "llfirstuse.h"
#include "llrender.h"
#include "llvector4a.h"
#include "llfontfreetype.h"
#include "llimpanel.h" // For LLVoiceClient and LLVoiceChannel
#include "llvoavatarself.h"
#include "llprogressview.h"
#include "llvocache.h"
#include "llvopartgroup.h"
#include "llfloaterteleporthistory.h"
@@ -92,10 +92,10 @@
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llcurl.h"
#include <boost/bind.hpp>
#if LL_WINDOWS
@@ -121,7 +121,6 @@
#include "aihttptimeoutpolicy.h"
// </edit>
// The files below handle dependencies from cleanup.
#include "llcalc.h"
#include "llkeyframemotion.h"
#include "llworldmap.h"
#include "llhudmanager.h"
@@ -133,7 +132,6 @@
#include "llviewermenu.h"
#include "llselectmgr.h"
#include "lltrans.h"
#include "lltrans.h"
#include "lltracker.h"
#include "llviewerparcelmgr.h"
#include "llworldmapview.h"
@@ -144,15 +142,12 @@
#include "lldebugview.h"
#include "llconsole.h"
#include "llcontainerview.h"
#include "llfloaterstats.h"
#include "llhoverview.h"
#include "llfloatermemleak.h"
#include "llsdserialize.h"
#include "llworld.h"
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llvectorperfoptions.h"
#include "llurlsimstring.h"
#include "llwatchdog.h"
@@ -160,24 +155,23 @@
// Included so that constants/settings might be initialized
// in save_settings_to_globals()
#include "llbutton.h"
#include "llcombobox.h"
#include "llstatusbar.h"
#include "llsurface.h"
#include "llvosky.h"
#include "llvotree.h"
#include "llvoavatarself.h"
#include "llfolderview.h"
#include "lltoolbar.h"
#include "llframestats.h"
#include "llagentpilot.h"
#include "llsrv.h"
#include "llvovolume.h"
#include "llflexibleobject.h"
#include "llvosurfacepatch.h"
#include "llcommandlineparser.h"
#include "llfloatermemleak.h"
#include "llfloatersnapshot.h"
#include "llfloaterinventory.h"
// includes for idle() idleShutdown()
#include "floaterao.h"
#include "llviewercontrol.h"
#include "lleventnotifier.h"
#include "llcallbacklist.h"
@@ -192,10 +186,7 @@
#include "llviewerthrottle.h"
#include "llparcel.h"
#include "llviewerassetstats.h"
#include "llcommandlineparser.h"
#include "llprogressview.h"
#include "llmemory.h"
#include "llmainlooprepeater.h"
// [RLVa:KB]
@@ -223,12 +214,6 @@
//----------------------------------------------------------------------------
// viewer.cpp - these are only used in viewer, should be easily moved.
#if LL_DARWIN
extern void init_apple_menu(const char* product);
#endif // LL_DARWIN
@@ -486,6 +471,7 @@ static void settings_to_globals()
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures");
LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
@@ -1199,6 +1185,7 @@ bool LLAppViewer::mainLoop()
// canonical per-frame event
mainloop.post(newFrame);
if (!LLApp::isExiting())
{
pingMainloopTimeout("Main:JoystickKeyboard");
@@ -1206,7 +1193,7 @@ bool LLAppViewer::mainLoop()
// Scan keyboard for movement keys. Command keys and typing
// are handled by windows callbacks. Don't do this until we're
// done initializing. JC
if (gViewerWindow->mWindow->getVisible()
if (gViewerWindow->mWindow->getVisible()
&& gViewerWindow->getActive()
&& !gViewerWindow->getWindow()->getMinimized()
&& LLStartUp::getStartupState() == STATE_STARTED
@@ -1323,7 +1310,6 @@ bool LLAppViewer::mainLoop()
ms_sleep(500);
}
const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds, 0.005); // 50ms/second, no more than 5ms/frame
idleTimer.reset();
while(1)
@@ -1385,7 +1371,6 @@ bool LLAppViewer::mainLoop()
pingMainloopTimeout("Main:End");
}
}
catch(std::bad_alloc)
{
@@ -1741,7 +1726,8 @@ bool LLAppViewer::cleanup()
writeDebugInfo();
if(!gDirUtilp->getLindenUserDir(true).empty())
LLViewerMedia::saveCookieFile();
LLViewerMedia::saveCookieFile();
// Stop the plugin read thread if it's running.
LLPluginProcessParent::setUseReadThread(false);
// Stop curl responder call backs.
@@ -1761,11 +1747,11 @@ bool LLAppViewer::cleanup()
pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
pending += LLVFSThread::updateClass(0);
pending += LLLFSThread::updateClass(0);
if (pending == 0)
if (!pending)
{
break;
}
if (idleTimer.getElapsedTimeF64() >= max_idle_time)
else if (idleTimer.getElapsedTimeF64() >= max_idle_time)
{
llwarns << "Quitting with pending background tasks." << llendl;
break;
@@ -1910,9 +1896,7 @@ bool LLAppViewer::initThreads()
// State machine thread.
startEngineThread();
AICurlInterface::startCurlThread(gSavedSettings.getU32("CurlMaxTotalConcurrentConnections"),
gSavedSettings.getU32("CurlConcurrentConnectionsPerHost"),
gSavedSettings.getBOOL("NoVerifySSLCert"));
AICurlInterface::startCurlThread(&gSavedSettings);
LLImage::initClass();
@@ -1930,6 +1914,7 @@ bool LLAppViewer::initThreads()
// Mesh streaming and caching
gMeshRepo.init();
// *FIX: no error handling here!
return true;
}
@@ -2125,20 +2110,14 @@ bool LLAppViewer::initConfiguration()
if(!loadSettingsFromDirectory(settings_w, "Default", set_defaults))
{
std::ostringstream msg;
msg << "Second Life could not load its default settings file. \n"
<< "The installation may be corrupted. \n";
OSMessageBox(
msg.str(),
LLStringUtil::null,
OSMB_OK);
msg << "Unable to load default settings file. The installation may be corrupted.";
OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
return false;
}
LLUICtrlFactory::getInstance()->setupPaths(); // setup paths for LLTrans based on settings files only
LLTrans::parseStrings("strings.xml", default_trans_args);
//COA vars in gSavedSettings will be linked to gSavedPerAccountSettings entries that will be created if not present.
//Signals will be shared between linked vars.
gSavedSettings.connectCOAVars(gSavedPerAccountSettings);
@@ -2168,8 +2147,8 @@ bool LLAppViewer::initConfiguration()
// timeout for mac and linux. There is no call stack info
// on these platform to help debug.
#ifndef LL_RELEASE_FOR_DOWNLOAD
gSavedSettings.setBOOL("WatchdogEnabled", FALSE);
gSavedSettings.setBOOL("QAMode", TRUE );
gSavedSettings.setBOOL("WatchdogEnabled", 0);
#endif
#ifndef LL_WINDOWS
@@ -2213,6 +2192,7 @@ bool LLAppViewer::initConfiguration()
LLControlGroupCLP clp;
std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
"cmd_line.xml");
clp.configure(cmd_line_config, &gSavedSettings);
if(!initParseCommandLine(clp))
@@ -2248,9 +2228,8 @@ bool LLAppViewer::initConfiguration()
clp.notify();
// Register the core crash option as soon as we can
// if we want gdb post-mortum on cores we need to be up and running
// if we want gdb post-mortem on cores we need to be up and running
// ASAP or we might miss init issue etc.
if(clp.hasOption("disablecrashlogger"))
{
llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" <<llendl;
@@ -2278,36 +2257,6 @@ bool LLAppViewer::initConfiguration()
return false;
}
//////////////////////////
// Apply settings...
if(clp.hasOption("setdefault"))
{
//const LLCommandLineParser::token_vector_t& setdefault = clp.getOption("setdefault");
//if(0x1 & setdefault.size())
//{
// llwarns << "Invalid '--setdefault' parameter count." << llendl;
//}
//else
//{
// LLCommandLineParser::token_vector_t::const_iterator itr = setdefault.begin();
// for(; itr != setdefault.end(); ++itr)
// {
// const std::string& name = *itr;
// const std::string& value = *(++itr);
// LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name);
// if(c)
// {
// c->setDefault(value);
// }
// else
// {
// llwarns << "'--setdefault' specified with unknown setting: '"
// << name << "'." << llendl;
// }
// }
//}
}
if(clp.hasOption("set"))
{
const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set");
@@ -2551,7 +2500,7 @@ bool LLAppViewer::initConfiguration()
if ( nextLoginLocation.length() )
{
LLURLSimString::setString( nextLoginLocation );
};
}
gLastRunVersion = gSavedSettings.getString("LastRunVersion");
@@ -2743,7 +2692,6 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["SLLog"] = LLError::logFileName();
gDebugInfo["ClientInfo"]["Name"] = gVersionChannel;
gDebugInfo["ClientInfo"]["MajorVersion"] = gVersionMajor;
gDebugInfo["ClientInfo"]["MinorVersion"] = gVersionMinor;
gDebugInfo["ClientInfo"]["PatchVersion"] = gVersionPatch;
@@ -2751,7 +2699,6 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
//need to put in something to lie about this stuff
gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMHz();
@@ -2764,10 +2711,10 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
// The user is not logged on yet, but record the current grid choice login url
// which may have been the intended grid. This can b
// which may have been the intended grid.
gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
// *FIX:Mani - move this ddown in llappviewerwin32
// *FIX:Mani - move this down in llappviewerwin32
#ifdef LL_WINDOWS
DWORD thread_id = GetCurrentThreadId();
gDebugInfo["MainloopThreadID"] = (S32)thread_id;
@@ -2817,6 +2764,7 @@ void LLAppViewer::handleViewerCrash()
llinfos << "Last render pool type: " << LLPipeline::sCurRenderPoolType << llendl ;
LLMemory::logMemoryInfo(true) ;
//print out recorded call stacks if there are any.
LLError::LLCallStacks::print();
@@ -2845,7 +2793,6 @@ void LLAppViewer::handleViewerCrash()
//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
//to check against no matter what
gDebugInfo["ClientInfo"]["Name"] = gVersionChannel;
gDebugInfo["ClientInfo"]["MajorVersion"] = gVersionMajor;
@@ -3023,13 +2970,11 @@ void LLAppViewer::initMarkerFile()
std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning())
{
gLastExecEvent = LAST_EXEC_FROZE;
LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
}
if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB))
{
gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
@@ -3741,17 +3686,6 @@ void LLAppViewer::loadNameCache()
{
if(gCacheName->importFile(cache_file)) return;
}
// Try to load from the legacy format. This should go away after a
// while. Phoenix 2008-01-30
#if 0
LLFILE* name_cache_fp = LLFile::fopen(name_cache, "r"); // Flawfinder: ignore
if (name_cache_fp)
{
gCacheName->importFile(name_cache_fp);
fclose(name_cache_fp);
}
#endif
}
void LLAppViewer::saveNameCache()
@@ -3804,6 +3738,7 @@ static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network");
static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager");
///////////////////////////////////////////////////////
// idle()
//
@@ -3864,7 +3799,6 @@ void LLAppViewer::idle()
//
// Special case idle if still starting up
//
if (LLStartUp::getStartupState() < STATE_STARTED)
{
// Skip rest if idle startup returns false (essentially, no world yet)
@@ -3916,10 +3850,7 @@ void LLAppViewer::idle()
LLFastTimer t(FTM_AGENT_UPDATE);
// Send avatar and camera info
last_control_flags = gAgent.getControlFlags();
if(!gAgent.getPhantom())
{
send_agent_update(TRUE);
}
send_agent_update(TRUE);
agent_update_timer.reset();
}
}
@@ -3929,7 +3860,6 @@ void LLAppViewer::idle()
// Manage statistics
//
//
{
// Initialize the viewer_stats_timer with an already elapsed time
// of SEND_STATS_PERIOD so that the initial stats report will
@@ -4328,7 +4258,6 @@ void LLAppViewer::sendLogoutRequest()
{
if(!mLogoutRequestSent && gMessageSystem)
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_LogoutRequest);
msg->nextBlockFast(_PREHASH_AgentData);
@@ -4432,6 +4361,7 @@ static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit");
static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check");
static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle");
static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit");
void LLAppViewer::idleNetwork()
{
pingMainloopTimeout("idleNetwork");
@@ -4449,7 +4379,8 @@ void LLAppViewer::idleNetwork()
// Read all available packets from network
const S64 frame_count = gFrameCount; // U32->S64
F32 total_time = 0.0f;
while (gMessageSystem->checkAllMessages(frame_count, gServicePump))
while (gMessageSystem->checkAllMessages(frame_count, gServicePump))
{
if (gDoDisconnect)
{

View File

@@ -3,10 +3,9 @@
* @brief Processes responses received for asset upload requests.
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Second Life Viewer Source Code
* Copyright (c) 2007-2009, 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
@@ -53,7 +52,6 @@
#include "llviewerobject.h"
#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
#include "llviewermenufile.h"
#include "llviewertexlayer.h"
#include "llviewerwindow.h"
#include "lltrans.h"
@@ -255,6 +253,7 @@ void LLAssetUploadResponder::result(const LLSD& content)
lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
std::string state = content["state"];
if (state == "upload")
{
uploadUpload(content);
@@ -343,6 +342,7 @@ void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reaso
//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
}
//virtual
void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
{
@@ -351,6 +351,7 @@ void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
(*mCallBack)(false, mUserData);
}
LLAssetUploadResponder::uploadFailure(content);
//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
}
@@ -397,10 +398,14 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
// continue uploading for bulk uploads
if (!gUploadQueue.empty())
/* Singu Note: sUploadQueue was never getting populated, anywhere! Therefore, this entire block never was reached.
** I have condensed it to here in the hopes it may one day see use. Apparently, it came in with Siana's prep work
** for mesh upload (697dd7e9298282590f8cf858a58335f70302532b), but we never needed it.
static std::deque<std::string> sUploadQueue;
if (!sUploadQueue.empty())
{
std::string next_file = gUploadQueue.front();
gUploadQueue.pop_front();
std::string next_file = sUploadQueue.front();
sUploadQueue.pop_front();
if (next_file.empty()) return;
std::string name = gDirUtilp->getBaseFileName(next_file, true);
@@ -448,6 +453,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
expected_upload_cost,
userdata);
}
*/
}
LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
@@ -698,6 +704,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
}
}
/////////////////////////////////////////////////////
// LLNewAgentInventoryVariablePriceResponder::Impl //
/////////////////////////////////////////////////////
@@ -1165,3 +1172,4 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(
boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)));
}
}

View File

@@ -56,7 +56,8 @@ public:
const std::string& getName() const { return mName; }
const LLUUID& getOwnerID() const { return mOwnerID; }
U32 getID() const { return mID; }
F32 getSunHour() const { return getUseFixedSun() ? mSunHour : 0.f; }
F32 getSunHour() const { return mSunHour; }
bool getGlobalTime() const { return !(mSunHour || getUseFixedSun()); }
// setters
void setUseFixedSun(bool val);

View File

@@ -237,7 +237,7 @@ namespace
if (!content.get("events") ||
!content.get("id"))
{
llwarns << "received event poll with no events or id key" << llendl;
//llwarns << "received event poll with no events or id key" << llendl;
makeRequest();
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,9 +2,7 @@
* @file llfloateranimpreview.h
* @brief LLFloaterAnimPreview class definition
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
* Copyright (c) 2012, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -34,112 +32,11 @@
#define LL_LLFLOATERANIMPREVIEW_H
#include "llfloaternamedesc.h"
#include "lldynamictexture.h"
#include "llcharacter.h"
#include "llquaternion.h"
class LLVOAvatar;
class LLViewerJointMesh;
class LLPreviewAnimation : public LLViewerDynamicTexture
{
protected:
virtual ~LLPreviewAnimation();
public:
LLPreviewAnimation(S32 width, S32 height);
/*virtual*/ S8 getType() const ;
BOOL render();
void requestUpdate();
void rotate(F32 yaw_radians, F32 pitch_radians);
void zoom(F32 zoom_delta);
void setZoom(F32 zoom_amt);
void pan(F32 right, F32 up);
virtual BOOL needsUpdate() { return mNeedsUpdate; }
LLVOAvatar* getDummyAvatar() { return mDummyAvatar; }
protected:
BOOL mNeedsUpdate;
F32 mCameraDistance;
F32 mCameraYaw;
F32 mCameraPitch;
F32 mCameraZoom;
LLVector3 mCameraOffset;
LLVector3 mCameraRelPos;
LLPointer<LLVOAvatar> mDummyAvatar;
};
class LLFloaterAnimPreview : public LLFloaterNameDesc
{
public:
//<edit>
LLFloaterAnimPreview(const std::string& filename, void* item = NULL);
//<edit>
virtual ~LLFloaterAnimPreview();
BOOL postBuild();
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
BOOL handleHover(S32 x, S32 y, MASK mask);
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
void onMouseCaptureLost();
void refresh();
void onBtnPlay();
void onBtnStop();
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
static void onSliderMove(LLUICtrl*, void*);
static void onCommitBaseAnim(LLUICtrl*, void*);
static void onCommitLoop(LLUICtrl*, void*);
static void onCommitLoopIn(LLUICtrl*, void*);
static void onCommitLoopOut(LLUICtrl*, void*);
static BOOL validateLoopIn(LLUICtrl*, void*);
static BOOL validateLoopOut(LLUICtrl*, void*);
static void onCommitName(LLUICtrl*, void*);
static void onCommitHandPose(LLUICtrl*, void*);
static void onCommitEmote(LLUICtrl*, void*);
static void onCommitPriority(LLUICtrl*, void*);
static void onCommitEaseIn(LLUICtrl*, void*);
static void onCommitEaseOut(LLUICtrl*, void*);
static BOOL validateEaseIn(LLUICtrl*, void*);
static BOOL validateEaseOut(LLUICtrl*, void*);
static void onBtnOK(void*);
static void onSaveComplete(const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data,
S32 status, LLExtStat ext_status);
private:
void setAnimCallbacks() ;
protected:
void draw();
void resetMotion();
LLPointer< LLPreviewAnimation> mAnimPreview;
S32 mLastMouseX;
S32 mLastMouseY;
LLButton* mPlayButton;
LLButton* mStopButton;
LLRect mPreviewRect;
LLRectf mPreviewImageRect;
LLAssetID mMotionID;
LLTransactionID mTransactionID;
BOOL mEnabled;
BOOL mInWorld;
LLAnimPauseRequest mPauseRequest;
std::map<std::string, LLUUID> mIDList;
static S32 sUploadAmount;
//<edit>
void* mItem;
//</edit>
class LLFloaterAnimPreview : public LLFloaterNameDesc {
public:
LLFloaterAnimPreview(LLSD const& filename);
virtual BOOL postBuild(void);
};
#endif // LL_LLFLOATERANIMPREVIEW_H

View File

@@ -43,6 +43,25 @@ void LLFloaterBlacklist::show()
sInstance->open();
}
}
// static
void LLFloaterBlacklist::toggle()
{
if (sInstance && sInstance->getVisible())
{
delete sInstance;
}
else
{
show();
}
}
// static
BOOL LLFloaterBlacklist::visible()
{
if (sInstance && sInstance->getVisible())
return TRUE;
return FALSE;
}
BOOL LLFloaterBlacklist::postBuild()
{
childSetAction("add_btn", onClickAdd, this);

View File

@@ -11,6 +11,8 @@ public:
LLFloaterBlacklist();
~LLFloaterBlacklist();
static void show();
static void toggle();
static BOOL visible();
BOOL postBuild();
void refresh();
static LLFloaterBlacklist* getInstance() { return sInstance; };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,145 @@
/**
* @file llfloaterbvhpreview.h
* @brief LLFloaterBvhPreview class definition
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLFLOATERBVHPREVIEW_H
#define LL_LLFLOATERBVHPREVIEW_H
#include "llfloaternamedesc.h"
#include "lldynamictexture.h"
#include "llcharacter.h"
#include "llquaternion.h"
class LLVOAvatar;
class LLViewerJointMesh;
class LLPreviewAnimation : public LLViewerDynamicTexture
{
protected:
virtual ~LLPreviewAnimation();
public:
LLPreviewAnimation(S32 width, S32 height);
/*virtual*/ S8 getType() const ;
BOOL render();
void requestUpdate();
void rotate(F32 yaw_radians, F32 pitch_radians);
void zoom(F32 zoom_delta);
void setZoom(F32 zoom_amt);
void pan(F32 right, F32 up);
virtual BOOL needsUpdate() { return mNeedsUpdate; }
LLVOAvatar* getDummyAvatar() { return mDummyAvatar; }
protected:
BOOL mNeedsUpdate;
F32 mCameraDistance;
F32 mCameraYaw;
F32 mCameraPitch;
F32 mCameraZoom;
LLVector3 mCameraOffset;
LLVector3 mCameraRelPos;
LLPointer<LLVOAvatar> mDummyAvatar;
};
class LLFloaterBvhPreview : public LLFloaterNameDesc
{
public:
//<edit>
LLFloaterBvhPreview(const std::string& filename, void* item = NULL);
//<edit>
virtual ~LLFloaterBvhPreview();
BOOL postBuild();
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
BOOL handleHover(S32 x, S32 y, MASK mask);
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
void onMouseCaptureLost();
void refresh();
void onBtnPlay();
void onBtnStop();
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
static void onSliderMove(LLUICtrl*, void*);
static void onCommitBaseAnim(LLUICtrl*, void*);
static void onCommitLoop(LLUICtrl*, void*);
static void onCommitLoopIn(LLUICtrl*, void*);
static void onCommitLoopOut(LLUICtrl*, void*);
static BOOL validateLoopIn(LLUICtrl*, void*);
static BOOL validateLoopOut(LLUICtrl*, void*);
static void onCommitName(LLUICtrl*, void*);
static void onCommitHandPose(LLUICtrl*, void*);
static void onCommitEmote(LLUICtrl*, void*);
static void onCommitPriority(LLUICtrl*, void*);
static void onCommitEaseIn(LLUICtrl*, void*);
static void onCommitEaseOut(LLUICtrl*, void*);
static BOOL validateEaseIn(LLUICtrl*, void*);
static BOOL validateEaseOut(LLUICtrl*, void*);
static void onBtnOK(void*);
static void onSaveComplete(const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data,
S32 status, LLExtStat ext_status);
private:
void setAnimCallbacks() ;
protected:
void draw();
void resetMotion();
LLPointer< LLPreviewAnimation> mAnimPreview;
S32 mLastMouseX;
S32 mLastMouseY;
LLButton* mPlayButton;
LLButton* mStopButton;
LLRect mPreviewRect;
LLRectf mPreviewImageRect;
LLAssetID mMotionID;
LLTransactionID mTransactionID;
BOOL mEnabled;
BOOL mInWorld;
LLAnimPauseRequest mPauseRequest;
std::map<std::string, LLUUID> mIDList;
static S32 sUploadAmount;
//<edit>
void* mItem;
//</edit>
};
#endif // LL_LLFLOATERBVHPREVIEW_H

View File

@@ -179,13 +179,26 @@ void LLFloaterChat::handleVisibilityChange(BOOL new_visibility)
if (new_visibility)
{
LLFloaterChatterBox::getInstance()->setFloaterFlashing(this, FALSE);
// Work around the chat bar no longer focusing from within the layout_stack
gFocusMgr.setKeyboardFocus(getChildView("Chat Editor"));
}
LLFloater::handleVisibilityChange(new_visibility);
}
// virtual
void LLFloaterChat::onFocusReceived()
{
LLView* chat_editor = getChildView("Chat Editor");
if (getVisible() && childIsVisible("Chat Editor"))
{
gFocusMgr.setKeyboardFocus(chat_editor);
LLUICtrl * ctrl = static_cast<LLUICtrl*>(chat_editor);
ctrl->setFocus(TRUE);
}
LLFloater::onFocusReceived();
}
void LLFloaterChat::setMinimized(BOOL minimized)
{
LLFloater::setMinimized(minimized);
@@ -735,3 +748,20 @@ void LLFloaterChat::hide(LLFloater* instance, const LLSD& key)
VisibilityPolicy<LLFloater>::hide(instance, key);
}
}
BOOL LLFloaterChat::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash )
{
LLView* chat_editor = getChildView("Chat Editor");
if (getVisible() && childIsVisible("Chat Editor"))
{
gFocusMgr.setKeyboardFocus(chat_editor);
LLUICtrl * ctrl = static_cast<LLUICtrl*>(chat_editor);
ctrl->setFocus(TRUE);
return TRUE;
}
return LLUICtrl::focusFirstItem(prefer_text_fields, focus_flash);
}

View File

@@ -63,6 +63,7 @@ public:
virtual void draw();
virtual BOOL postBuild();
virtual void onClose(bool app_quitting);
virtual void onFocusReceived();
virtual void handleVisibilityChange(BOOL cur_visibility);
virtual void setMinimized(BOOL);
void updateConsoleVisibility();
@@ -97,6 +98,8 @@ public:
LLPanelActiveSpeakers* mPanel;
BOOL mScrolledToEnd;
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
CachedUICtrl<LLButton> mToggleActiveSpeakersBtn;
CachedUICtrl<LLChatBar> mChatPanel;
};

View File

@@ -4,7 +4,7 @@
#include "llfloaterexploreanimations.h"
#include "lluictrlfactory.h"
#include "llscrolllistctrl.h"
#include "llfloateranimpreview.h"
#include "llfloaterbvhpreview.h"
#include "llvoavatar.h"
#include "lllocalinventory.h"
#include "llviewercamera.h"

View File

@@ -3,7 +3,7 @@
#define LL_LLFLOATEREXPLOREANIMATIONS_H
#include "llfloater.h"
#include "llfloateranimpreview.h"
#include "llfloaterbvhpreview.h"
#include "llviewerwindow.h" // gViewerWindow
class LLAnimHistoryItem

View File

@@ -68,6 +68,13 @@ void LLFloaterExploreSounds::toggle()
else LLFloaterExploreSounds::sInstance = new LLFloaterExploreSounds();
}
BOOL LLFloaterExploreSounds::visible()
{
if (LLFloaterExploreSounds::sInstance)
return TRUE;
return FALSE;
}
void LLFloaterExploreSounds::close(bool app_quitting)
{
LLFloater::close(app_quitting);

View File

@@ -36,6 +36,7 @@ public:
static LLFloaterExploreSounds* sInstance;
static void toggle();
static BOOL visible();
};
#endif

View File

@@ -86,7 +86,7 @@ public:
if (added_category_type == LLFolderType::FT_OUTBOX)
{
mOutboxFloater->setupOutbox(added_category->getUUID());
mOutboxFloater->initializeMarketPlace();
}
}
}
@@ -152,13 +152,17 @@ BOOL LLFloaterOutbox::postBuild()
//
// Set up the outbox inventory view
//
mOutboxInventoryPanel = getChild<LLInventoryPanel>("panel_outbox_inventory");
llassert(mOutboxInventoryPanel);
mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target");
LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this));
// Observe category creation to catch outbox creation (moot if already existing)
mCategoryAddedObserver = new LLOutboxAddedObserver(this);
gInventory.addObserver(mCategoryAddedObserver);
return TRUE;
}
@@ -179,34 +183,26 @@ void LLFloaterOutbox::onClose(bool app_quitting)
void LLFloaterOutbox::onOpen()
{
//
// Look for an outbox and set up the inventory API
// Initialize the Market Place or go update the outbox
//
if (mOutboxId.isNull())
if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
{
const bool do_not_create_folder = false;
const bool do_not_find_in_library = false;
const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, do_not_create_folder, do_not_find_in_library);
if (outbox_id.isNull())
{
// Observe category creation to catch outbox creation
mCategoryAddedObserver = new LLOutboxAddedObserver(this);
gInventory.addObserver(mCategoryAddedObserver);
}
else
{
setupOutbox(outbox_id);
}
initializeMarketPlace();
}
else
{
setupOutbox();
}
//
// Update the floater view
//
updateView();
//
// Trigger fetch of outbox contents
//
fetchOutboxContents();
}
@@ -223,13 +219,22 @@ void LLFloaterOutbox::fetchOutboxContents()
}
}
void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId)
void LLFloaterOutbox::setupOutbox()
{
llassert(outboxId.notNull());
llassert(mOutboxId.isNull());
llassert(mCategoriesObserver == NULL);
if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)
{
// If we are *not* a merchant or we have no market place connection established yet, do nothing
return;
}
mOutboxId = outboxId;
// We are a merchant. Get the outbox, create it if needs be.
mOutboxId = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true, false);
if (mOutboxId.isNull())
{
// We should never get there unles inventory fails badly
llerrs << "Inventory problem: failure to create the outbox for a merchant!" << llendl;
return;
}
// No longer need to observe new category creation
if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
@@ -238,14 +243,19 @@ void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId)
delete mCategoryAddedObserver;
mCategoryAddedObserver = NULL;
}
llassert(!mCategoryAddedObserver);
// Create observer for outbox modifications
mCategoriesObserver = new LLInventoryCategoriesObserver();
gInventory.addObserver(mCategoriesObserver);
if (mCategoriesObserver == NULL)
{
mCategoriesObserver = new LLInventoryCategoriesObserver();
gInventory.addObserver(mCategoriesObserver);
mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this));
}
llassert(mCategoriesObserver);
mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this));
llassert(mOutboxInventoryPanel);
// Set up the outbox inventory view
// Singu Note: we handle this in postBuild, grabbing the panel from the built xml.
// Reshape the inventory to the proper size
LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect();
@@ -255,8 +265,12 @@ void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId)
mOutboxInventoryPanel->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME);
mOutboxInventoryPanel->getFilter()->markDefault();
// Get the content of the outbox
fetchOutboxContents();
}
void LLFloaterOutbox::initializeMarketPlace()
{
//
// Initialize the marketplace import API
//
@@ -330,6 +344,7 @@ void LLFloaterOutbox::updateView()
{
mOutboxInventoryPanel->setVisible(TRUE);
mInventoryPlaceholder->setVisible(FALSE);
mOutboxTopLevelDropZone->setVisible(TRUE);
}
else
{
@@ -338,13 +353,18 @@ void LLFloaterOutbox::updateView()
mOutboxInventoryPanel->setVisible(FALSE);
}
// Show the drop zone if there is an outbox folder
mOutboxTopLevelDropZone->setVisible(mOutboxId.notNull());
mInventoryPlaceholder->setVisible(TRUE);
std::string outbox_text;
std::string outbox_text2;
std::string outbox_title;
std::string outbox_tooltip;
const LLSD& subs = getMarketplaceStringSubstitutions();
U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus();
// Text styles for marketplace hyperlinks
std::string subs_link;
@@ -352,28 +372,54 @@ void LLFloaterOutbox::updateView()
if (mOutboxId.notNull())
{
// "Outbox is empty!" message strings
outbox_text = LLTrans::getString("InventoryOutboxNoItems");
subs_link = "[MARKETPLACE_DASHBOARD_URL]";
subs_text = " " + LLTrans::getString("InventoryOutboxNoItemsSubs");
outbox_text2 = LLTrans::getString("InventoryOutboxNoItems2");
outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle");
outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip");
}
else
else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING)
{
// "Initializing!" message strings
outbox_text = LLTrans::getString("InventoryOutboxInitializing");
subs_link = "[MARKETPLACE_CREATE_STORE_URL]";
subs_text = " " + LLTrans::getString("InventoryOutboxInitializingSubs");
outbox_text2 = LLTrans::getString("InventoryOutboxInitializing2");
outbox_title = LLTrans::getString("InventoryOutboxInitializingTitle");
outbox_tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip");
}
else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT)
{
// "Not a merchant!" message strings
outbox_text = LLTrans::getString("InventoryOutboxNotMerchant");
subs_link = "[MARKETPLACE_CREATE_STORE_URL]";
subs_text = " " + LLTrans::getString("InventoryOutboxNotMerchantSubs");
outbox_text2 = LLTrans::getString("InventoryOutboxNotMerchant2");
outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle");
outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip");
}
else
{
// "Errors!" message strings
outbox_text = LLTrans::getString("InventoryOutboxError");
subs_link = "[MARKETPLACE_CREATE_STORE_URL]";
subs_text = " " + LLTrans::getString("InventoryOutboxErrorSubs");
outbox_text2 = " " + LLTrans::getString("InventoryOutboxError2");
outbox_title = LLTrans::getString("InventoryOutboxErrorTitle");
outbox_tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
}
mInventoryText->clear();
mInventoryText->appendColoredText(outbox_text, false, false, gColors.getColor("TextFgReadOnlyColor"));
const LLColor4 color = gColors.getColor("TextFgReadOnlyColor");
mInventoryText->appendColoredText(outbox_text, false, false, color);
LLStringUtil::format(subs_link, subs);
LLStyleSP subs_link_style(new LLStyle);
subs_link_style->setLinkHREF(subs_link);
subs_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor"));
mInventoryText->appendStyledText(subs_text, false, false, subs_link_style);
mInventoryText->appendColoredText(outbox_text2, false, false, color);
mInventoryTitle->setValue(outbox_title);
mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip);
}
@@ -498,6 +544,11 @@ void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content)
void LLFloaterOutbox::importStatusChanged(bool inProgress)
{
if (mOutboxId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT))
{
setupOutbox();
}
if (inProgress)
{
if (mImportBusy)
@@ -515,6 +566,7 @@ void LLFloaterOutbox::importStatusChanged(bool inProgress)
}
else
{
setStatusString("");
mImportBusy = false;
mImportButton->setEnabled(mOutboxItemCount > 0);
mInventoryImportInProgress->setVisible(false);
@@ -525,7 +577,7 @@ void LLFloaterOutbox::importStatusChanged(bool inProgress)
void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content)
{
if (status != MarketplaceErrorCodes::IMPORT_DONE)
if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
{
char status_string[16];
sprintf(status_string, "%d", status);

View File

@@ -55,7 +55,7 @@ public:
LLFloaterOutbox(const LLSD& key);
~LLFloaterOutbox();
void setupOutbox(const LLUUID& outboxId);
void initializeMarketPlace();
// virtuals
BOOL postBuild();
@@ -71,6 +71,7 @@ public:
// void onMouseLeave(S32 x, S32 y, MASK mask);
protected:
void setupOutbox();
void fetchOutboxContents();
void importReportResults(U32 status, const LLSD& content);

View File

@@ -32,6 +32,7 @@
*/
#include "llviewerprecompiledheaders.h"
#include "lfsimfeaturehandler.h"
#include "llcheckboxctrl.h"
#include "llfloaterperms.h"
#include "llnotificationsutil.h"
@@ -39,7 +40,35 @@
#include "llviewerwindow.h"
#include "lluictrlfactory.h"
#include "llpermissions.h"
#include "hippogridmanager.h"
namespace
{
bool everyone_export;
void handle_checkboxes(LLUICtrl* ctrl, const LLSD& value)
{
LLPanel* view = static_cast<LLPanel*>(ctrl->getParent());
if (ctrl->getName() == "everyone_export")
{
view->childSetEnabled("next_owner_copy", !value);
view->childSetEnabled("next_owner_modify", !value);
view->childSetEnabled("next_owner_transfer", !value);
}
else
{
if (ctrl->getName() == "next_owner_copy")
{
if (!value) // Implements fair use
gSavedSettings.setBOOL("NextOwnerTransfer", true);
view->childSetEnabled("next_owner_transfer", value);
}
if (!value) // If any of these are unchecked, export can no longer be checked.
view->childSetEnabled("everyone_export", false);
else
view->childSetEnabled("everyone_export", LFSimFeatureHandler::instance().simSupportsExport() && (LLFloaterPerms::getNextOwnerPerms() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED);
}
}
}
LLFloaterPerms::LLFloaterPerms(const LLSD& seed)
{
@@ -48,11 +77,35 @@ LLFloaterPerms::LLFloaterPerms(const LLSD& seed)
BOOL LLFloaterPerms::postBuild()
{
childSetEnabled("next_owner_transfer", gSavedSettings.getBOOL("NextOwnerCopy"));
//handle_checkboxes
{
bool export_support = LFSimFeatureHandler::instance().simSupportsExport();
const U32 next_owner_perms = getNextOwnerPerms();
childSetEnabled("everyone_export", export_support && (next_owner_perms & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED);
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
childSetVisible("everyone_export", false);
if (!(next_owner_perms & PERM_COPY))
{
childSetEnabled("next_owner_transfer", false);
}
else if (export_support)
{
bool export_off = !gSavedPerAccountSettings.getBOOL("EveryoneExport");
childSetEnabled("next_owner_copy", export_off);
childSetEnabled("next_owner_modify", export_off);
childSetEnabled("next_owner_transfer", export_off);
}
else // Set EveryoneExport false, just in case.
gSavedPerAccountSettings.setBOOL("EveryoneExport", false);
}
childSetAction("help", onClickHelp, this);
childSetAction("ok", onClickOK, this);
childSetAction("cancel", onClickCancel, this);
childSetCommitCallback("next_owner_copy", &onCommitCopy, this);
getChild<LLUICtrl>("next_owner_copy")->setCommitCallback(handle_checkboxes);
getChild<LLUICtrl>("next_owner_modify")->setCommitCallback(handle_checkboxes);
getChild<LLUICtrl>("next_owner_transfer")->setCommitCallback(handle_checkboxes);
getChild<LLUICtrl>("everyone_export")->setCommitCallback(handle_checkboxes);
refresh();
@@ -75,20 +128,6 @@ void LLFloaterPerms::onClickCancel(void* data)
self->close();
}
//static
void LLFloaterPerms::onCommitCopy(LLUICtrl* ctrl, void* data)
{
LLFloaterPerms* self = static_cast<LLFloaterPerms*>(data);
// Implements fair use
BOOL copyable = gSavedSettings.getBOOL("NextOwnerCopy");
if(!copyable)
{
gSavedSettings.setBOOL("NextOwnerTransfer", TRUE);
}
LLCheckBoxCtrl* xfer = self->getChild<LLCheckBoxCtrl>("next_owner_transfer");
xfer->setEnabled(copyable);
}
void LLFloaterPerms::ok()
{
refresh(); // Changes were already applied to saved settings. Refreshing internal values makes it official.
@@ -101,6 +140,7 @@ void LLFloaterPerms::cancel()
gSavedSettings.setBOOL("NextOwnerCopy", mNextOwnerCopy);
gSavedSettings.setBOOL("NextOwnerModify", mNextOwnerModify);
gSavedSettings.setBOOL("NextOwnerTransfer", mNextOwnerTransfer);
gSavedPerAccountSettings.setBOOL("EveryoneExport", everyone_export);
}
void LLFloaterPerms::refresh()
@@ -110,6 +150,7 @@ void LLFloaterPerms::refresh()
mNextOwnerCopy = gSavedSettings.getBOOL("NextOwnerCopy");
mNextOwnerModify = gSavedSettings.getBOOL("NextOwnerModify");
mNextOwnerTransfer = gSavedSettings.getBOOL("NextOwnerTransfer");
everyone_export = gSavedPerAccountSettings.getBOOL("EveryoneExport");
}
void LLFloaterPerms::onClose(bool app_quitting)
@@ -129,7 +170,12 @@ U32 LLFloaterPerms::getGroupPerms(std::string prefix)
//static
U32 LLFloaterPerms::getEveryonePerms(std::string prefix)
{
return gSavedSettings.getBOOL(prefix+"EveryoneCopy") ? PERM_COPY : PERM_NONE;
U32 flags = PERM_NONE;
if (LFSimFeatureHandler::instance().simSupportsExport() && prefix.empty() && gSavedPerAccountSettings.getBOOL("EveryoneExport")) // TODO: Bulk enable export?
flags |= PERM_EXPORT;
if (gSavedSettings.getBOOL(prefix+"EveryoneCopy"))
flags |= PERM_COPY;
return flags;
}
//static

View File

@@ -47,7 +47,6 @@ public:
void cancel();
static void onClickOK(void*);
static void onClickCancel(void*);
static void onCommitCopy(LLUICtrl* ctrl, void* data);
// Convenience methods to get current permission preference bitfields from saved settings:
static U32 getEveryonePerms(std::string prefix=""); // prefix + "EveryoneCopy"
static U32 getGroupPerms(std::string prefix=""); // prefix + "ShareWithGroup"

View File

@@ -60,6 +60,7 @@
#include "lluictrlfactory.h"
#include "lfsimfeaturehandler.h"
#include "hippogridmanager.h"
@@ -67,6 +68,8 @@
#include "rlvhandler.h"
// [/RLVa:KB]
bool can_set_export(const U32& base, const U32& own, const U32& next);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLPropertiesObserver
//
@@ -178,6 +181,9 @@ BOOL LLFloaterProperties::postBuild()
// everyone permissions
getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
getChild<LLUICtrl>("CheckEveryoneMove")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
getChild<LLUICtrl>("CheckExport")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
LFSimFeatureHandler::instance().setSupportsExportCallback(boost::bind(&LLFloaterProperties::refresh, this));
// next owner permissions
getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
@@ -223,11 +229,13 @@ void LLFloaterProperties::refresh()
"CheckOwnerModify",
"CheckOwnerCopy",
"CheckOwnerTransfer",
"CheckOwnerExport",
"CheckGroupCopy",
"CheckGroupMod",
"CheckGroupMove",
"CheckEveryoneCopy",
"CheckEveryoneMove",
"CheckExport",
"CheckNextOwnerModify",
"CheckNextOwnerCopy",
"CheckNextOwnerTransfer",
@@ -411,6 +419,12 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
bool supports_export = LFSimFeatureHandler::instance().simSupportsExport();
getChildView("CheckOwnerExport")->setEnabled(false);
getChild<LLUICtrl>("CheckOwnerExport")->setValue(LLSD((BOOL)(supports_export && owner_mask & PERM_EXPORT)));
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
getChildView("CheckOwnerExport")->setVisible(false);
///////////////////////
// DEBUG PERMISSIONS //
///////////////////////
@@ -433,11 +447,15 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
perm_string = "B: ";
perm_string += mask_to_string(base_mask);
if (!supports_export && base_mask & PERM_EXPORT) // Hide Export when not available
perm_string.erase(perm_string.find_last_of("E"));
getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
getChildView("BaseMaskDebug")->setVisible(TRUE);
perm_string = "O: ";
perm_string += mask_to_string(owner_mask);
if (!supports_export && owner_mask & PERM_EXPORT) // Hide Export when not available
perm_string.erase(perm_string.find_last_of("E"));
getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
getChildView("OwnerMaskDebug")->setVisible(TRUE);
@@ -450,9 +468,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
perm_string = "E";
perm_string += overwrite_everyone ? "*: " : ": ";
perm_string += mask_to_string(everyone_mask);
if (!supports_export && everyone_mask & PERM_EXPORT) // Hide Export when not available
perm_string.erase(perm_string.find_last_of("E"));
getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
getChildView("EveryoneMaskDebug")->setVisible(TRUE);
perm_string = "N";
perm_string += slam_perm ? "*: " : ": ";
perm_string += mask_to_string(next_owner_mask);
@@ -493,6 +513,8 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChild<LLUICtrl>("CheckEveryoneCopy")->setEnabled(FALSE);
getChild<LLUICtrl>("CheckEveryoneMove")->setEnabled(FALSE);
}
getChild<LLUICtrl>("CheckExport")->setEnabled(supports_export && item->getType() != LLAssetType::AT_OBJECT && gAgentID == item->getCreatorUUID()
&& can_set_export(base_mask, owner_mask, next_owner_mask));
// Set values.
BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
@@ -505,6 +527,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChild<LLUICtrl>("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
getChild<LLUICtrl>("CheckEveryoneMove")->setValue(LLSD((BOOL)(everyone_mask & PERM_MOVE)));
getChild<LLUICtrl>("CheckExport")->setValue(LLSD((BOOL)(supports_export && everyone_mask & PERM_EXPORT)));
///////////////
// SALE INFO //
@@ -519,10 +542,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChildView("SaleLabel")->setEnabled(is_complete);
getChildView("CheckPurchase")->setEnabled(is_complete);
getChildView("NextOwnerLabel")->setEnabled(TRUE);
getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions);
getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
bool no_export = !(everyone_mask & PERM_EXPORT); // Next owner perms can't be changed if set
getChildView("NextOwnerLabel")->setEnabled(no_export);
getChildView("CheckNextOwnerModify")->setEnabled(no_export && (base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
getChildView("CheckNextOwnerCopy")->setEnabled(no_export && (base_mask & PERM_COPY) && !cannot_restrict_permissions);
getChildView("CheckNextOwnerTransfer")->setEnabled(no_export && (next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
getChildView("RadioSaleType")->setEnabled(is_complete && is_for_sale);
getChildView("TextPrice")->setEnabled(is_complete && is_for_sale);
@@ -670,7 +694,6 @@ void LLFloaterProperties::onCommitDescription()
}
}
// static
void LLFloaterProperties::onCommitPermissions()
{
//llinfos << "LLFloaterProperties::onCommitPermissions()" << llendl;
@@ -710,6 +733,11 @@ void LLFloaterProperties::onCommitPermissions()
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
CheckEveryoneCopy->get(), PERM_COPY);
}
LLCheckBoxCtrl* CheckExport = getChild<LLCheckBoxCtrl>("CheckExport");
if(CheckExport)
{
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT);
}
LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
if(CheckNextOwnerModify)

View File

@@ -159,6 +159,39 @@ void unpack_request_params(
*/
namespace
{
void on_caps_received(LLTabContainer* tab)
{
if (!tab) return;
const LLViewerRegion* region = gAgent.getRegion();
tab->enableTabButton(tab->getIndexForPanel(tab->getPanelByName("panel_env_info")), region && !region->getCapability("EnvironmentSettings").empty());
}
void handle_opposite(const bool& off, LLUICtrl* opposite)
{
opposite->setEnabled(!off);
if (off) opposite->setValue(false);
}
void on_change_use_other_sun(const LLSD& param, LLUICtrl* opposite, LLUICtrl* slider)
{
handle_opposite(param.asBoolean(), opposite);
slider->setEnabled(false);
}
void on_change_fixed_sun(const LLSD& param, LLUICtrl* opposite, LLUICtrl* slider)
{
bool fixed_sun = param.asBoolean();
handle_opposite(fixed_sun, opposite);
slider->setEnabled(fixed_sun);
}
const float get_sun_hour(const LLUICtrl* sun_hour)
{
return sun_hour->getEnabled() ? sun_hour->getValue().asFloat() : 0.f;
}
}
bool estate_dispatch_initialized = false;
@@ -351,6 +384,15 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
LLTrans::findString(sim_type, sim_type); // try localizing sim product name
}
// Disable Environment Tab when not supported
if (region)
{
if (region->capabilitiesReceived())
on_caps_received(tab);
else
region->setCapabilitiesReceivedCallback(boost::bind(on_caps_received, tab));
}
// GENERAL PANEL
panel = tab->getChild<LLPanel>("General");
panel->getChild<LLUICtrl>("region_text")->setValue(LLSD(sim_name));
@@ -628,6 +670,27 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region)
getChildView("im_btn")->setEnabled(allow_modify);
getChildView("manage_telehub_btn")->setEnabled(allow_modify);
// Support Legacy Region Environment
{
const LLRegionInfoModel& region_info = LLRegionInfoModel::instance();
bool estate_sun = region_info.mUseEstateSun;
getChild<LLUICtrl>("use_estate_sun_check")->setValue(estate_sun);
getChild<LLUICtrl>("fixed_sun_check")->setEnabled(allow_modify && !estate_sun);
getChild<LLUICtrl>("sun_hour_slider")->setEnabled(allow_modify && !estate_sun);
if (estate_sun)
{
getChild<LLUICtrl>("use_estate_sun_check")->setEnabled(allow_modify);
getChild<LLUICtrl>("fixed_sun_check")->setValue(false);
}
else
{
bool fixed_sun = region_info.getUseFixedSun();
getChild<LLUICtrl>("use_estate_sun_check")->setEnabled(allow_modify && !fixed_sun);
getChild<LLUICtrl>("fixed_sun_check")->setValue(fixed_sun);
getChild<LLUICtrl>("sun_hour_slider")->setValue(region_info.mSunHour);
}
}
// Data gets filled in by processRegionInfo
return LLPanelRegionInfo::refreshFromRegion(region);
@@ -646,6 +709,9 @@ BOOL LLPanelRegionGeneralInfo::postBuild()
initCtrl("access_combo");
initCtrl("restrict_pushobject");
initCtrl("block_parcel_search_check");
initCtrl("use_estate_sun_check");
initCtrl("fixed_sun_check");
initCtrl("sun_hour_slider");
initHelpBtn("terraform_help", "HelpRegionBlockTerraform");
initHelpBtn("fly_help", "HelpRegionBlockFly");
@@ -657,12 +723,23 @@ BOOL LLPanelRegionGeneralInfo::postBuild()
initHelpBtn("land_resell_help", "HelpRegionLandResell");
initHelpBtn("parcel_changes_help", "HelpParcelChanges");
initHelpBtn("parcel_search_help", "HelpRegionSearch");
initHelpBtn("use_estate_sun_help", "HelpRegionUseEstateSun");
initHelpBtn("fixed_sun_help", "HelpRegionFixedSun");
childSetAction("kick_btn", boost::bind(&LLPanelRegionGeneralInfo::onClickKick, this));
childSetAction("kick_all_btn", onClickKickAll, this);
childSetAction("im_btn", onClickMessage, this);
childSetAction("manage_telehub_btn", boost::bind(&LLPanelRegionGeneralInfo::onClickManageTelehub, this));
// Set up the Legacy Region Environment checkboxes
{
LLUICtrl* estate_sun = getChild<LLUICtrl>("use_estate_sun_check");
LLUICtrl* fixed_sun = getChild<LLUICtrl>("fixed_sun_check");
LLUICtrl* hour_slider = getChild<LLUICtrl>("sun_hour_slider");
estate_sun->setCommitCallback(boost::bind(on_change_use_other_sun, _2, fixed_sun, hour_slider));
fixed_sun->setCommitCallback(boost::bind(on_change_fixed_sun, _2, estate_sun, hour_slider));
}
return LLPanelRegionInfo::postBuild();
}
@@ -838,6 +915,13 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate()
sendEstateOwnerMessage(gMessageSystem, "setregioninfo", invoice, strings);
}
// Send the Legacy Region Environment
LLRegionInfoModel& region_info = LLRegionInfoModel::instance();
region_info.mUseEstateSun = getChild<LLUICtrl>("use_estate_sun_check")->getValue().asBoolean();
region_info.setUseFixedSun(getChild<LLUICtrl>("fixed_sun_check")->getValue().asBoolean());
region_info.mSunHour = get_sun_hour(getChild<LLUICtrl>("sun_hour_slider"));
region_info.sendRegionTerrain(LLFloaterRegionInfo::getLastInvoice());
// if we changed access levels, tell user about it
LLViewerRegion* region = gAgent.getRegion();
if (region && (getChild<LLUICtrl>("access_combo")->getValue().asInteger() != region->getSimAccess()) )
@@ -2014,11 +2098,16 @@ BOOL LLPanelEstateInfo::postBuild()
{
// set up the callbacks for the generic controls
initCtrl("externally_visible_check");
initCtrl("use_global_time_check");
initCtrl("fixed_sun_check");
initCtrl("sun_hour_slider");
initCtrl("allow_direct_teleport");
initCtrl("limit_payment");
initCtrl("limit_age_verified");
initCtrl("voice_chat_check");
initHelpBtn("estate_manager_help", "HelpEstateEstateManager");
initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime");
initHelpBtn("fixed_sun_help", "HelpEstateFixedSun");
initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible");
initHelpBtn("allow_direct_teleport_help", "HelpEstateAllowDirectTeleport");
initHelpBtn("allow_resident_help", "HelpEstateAllowResident");
@@ -2026,6 +2115,15 @@ BOOL LLPanelEstateInfo::postBuild()
initHelpBtn("ban_resident_help", "HelpEstateBanResident");
initHelpBtn("voice_chat_help", "HelpEstateVoiceChat");
// Set up the Legacy Estate Environment checkboxes
{
LLUICtrl* global_time = getChild<LLUICtrl>("use_global_time_check");
LLUICtrl* fixed_sun = getChild<LLUICtrl>("fixed_sun_check");
LLUICtrl* hour_slider = getChild<LLUICtrl>("sun_hour_slider");
global_time->setCommitCallback(boost::bind(on_change_use_other_sun, _2, fixed_sun, hour_slider));
fixed_sun->setCommitCallback(boost::bind(on_change_fixed_sun, _2, global_time, hour_slider));
}
getChild<LLUICtrl>("allowed_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
LLNameListCtrl *avatar_name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list");
if (avatar_name_list)
@@ -2105,14 +2203,36 @@ void LLPanelEstateInfo::refreshFromEstate()
getChild<LLUICtrl>("limit_payment")->setValue(estate_info.getDenyAnonymous());
getChild<LLUICtrl>("limit_age_verified")->setValue(estate_info.getDenyAgeUnverified());
// Ensure appriopriate state of the management UI
// Ensure appropriate state of the management UI
updateControls(gAgent.getRegion());
// Support Legacy Estate Environment
{
const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
bool global_time = estate_info.getGlobalTime();
getChild<LLUICtrl>("use_global_time_check")->setValue(global_time);
getChild<LLUICtrl>("fixed_sun_check")->setEnabled(!global_time);
getChild<LLUICtrl>("sun_hour_slider")->setEnabled(!global_time);
if (global_time)
{
getChild<LLUICtrl>("use_global_time_check")->setEnabled(true);
getChild<LLUICtrl>("fixed_sun_check")->setValue(false);
}
else
{
bool fixed_sun = estate_info.getUseFixedSun();
getChild<LLUICtrl>("use_global_time_check")->setEnabled(!fixed_sun);
getChild<LLUICtrl>("fixed_sun_check")->setValue(fixed_sun);
F32 sun_hour = estate_info.getSunHour();
if (sun_hour < 6.0f) sun_hour += 24.0f;
getChild<LLUICtrl>("sun_hour_slider")->setValue(sun_hour);
}
}
refresh();
}
BOOL LLPanelEstateInfo::sendUpdate()
{
llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl;
llinfos << "LLPanelEstateInfo::sendUpdate()" << llendl;
LLNotification::Params params("ChangeLindenEstate");
params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2));
@@ -2140,8 +2260,9 @@ bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, con
LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
// update model
estate_info.setUseFixedSun(false); // we don't support fixed sun estates anymore
estate_info.setIsExternallyVisible(getChild<LLUICtrl>("externally_visible_check")->getValue().asBoolean());
estate_info.setUseFixedSun(getChild<LLUICtrl>("fixed_sun_check")->getValue().asBoolean());
estate_info.setSunHour(get_sun_hour(getChild<LLUICtrl>("sun_hour_slider")));
estate_info.setAllowDirectTeleport(getChild<LLUICtrl>("allow_direct_teleport")->getValue().asBoolean());
estate_info.setDenyAnonymous(getChild<LLUICtrl>("limit_payment")->getValue().asBoolean());
estate_info.setDenyAgeUnverified(getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean());

View File

@@ -88,10 +88,6 @@
#include "lltrans.h"
// <edit>
#include "llviewercontrol.h"
// </edit>
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]

View File

@@ -238,25 +238,53 @@ void LLFloaterStats::buildStats()
// Network statistics
LLStatView *net_statviewp = stat_viewp->addStatView("network stat view", "Network", "OpenDebugStatNet", rect);
stat_barp = net_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn");
stat_barp = net_statviewp->addStat("UDP Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn");
stat_barp->setUnitLabel("/sec");
stat_barp = net_statviewp->addStat("Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut");
stat_barp = net_statviewp->addStat("UDP Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut");
stat_barp->setUnitLabel("/sec");
stat_barp = net_statviewp->addStat("Objects", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects");
stat_barp = net_statviewp->addStat("HTTP Textures", &(LLViewerStats::getInstance()->mHTTPTextureKBitStat), "DebugStatModeHTTPTexture");
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
stat_barp->mMaxBar = gSavedSettings.getF32("HTTPThrottleBandwidth");
stat_barp->mMaxBar *= llclamp(2.0 - (stat_barp->mMaxBar - 400.f) / 3600.f, 1.0, 2.0); // Allow for overshoot (allow more for low bandwidth values).
stat_barp->mTickSpacing = 1.f;
while (stat_barp->mTickSpacing < stat_barp->mMaxBar / 8)
stat_barp->mTickSpacing *= 2.f;
stat_barp->mLabelSpacing = 2 * stat_barp->mTickSpacing;
stat_barp->mPerSec = FALSE;
stat_barp->mDisplayMean = FALSE;
stat_barp = net_statviewp->addStat("Texture", &(LLViewerStats::getInstance()->mTextureKBitStat), "DebugStatModeTexture");
stat_barp = net_statviewp->addStat("UDP Textures", &(LLViewerStats::getInstance()->mUDPTextureKBitStat), "DebugStatModeUDPTexture");
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
stat_barp->mMaxBar = 1024.f;
stat_barp->mTickSpacing = 128.f;
stat_barp->mLabelSpacing = 256.f;
stat_barp = net_statviewp->addStat("Asset", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset");
stat_barp = net_statviewp->addStat("Objects (UDP)", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects");
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
stat_barp->mMaxBar = 1024.f;
stat_barp->mTickSpacing = 128.f;
stat_barp->mLabelSpacing = 256.f;
stat_barp = net_statviewp->addStat("Layers", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers");
stat_barp = net_statviewp->addStat("Assets (UDP)", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset");
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
stat_barp->mMaxBar = 1024.f;
stat_barp->mTickSpacing = 128.f;
stat_barp->mLabelSpacing = 256.f;
stat_barp = net_statviewp->addStat("Actual In", &(LLViewerStats::getInstance()->mActualInKBitStat),
stat_barp = net_statviewp->addStat("Layers (UDP)", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers");
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
stat_barp->mMaxBar = 1024.f;
stat_barp->mTickSpacing = 128.f;
stat_barp->mLabelSpacing = 256.f;
stat_barp = net_statviewp->addStat("Actual In (UDP)", &(LLViewerStats::getInstance()->mActualInKBitStat),
"DebugStatModeActualIn", TRUE, FALSE);
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;
@@ -264,7 +292,7 @@ void LLFloaterStats::buildStats()
stat_barp->mTickSpacing = 128.f;
stat_barp->mLabelSpacing = 256.f;
stat_barp = net_statviewp->addStat("Actual Out", &(LLViewerStats::getInstance()->mActualOutKBitStat),
stat_barp = net_statviewp->addStat("Actual Out (UDP)", &(LLViewerStats::getInstance()->mActualOutKBitStat),
"DebugStatModeActualOut", TRUE, FALSE);
stat_barp->setUnitLabel(" kbps");
stat_barp->mMinBar = 0.f;

View File

@@ -2590,3 +2590,32 @@ const bool LLFloaterIMPanel::isModerator(const LLUUID& speaker_id)
return FALSE;
}
BOOL LLFloaterIMPanel::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash )
{
LLView* chat_editor = getChildView("chat_editor");
if (getVisible() && childIsVisible("chat_editor"))
{
gFocusMgr.setKeyboardFocus(chat_editor);
LLUICtrl * ctrl = static_cast<LLUICtrl*>(chat_editor);
ctrl->setFocus(TRUE);
return TRUE;
}
return LLUICtrl::focusFirstItem(prefer_text_fields, focus_flash);
}
void LLFloaterIMPanel::onFocusReceived()
{
LLView* chat_editor = getChildView("chat_editor");
if (getVisible() && childIsVisible("chat_editor"))
{
gFocusMgr.setKeyboardFocus(chat_editor);
LLUICtrl * ctrl = static_cast<LLUICtrl*>(chat_editor);
ctrl->setFocus(TRUE);
}
LLFloater::onFocusReceived();
}

View File

@@ -231,6 +231,9 @@ public:
void *cargo_data, EAcceptance *accept,
std::string& tooltip_msg);
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
void onFocusReceived();
void onInputEditorFocusReceived();
void onInputEditorFocusLost();
void onInputEditorKeystroke(LLLineEditor* caller);

View File

@@ -31,79 +31,26 @@
*/
#include "llviewerprecompiledheaders.h"
#include <utility> // for std::pair<>
#include "llinventorypanel.h"
#include "llpanelobjectinventory.h"
#include "llinventorybridge.h"
#include "message.h"
#include "llagent.h"
#include "llagentwearables.h"
#include "llcallingcard.h"
#include "llcheckboxctrl.h" // for radio buttons
#include "llfoldervieweventlistener.h"
#include "llnotificationsutil.h"
#include "llradiogroup.h"
#include "llspinctrl.h"
#include "lltextbox.h"
#include "llui.h"
#include "llviewercontrol.h"
#include "llfirstuse.h"
#include "llfloateravatarinfo.h"
#include "llfloaterchat.h"
#include "llfloatercustomize.h"
#include "llfloaterinventory.h"
#include "llfloaterproperties.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
#include "llgesturemgr.h"
#include "lliconctrl.h"
#include "llimview.h"
#include "llinventoryfunctions.h"
#include "llinventorybridge.h"
#include "llinventoryclipboard.h"
#include "llinventorymodelbackgroundfetch.h"
#include "lllineeditor.h"
#include "llinventorypanel.h"
#include "llmakeoutfitdialog.h"
#include "llmenugl.h"
#include "llpreviewanim.h"
#include "llpreviewgesture.h"
#include "llpreviewlandmark.h"
#include "llpreviewnotecard.h"
#include "llpreviewscript.h"
#include "llpreviewsound.h"
#include "llpreviewtexture.h"
#include "llresmgr.h"
#include "llscrollcontainer.h"
#include "llimview.h"
#include "lltooldraganddrop.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llnotificationsutil.h"
#include "llpanelmaininventory.h"
#include "llpanelobjectinventory.h"
#include "llpreview.h" // For LLMultiPreview
#include "llfoldervieweventlistener.h"
#include "lltrans.h"
#include "llvoavatarself.h"
#include "llwearable.h"
#include "llwearablelist.h"
#include "llviewermessage.h"
#include "llviewerregion.h"
#include "lltabcontainer.h"
#include "lluictrlfactory.h"
#include "llselectmgr.h"
// <edit>
#include "lllocalinventory.h"
#include "statemachine/aifilepicker.h"
// </edit>
extern LLUUID gAgentID;
using namespace LLOldEvents;
const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
typedef LLMemberListener<LLPanelObjectInventory> object_inventory_listener_t;
typedef LLMemberListener<LLInventoryView> inventory_listener_t;
typedef LLMemberListener<LLInventoryPanel> inventory_panel_listener_t;
@@ -116,42 +63,39 @@ bool doToSelected(LLFolderView* folder, std::string action)
folder->startRenamingSelectedItem();
return true;
}
if ("delete" == action)
else if ("delete" == action)
{
folder->removeSelectedItems();
return true;
}
if ("copy" == action || "cut" == action)
else if ("copy" == action || "cut" == action)
{
LLInventoryClipboard::instance().reset();
}
std::set<LLUUID> selected_items = folder->getSelectionList();
LLMultiPreview* multi_previewp = NULL;
LLMultiProperties* multi_propertiesp = NULL;
LLMultiFloater* multi_floaterp = NULL;
if (("task_open" == action || "open" == action) && selected_items.size() > 1)
{
S32 left, top;
gFloaterView->getNewFloaterPosition(&left, &top);
multi_previewp = new LLMultiPreview(LLRect(left, top, left + 300, top - 100));
gFloaterView->addChild(multi_previewp);
multi_floaterp = new LLMultiPreview(LLRect(left, top, left + 300, top - 100));
gFloaterView->addChild(multi_floaterp);
LLFloater::setFloaterHost(multi_previewp);
LLFloater::setFloaterHost(multi_floaterp);
}
else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1)
{
S32 left, top;
gFloaterView->getNewFloaterPosition(&left, &top);
multi_propertiesp = new LLMultiProperties(LLRect(left, top, left + 100, top - 100));
gFloaterView->addChild(multi_propertiesp);
multi_floaterp = new LLMultiProperties(LLRect(left, top, left + 100, top - 100));
gFloaterView->addChild(multi_floaterp);
LLFloater::setFloaterHost(multi_propertiesp);
LLFloater::setFloaterHost(multi_floaterp);
}
std::set<LLUUID>::iterator set_iter;
@@ -167,13 +111,9 @@ bool doToSelected(LLFolderView* folder, std::string action)
}
LLFloater::setFloaterHost(NULL);
if (multi_previewp)
if (multi_floaterp)
{
multi_previewp->open();
}
else if (multi_propertiesp)
{
multi_propertiesp->open(); /*Flawfinder: ignore*/
multi_floaterp->open();
}
return true;
@@ -183,12 +123,11 @@ class LLDoToSelectedPanel : public object_inventory_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
std::string action = userdata.asString();
LLPanelObjectInventory *panel = mPtr;
LLFolderView* folder = panel->getRootFolder();
if(!folder) return true;
return doToSelected(folder, action);
return doToSelected(folder, userdata.asString());
}
};
@@ -196,12 +135,11 @@ class LLDoToSelectedFloater : public inventory_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
std::string action = userdata.asString();
LLInventoryPanel *panel = mPtr->getPanel();
LLFolderView* folder = panel->getRootFolder();
if(!folder) return true;
return doToSelected(folder, action);
return doToSelected(folder, userdata.asString());
}
};
@@ -209,12 +147,11 @@ class LLDoToSelected : public inventory_panel_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
std::string action = userdata.asString();
LLInventoryPanel *panel = mPtr;
LLFolderView* folder = panel->getRootFolder();
if(!folder) return true;
return doToSelected(folder, action);
return doToSelected(folder, userdata.asString());
}
};
@@ -356,7 +293,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type,
else if ("lsl" == type)
{
LLUUID parent_id = self ? self->getUUID() : model->findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
ptr->createNewItem(NEW_LSL_NAME,
ptr->createNewItem(LLTrans::getString("New Script"),
parent_id,
LLAssetType::AT_LSL_TEXT,
LLInventoryType::IT_LSL,
@@ -365,7 +302,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type,
else if ("notecard" == type)
{
LLUUID parent_id = self ? self->getUUID() : model->findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
ptr->createNewItem(NEW_NOTECARD_NAME,
ptr->createNewItem(LLTrans::getString("New Note"),
parent_id,
LLAssetType::AT_NOTECARD,
LLInventoryType::IT_NOTECARD,
@@ -374,7 +311,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type,
else if ("gesture" == type)
{
LLUUID parent_id = self ? self->getUUID() : model->findCategoryUUIDForType(LLFolderType::FT_GESTURE);
ptr->createNewItem(NEW_GESTURE_NAME,
ptr->createNewItem(LLTrans::getString("New Gesture"),
parent_id,
LLAssetType::AT_GESTURE,
LLInventoryType::IT_GESTURE,
@@ -383,11 +320,11 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type,
else if ("outfit" == type)
{
new LLMakeOutfitDialog(false);
return;
}
else
{
LLWearableType::EType wear_type = LLWearableType::typeNameToType(type);
LLAgentWearables::createWearable(wear_type, false, self ? self->getUUID() : LLUUID::null);
LLAgentWearables::createWearable(LLWearableType::typeNameToType(type), false, self ? self->getUUID() : LLUUID::null);
}
ptr->getRootFolder()->setNeedsAutoRename(TRUE);
}
@@ -411,14 +348,6 @@ class LLDoCreateFloater : public inventory_listener_t
LLInventoryModel* model = mPtr->getPanel()->getModel();
if(!model) return false;
std::string type = userdata.asString();
// <edit>
if(type == "pretend")
{
LLFloaterNewLocalInventory* floater = new LLFloaterNewLocalInventory();
floater->center();
}
else
// </edit>
do_create(model, mPtr->getPanel(), type);
return true;
}
@@ -484,28 +413,6 @@ class LLSetSortBy : public inventory_listener_t
}
};
// <edit>
class LLLoadInvCacheFloater : public inventory_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
LLInventoryModel* model = mPtr->getPanel()->getModel();
if(!model) return false;
AIFilePicker* filepicker = AIFilePicker::create();
filepicker->open(FFLOAD_INVGZ, "", "invgz");
filepicker->run(boost::bind(&LLLoadInvCacheFloater::filepicker_callback, this, filepicker));
return true;
}
void filepicker_callback(AIFilePicker* filepicker)
{
if(filepicker->hasFilename())
{
LLLocalInventory::loadInvCache(filepicker->getFilename());
}
}
};
class LLRefreshInvModel : public inventory_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -522,8 +429,7 @@ class LLSetSearchType : public inventory_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
std::string toggle = userdata.asString();
U32 flags = mPtr->getActivePanel()->getRootFolder()->toggleSearchType(toggle);
U32 flags = mPtr->getActivePanel()->getRootFolder()->toggleSearchType(userdata.asString());
mPtr->getControl("Inventory.SearchName")->setValue((BOOL)(flags & 1));
mPtr->getControl("Inventory.SearchDesc")->setValue((BOOL)(flags & 2));
mPtr->getControl("Inventory.SearchCreator")->setValue((BOOL)(flags & 4));
@@ -546,8 +452,7 @@ class LLBeginIMSession : public inventory_panel_listener_t
LLDynamicArray<LLUUID> members;
EInstantMessage type = IM_SESSION_CONFERENCE_START;
std::set<LLUUID>::const_iterator iter;
for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
for (std::set<LLUUID>::const_iterator iter = selected_items.begin(); iter != selected_items.end(); iter++)
{
LLUUID item = *iter;
@@ -577,11 +482,10 @@ class LLBeginIMSession : public inventory_panel_listener_t
{
// create the session
gIMMgr->setFloaterOpen(TRUE);
S32 i;
LLAvatarTracker& at = LLAvatarTracker::instance();
LLUUID id;
for(i = 0; i < count; ++i)
for(S32 i = 0; i < count; ++i)
{
id = item_array.get(i)->getCreatorUUID();
if(at.isBuddyOnline(id))
@@ -660,27 +564,28 @@ class LLAttachObject : public inventory_panel_listener_t
break;
}
}
if (attachmentp == NULL)
if (!attachmentp)
{
return true;
}
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id);
if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
if (LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id))
{
rez_attachment(item, attachmentp); // don't replace if called from an "Attach To..." menu
}
else if(item && item->isFinished())
{
// must be in library. copy it to our inventory and put it on.
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp, false));
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
LLUUID::null,
std::string(),
cb);
if(gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
{
rez_attachment(item, attachmentp); // don't replace if called from an "Attach To..." menu
}
else if(item->isFinished())
{
// must be in library. copy it to our inventory and put it on.
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp, false));
copy_inventory_item(
gAgentID,
item->getPermissions().getOwner(),
item->getUUID(),
LLUUID::null,
std::string(),
cb);
}
}
gFocusMgr.setKeyboardFocus(NULL);
@@ -688,16 +593,6 @@ class LLAttachObject : public inventory_panel_listener_t
}
};
/*
class LL : public listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
return true;
}
};
*/
void init_object_inventory_panel_actions(LLPanelObjectInventory *panel)
{
(new LLDoToSelectedPanel())->registerListener(panel, "Inventory.DoToSelected");
@@ -709,9 +604,6 @@ void init_inventory_actions(LLInventoryView *floater)
(new LLCloseAllFoldersFloater())->registerListener(floater, "Inventory.CloseAllFolders");
(new LLEmptyTrashFloater())->registerListener(floater, "Inventory.EmptyTrash");
(new LLDoCreateFloater())->registerListener(floater, "Inventory.DoCreate");
// <edit>
(new LLLoadInvCacheFloater())->registerListener(floater, "Inventory.LoadInvCache");
// </edit>
(new LLNewWindow())->registerListener(floater, "Inventory.NewWindow");
(new LLShowFilters())->registerListener(floater, "Inventory.ShowFilters");
@@ -719,7 +611,6 @@ void init_inventory_actions(LLInventoryView *floater)
(new LLSetSortBy())->registerListener(floater, "Inventory.SetSortBy");
(new LLSetSearchType())->registerListener(floater, "Inventory.SetSearchType");
}
void init_inventory_panel_actions(LLInventoryPanel *panel)

Some files were not shown because too many files have changed in this diff Show More