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:
@@ -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)
|
||||
|
||||
@@ -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 << "]");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "llmath.h"
|
||||
|
||||
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
|
||||
|
||||
@@ -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
|
||||
|
||||
81
indra/llmessage/aiaverage.cpp
Normal file
81
indra/llmessage/aiaverage.cpp
Normal 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
108
indra/llmessage/aiaverage.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
356
indra/llmessage/aicurlperservice.cpp
Normal file
356
indra/llmessage/aicurlperservice.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
187
indra/llmessage/aicurlperservice.h
Normal file
187
indra/llmessage/aicurlperservice.h
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -6,7 +6,6 @@ include(LLPlugin)
|
||||
include(Linking)
|
||||
include(PluginAPI)
|
||||
include(LLMessage)
|
||||
include(GooglePerfTools)
|
||||
|
||||
include_directories(
|
||||
${LLPLUGIN_INCLUDE_DIRS}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -66,6 +66,7 @@ protected:
|
||||
BOOL mHideTypingNotification;
|
||||
BOOL mShowGroupNameInChatIM;
|
||||
bool mShowDisplayNameChanges;
|
||||
bool mUseTypingBubbles;
|
||||
BOOL mPlayTypingSound;
|
||||
BOOL mHideNotificationsInChat;
|
||||
BOOL mEnableMUPose;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ protected:
|
||||
BOOL mDetachBridge;
|
||||
BOOL mRevokePermsOnStandUp;
|
||||
BOOL mDisableClickSit;
|
||||
bool mDisableClickSitOtherOwner;
|
||||
BOOL mDisplayScriptJumps;
|
||||
F32 mNumScriptDiff;
|
||||
//Build -------------------------------------------------------------------------------
|
||||
|
||||
75
indra/newview/generichandlers.cpp
Normal file
75
indra/newview/generichandlers.cpp
Normal 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);
|
||||
}
|
||||
|
||||
31
indra/newview/generichandlers.h
Normal file
31
indra/newview/generichandlers.h
Normal 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;
|
||||
@@ -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(¬ifyCallback, _1), ctrl);
|
||||
ctrl->setCommitCallback(boost::bind(¬ifyCallback, _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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
66
indra/newview/lfsimfeaturehandler.cpp
Normal file
66
indra/newview/lfsimfeaturehandler.cpp
Normal 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);
|
||||
}
|
||||
|
||||
70
indra/newview/lfsimfeaturehandler.h
Normal file
70
indra/newview/lfsimfeaturehandler.h
Normal 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
106
indra/newview/linux_tools/install.sh
Normal file
106
indra/newview/linux_tools/install.sh
Normal 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
|
||||
36
indra/newview/linux_tools/refresh_desktop_app_entry.sh
Executable file
36
indra/newview/linux_tools/refresh_desktop_app_entry.sh
Executable 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; };
|
||||
|
||||
1628
indra/newview/llfloaterbvhpreview.cpp
Normal file
1628
indra/newview/llfloaterbvhpreview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
indra/newview/llfloaterbvhpreview.h
Normal file
145
indra/newview/llfloaterbvhpreview.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#define LL_LLFLOATEREXPLOREANIMATIONS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llfloateranimpreview.h"
|
||||
#include "llfloaterbvhpreview.h"
|
||||
#include "llviewerwindow.h" // gViewerWindow
|
||||
|
||||
class LLAnimHistoryItem
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
static LLFloaterExploreSounds* sInstance;
|
||||
|
||||
static void toggle();
|
||||
static BOOL visible();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -88,10 +88,6 @@
|
||||
|
||||
#include "lltrans.h"
|
||||
|
||||
// <edit>
|
||||
#include "llviewercontrol.h"
|
||||
// </edit>
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user