diff options
52 files changed, 804 insertions, 441 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index 039d00cbbf..90bbb1c2c6 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -220,7 +220,6 @@ Ansariel Hiller STORM-2151 MAINT-6917 MAINT-8085 - STORM-2122 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index fda84aa5a8..a00a82aff0 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -323,6 +323,7 @@ const U8 CLICK_ACTION_OPEN = 4; const U8 CLICK_ACTION_PLAY = 5; const U8 CLICK_ACTION_OPEN_MEDIA = 6; const U8 CLICK_ACTION_ZOOM = 7; +const U8 CLICK_ACTION_DISABLED = 8; // DO NOT CHANGE THE SEQUENCE OF THIS LIST!! diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c5ba23f68c..3165ce0743 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -35,6 +35,7 @@ // external library headers #include <boost/bind.hpp> // other Linden headers +#include "lltimer.h" #include "llevents.h" #include "llerror.h" #include "stringize.h" @@ -280,6 +281,22 @@ void LLCoros::setStackSize(S32 stacksize) mStackSize = stacksize; } +void LLCoros::printActiveCoroutines() +{ + LL_INFOS("LLCoros") << "Number of active coroutines: " << (S32)mCoros.size() << LL_ENDL; + LL_INFOS("LLCoros") << "-------------- List of active coroutines ------------"; + CoroMap::iterator iter; + CoroMap::iterator end = mCoros.end(); + F64 time = LLTimer::getTotalSeconds(); + for (iter = mCoros.begin(); iter != end; iter++) + { + F64 life_time = time - iter->second->mCreationTime; + LL_CONT << LL_NEWLINE << "Name: " << iter->first << " life: " << life_time; + } + LL_CONT << LL_ENDL; + LL_INFOS("LLCoros") << "-----------------------------------------------------" << LL_ENDL; +} + #if LL_WINDOWS static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific @@ -375,7 +392,8 @@ LLCoros::CoroData::CoroData(CoroData* prev, const std::string& name, mCoro(boost::bind(toplevel, _1, this, callable), stacksize), // don't consume events unless specifically directed mConsuming(false), - mSelf(0) + mSelf(0), + mCreationTime(LLTimer::getTotalSeconds()) { } @@ -384,7 +402,13 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl std::string name(generateDistinctName(prefix)); Current current; // pass the current value of Current as previous context - CoroData* newCoro = new CoroData(current, name, callable, mStackSize); + CoroData* newCoro = new(std::nothrow) CoroData(current, name, callable, mStackSize); + if (newCoro == NULL) + { + // Out of memory? + printActiveCoroutines(); + LL_ERRS("LLCoros") << "Failed to start coroutine: " << name << " Stacksize: " << mStackSize << " Total coroutines: " << mCoros.size() << LL_ENDL; + } // Store it in our pointer map mCoros.insert(name, newCoro); // also set it as current diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 884d6b159c..8fb27af6a4 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -151,6 +151,9 @@ public: /// for delayed initialization void setStackSize(S32 stacksize); + /// for delayed initialization + void printActiveCoroutines(); + /// get the current coro::self& for those who really really care static coro::self& get_self(); @@ -223,6 +226,7 @@ private: // function signature down to that point -- and of course through every // other caller of every such function. LLCoros::coro::self* mSelf; + F64 mCreationTime; // since epoch }; typedef boost::ptr_map<std::string, CoroData> CoroMap; CoroMap mCoros; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index f31a054139..29de79dc64 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -249,23 +249,13 @@ namespace LLError { #ifdef __GNUC__ // GCC: type_info::name() returns a mangled class name,st demangle - - static size_t abi_name_len = 100; - static char* abi_name_buf = (char*)malloc(abi_name_len); - // warning: above is voodoo inferred from the GCC manual, - // do NOT change - - int status; - // We don't use status, and shouldn't have to pass apointer to it - // but gcc 3.3 libstc++'s implementation of demangling is broken - // and fails without. - - char* name = abi::__cxa_demangle(mangled, - abi_name_buf, &abi_name_len, &status); - // this call can realloc the abi_name_buf pointer (!) - - return name ? name : mangled; - + // passing nullptr, 0 forces allocation of a unique buffer we can free + // fixing MAINT-8724 on OSX 10.14 + int status = -1; + char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); + std::string result(name ? name : mangled); + free(name); + return result; #elif LL_WINDOWS // DevStudio: type_info::name() includes the text "class " at the start diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 49d865cbfa..0b72b53186 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -95,10 +95,12 @@ HttpService::~HttpService() if (! mThread->timedJoin(250)) { // Failed to join, expect problems ahead so do a hard termination. - mThread->cancel(); + LL_WARNS(LOG_CORE) << "Destroying HttpService with running thread. Expect problems." << LL_NEWLINE + << "State: " << S32(sState) + << " Last policy: " << U32(mLastPolicy) + << LL_ENDL; - LL_WARNS(LOG_CORE) << "Destroying HttpService with running thread. Expect problems." - << LL_ENDL; + mThread->cancel(); } } } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index e3e605d040..1312f6afda 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -192,7 +192,13 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) ret = (U8*) ll_aligned_malloc<64>(size); if (!ret) { - LL_ERRS() << "Failed to allocate for LLVBOPool buffer" << LL_ENDL; + LL_ERRS() << "Failed to allocate "<< size << " bytes for LLVBOPool buffer " << name <<"." << LL_NEWLINE + << "Free list size: " << mFreeList.size() // this happens if we are out of memory so a solution might be to clear some from freelist + << " Allocated Bytes: " << LLVertexBuffer::sAllocatedBytes + << " Allocated Index Bytes: " << LLVertexBuffer::sAllocatedIndexBytes + << " Pooled Bytes: " << sBytesPooled + << " Pooled Index Bytes: " << sIndexBytesPooled + << LL_ENDL; } } } diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 212e27477b..ed65b1e45f 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2784,7 +2784,6 @@ void LLScrollListCtrl::onClickColumn(void *userdata) } // if this column is the primary sort key, reverse the direction - sort_column_t cur_sort_column; if (!parent->mSortColumns.empty() && parent->mSortColumns.back().first == column_index) { ascending = !parent->mSortColumns.back().second; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b7a860aae0..367d4577ca 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2055,7 +2055,12 @@ if (DARWIN) # These all get set with PROPERTIES set(product "Second Life") # this is the setting for the Python wrapper, see SL-322 and WRAPPER line in Info-SecondLife.plist - set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher") + if (PACKAGE) + set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher") + else (PACKAGE) + # force the name of the actual executable to allow running it within Xcode for debugging + set(MACOSX_WRAPPER_EXECUTABLE_NAME "../Resources/Second Life Viewer.app/Contents/MacOS/Second Life") + endif (PACKAGE) set(MACOSX_BUNDLE_INFO_STRING "Second Life Viewer") set(MACOSX_BUNDLE_ICON_FILE "secondlife.icns") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.secondlife.indra.viewer") diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f0782e0bf7..a01435626f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3703,13 +3703,13 @@ <key>FeatureManagerHTTPTable</key> <map> <key>Comment</key> - <string>Base directory for HTTP feature/gpu table fetches</string> + <string>Deprecated</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> <string>String</string> <key>Value</key> - <string>http://viewer-settings.secondlife.com</string> + <string></string> </map> <key>FPSLogFrequency</key> <map> diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 5b9f1b9d4f..92a3026096 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -76,6 +76,8 @@ const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f; const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f; const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f; +const F32 MAX_CAMERA_DISTANCE_FROM_OBJECT = 496.f; +const F32 CAMERA_FUDGE_FROM_OBJECT = 16.f; const F32 MAX_CAMERA_SMOOTH_DISTANCE = 50.0f; @@ -738,10 +740,7 @@ F32 LLAgentCamera::getCameraZoomFraction() else { F32 min_zoom; - const F32 DIST_FUDGE = 16.f; // meters - F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE, - LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE, - MAX_CAMERA_DISTANCE_FROM_AGENT); + F32 max_zoom = getCameraMaxZoomDistance(); F32 distance = (F32)mCameraFocusOffsetTarget.magVec(); if (mFocusObject.notNull()) @@ -787,23 +786,17 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) else { F32 min_zoom = LAND_MIN_ZOOM; - const F32 DIST_FUDGE = 16.f; // meters - F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE, - LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE, - MAX_CAMERA_DISTANCE_FROM_AGENT); + F32 max_zoom = getCameraMaxZoomDistance(); if (mFocusObject.notNull()) { - if (mFocusObject.notNull()) + if (mFocusObject->isAvatar()) { - if (mFocusObject->isAvatar()) - { - min_zoom = AVATAR_MIN_ZOOM; - } - else - { - min_zoom = OBJECT_MIN_ZOOM; - } + min_zoom = AVATAR_MIN_ZOOM; + } + else + { + min_zoom = OBJECT_MIN_ZOOM; } } @@ -909,10 +902,7 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) new_distance = llmax(new_distance, min_zoom); - // Don't zoom too far back - const F32 DIST_FUDGE = 16.f; // meters - F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, - LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE ); + F32 max_distance = getCameraMaxZoomDistance(); max_distance = llmin(max_distance, current_distance * 4.f); //Scaled max relative to current distance. MAINT-3154 @@ -978,10 +968,7 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters) new_distance = llmax(new_distance, min_zoom); - // Don't zoom too far back - const F32 DIST_FUDGE = 16.f; // meters - F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, - LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE ); + F32 max_distance = getCameraMaxZoomDistance(); if (new_distance > max_distance) { @@ -1946,6 +1933,13 @@ LLVector3 LLAgentCamera::getCameraOffsetInitial() return convert_from_llsd<LLVector3>(mCameraOffsetInitial[mCameraPreset]->get(), TYPE_VEC3, ""); } +F32 LLAgentCamera::getCameraMaxZoomDistance() +{ + // Ignore "DisableCameraConstraints", we don't want to be out of draw range when we focus onto objects or avatars + return llmin(MAX_CAMERA_DISTANCE_FROM_OBJECT, + mDrawDistance - 1, // convenience, don't hit draw limit when focusing on something + LLWorld::getInstance()->getRegionWidthInMeters() - CAMERA_FUDGE_FROM_OBJECT); +} //----------------------------------------------------------------------------- // handleScrollWheel() diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index ab793ff316..d087de1e2f 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -112,6 +112,8 @@ public: private: /** Determines default camera offset depending on the current camera preset */ LLVector3 getCameraOffsetInitial(); + /** Determines maximum camera distance from target for mouselook, opposite to LAND_MIN_ZOOM */ + F32 getCameraMaxZoomDistance(); /** Camera preset in Third Person Mode */ ECameraPreset mCameraPreset; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f705084bdb..acec68f393 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -42,6 +42,7 @@ #include "llagentlanguage.h" #include "llagentui.h" #include "llagentwearables.h" +#include "lldirpicker.h" #include "llfloaterimcontainer.h" #include "llimprocessing.h" #include "llwindow.h" @@ -1082,6 +1083,8 @@ bool LLAppViewer::init() } } +// don't nag developers who need to run the executable directly +#if LL_RELEASE_FOR_DOWNLOAD // MAINT-8305: If we're processing a SLURL, skip the launcher check. if (gSavedSettings.getString("CmdLineLoginLocation").empty()) { @@ -1098,6 +1101,7 @@ bool LLAppViewer::init() LLNotificationsUtil::add("RunLauncher"); } } +#endif #if LL_WINDOWS if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) @@ -1794,6 +1798,8 @@ bool LLAppViewer::cleanup() // (Deleted observers should have already removed themselves) gInventory.cleanupInventory(); + LLCoros::getInstance()->printActiveCoroutines(); + LL_INFOS() << "Cleaning up Selections" << LL_ENDL; // Clean up selection managers after UI is destroyed, as UI may be observing them. @@ -1980,6 +1986,7 @@ bool LLAppViewer::cleanup() mAppCoreHttp.cleanup(); SUBSYSTEM_CLEANUP(LLFilePickerThread); + SUBSYSTEM_CLEANUP(LLDirPickerThread); //MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl) delete sTextureCache; @@ -2150,6 +2157,7 @@ bool LLAppViewer::initThreads() gMeshRepo.init(); LLFilePickerThread::initClass(); + LLDirPickerThread::initClass(); // *FIX: no error handling here! return true; @@ -4584,7 +4592,7 @@ void LLAppViewer::idle() LLSmoothInterpolation::updateInterpolants(); LLMortician::updateClass(); LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() - + LLDirPickerThread::clearDead(); F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); // Cap out-of-control frame times diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 97a71a8802..1099d4bc09 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -528,10 +528,24 @@ public: registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mPopupMenuHandleAvatar = menu->getHandle(); + if (menu) + { + mPopupMenuHandleAvatar = menu->getHandle(); + } + else + { + LL_WARNS() << " Failed to create menu_avatar_icon.xml" << LL_ENDL; + } menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mPopupMenuHandleObject = menu->getHandle(); + if (menu) + { + mPopupMenuHandleObject = menu->getHandle(); + } + else + { + LL_WARNS() << " Failed to create menu_object_icon.xml" << LL_ENDL; + } setDoubleClickCallback(boost::bind(&LLChatHistoryHeader::showInspector, this)); @@ -619,7 +633,12 @@ public: } mUserNameFont = style_params.font(); - LLTextBox* user_name = getChild<LLTextBox>("user_name"); + if (!mUserNameTextBox) + { + mUserNameTextBox = getChild<LLTextBox>("user_name"); + mTimeBoxTextBox = getChild<LLTextBox>("time_box"); + } + LLTextBox* user_name = mUserNameTextBox; user_name->setReadOnlyColor(style_params.readonly_color()); user_name->setColor(style_params.color()); diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 5c4f0f4d5d..5443afe60c 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -77,6 +77,14 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { + bi.hwndOwner = NULL; + bi.pidlRoot = NULL; + bi.pszDisplayName = NULL; + bi.lpszTitle = NULL; + bi.ulFlags = BIF_USENEWUI; + bi.lpfn = NULL; + bi.lParam = NULL; + bi.iImage = 0; } LLDirPicker::~LLDirPicker() @@ -84,7 +92,7 @@ LLDirPicker::~LLDirPicker() // nothing } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { if( mLocked ) { @@ -99,39 +107,39 @@ BOOL LLDirPicker::getDir(std::string* filename) BOOL success = FALSE; - // Modal, so pause agent - send_agent_pause(); - - BROWSEINFO bi; - memset(&bi, 0, sizeof(bi)); - - bi.ulFlags = BIF_USENEWUI; - bi.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - bi.lpszTitle = NULL; - - ::OleInitialize(NULL); + + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } - LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi); + bi.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - if(pIDL != NULL) - { - WCHAR buffer[_MAX_PATH] = {'\0'}; + ::OleInitialize(NULL); + LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi); - if(::SHGetPathFromIDList(pIDL, buffer) != 0) - { - // Set the string value. + if(pIDL != NULL) + { + WCHAR buffer[_MAX_PATH] = {'\0'}; - mDir = utf16str_to_utf8str(llutf16string(buffer)); - success = TRUE; - } + if(::SHGetPathFromIDList(pIDL, buffer) != 0) + { + // Set the string value. - // free the item id list - CoTaskMemFree(pIDL); - } + mDir = utf16str_to_utf8str(llutf16string(buffer)); + success = TRUE; + } + // free the item id list + CoTaskMemFree(pIDL); + } - ::OleUninitialize(); + ::OleUninitialize(); - send_agent_resume(); + if (blocking) + { + send_agent_resume(); + } // Account for the fact that the app has been stalled. LLFrameTimer::updateFrameTime(); @@ -167,7 +175,7 @@ void LLDirPicker::reset() //static -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { LLFilePicker::ELoadFilter filter=LLFilePicker::FFLOAD_DIRECTORY; @@ -201,7 +209,7 @@ void LLDirPicker::reset() mFilePicker->reset(); } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { reset(); @@ -256,7 +264,7 @@ void LLDirPicker::reset() { } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { return FALSE; } @@ -267,3 +275,94 @@ std::string LLDirPicker::getDirName() } #endif + + +LLMutex* LLDirPickerThread::sMutex = NULL; +std::queue<LLDirPickerThread*> LLDirPickerThread::sDeadQ; + +void LLDirPickerThread::getFile() +{ +#if LL_WINDOWS + start(); +#else + run(); +#endif +} + +//virtual +void LLDirPickerThread::run() +{ +#if LL_WINDOWS + bool blocking = false; +#else + bool blocking = true; // modal +#endif + + LLDirPicker picker; + + if (picker.getDir(&mProposedName, blocking)) + { + mResponses.push_back(picker.getDirName()); + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } + +} + +//static +void LLDirPickerThread::initClass() +{ + sMutex = new LLMutex(NULL); +} + +//static +void LLDirPickerThread::cleanupClass() +{ + clearDead(); + + delete sMutex; + sMutex = NULL; +} + +//static +void LLDirPickerThread::clearDead() +{ + if (!sDeadQ.empty()) + { + LLMutexLock lock(sMutex); + while (!sDeadQ.empty()) + { + LLDirPickerThread* thread = sDeadQ.front(); + thread->notify(thread->mResponses); + delete thread; + sDeadQ.pop(); + } + } +} + +LLDirPickerThread::LLDirPickerThread(const dir_picked_signal_t::slot_type& cb, const std::string &proposed_name) + : LLThread("dir picker"), + mFilePickedSignal(NULL) +{ + mFilePickedSignal = new dir_picked_signal_t(); + mFilePickedSignal->connect(cb); +} + +LLDirPickerThread::~LLDirPickerThread() +{ + delete mFilePickedSignal; +} + +void LLDirPickerThread::notify(const std::vector<std::string>& filenames) +{ + if (!filenames.empty()) + { + if (mFilePickedSignal) + { + (*mFilePickedSignal)(filenames, mProposedName); + } + } +} diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 8656b23afd..c7dba12130 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -33,6 +33,13 @@ #include "stdtypes.h" +#include "llthread.h" +#include <queue> + +#if LL_WINDOWS +#include <shlobj.h> +#endif + #if LL_DARWIN // AssertMacros.h does bad things. @@ -53,7 +60,7 @@ public: // calling this before main() is undefined static LLDirPicker& instance( void ) { return sInstance; } - BOOL getDir(std::string* filename); + BOOL getDir(std::string* filename, bool blocking = true); std::string getDirName(); // clear any lists of buffers or whatever, and make sure the dir @@ -76,11 +83,15 @@ private: LLFilePicker *mFilePicker; #endif + std::string* mFileName; std::string mDir; bool mLocked; static LLDirPicker sInstance; +#if LL_WINDOWS + BROWSEINFO bi; +#endif public: // don't call these directly please. @@ -88,4 +99,33 @@ public: ~LLDirPicker(); }; +class LLDirPickerThread : public LLThread +{ +public: + + static std::queue<LLDirPickerThread*> sDeadQ; + static LLMutex* sMutex; + + static void initClass(); + static void cleanupClass(); + static void clearDead(); + + std::vector<std::string> mResponses; + std::string mProposedName; + + typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, std::string proposed_name)> dir_picked_signal_t; + + LLDirPickerThread(const dir_picked_signal_t::slot_type& cb, const std::string &proposed_name); + ~LLDirPickerThread(); + + void getFile(); + + virtual void run(); + + virtual void notify(const std::vector<std::string>& filenames); + +private: + dir_picked_signal_t* mFilePickedSignal; +}; + #endif diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index b0d48abb14..0873300cd2 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -328,6 +328,9 @@ void LLDrawPoolAlpha::render(S32 pass) gGL.diffuseColor4f(0, 0, 1, 1); pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + gGL.diffuseColor4f(0, 1, 0, 1); + pushBatches(LLRenderPass::PASS_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + if(shaders) { gHighlightProgram.unbind(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index bc96ee00f7..487496df9a 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -62,13 +62,10 @@ #if LL_DARWIN const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt"; #elif LL_LINUX const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt"; #else const char FEATURE_TABLE_FILENAME[] = "featuretable.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable.%s.txt"; #endif #if 0 // consuming code in #if 0 below @@ -273,33 +270,11 @@ bool LLFeatureManager::loadFeatureTables() app_path += gDirUtilp->getDirDelimiter(); std::string filename; - std::string http_filename; filename = FEATURE_TABLE_FILENAME; - http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); app_path += filename; - // second table is downloaded with HTTP - note that this will only be used on the run _after_ it is downloaded - std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); - - // use HTTP table if it exists - std::string path; - bool parse_ok = false; - if (gDirUtilp->fileExists(http_path)) - { - parse_ok = parseFeatureTable(http_path); - if (!parse_ok) - { - // the HTTP table failed to parse, so delete it - LLFile::remove(http_path); - LL_WARNS("RenderInit") << "Removed invalid feature table '" << http_path << "'" << LL_ENDL; - } - } - - if (!parse_ok) - { - parse_ok = parseFeatureTable(app_path); - } + bool parse_ok = parseFeatureTable(app_path); return parse_ok; } @@ -407,7 +382,16 @@ bool LLFeatureManager::loadGPUClass() if (!gSavedSettings.getBOOL("SkipBenchmark")) { //get memory bandwidth from benchmark - F32 gbps = gpu_benchmark(); + F32 gbps; + try + { + gbps = gpu_benchmark(); + } + catch (const std::exception& e) + { + gbps = -1.f; + LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL; + } if (gbps < 0.f) { //couldn't bench, use GLVersion @@ -486,70 +470,6 @@ bool LLFeatureManager::loadGPUClass() return true; // indicates that a gpu value was established } -void LLFeatureManager::fetchFeatureTableCoro(std::string tableName) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FeatureManagerHTTPTable", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); - - -#if LL_WINDOWS - std::string os_string = LLOSInfo::instance().getOSStringSimple(); - std::string filename; - - if (os_string.find("Microsoft Windows XP") == 0) - { - filename = llformat(tableName.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); - } - else - { - filename = llformat(tableName.c_str(), "", LLVersionInfo::getVersion().c_str()); - } -#else - const std::string filename = llformat(tableName.c_str(), LLVersionInfo::getVersion().c_str()); -#endif - - std::string url = base + "/" + filename; - // testing url below - //url = "http://viewer-settings.secondlife.com/featuretable.2.1.1.208406.txt"; - const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - - - LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL; - - LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (status) - { // There was a newer feature table on the server. We've grabbed it and now should write it. - // write to file - const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); - - LL_INFOS() << "writing feature table to " << path << LL_ENDL; - - S32 size = raw.size(); - if (size > 0) - { - // write to file - LLAPRFile out(path, LL_APR_WB); - out.write(raw.data(), size); - out.close(); - } - } -} - -// fetch table(s) from a website (S3) -void LLFeatureManager::fetchHTTPTables() -{ - LLCoros::instance().launch("LLFeatureManager::fetchFeatureTableCoro", - boost::bind(&LLFeatureManager::fetchFeatureTableCoro, this, FEATURE_TABLE_VER_FILENAME)); -} - void LLFeatureManager::cleanupFeatureTables() { std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 54bd07329a..f77861a1a7 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -145,9 +145,6 @@ public: // in the skip list if true void applyFeatures(bool skipFeatures); - // load the dynamic GPU/feature table from a website - void fetchHTTPTables(); - LLSD getRecommendedSettingsMap(); protected: @@ -158,8 +155,6 @@ protected: void initBaseMask(); - void fetchFeatureTableCoro(std::string name); - std::map<std::string, LLFeatureList *> mMaskList; std::set<std::string> mSkippedFeatures; BOOL mInited; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9d723bdd9d..4ce35643b1 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1096,16 +1096,15 @@ void LLFloaterPreference::onClickSetCache() std::string proposed_name(cur_name); - LLDirPicker& picker = LLDirPicker::instance(); - if (! picker.getDir(&proposed_name ) ) - { - return; //Canceled! - } + (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeCachePath, this, _1, _2), proposed_name))->getFile(); +} - std::string dir_name = picker.getDirName(); - if (!dir_name.empty() && dir_name != cur_name) +void LLFloaterPreference::changeCachePath(const std::vector<std::string>& filenames, std::string proposed_name) +{ + std::string dir_name = filenames[0]; + if (!dir_name.empty() && dir_name != proposed_name) { - std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); + std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); LLNotificationsUtil::add("CacheWillBeMoved"); gSavedSettings.setString("NewCacheLocation", dir_name); gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); @@ -1744,25 +1743,21 @@ void LLFloaterPreference::onClickLogPath() std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); mPriorInstantMessageLogPath.clear(); - LLDirPicker& picker = LLDirPicker::instance(); - //Launches a directory picker and waits for feedback - if (!picker.getDir(&proposed_name ) ) - { - return; //Canceled! - } - //Gets the path from the directory picker - std::string dir_name = picker.getDirName(); + (new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeLogPath, this, _1, _2), proposed_name))->getFile(); +} +void LLFloaterPreference::changeLogPath(const std::vector<std::string>& filenames, std::string proposed_name) +{ //Path changed - if(proposed_name != dir_name) + if (proposed_name != filenames[0]) { - gSavedPerAccountSettings.setString("InstantMessageLogPath", dir_name); + gSavedPerAccountSettings.setString("InstantMessageLogPath", filenames[0]); mPriorInstantMessageLogPath = proposed_name; - - // enable/disable 'Delete transcripts button - updateDeleteTranscriptsButton(); -} + + // enable/disable 'Delete transcripts button + updateDeleteTranscriptsButton(); + } } bool LLFloaterPreference::moveTranscriptsAndLog() diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 0cd7bac20f..8339a18296 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -133,6 +133,7 @@ public: void setCacheLocation(const LLStringExplicit& location); void onClickSetCache(); + void changeCachePath(const std::vector<std::string>& filenames, std::string proposed_name); void onClickResetCache(); void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); void onSelectSkin(); @@ -145,6 +146,7 @@ public: void resetAllIgnored(); void setAllIgnored(); void onClickLogPath(); + void changeLogPath(const std::vector<std::string>& filenames, std::string proposed_name); bool moveTranscriptsAndLog(); void enableHistory(); void setPersonalInfo(const std::string& visibility, bool im_via_email, bool is_verified_email); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 156b2ba7b1..c08aaf3f50 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1309,17 +1309,15 @@ void LLFloaterSnapshot::saveTexture() previewp->saveTexture(); } -BOOL LLFloaterSnapshot::saveLocal() +void LLFloaterSnapshot::saveLocal(const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) { LL_DEBUGS() << "saveLocal" << LL_ENDL; LLSnapshotLivePreview* previewp = getPreviewView(); - if (!previewp) + llassert(previewp != NULL); + if (previewp) { - llassert(previewp != NULL); - return FALSE; + previewp->saveLocal(success_cb, failure_cb); } - - return previewp->saveLocal(); } void LLFloaterSnapshotBase::postSave() diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 698273ac90..bcba14d63d 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -156,7 +156,9 @@ public: static LLFloaterSnapshot* getInstance(); static LLFloaterSnapshot* findInstance(); /*virtual*/ void saveTexture(); - BOOL saveLocal(); + + typedef boost::signals2::signal<void(void)> snapshot_saved_signal_t; + void saveLocal(const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb); static void setAgentEmail(const std::string& email); BOOL isWaitingState(); diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 4b0b10dd5a..a9b15fc8b6 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -966,15 +966,6 @@ private: //----------------------------------------------------------------------------- F32 gpu_benchmark() { -#if LL_WINDOWS - if (gGLManager.mIsIntel - && std::string::npos != LLOSInfo::instance().getOSStringSimple().find("Microsoft Windows 8")) // or 8.1 - { // don't run benchmark on Windows 8/8.1 based PCs with Intel GPU (MAINT-8197) - LL_WARNS() << "Skipping gpu_benchmark() for Intel graphics on Windows 8." << LL_ENDL; - return -1.f; - } -#endif - if (!gGLManager.mHasShaderObjects || !gGLManager.mHasTimerQuery) { // don't bother benchmarking the fixed function // or venerable drivers which don't support accurate timing anyway diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index dc3b153da2..a90a29a731 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1166,72 +1166,72 @@ void LLOutfitGallery::refreshTextures(const LLUUID& category_id) void LLOutfitGallery::uploadPhoto(LLUUID outfit_id) { - outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id); - if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull()) - { - return; - } + outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id); + if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull()) + { + return; + } + (new LLFilePickerReplyThread(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false))->getFile(); +} - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE)) +void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id) +{ + std::string filename = filenames[0]; + LLLocalBitmap* unit = new LLLocalBitmap(filename); + if (unit->getValid()) { - std::string filename = picker.getFirstFile(); - LLLocalBitmap* unit = new LLLocalBitmap(filename); - if (unit->getValid()) + std::string exten = gDirUtilp->getExtension(filename); + U32 codec = LLImageBase::getCodecFromExtension(exten); + + LLImageDimensionsInfo image_info; + std::string image_load_error; + if (!image_info.load(filename, codec)) { - std::string exten = gDirUtilp->getExtension(filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); + image_load_error = image_info.getLastError(); + } - LLImageDimensionsInfo image_info; - std::string image_load_error; - if (!image_info.load(filename, codec)) - { - image_load_error = image_info.getLastError(); - } + S32 max_width = MAX_OUTFIT_PHOTO_WIDTH; + S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT; - S32 max_width = MAX_OUTFIT_PHOTO_WIDTH; - S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT; + if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) + { + LLStringUtil::format_map_t args; + args["WIDTH"] = llformat("%d", max_width); + args["HEIGHT"] = llformat("%d", max_height); - if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) - { - LLStringUtil::format_map_t args; - args["WIDTH"] = llformat("%d", max_width); - args["HEIGHT"] = llformat("%d", max_height); + image_load_error = LLTrans::getString("outfit_photo_load_dimensions_error", args); + } - image_load_error = LLTrans::getString("outfit_photo_load_dimensions_error", args); - } + if (!image_load_error.empty()) + { + LLSD subst; + subst["REASON"] = image_load_error; + LLNotificationsUtil::add("OutfitPhotoLoadError", subst); + return; + } - if (!image_load_error.empty()) - { - LLSD subst; - subst["REASON"] = image_load_error; - LLNotificationsUtil::add("OutfitPhotoLoadError", subst); - return; - } + S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass). + void *nruserdata = NULL; + nruserdata = (void *)&outfit_id; - S32 expected_upload_cost = LLGlobalEconomy::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass). - void *nruserdata = NULL; - nruserdata = (void *)&outfit_id; - - LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(outfit_id); - if (!outfit_cat) return; - updateSnapshotFolderObserver(); - checkRemovePhoto(outfit_id); - std::string upload_pending_name = outfit_id.asString(); - std::string upload_pending_desc = ""; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - LLUUID photo_id = upload_new_resource(filename, // file - upload_pending_name, - upload_pending_desc, - 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - upload_pending_name, callback, expected_upload_cost, nruserdata); - mOutfitLinkPending = outfit_id; - } - delete unit; - } + LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(outfit_id); + if (!outfit_cat) return; + updateSnapshotFolderObserver(); + checkRemovePhoto(outfit_id); + std::string upload_pending_name = outfit_id.asString(); + std::string upload_pending_desc = ""; + LLAssetStorage::LLStoreAssetCallback callback = NULL; + LLUUID photo_id = upload_new_resource(filename, // file + upload_pending_name, + upload_pending_desc, + 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + upload_pending_name, callback, expected_upload_cost, nruserdata); + mOutfitLinkPending = outfit_id; + } + delete unit; } void LLOutfitGallery::linkPhotoToOutfit(LLUUID photo_id, LLUUID outfit_id) diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 383924a7d6..6dd8a6298f 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -130,6 +130,7 @@ protected: private: void loadPhotos(); void uploadPhoto(LLUUID outfit_id); + void uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id); void updateSnapshotFolderObserver(); LLUUID getPhotoAssetId(const LLUUID& outfit_id); LLUUID getDefaultPhoto(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index ef5ce155b1..142dea83e2 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -204,6 +204,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("forgot_password_text")); + sendChildToBack(getChildView("sign_up_text")); LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); updateLocationSelectorsVisibility(); // separate so that it can be called from preferences @@ -271,6 +272,9 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text"); forgot_password_text->setClickedCallback(onClickForgotPassword, NULL); + LLTextBox* sign_up_text = getChild<LLTextBox>("sign_up_text"); + sign_up_text->setClickedCallback(onClickSignUp, NULL); + // get the web browser control LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); web_browser->addObserver(this); @@ -921,6 +925,15 @@ void LLPanelLogin::onClickForgotPassword(void*) } } +//static +void LLPanelLogin::onClickSignUp(void*) +{ + if (sInstance) + { + LLWeb::loadURLExternal(sInstance->getString("sign_up_url")); + } +} + // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 852195b304..c633582d89 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -99,6 +99,7 @@ private: static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); + static void onClickSignUp(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index a7c53a7050..fc44ce340c 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -100,6 +100,10 @@ U8 string_value_to_click_action(std::string p_value) { return CLICK_ACTION_ZOOM; } + if (p_value == "None") + { + return CLICK_ACTION_DISABLED; + } return CLICK_ACTION_TOUCH; } @@ -126,6 +130,9 @@ std::string click_action_to_string_value( U8 action) case CLICK_ACTION_ZOOM: return "Zoom"; break; + case CLICK_ACTION_DISABLED: + return "None"; + break; } } diff --git a/indra/newview/llpanelsnapshotlocal.cpp b/indra/newview/llpanelsnapshotlocal.cpp index 77378f8092..e7fced92a7 100644 --- a/indra/newview/llpanelsnapshotlocal.cpp +++ b/indra/newview/llpanelsnapshotlocal.cpp @@ -65,6 +65,9 @@ private: void onFormatComboCommit(LLUICtrl* ctrl); void onQualitySliderCommit(LLUICtrl* ctrl); void onSaveFlyoutCommit(LLUICtrl* ctrl); + + void onLocalSaved(); + void onLocalCanceled(); }; static LLPanelInjector<LLPanelSnapshotLocal> panel_class("llpanelsnapshotlocal"); @@ -164,19 +167,22 @@ void LLPanelSnapshotLocal::onSaveFlyoutCommit(LLUICtrl* ctrl) LLFloaterSnapshot* floater = LLFloaterSnapshot::getInstance(); floater->notify(LLSD().with("set-working", true)); - BOOL saved = floater->saveLocal(); - if (saved) - { - mSnapshotFloater->postSave(); - floater->notify(LLSD().with("set-finished", LLSD().with("ok", true).with("msg", "local"))); - } - else - { - cancel(); - floater->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "local"))); - } + floater->saveLocal((boost::bind(&LLPanelSnapshotLocal::onLocalSaved, this)), (boost::bind(&LLPanelSnapshotLocal::onLocalCanceled, this))); +} + +void LLPanelSnapshotLocal::onLocalSaved() +{ + mSnapshotFloater->postSave(); + LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", true).with("msg", "local"))); +} + +void LLPanelSnapshotLocal::onLocalCanceled() +{ + cancel(); + LLFloaterSnapshot::getInstance()->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "local"))); } + LLSnapshotModel::ESnapshotType LLPanelSnapshotLocal::getSnapshotType() { return LLSnapshotModel::SNAPSHOT_LOCAL; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d4eecaffce..9431914ba3 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1741,14 +1741,22 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset buffer[file_length] = 0; preview->mScriptEd->setScriptText(LLStringExplicit(&buffer[0]), TRUE); preview->mScriptEd->mEditor->makePristine(); + + std::string script_name = DEFAULT_SCRIPT_NAME; LLInventoryItem* item = gInventory.getItem(*item_uuid); BOOL is_modifiable = FALSE; - if(item - && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), - GP_OBJECT_MANIPULATE)) + if (item) { - is_modifiable = TRUE; + if (!item->getName().empty()) + { + script_name = item->getName(); + } + if (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) + { + is_modifiable = TRUE; + } } + preview->mScriptEd->setScriptName(script_name); preview->mScriptEd->setEnableEditing(is_modifiable); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index f73722521a..f03c7abc4d 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -1130,6 +1130,8 @@ static U8 string_value_to_click_action(std::string p_value) return CLICK_ACTION_OPEN; if (p_value == "Zoom") return CLICK_ACTION_ZOOM; + if (p_value == "None") + return CLICK_ACTION_DISABLED; return CLICK_ACTION_TOUCH; } diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index ee8b2d79c0..d0cff1464b 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -70,6 +70,7 @@ S32 BORDER_WIDTH = 6; const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList; +LLPointer<LLImageFormatted> LLSnapshotLivePreview::sSaveLocalImage = NULL; LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p) : LLView(p), @@ -131,6 +132,7 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview() // gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); sList.erase(this); + sSaveLocalImage = NULL; } void LLSnapshotLivePreview::setMaxImageSize(S32 size) @@ -1065,53 +1067,19 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) mDataSize = 0; } -BOOL LLSnapshotLivePreview::saveLocal() +void LLSnapshotLivePreview::saveLocal(const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) { // Update mFormattedImage if necessary getFormattedImage(); // Save the formatted image - BOOL success = saveLocal(mFormattedImage); - - if(success) - { - gViewerWindow->playSnapshotAnimAndSound(); - } - return success; + saveLocal(mFormattedImage, success_cb, failure_cb); } //Check if failed due to insufficient memory -BOOL LLSnapshotLivePreview::saveLocal(LLPointer<LLImageFormatted> mFormattedImage) +void LLSnapshotLivePreview::saveLocal(LLPointer<LLImageFormatted> image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) { - BOOL insufficient_memory; - BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage, FALSE, insufficient_memory); + sSaveLocalImage = image; - if (insufficient_memory) - { - std::string lastSnapshotDir = LLViewerWindow::getLastSnapshotDir(); - -#ifdef LL_WINDOWS - boost::filesystem::path b_path(utf8str_to_utf16str(lastSnapshotDir)); -#else - boost::filesystem::path b_path(lastSnapshotDir); -#endif - boost::filesystem::space_info b_space = boost::filesystem::space(b_path); - if (b_space.free < mFormattedImage->getDataSize()) - { - LLSD args; - args["PATH"] = lastSnapshotDir; - - std::string needM_bytes_string; - LLResMgr::getInstance()->getIntegerString(needM_bytes_string, (mFormattedImage->getDataSize()) >> 10); - args["NEED_MEMORY"] = needM_bytes_string; - - std::string freeM_bytes_string; - LLResMgr::getInstance()->getIntegerString(freeM_bytes_string, (b_space.free) >> 10); - args["FREE_MEMORY"] = freeM_bytes_string; - - LLNotificationsUtil::add("SnapshotToComputerFailed", args); - return false; - } - } - return success; + gViewerWindow->saveImageNumbered(sSaveLocalImage, FALSE, success_cb, failure_cb); } diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h index 4ea8d25a5a..683cd016d8 100644 --- a/indra/newview/llsnapshotlivepreview.h +++ b/indra/newview/llsnapshotlivepreview.h @@ -40,8 +40,9 @@ class LLSnapshotLivePreview : public LLView { LOG_CLASS(LLSnapshotLivePreview); public: + typedef boost::signals2::signal<void(void)> snapshot_saved_signal_t; - static BOOL saveLocal(LLPointer<LLImageFormatted>); + static void saveLocal(LLPointer<LLImageFormatted> image, const snapshot_saved_signal_t::slot_type& success_cb = snapshot_saved_signal_t(), const snapshot_saved_signal_t::slot_type& failure_cb = snapshot_saved_signal_t()); struct Params : public LLInitParam::Block<Params, LLView::Params> { Params() @@ -101,7 +102,7 @@ public: std::string getFilter() const { return mFilterName; } void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); void saveTexture(BOOL outfit_snapshot = FALSE, std::string name = ""); - BOOL saveLocal(); + void saveLocal(const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb); LLPointer<LLImageFormatted> getFormattedImage(); LLPointer<LLImageRaw> getEncodedImage(); @@ -170,7 +171,9 @@ private: LLQuaternion mCameraRot; BOOL mSnapshotActive; LLSnapshotModel::ESnapshotLayerType mSnapshotBufferType; - std::string mFilterName; + std::string mFilterName; + + static LLPointer<LLImageFormatted> sSaveLocalImage; public: static std::set<LLSnapshotLivePreview*> sList; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2a0d961952..dd5dce3279 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -2027,13 +2027,15 @@ bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 dis if(w * h *c > 0) //valid { //make a duplicate to keep the original raw image untouched. - raw = raw->scaled(w, h); + raw = raw->duplicate(); if (raw->isBufferInvalid()) { LL_WARNS() << "Invalid image duplicate buffer" << LL_ENDL; return false; } + raw->scale(w, h); + discardlevel += i ; } } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 9fb53dc9ab..0f38cca56f 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -263,7 +263,7 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_CLOTHING, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_OBJECT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv, &LLToolDragAndDrop::dad3dGiveInventoryObject, &LLToolDragAndDrop::dad3dRezObjectOnObject, &LLToolDragAndDrop::dad3dRezObjectOnLand)); addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); - addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL)); + addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dRezCategoryOnObject, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); @@ -2335,6 +2335,21 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( return rv; } + +EAcceptance LLToolDragAndDrop::dad3dRezCategoryOnObject( + LLViewerObject* obj, S32 face, MASK mask, BOOL drop) +{ + if ((mask & MASK_CONTROL)) + { + return dad3dUpdateInventoryCategory(obj, face, mask, drop); + } + else + { + return ACCEPT_NO; + } +} + + BOOL LLToolDragAndDrop::dadUpdateInventoryCategory(LLViewerObject* obj, BOOL drop) { diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 2d99de2244..24a712029c 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -162,6 +162,8 @@ protected: MASK mask, BOOL drop); EAcceptance dad3dRezObjectOnObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop); + EAcceptance dad3dRezCategoryOnObject(LLViewerObject* obj, S32 face, + MASK mask, BOOL drop); EAcceptance dad3dRezScript(LLViewerObject* obj, S32 face, MASK mask, BOOL drop); EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face, diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index f473000657..6a8843cb44 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -300,6 +300,8 @@ BOOL LLToolPie::handleLeftClickPick() } } return TRUE; + case CLICK_ACTION_DISABLED: + return TRUE; default: // nothing break; @@ -463,6 +465,8 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object) case CLICK_ACTION_OPEN_MEDIA: cursor = cursor_from_parcel_media(click_action); break; + case CLICK_ACTION_DISABLED: + break; default: break; } @@ -528,6 +532,8 @@ void LLToolPie::selectionPropertiesReceived() case CLICK_ACTION_OPEN: LLFloaterReg::showInstance("openobject"); break; + case CLICK_ACTION_DISABLED: + break; default: break; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index dc05d98228..cf1c442ce9 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -203,38 +203,55 @@ void LLFilePickerThread::clearDead() } } -LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple) +LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb) : LLFilePickerThread(filter, get_multiple), mLoadFilter(filter), mSaveFilter(LLFilePicker::FFSAVE_ALL), - mFilePickedSignal(NULL) + mFilePickedSignal(NULL), + mFailureSignal(NULL) { mFilePickedSignal = new file_picked_signal_t(); mFilePickedSignal->connect(cb); + + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } -LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name) +LLFilePickerReplyThread::LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb) : LLFilePickerThread(filter, proposed_name), mLoadFilter(LLFilePicker::FFLOAD_ALL), mSaveFilter(filter), - mFilePickedSignal(NULL) + mFilePickedSignal(NULL), + mFailureSignal(NULL) { mFilePickedSignal = new file_picked_signal_t(); mFilePickedSignal->connect(cb); + + mFailureSignal = new file_picked_signal_t(); + mFailureSignal->connect(failure_cb); } LLFilePickerReplyThread::~LLFilePickerReplyThread() { delete mFilePickedSignal; + delete mFailureSignal; } void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames) { - if (filenames.empty()) return; - - if (mFilePickedSignal) + if (filenames.empty()) + { + if (mFailureSignal) + { + (*mFailureSignal)(filenames, mLoadFilter, mSaveFilter); + } + } + else { - (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); + if (mFilePickedSignal) + { + (*mFilePickedSignal)(filenames, mLoadFilter, mSaveFilter); + } } } @@ -592,7 +609,6 @@ class LLFileTakeSnapshotToDisk : public view_listener_t gSavedSettings.getBOOL("RenderUIInSnapshot"), FALSE)) { - gViewerWindow->playSnapshotAnimAndSound(); LLPointer<LLImageFormatted> formatted; LLSnapshotModel::ESnapshotFormat fmt = (LLSnapshotModel::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); switch (fmt) diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 15bbdd1e2d..35f86f606b 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -113,8 +113,8 @@ public: typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; - LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple); - LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name); + LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); + LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); ~LLFilePickerReplyThread(); virtual void notify(const std::vector<std::string>& filenames); @@ -123,6 +123,7 @@ private: LLFilePicker::ELoadFilter mLoadFilter; LLFilePicker::ESaveFilter mSaveFilter; file_picked_signal_t* mFilePickedSignal; + file_picked_signal_t* mFailureSignal; }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0f326efe09..4180da17c2 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -153,6 +153,96 @@ const U8 AU_FLAGS_NONE = 0x00; const U8 AU_FLAGS_HIDETITLE = 0x01; const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; +void accept_friendship_coro(std::string url, LLSD notification) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("friendshipResponceErrorProcessing", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + if (url.empty()) + { + LL_WARNS() << "Empty capability!" << LL_ENDL; + return; + } + + LLSD payload = notification["payload"]; + url += "?from=" + payload["from_id"].asString(); + url += "&agent_name=\"" + LLURI::escape(gAgentAvatarp->getFullname()) + "\""; + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "HTTP status, " << status.toTerseString() << + ". friendship offer accept failed." << LL_ENDL; + } + else + { + if (!result.has("success") || result["success"].asBoolean() == false) + { + LL_WARNS() << "Server failed to process accepted friendship. " << httpResults << LL_ENDL; + } + else + { + // add friend to recent people list + LLRecentPeople::instance().add(payload["from_id"]); + + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + } +} + +void decline_friendship_coro(std::string url, LLSD notification, S32 option) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("friendshipResponceErrorProcessing", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + if (url.empty()) + { + LL_WARNS() << "Empty capability!" << LL_ENDL; + return; + } + + LLSD payload = notification["payload"]; + url += "?from=" + payload["from_id"].asString(); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "HTTP status, " << status.toTerseString() << + ". friendship offer decline failed." << LL_ENDL; + } + else + { + if (!result.has("success") || result["success"].asBoolean() == false) + { + LL_WARNS() << "Server failed to process declined friendship. " << httpResults << LL_ENDL; + } + else + { + if (option == 1) + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + else if (option == 2) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } + } +} + bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -163,9 +253,6 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) // this will be skipped if the user offering friendship is blocked if (notification_ptr) { - // add friend to recent people list - LLRecentPeople::instance().add(payload["from_id"]); - switch(option) { case 0: @@ -176,46 +263,73 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(payload["sender"].asString())); - - LLSD payload = notification["payload"]; - LLNotificationsUtil::add("FriendshipAcceptedByMe", - notification["substitutions"], payload); + std::string url = gAgent.getRegionCapability("AcceptFriendship"); + if (!url.empty()) + { + LLCoros::instance().launch("LLMessageSystem::acceptFriendshipOffer", + boost::bind(accept_friendship_coro, url, notification)); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + msg->newMessageFast(_PREHASH_AcceptFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(payload["sender"].asString())); + + // add friend to recent people list + LLRecentPeople::instance().add(payload["from_id"]); + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + else + { + LL_WARNS() << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } break; } case 1: // Decline - { - LLSD payload = notification["payload"]; - LLNotificationsUtil::add("FriendshipDeclinedByMe", - notification["substitutions"], payload); - } // fall-through case 2: // Send IM - decline and start IM session { // decline // We no longer notify other viewers, but we DO still send - // the rejection to the simulator to delete the pending userop. - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->sendReliable(LLHost(payload["sender"].asString())); - - // start IM session - if(2 == option) - { - LLAvatarActions::startIM(payload["from_id"].asUUID()); - } + // the rejection to the simulator to delete the pending userop. + std::string url = gAgent.getRegionCapability("DeclineFriendship"); + if (!url.empty()) + { + LLCoros::instance().launch("LLMessageSystem::declineFriendshipOffer", + boost::bind(decline_friendship_coro, url, notification, option)); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + msg->newMessageFast(_PREHASH_DeclineFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->sendReliable(LLHost(payload["sender"].asString())); + + if (option == 1) // due to fall-through + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + else if (option == 2) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } + else + { + LL_WARNS() << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } } default: // close button probably, possibly timed out diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 6937d064f9..9f6d606a22 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -63,7 +63,7 @@ const std::string GRID_LOGIN_IDENTIFIER_TYPES = "login_identifier_types"; const std::string GRID_SLURL_BASE = "slurl_base"; const std::string GRID_APP_SLURL_BASE = "app_slurl_base"; -const std::string DEFAULT_LOGIN_PAGE = "http://viewer-login.agni.lindenlab.com/"; +const std::string DEFAULT_LOGIN_PAGE = "https://viewer-splash.secondlife.com/"; const std::string MAIN_GRID_LOGIN_URI = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index feaafad2e1..832dcc2dd8 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1877,7 +1877,7 @@ void LLViewerRegion::updateNetStats() mLastPacketsLost = mPacketsLost; mPacketsIn = cdp->getPacketsIn(); - mBitsIn = cdp->getBytesIn(); + mBitsIn = 8 * cdp->getBytesIn(); mPacketsOut = cdp->getPacketsOut(); mPacketsLost = cdp->getPacketsLost(); mPingDelay = cdp->getPingDelay(); @@ -2817,6 +2817,7 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { capabilityNames.append("AbuseCategories"); + capabilityNames.append("AcceptFriendship"); capabilityNames.append("AgentPreferences"); capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); @@ -2826,6 +2827,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); + capabilityNames.append("DeclineFriendship"); capabilityNames.append("DispatchRegionInfo"); capabilityNames.append("DirectDelivery"); capabilityNames.append("EnvironmentSettings"); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f394d6913f..cef19c9c2d 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -193,6 +193,7 @@ #include "llviewerdisplay.h" #include "llspatialpartition.h" #include "llviewerjoystick.h" +#include "llviewermenufile.h" // LLFilePickerReplyThread #include "llviewernetwork.h" #include "llpostprocess.h" #include "llfloaterimnearbychat.h" @@ -4365,77 +4366,110 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picker, BOOL& insufficient_memory) +void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picker, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) { - insufficient_memory = FALSE; - if (!image) { LL_WARNS() << "No image to save" << LL_ENDL; - return FALSE; + return; } - - LLFilePicker::ESaveFilter pick_type; std::string extension("." + image->getExtension()); - if (extension == ".j2c") - pick_type = LLFilePicker::FFSAVE_J2C; - else if (extension == ".bmp") - pick_type = LLFilePicker::FFSAVE_BMP; - else if (extension == ".jpg") - pick_type = LLFilePicker::FFSAVE_JPEG; - else if (extension == ".png") - pick_type = LLFilePicker::FFSAVE_PNG; - else if (extension == ".tga") - pick_type = LLFilePicker::FFSAVE_TGA; - else - pick_type = LLFilePicker::FFSAVE_ALL; // ??? - - BOOL is_snapshot_name_loc_set = isSnapshotLocSet(); - + LLImageFormatted* formatted_image = image; // Get a base file location if needed. if (force_picker || !isSnapshotLocSet()) { - std::string proposed_name( sSnapshotBaseName ); + std::string proposed_name(sSnapshotBaseName); // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. + LLFilePicker::ESaveFilter pick_type; + + if (extension == ".j2c") + pick_type = LLFilePicker::FFSAVE_J2C; + else if (extension == ".bmp") + pick_type = LLFilePicker::FFSAVE_BMP; + else if (extension == ".jpg") + pick_type = LLFilePicker::FFSAVE_JPEG; + else if (extension == ".png") + pick_type = LLFilePicker::FFSAVE_PNG; + else if (extension == ".tga") + pick_type = LLFilePicker::FFSAVE_TGA; + else + pick_type = LLFilePicker::FFSAVE_ALL; - // pick a directory in which to save - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(pick_type, proposed_name)) - { - // Clicked cancel - return FALSE; - } + (new LLFilePickerReplyThread(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name, + boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb)))->getFile(); + } + else + { + saveImageLocal(formatted_image, success_cb, failure_cb); + } +} + +void LLViewerWindow::onDirectorySelected(const std::vector<std::string>& filenames, LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) +{ + // Copy the directory + file name + std::string filepath = filenames[0]; - // Copy the directory + file name - std::string filepath = picker.getFirstFile(); + gSavedPerAccountSettings.setString("SnapshotBaseName", gDirUtilp->getBaseFileName(filepath, true)); + gSavedPerAccountSettings.setString("SnapshotBaseDir", gDirUtilp->getDirName(filepath)); + saveImageLocal(image, success_cb, failure_cb); +} - gSavedPerAccountSettings.setString("SnapshotBaseName", gDirUtilp->getBaseFileName(filepath, true)); - gSavedPerAccountSettings.setString("SnapshotBaseDir", gDirUtilp->getDirName(filepath)); - } +void LLViewerWindow::onSelectionFailure(const snapshot_saved_signal_t::slot_type& failure_cb) +{ + failure_cb(); +} - std::string snapshot_dir = sSnapshotDir; - if(snapshot_dir.empty()) + +void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb) +{ + std::string lastSnapshotDir = LLViewerWindow::getLastSnapshotDir(); + if (lastSnapshotDir.empty()) { - return FALSE; + failure_cb(); + return; } // Check if there is enough free space to save snapshot #ifdef LL_WINDOWS - boost::filesystem::space_info b_space = boost::filesystem::space(utf8str_to_utf16str(snapshot_dir)); + boost::filesystem::path b_path(utf8str_to_utf16str(lastSnapshotDir)); #else - boost::filesystem::space_info b_space = boost::filesystem::space(snapshot_dir); + boost::filesystem::path b_path(lastSnapshotDir); #endif + if (!boost::filesystem::is_directory(b_path)) + { + LLSD args; + args["PATH"] = lastSnapshotDir; + LLNotificationsUtil::add("SnapshotToLocalDirNotExist", args); + resetSnapshotLoc(); + failure_cb(); + return; + } + boost::filesystem::space_info b_space = boost::filesystem::space(b_path); if (b_space.free < image->getDataSize()) { - insufficient_memory = TRUE; - return FALSE; + LLSD args; + args["PATH"] = lastSnapshotDir; + + std::string needM_bytes_string; + LLResMgr::getInstance()->getIntegerString(needM_bytes_string, (image->getDataSize()) >> 10); + args["NEED_MEMORY"] = needM_bytes_string; + + std::string freeM_bytes_string; + LLResMgr::getInstance()->getIntegerString(freeM_bytes_string, (b_space.free) >> 10); + args["FREE_MEMORY"] = freeM_bytes_string; + + LLNotificationsUtil::add("SnapshotToComputerFailed", args); + + failure_cb(); } + // Look for an unused file name + BOOL is_snapshot_name_loc_set = isSnapshotLocSet(); std::string filepath; S32 i = 1; S32 err = 0; - + std::string extension("." + image->getExtension()); do { filepath = sSnapshotDir; @@ -4457,7 +4491,15 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picke && is_snapshot_name_loc_set); // Or stop if we are rewriting. LL_INFOS() << "Saving snapshot to " << filepath << LL_ENDL; - return image->save(filepath); + if (image->save(filepath)) + { + playSnapshotAnimAndSound(); + success_cb(); + } + else + { + failure_cb(); + } } void LLViewerWindow::resetSnapshotLoc() diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index c01921641c..d8d420e6be 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -352,7 +352,13 @@ public: BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; - BOOL saveImageNumbered(LLImageFormatted *image, BOOL force_picker, BOOL& insufficient_memory); + + typedef boost::signals2::signal<void(void)> snapshot_saved_signal_t; + + void saveImageNumbered(LLImageFormatted *image, BOOL force_picker, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb); + void onDirectorySelected(const std::vector<std::string>& filenames, LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb); + void saveImageLocal(LLImageFormatted *image, const snapshot_saved_signal_t::slot_type& success_cb, const snapshot_saved_signal_t::slot_type& failure_cb); + void onSelectionFailure(const snapshot_saved_signal_t::slot_type& failure_cb); // Reset the directory where snapshots are saved. // Client will open directory picker on next snapshot save. diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index da4b6a5008..6a3242b43f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6193,6 +6193,7 @@ void LLVivoxVoiceClient::expireVoiceFonts() LLSD args; args["URL"] = LLTrans::getString("voice_morphing_url"); + args["PREMIUM_URL"] = LLTrans::getString("premium_voice_morphing_url"); // Give a notification if any voice fonts have expired. if (have_expired) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index ed3cc26851..bdcf3648fa 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1115,6 +1115,10 @@ label="Zoom" name="Zoom" value="Zoom" /> + <combo_box.item + label="None" + name="None" + value="None" /> </combo_box> <check_box height="23" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 7f9dc0c41f..6b164c660a 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8102,6 +8102,8 @@ Failed to connect to [VOICE_CHANNEL_NAME], please try again later. You will now <unique/> One or more of your subscribed Voice Morphs has expired. [[URL] Click here] to renew your subscription. + +If you are a Premium Member, [[PREMIUM_URL] click here] to receive your voice morphing perk. <tag>fail</tag> <tag>voice</tag> </notification> @@ -8115,6 +8117,8 @@ One or more of your subscribed Voice Morphs has expired. <unique/> The active Voice Morph has expired, your normal voice settings have been applied. [[URL] Click here] to renew your subscription. + +If you are a Premium Member, [[PREMIUM_URL] click here] to receive your voice morphing perk. <tag>fail</tag> <tag>voice</tag> </notification> @@ -8128,6 +8132,8 @@ The active Voice Morph has expired, your normal voice settings have been applied <unique/> One or more of your Voice Morphs will expire in less than [INTERVAL] days. [[URL] Click here] to renew your subscription. + +If you are a Premium Member, [[PREMIUM_URL] click here] to receive your voice morphing perk. <tag>fail</tag> <tag>voice</tag> </notification> @@ -8260,6 +8266,11 @@ Failed to save appearance to XML. Failed to save snapshot to [PATH]: Disk is full. [NEED_MEMORY]KB is required but only [FREE_MEMORY]KB is free. </notification> + <notification icon="notifytip.tga" + name="SnapshotToLocalDirNotExist" type="notifytip"> +Failed to save snapshot to [PATH]: Directory does not exist. + </notification> + <notification icon="notifytip.tga" name="PresetNotSaved" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 3a34bcbe21..7759d4fdb2 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -12,6 +12,10 @@ name="forgot_password_url"> http://secondlife.com/account/request.php </panel.string> + <panel.string + name="sign_up_url"> + https://join.secondlife.com/ + </panel.string> <layout_stack follows="left|right|top" height="172" @@ -149,7 +153,18 @@ label="Select grid" layout="topleft" name="server_combo" - width="149" /> + width="149" /> + <text + follows="left|top" + font="SansSerifMedium" + text_color="EmphasisColor" + height="16" + name="sign_up_text" + left="778" + bottom_delta="-10" + width="200"> + Sign up + </text> </layout_panel> <layout_panel height="172" diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index 35b80c56ab..213f9a6b0c 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -12,6 +12,10 @@ name="forgot_password_url"> http://secondlife.com/account/request.php </panel.string> + <panel.string + name="sign_up_url"> + https://join.secondlife.com/ + </panel.string> <layout_stack follows="left|right|top|bottom" width="1024" @@ -168,6 +172,17 @@ width="200"> Forgotten password </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="EmphasisColor" + height="16" + name="sign_up_text" + left="432" + top="34" + width="200"> + Sign up + </text> </layout_panel> <layout_panel height="100" diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index b84dce222f..efedb9559e 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -292,10 +292,14 @@ label="Open" name="Open" value="Open" /> - <combo_box.item - label="Zoom" - name="Zoom" - value="Zoom" /> + <combo_box.item + label="Zoom" + name="Zoom" + value="Zoom" /> + <combo_box.item + label="None" + name="None" + value="None" /> </combo_box> <panel border="false" diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp index 3dd327591e..d1dddf8e7e 100644 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ b/indra/newview/tests/llviewernetwork_test.cpp @@ -236,7 +236,7 @@ namespace tut std::string("https://secondlife.com/helpers/")); ensure_equals("Agni login page", LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"), - std::string("http://viewer-login.agni.lindenlab.com/")); + std::string("https://viewer-splash.secondlife.com/")); ensure("Agni is a system grid", LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); @@ -261,7 +261,7 @@ namespace tut std::string("http://aditi-secondlife.webdev.lindenlab.com/helpers/")); ensure_equals("Aditi login page", LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), - std::string("http://viewer-login.agni.lindenlab.com/")); + std::string("https://viewer-splash.secondlife.com/")); ensure("Aditi is a system grid", LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); } @@ -309,7 +309,7 @@ namespace tut std::string("https://secondlife.com/helpers/")); ensure_equals("Agni login page", LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"), - std::string("http://viewer-login.agni.lindenlab.com/")); + std::string("https://viewer-splash.secondlife.com/")); ensure("Agni is a system grid", LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); @@ -333,7 +333,7 @@ namespace tut std::string("http://aditi-secondlife.webdev.lindenlab.com/helpers/")); ensure_equals("Aditi login page", LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), - std::string("http://viewer-login.agni.lindenlab.com/")); + std::string("https://viewer-splash.secondlife.com/")); ensure("Aditi is a system grid", LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); @@ -422,7 +422,7 @@ namespace tut std::string("https://secondlife.com/helpers/")); ensure_equals("getLoginPage", LLGridManager::getInstance()->getLoginPage(), - std::string("http://viewer-login.agni.lindenlab.com/")); + std::string("https://viewer-splash.secondlife.com/")); ensure_equals("update url base for Agni", // relies on agni being the default std::string("https://update.secondlife.com/update"), LLGridManager::getInstance()->getUpdateServiceURL()); |